1*17314648SMatthew G. Knepley #include "petscdm.h" 2*17314648SMatthew G. Knepley #include "petscerror.h" 3af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 4da97024aSMatthew G. Knepley #include <petscsf.h> 5cb1e1211SMatthew G Knepley 68e3a2eefSMatthew G. Knepley #include <petscblaslapack.h> 7e8f14785SLisandro Dalcin #include <petsc/private/hashsetij.h> 8af0996ceSBarry Smith #include <petsc/private/petscfeimpl.h> 9af0996ceSBarry Smith #include <petsc/private/petscfvimpl.h> 10a0845e3aSMatthew G. Knepley 115f0b18bfSMatthew G. Knepley PetscBool Clementcite = PETSC_FALSE; 125f0b18bfSMatthew G. Knepley const char ClementCitation[] = "@article{clement1975approximation,\n" 135f0b18bfSMatthew G. Knepley " title = {Approximation by finite element functions using local regularization},\n" 145f0b18bfSMatthew G. Knepley " author = {Philippe Cl{\\'e}ment},\n" 155f0b18bfSMatthew G. Knepley " journal = {Revue fran{\\c{c}}aise d'automatique, informatique, recherche op{\\'e}rationnelle. Analyse num{\\'e}rique},\n" 165f0b18bfSMatthew G. Knepley " volume = {9},\n" 175f0b18bfSMatthew G. Knepley " number = {R2},\n" 185f0b18bfSMatthew G. Knepley " pages = {77--84},\n" 195f0b18bfSMatthew G. Knepley " year = {1975}\n}\n"; 205f0b18bfSMatthew G. Knepley 21d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexConvertPlex(DM dm, DM *plex, PetscBool copy) 22d71ae5a4SJacob Faibussowitsch { 232f856554SMatthew G. Knepley PetscBool isPlex; 242f856554SMatthew G. Knepley 252f856554SMatthew G. Knepley PetscFunctionBegin; 269566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex)); 272f856554SMatthew G. Knepley if (isPlex) { 282f856554SMatthew G. Knepley *plex = dm; 299566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)dm)); 302f856554SMatthew G. Knepley } else { 319566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex)); 322f856554SMatthew G. Knepley if (!*plex) { 339566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, plex)); 349566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex)); 35cbf8eb3cSStefano Zampini } else { 36cbf8eb3cSStefano Zampini PetscCall(PetscObjectReference((PetscObject)*plex)); 37cbf8eb3cSStefano Zampini } 382f856554SMatthew G. Knepley if (copy) { 392f856554SMatthew G. Knepley DMSubDomainHookLink link; 409a2a23afSMatthew G. Knepley 41bb4b53efSMatthew G. Knepley PetscCall(DMCopyDS(dm, PETSC_DETERMINE, PETSC_DETERMINE, *plex)); 429566063dSJacob Faibussowitsch PetscCall(DMCopyAuxiliaryVec(dm, *plex)); 439a2a23afSMatthew G. Knepley /* Run the subdomain hook (this will copy the DMSNES/DMTS) */ 442f856554SMatthew G. Knepley for (link = dm->subdomainhook; link; link = link->next) { 459566063dSJacob Faibussowitsch if (link->ddhook) PetscCall((*link->ddhook)(dm, *plex, link->ctx)); 462f856554SMatthew G. Knepley } 472f856554SMatthew G. Knepley } 482f856554SMatthew G. Knepley } 493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 502f856554SMatthew G. Knepley } 512f856554SMatthew G. Knepley 5249abdd8aSBarry Smith static PetscErrorCode PetscContainerCtxDestroy_PetscFEGeom(void **ctx) 53d71ae5a4SJacob Faibussowitsch { 5449abdd8aSBarry Smith PetscFEGeom *geom = (PetscFEGeom *)*ctx; 559b6f715bSMatthew G. Knepley 569b6f715bSMatthew G. Knepley PetscFunctionBegin; 579566063dSJacob Faibussowitsch PetscCall(PetscFEGeomDestroy(&geom)); 583ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 599b6f715bSMatthew G. Knepley } 609b6f715bSMatthew G. Knepley 61d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 62d71ae5a4SJacob Faibussowitsch { 639b6f715bSMatthew G. Knepley char composeStr[33] = {0}; 649b6f715bSMatthew G. Knepley PetscObjectId id; 659b6f715bSMatthew G. Knepley PetscContainer container; 669b6f715bSMatthew G. Knepley 679b6f715bSMatthew G. Knepley PetscFunctionBegin; 689566063dSJacob Faibussowitsch PetscCall(PetscObjectGetId((PetscObject)quad, &id)); 6963a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(composeStr, 32, "DMPlexGetFEGeom_%" PetscInt64_FMT "\n", id)); 709566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)pointIS, composeStr, (PetscObject *)&container)); 719b6f715bSMatthew G. Knepley if (container) { 729566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(container, (void **)geom)); 739b6f715bSMatthew G. Knepley } else { 749566063dSJacob Faibussowitsch PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom)); 759566063dSJacob Faibussowitsch PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container)); 769566063dSJacob Faibussowitsch PetscCall(PetscContainerSetPointer(container, (void *)*geom)); 7749abdd8aSBarry Smith PetscCall(PetscContainerSetCtxDestroy(container, PetscContainerCtxDestroy_PetscFEGeom)); 789566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)pointIS, composeStr, (PetscObject)container)); 799566063dSJacob Faibussowitsch PetscCall(PetscContainerDestroy(&container)); 809b6f715bSMatthew G. Knepley } 813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 829b6f715bSMatthew G. Knepley } 839b6f715bSMatthew G. Knepley 84d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 85d71ae5a4SJacob Faibussowitsch { 869b6f715bSMatthew G. Knepley PetscFunctionBegin; 879b6f715bSMatthew G. Knepley *geom = NULL; 883ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 899b6f715bSMatthew G. Knepley } 909b6f715bSMatthew G. Knepley 9146fa42a0SMatthew G. Knepley /*@ 9246fa42a0SMatthew G. Knepley DMPlexGetScale - Get the scale for the specified fundamental unit 9346fa42a0SMatthew G. Knepley 9420f4b53cSBarry Smith Not Collective 9546fa42a0SMatthew G. Knepley 964165533cSJose E. Roman Input Parameters: 97a1cb98faSBarry Smith + dm - the `DM` 9846fa42a0SMatthew G. Knepley - unit - The SI unit 9946fa42a0SMatthew G. Knepley 1004165533cSJose E. Roman Output Parameter: 10146fa42a0SMatthew G. Knepley . scale - The value used to scale all quantities with this unit 10246fa42a0SMatthew G. Knepley 10346fa42a0SMatthew G. Knepley Level: advanced 10446fa42a0SMatthew G. Knepley 1051cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetScale()`, `PetscUnit` 10646fa42a0SMatthew G. Knepley @*/ 107d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale) 108d71ae5a4SJacob Faibussowitsch { 109cb1e1211SMatthew G Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 110cb1e1211SMatthew G Knepley 111cb1e1211SMatthew G Knepley PetscFunctionBegin; 112cb1e1211SMatthew G Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1134f572ea9SToby Isaac PetscAssertPointer(scale, 3); 114cb1e1211SMatthew G Knepley *scale = mesh->scale[unit]; 1153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 116cb1e1211SMatthew G Knepley } 117cb1e1211SMatthew G Knepley 11846fa42a0SMatthew G. Knepley /*@ 11946fa42a0SMatthew G. Knepley DMPlexSetScale - Set the scale for the specified fundamental unit 12046fa42a0SMatthew G. Knepley 12120f4b53cSBarry Smith Not Collective 12246fa42a0SMatthew G. Knepley 1234165533cSJose E. Roman Input Parameters: 124a1cb98faSBarry Smith + dm - the `DM` 12546fa42a0SMatthew G. Knepley . unit - The SI unit 12646fa42a0SMatthew G. Knepley - scale - The value used to scale all quantities with this unit 12746fa42a0SMatthew G. Knepley 12846fa42a0SMatthew G. Knepley Level: advanced 12946fa42a0SMatthew G. Knepley 1301cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetScale()`, `PetscUnit` 13146fa42a0SMatthew G. Knepley @*/ 132d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale) 133d71ae5a4SJacob Faibussowitsch { 134cb1e1211SMatthew G Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 135cb1e1211SMatthew G Knepley 136cb1e1211SMatthew G Knepley PetscFunctionBegin; 137cb1e1211SMatthew G Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 138cb1e1211SMatthew G Knepley mesh->scale[unit] = scale; 1393ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 140cb1e1211SMatthew G Knepley } 141cb1e1211SMatthew G Knepley 142d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexGetUseCeed_Plex(DM dm, PetscBool *useCeed) 143d2b2dc1eSMatthew G. Knepley { 144d2b2dc1eSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 145d2b2dc1eSMatthew G. Knepley 146d2b2dc1eSMatthew G. Knepley PetscFunctionBegin; 147d2b2dc1eSMatthew G. Knepley *useCeed = mesh->useCeed; 148d2b2dc1eSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 149d2b2dc1eSMatthew G. Knepley } 150d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexSetUseCeed_Plex(DM dm, PetscBool useCeed) 151d2b2dc1eSMatthew G. Knepley { 152d2b2dc1eSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 153d2b2dc1eSMatthew G. Knepley 154d2b2dc1eSMatthew G. Knepley PetscFunctionBegin; 155d2b2dc1eSMatthew G. Knepley mesh->useCeed = useCeed; 156d2b2dc1eSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 157d2b2dc1eSMatthew G. Knepley } 158d2b2dc1eSMatthew G. Knepley 159d2b2dc1eSMatthew G. Knepley /*@ 160d2b2dc1eSMatthew G. Knepley DMPlexGetUseCeed - Get flag for using the LibCEED backend 161d2b2dc1eSMatthew G. Knepley 162d2b2dc1eSMatthew G. Knepley Not collective 163d2b2dc1eSMatthew G. Knepley 164d2b2dc1eSMatthew G. Knepley Input Parameter: 165d2b2dc1eSMatthew G. Knepley . dm - The `DM` 166d2b2dc1eSMatthew G. Knepley 167d2b2dc1eSMatthew G. Knepley Output Parameter: 168d2b2dc1eSMatthew G. Knepley . useCeed - The flag 169d2b2dc1eSMatthew G. Knepley 170d2b2dc1eSMatthew G. Knepley Level: intermediate 171d2b2dc1eSMatthew G. Knepley 172d2b2dc1eSMatthew G. Knepley .seealso: `DMPlexSetUseCeed()` 173d2b2dc1eSMatthew G. Knepley @*/ 174d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexGetUseCeed(DM dm, PetscBool *useCeed) 175d2b2dc1eSMatthew G. Knepley { 176d2b2dc1eSMatthew G. Knepley PetscFunctionBegin; 177d2b2dc1eSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 178d2b2dc1eSMatthew G. Knepley PetscAssertPointer(useCeed, 2); 179d2b2dc1eSMatthew G. Knepley *useCeed = PETSC_FALSE; 180d2b2dc1eSMatthew G. Knepley PetscTryMethod(dm, "DMPlexGetUseCeed_C", (DM, PetscBool *), (dm, useCeed)); 181d2b2dc1eSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 182d2b2dc1eSMatthew G. Knepley } 183d2b2dc1eSMatthew G. Knepley 184d2b2dc1eSMatthew G. Knepley /*@ 185d2b2dc1eSMatthew G. Knepley DMPlexSetUseCeed - Set flag for using the LibCEED backend 186d2b2dc1eSMatthew G. Knepley 187d2b2dc1eSMatthew G. Knepley Not collective 188d2b2dc1eSMatthew G. Knepley 189d2b2dc1eSMatthew G. Knepley Input Parameters: 190d2b2dc1eSMatthew G. Knepley + dm - The `DM` 191d2b2dc1eSMatthew G. Knepley - useCeed - The flag 192d2b2dc1eSMatthew G. Knepley 193d2b2dc1eSMatthew G. Knepley Level: intermediate 194d2b2dc1eSMatthew G. Knepley 195fe8e7dddSPierre Jolivet .seealso: `DMPlexGetUseCeed()` 196d2b2dc1eSMatthew G. Knepley @*/ 197d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexSetUseCeed(DM dm, PetscBool useCeed) 198d2b2dc1eSMatthew G. Knepley { 199d2b2dc1eSMatthew G. Knepley PetscFunctionBegin; 200d2b2dc1eSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 201d2b2dc1eSMatthew G. Knepley PetscValidLogicalCollectiveBool(dm, useCeed, 2); 202d2b2dc1eSMatthew G. Knepley PetscUseMethod(dm, "DMPlexSetUseCeed_C", (DM, PetscBool), (dm, useCeed)); 203d2b2dc1eSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 204d2b2dc1eSMatthew G. Knepley } 205d2b2dc1eSMatthew G. Knepley 206e8e188d2SZach Atkins /*@ 207e8e188d2SZach Atkins DMPlexGetUseMatClosurePermutation - Get flag for using a closure permutation for matrix insertion 208e8e188d2SZach Atkins 209e8e188d2SZach Atkins Not collective 210e8e188d2SZach Atkins 211e8e188d2SZach Atkins Input Parameter: 212e8e188d2SZach Atkins . dm - The `DM` 213e8e188d2SZach Atkins 214e8e188d2SZach Atkins Output Parameter: 215e8e188d2SZach Atkins . useClPerm - The flag 216e8e188d2SZach Atkins 217e8e188d2SZach Atkins Level: intermediate 218e8e188d2SZach Atkins 219e8e188d2SZach Atkins .seealso: `DMPlexSetUseMatClosurePermutation()` 220e8e188d2SZach Atkins @*/ 221e8e188d2SZach Atkins PetscErrorCode DMPlexGetUseMatClosurePermutation(DM dm, PetscBool *useClPerm) 222e8e188d2SZach Atkins { 223e8e188d2SZach Atkins DM_Plex *mesh = (DM_Plex *)dm->data; 224e8e188d2SZach Atkins 225e8e188d2SZach Atkins PetscFunctionBegin; 226e8e188d2SZach Atkins PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 227e8e188d2SZach Atkins PetscAssertPointer(useClPerm, 2); 228e8e188d2SZach Atkins *useClPerm = mesh->useMatClPerm; 229e8e188d2SZach Atkins PetscFunctionReturn(PETSC_SUCCESS); 230e8e188d2SZach Atkins } 231e8e188d2SZach Atkins 232e8e188d2SZach Atkins /*@ 233e8e188d2SZach Atkins DMPlexSetUseMatClosurePermutation - Set flag for using a closure permutation for matrix insertion 234e8e188d2SZach Atkins 235e8e188d2SZach Atkins Not collective 236e8e188d2SZach Atkins 237e8e188d2SZach Atkins Input Parameters: 238e8e188d2SZach Atkins + dm - The `DM` 239e8e188d2SZach Atkins - useClPerm - The flag 240e8e188d2SZach Atkins 241e8e188d2SZach Atkins Level: intermediate 242e8e188d2SZach Atkins 243e8e188d2SZach Atkins .seealso: `DMPlexGetUseMatClosurePermutation()` 244e8e188d2SZach Atkins @*/ 245e8e188d2SZach Atkins PetscErrorCode DMPlexSetUseMatClosurePermutation(DM dm, PetscBool useClPerm) 246e8e188d2SZach Atkins { 247e8e188d2SZach Atkins DM_Plex *mesh = (DM_Plex *)dm->data; 248e8e188d2SZach Atkins 249e8e188d2SZach Atkins PetscFunctionBegin; 250e8e188d2SZach Atkins PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 251e8e188d2SZach Atkins PetscValidLogicalCollectiveBool(dm, useClPerm, 2); 252e8e188d2SZach Atkins mesh->useMatClPerm = useClPerm; 253e8e188d2SZach Atkins PetscFunctionReturn(PETSC_SUCCESS); 254e8e188d2SZach Atkins } 255e8e188d2SZach Atkins 256d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexProjectRigidBody_Private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nc, PetscScalar *mode, void *ctx) 257d71ae5a4SJacob Faibussowitsch { 2589371c9d4SSatish Balay const PetscInt eps[3][3][3] = { 2599371c9d4SSatish Balay {{0, 0, 0}, {0, 0, 1}, {0, -1, 0}}, 2609371c9d4SSatish Balay {{0, 0, -1}, {0, 0, 0}, {1, 0, 0} }, 2619371c9d4SSatish Balay {{0, 1, 0}, {-1, 0, 0}, {0, 0, 0} } 2629371c9d4SSatish Balay }; 263026175e5SToby Isaac PetscInt *ctxInt = (PetscInt *)ctx; 264ad917190SMatthew G. Knepley PetscInt dim2 = ctxInt[0]; 265026175e5SToby Isaac PetscInt d = ctxInt[1]; 266026175e5SToby Isaac PetscInt i, j, k = dim > 2 ? d - dim : d; 267026175e5SToby Isaac 268ad917190SMatthew G. Knepley PetscFunctionBegin; 26963a3b9bcSJacob Faibussowitsch PetscCheck(dim == dim2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Input dimension %" PetscInt_FMT " does not match context dimension %" PetscInt_FMT, dim, dim2); 270026175e5SToby Isaac for (i = 0; i < dim; i++) mode[i] = 0.; 271026175e5SToby Isaac if (d < dim) { 27212adca46SMatthew G. Knepley mode[d] = 1.; /* Translation along axis d */ 273ad917190SMatthew G. Knepley } else { 274026175e5SToby Isaac for (i = 0; i < dim; i++) { 2759371c9d4SSatish Balay for (j = 0; j < dim; j++) { mode[j] += eps[i][j][k] * X[i]; /* Rotation about axis d */ } 276026175e5SToby Isaac } 277026175e5SToby Isaac } 2783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 279026175e5SToby Isaac } 280026175e5SToby Isaac 281cc4e42d9SMartin Diehl /*@ 28212adca46SMatthew G. Knepley DMPlexCreateRigidBody - For the default global section, create rigid body modes by function space interpolation 283cb1e1211SMatthew G Knepley 28420f4b53cSBarry Smith Collective 285cb1e1211SMatthew G Knepley 2864165533cSJose E. Roman Input Parameters: 287a1cb98faSBarry Smith + dm - the `DM` 28856cf3b9cSMatthew G. Knepley - field - The field number for the rigid body space, or 0 for the default 289cb1e1211SMatthew G Knepley 2904165533cSJose E. Roman Output Parameter: 291cb1e1211SMatthew G Knepley . sp - the null space 292cb1e1211SMatthew G Knepley 293cb1e1211SMatthew G Knepley Level: advanced 294cb1e1211SMatthew G Knepley 295a1cb98faSBarry Smith Note: 296a1cb98faSBarry Smith This is necessary to provide a suitable coarse space for algebraic multigrid 297a1cb98faSBarry Smith 2981cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `MatNullSpaceCreate()`, `PCGAMG` 299cb1e1211SMatthew G Knepley @*/ 300d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscInt field, MatNullSpace *sp) 301d71ae5a4SJacob Faibussowitsch { 30256cf3b9cSMatthew G. Knepley PetscErrorCode (**func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *); 303cb1e1211SMatthew G Knepley MPI_Comm comm; 304026175e5SToby Isaac Vec mode[6]; 305026175e5SToby Isaac PetscSection section, globalSection; 30656cf3b9cSMatthew G. Knepley PetscInt dim, dimEmbed, Nf, n, m, mmin, d, i, j; 307db14aad5SMatthew G. Knepley void **ctxs; 308cb1e1211SMatthew G Knepley 309cb1e1211SMatthew G Knepley PetscFunctionBegin; 3109566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 3119566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 3129566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &dimEmbed)); 3139566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 31463a3b9bcSJacob Faibussowitsch PetscCheck(!Nf || !(field < 0 || field >= Nf), comm, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", field, Nf); 31556cf3b9cSMatthew G. Knepley if (dim == 1 && Nf < 2) { 3169566063dSJacob Faibussowitsch PetscCall(MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp)); 3173ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 318cb1e1211SMatthew G Knepley } 3199566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 3209566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 3219566063dSJacob Faibussowitsch PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &n)); 322db14aad5SMatthew G. Knepley PetscCall(PetscCalloc2(Nf, &func, Nf, &ctxs)); 323b247467aSMatthew G. Knepley m = (dim * (dim + 1)) / 2; 3249566063dSJacob Faibussowitsch PetscCall(VecCreate(comm, &mode[0])); 3259566063dSJacob Faibussowitsch PetscCall(VecSetType(mode[0], dm->vectype)); 3269566063dSJacob Faibussowitsch PetscCall(VecSetSizes(mode[0], n, PETSC_DETERMINE)); 3279566063dSJacob Faibussowitsch PetscCall(VecSetUp(mode[0])); 3289566063dSJacob Faibussowitsch PetscCall(VecGetSize(mode[0], &n)); 329b247467aSMatthew G. Knepley mmin = PetscMin(m, n); 33056cf3b9cSMatthew G. Knepley func[field] = DMPlexProjectRigidBody_Private; 3319566063dSJacob Faibussowitsch for (i = 1; i < m; ++i) PetscCall(VecDuplicate(mode[0], &mode[i])); 332026175e5SToby Isaac for (d = 0; d < m; d++) { 333330485fdSToby Isaac PetscInt ctx[2]; 334cb1e1211SMatthew G Knepley 335db14aad5SMatthew G. Knepley ctxs[field] = (void *)(&ctx[0]); 3369d8fbdeaSMatthew G. Knepley ctx[0] = dimEmbed; 337330485fdSToby Isaac ctx[1] = d; 338db14aad5SMatthew G. Knepley PetscCall(DMProjectFunction(dm, 0.0, func, ctxs, INSERT_VALUES, mode[d])); 339cb1e1211SMatthew G Knepley } 3403b2202bfSJacob Faibussowitsch /* Orthonormalize system */ 341b50a2c0aSJacob Faibussowitsch for (i = 0; i < mmin; ++i) { 342b77f2eeeSJacob Faibussowitsch PetscScalar dots[6]; 343b50a2c0aSJacob Faibussowitsch 3449566063dSJacob Faibussowitsch PetscCall(VecNormalize(mode[i], NULL)); 3459566063dSJacob Faibussowitsch PetscCall(VecMDot(mode[i], mmin - i - 1, mode + i + 1, dots + i + 1)); 346b50a2c0aSJacob Faibussowitsch for (j = i + 1; j < mmin; ++j) { 347b77f2eeeSJacob Faibussowitsch dots[j] *= -1.0; 3489566063dSJacob Faibussowitsch PetscCall(VecAXPY(mode[j], dots[j], mode[i])); 349b50a2c0aSJacob Faibussowitsch } 350cb1e1211SMatthew G Knepley } 3519566063dSJacob Faibussowitsch PetscCall(MatNullSpaceCreate(comm, PETSC_FALSE, mmin, mode, sp)); 3529566063dSJacob Faibussowitsch for (i = 0; i < m; ++i) PetscCall(VecDestroy(&mode[i])); 353db14aad5SMatthew G. Knepley PetscCall(PetscFree2(func, ctxs)); 3543ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 355cb1e1211SMatthew G Knepley } 356cb1e1211SMatthew G Knepley 357cc4e42d9SMartin Diehl /*@ 35812adca46SMatthew G. Knepley DMPlexCreateRigidBodies - For the default global section, create rigid body modes by function space interpolation 35912adca46SMatthew G. Knepley 36020f4b53cSBarry Smith Collective 36112adca46SMatthew G. Knepley 3624165533cSJose E. Roman Input Parameters: 363a1cb98faSBarry Smith + dm - the `DM` 36412adca46SMatthew G. Knepley . nb - The number of bodies 365a1cb98faSBarry Smith . label - The `DMLabel` marking each domain 36612adca46SMatthew G. Knepley . nids - The number of ids per body 36712adca46SMatthew G. Knepley - ids - An array of the label ids in sequence for each domain 36812adca46SMatthew G. Knepley 3694165533cSJose E. Roman Output Parameter: 37012adca46SMatthew G. Knepley . sp - the null space 37112adca46SMatthew G. Knepley 37212adca46SMatthew G. Knepley Level: advanced 37312adca46SMatthew G. Knepley 374a1cb98faSBarry Smith Note: 375a1cb98faSBarry Smith This is necessary to provide a suitable coarse space for algebraic multigrid 376a1cb98faSBarry Smith 3771cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `MatNullSpaceCreate()` 37812adca46SMatthew G. Knepley @*/ 379d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRigidBodies(DM dm, PetscInt nb, DMLabel label, const PetscInt nids[], const PetscInt ids[], MatNullSpace *sp) 380d71ae5a4SJacob Faibussowitsch { 38112adca46SMatthew G. Knepley MPI_Comm comm; 38212adca46SMatthew G. Knepley PetscSection section, globalSection; 38312adca46SMatthew G. Knepley Vec *mode; 38412adca46SMatthew G. Knepley PetscScalar *dots; 38512adca46SMatthew G. Knepley PetscInt dim, dimEmbed, n, m, b, d, i, j, off; 38612adca46SMatthew G. Knepley 38712adca46SMatthew G. Knepley PetscFunctionBegin; 3889566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 3899566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 3909566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &dimEmbed)); 3919566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 3929566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 3939566063dSJacob Faibussowitsch PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &n)); 39412adca46SMatthew G. Knepley m = nb * (dim * (dim + 1)) / 2; 3959566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(m, &mode, m, &dots)); 3969566063dSJacob Faibussowitsch PetscCall(VecCreate(comm, &mode[0])); 3979566063dSJacob Faibussowitsch PetscCall(VecSetSizes(mode[0], n, PETSC_DETERMINE)); 3989566063dSJacob Faibussowitsch PetscCall(VecSetUp(mode[0])); 3999566063dSJacob Faibussowitsch for (i = 1; i < m; ++i) PetscCall(VecDuplicate(mode[0], &mode[i])); 40012adca46SMatthew G. Knepley for (b = 0, off = 0; b < nb; ++b) { 40112adca46SMatthew G. Knepley for (d = 0; d < m / nb; ++d) { 40212adca46SMatthew G. Knepley PetscInt ctx[2]; 40312adca46SMatthew G. Knepley PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *) = DMPlexProjectRigidBody_Private; 40412adca46SMatthew G. Knepley void *voidctx = (void *)(&ctx[0]); 40512adca46SMatthew G. Knepley 40612adca46SMatthew G. Knepley ctx[0] = dimEmbed; 40712adca46SMatthew G. Knepley ctx[1] = d; 4089566063dSJacob Faibussowitsch PetscCall(DMProjectFunctionLabel(dm, 0.0, label, nids[b], &ids[off], 0, NULL, &func, &voidctx, INSERT_VALUES, mode[d])); 40912adca46SMatthew G. Knepley off += nids[b]; 41012adca46SMatthew G. Knepley } 41112adca46SMatthew G. Knepley } 4123b2202bfSJacob Faibussowitsch /* Orthonormalize system */ 413606c1a1cSJacob Faibussowitsch for (i = 0; i < m; ++i) { 414b77f2eeeSJacob Faibussowitsch PetscScalar dots[6]; 4155a0e29b9SJacob Faibussowitsch 4169566063dSJacob Faibussowitsch PetscCall(VecNormalize(mode[i], NULL)); 4179566063dSJacob Faibussowitsch PetscCall(VecMDot(mode[i], m - i - 1, mode + i + 1, dots + i + 1)); 4185a0e29b9SJacob Faibussowitsch for (j = i + 1; j < m; ++j) { 419b77f2eeeSJacob Faibussowitsch dots[j] *= -1.0; 4209566063dSJacob Faibussowitsch PetscCall(VecAXPY(mode[j], dots[j], mode[i])); 4215a0e29b9SJacob Faibussowitsch } 42212adca46SMatthew G. Knepley } 4239566063dSJacob Faibussowitsch PetscCall(MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp)); 4249566063dSJacob Faibussowitsch for (i = 0; i < m; ++i) PetscCall(VecDestroy(&mode[i])); 4259566063dSJacob Faibussowitsch PetscCall(PetscFree2(mode, dots)); 4263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 42712adca46SMatthew G. Knepley } 42812adca46SMatthew G. Knepley 429b29cfa1cSToby Isaac /*@ 430b29cfa1cSToby Isaac DMPlexSetMaxProjectionHeight - In DMPlexProjectXXXLocal() functions, the projected values of a basis function's dofs 431b29cfa1cSToby Isaac are computed by associating the basis function with one of the mesh points in its transitively-closed support, and 432a4e35b19SJacob Faibussowitsch evaluating the dual space basis of that point. 433b29cfa1cSToby Isaac 434b29cfa1cSToby Isaac Input Parameters: 435a1cb98faSBarry Smith + dm - the `DMPLEX` object 436b29cfa1cSToby Isaac - height - the maximum projection height >= 0 437b29cfa1cSToby Isaac 438b29cfa1cSToby Isaac Level: advanced 439b29cfa1cSToby Isaac 440a4e35b19SJacob Faibussowitsch Notes: 441a4e35b19SJacob Faibussowitsch A basis function is associated with the point in its transitively-closed support whose mesh 442a4e35b19SJacob Faibussowitsch height is highest (w.r.t. DAG height), but not greater than the maximum projection height, 443a4e35b19SJacob Faibussowitsch which is set with this function. By default, the maximum projection height is zero, which 444a4e35b19SJacob Faibussowitsch means that only mesh cells are used to project basis functions. A height of one, for 445a4e35b19SJacob Faibussowitsch example, evaluates a cell-interior basis functions using its cells dual space basis, but all 446a4e35b19SJacob Faibussowitsch other basis functions with the dual space basis of a face. 447a4e35b19SJacob Faibussowitsch 4481cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMaxProjectionHeight()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()` 449b29cfa1cSToby Isaac @*/ 450d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetMaxProjectionHeight(DM dm, PetscInt height) 451d71ae5a4SJacob Faibussowitsch { 452b29cfa1cSToby Isaac DM_Plex *plex = (DM_Plex *)dm->data; 453b29cfa1cSToby Isaac 454b29cfa1cSToby Isaac PetscFunctionBegin; 455b29cfa1cSToby Isaac PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 456b29cfa1cSToby Isaac plex->maxProjectionHeight = height; 4573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 458b29cfa1cSToby Isaac } 459b29cfa1cSToby Isaac 460b29cfa1cSToby Isaac /*@ 461b29cfa1cSToby Isaac DMPlexGetMaxProjectionHeight - Get the maximum height (w.r.t. DAG) of mesh points used to evaluate dual bases in 462b29cfa1cSToby Isaac DMPlexProjectXXXLocal() functions. 463b29cfa1cSToby Isaac 4642fe279fdSBarry Smith Input Parameter: 465a1cb98faSBarry Smith . dm - the `DMPLEX` object 466b29cfa1cSToby Isaac 4672fe279fdSBarry Smith Output Parameter: 468b29cfa1cSToby Isaac . height - the maximum projection height 469b29cfa1cSToby Isaac 470b29cfa1cSToby Isaac Level: intermediate 471b29cfa1cSToby Isaac 4721cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetMaxProjectionHeight()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()` 473b29cfa1cSToby Isaac @*/ 474d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetMaxProjectionHeight(DM dm, PetscInt *height) 475d71ae5a4SJacob Faibussowitsch { 476b29cfa1cSToby Isaac DM_Plex *plex = (DM_Plex *)dm->data; 477b29cfa1cSToby Isaac 478b29cfa1cSToby Isaac PetscFunctionBegin; 479b29cfa1cSToby Isaac PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 480b29cfa1cSToby Isaac *height = plex->maxProjectionHeight; 4813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 482b29cfa1cSToby Isaac } 483b29cfa1cSToby Isaac 484ca3d3a14SMatthew G. Knepley typedef struct { 485ca3d3a14SMatthew G. Knepley PetscReal alpha; /* The first Euler angle, and in 2D the only one */ 486ca3d3a14SMatthew G. Knepley PetscReal beta; /* The second Euler angle */ 487ca3d3a14SMatthew G. Knepley PetscReal gamma; /* The third Euler angle */ 488ca3d3a14SMatthew G. Knepley PetscInt dim; /* The dimension of R */ 489ca3d3a14SMatthew G. Knepley PetscScalar *R; /* The rotation matrix, transforming a vector in the local basis to the global basis */ 490ca3d3a14SMatthew G. Knepley PetscScalar *RT; /* The transposed rotation matrix, transforming a vector in the global basis to the local basis */ 491ca3d3a14SMatthew G. Knepley } RotCtx; 492ca3d3a14SMatthew G. Knepley 493ca3d3a14SMatthew G. Knepley /* 494ca3d3a14SMatthew G. Knepley Note: Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that 495ca3d3a14SMatthew 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: 496ca3d3a14SMatthew 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. 497ca3d3a14SMatthew 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. 498ca3d3a14SMatthew G. Knepley $ The XYZ system rotates a third time about the z axis by gamma. 499ca3d3a14SMatthew G. Knepley */ 500d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformSetUp_Rotation_Internal(DM dm, void *ctx) 501d71ae5a4SJacob Faibussowitsch { 502ca3d3a14SMatthew G. Knepley RotCtx *rc = (RotCtx *)ctx; 503ca3d3a14SMatthew G. Knepley PetscInt dim = rc->dim; 504ca3d3a14SMatthew G. Knepley PetscReal c1, s1, c2, s2, c3, s3; 505ca3d3a14SMatthew G. Knepley 506ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 5079566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(PetscSqr(dim), &rc->R, PetscSqr(dim), &rc->RT)); 508ca3d3a14SMatthew G. Knepley switch (dim) { 509ca3d3a14SMatthew G. Knepley case 2: 5109371c9d4SSatish Balay c1 = PetscCosReal(rc->alpha); 5119371c9d4SSatish Balay s1 = PetscSinReal(rc->alpha); 5129371c9d4SSatish Balay rc->R[0] = c1; 5139371c9d4SSatish Balay rc->R[1] = s1; 5149371c9d4SSatish Balay rc->R[2] = -s1; 5159371c9d4SSatish Balay rc->R[3] = c1; 5169566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(rc->RT, rc->R, PetscSqr(dim))); 517b458e8f1SJose E. Roman DMPlex_Transpose2D_Internal(rc->RT); 518ca3d3a14SMatthew G. Knepley break; 519ca3d3a14SMatthew G. Knepley case 3: 5209371c9d4SSatish Balay c1 = PetscCosReal(rc->alpha); 5219371c9d4SSatish Balay s1 = PetscSinReal(rc->alpha); 5229371c9d4SSatish Balay c2 = PetscCosReal(rc->beta); 5239371c9d4SSatish Balay s2 = PetscSinReal(rc->beta); 5249371c9d4SSatish Balay c3 = PetscCosReal(rc->gamma); 5259371c9d4SSatish Balay s3 = PetscSinReal(rc->gamma); 5269371c9d4SSatish Balay rc->R[0] = c1 * c3 - c2 * s1 * s3; 5279371c9d4SSatish Balay rc->R[1] = c3 * s1 + c1 * c2 * s3; 5289371c9d4SSatish Balay rc->R[2] = s2 * s3; 5299371c9d4SSatish Balay rc->R[3] = -c1 * s3 - c2 * c3 * s1; 5309371c9d4SSatish Balay rc->R[4] = c1 * c2 * c3 - s1 * s3; 5319371c9d4SSatish Balay rc->R[5] = c3 * s2; 5329371c9d4SSatish Balay rc->R[6] = s1 * s2; 5339371c9d4SSatish Balay rc->R[7] = -c1 * s2; 5349371c9d4SSatish Balay rc->R[8] = c2; 5359566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(rc->RT, rc->R, PetscSqr(dim))); 536b458e8f1SJose E. Roman DMPlex_Transpose3D_Internal(rc->RT); 537ca3d3a14SMatthew G. Knepley break; 538d71ae5a4SJacob Faibussowitsch default: 539d71ae5a4SJacob Faibussowitsch SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Dimension %" PetscInt_FMT " not supported", dim); 540ca3d3a14SMatthew G. Knepley } 5413ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 542ca3d3a14SMatthew G. Knepley } 543ca3d3a14SMatthew G. Knepley 544d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformDestroy_Rotation_Internal(DM dm, void *ctx) 545d71ae5a4SJacob Faibussowitsch { 546ca3d3a14SMatthew G. Knepley RotCtx *rc = (RotCtx *)ctx; 547ca3d3a14SMatthew G. Knepley 548ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 5499566063dSJacob Faibussowitsch PetscCall(PetscFree2(rc->R, rc->RT)); 5509566063dSJacob Faibussowitsch PetscCall(PetscFree(rc)); 5513ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 552ca3d3a14SMatthew G. Knepley } 553ca3d3a14SMatthew G. Knepley 554d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformGetMatrix_Rotation_Internal(DM dm, const PetscReal x[], PetscBool l2g, const PetscScalar **A, void *ctx) 555d71ae5a4SJacob Faibussowitsch { 556ca3d3a14SMatthew G. Knepley RotCtx *rc = (RotCtx *)ctx; 557ca3d3a14SMatthew G. Knepley 558ca3d3a14SMatthew G. Knepley PetscFunctionBeginHot; 5594f572ea9SToby Isaac PetscAssertPointer(ctx, 5); 5609371c9d4SSatish Balay if (l2g) { 5619371c9d4SSatish Balay *A = rc->R; 5629371c9d4SSatish Balay } else { 5639371c9d4SSatish Balay *A = rc->RT; 5649371c9d4SSatish Balay } 5653ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 566ca3d3a14SMatthew G. Knepley } 567ca3d3a14SMatthew G. Knepley 568d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformApplyReal_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscReal *y, PetscReal *z, void *ctx) 569d71ae5a4SJacob Faibussowitsch { 570ec277c0fSMatthew G. Knepley PetscFunctionBegin; 571ab6a9622SMatthew G. Knepley #if defined(PETSC_USE_COMPLEX) 572ab6a9622SMatthew G. Knepley switch (dim) { 5739371c9d4SSatish Balay case 2: { 57427104ee2SJacob Faibussowitsch PetscScalar yt[2] = {y[0], y[1]}, zt[2] = {0.0, 0.0}; 575ab6a9622SMatthew G. Knepley 5769566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx)); 5779371c9d4SSatish Balay z[0] = PetscRealPart(zt[0]); 5789371c9d4SSatish Balay z[1] = PetscRealPart(zt[1]); 5799371c9d4SSatish Balay } break; 5809371c9d4SSatish Balay case 3: { 58127104ee2SJacob Faibussowitsch PetscScalar yt[3] = {y[0], y[1], y[2]}, zt[3] = {0.0, 0.0, 0.0}; 582ab6a9622SMatthew G. Knepley 5839566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx)); 5849371c9d4SSatish Balay z[0] = PetscRealPart(zt[0]); 5859371c9d4SSatish Balay z[1] = PetscRealPart(zt[1]); 5869371c9d4SSatish Balay z[2] = PetscRealPart(zt[2]); 5879371c9d4SSatish Balay } break; 588ab6a9622SMatthew G. Knepley } 589ab6a9622SMatthew G. Knepley #else 5909566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, y, z, ctx)); 591ab6a9622SMatthew G. Knepley #endif 5923ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 593ab6a9622SMatthew G. Knepley } 594ab6a9622SMatthew G. Knepley 595d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformApply_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscScalar *y, PetscScalar *z, void *ctx) 596d71ae5a4SJacob Faibussowitsch { 597ca3d3a14SMatthew G. Knepley const PetscScalar *A; 598ca3d3a14SMatthew G. Knepley 599ca3d3a14SMatthew G. Knepley PetscFunctionBeginHot; 6009566063dSJacob Faibussowitsch PetscCall((*dm->transformGetMatrix)(dm, x, l2g, &A, ctx)); 601ca3d3a14SMatthew G. Knepley switch (dim) { 602d71ae5a4SJacob Faibussowitsch case 2: 603d71ae5a4SJacob Faibussowitsch DMPlex_Mult2D_Internal(A, 1, y, z); 604d71ae5a4SJacob Faibussowitsch break; 605d71ae5a4SJacob Faibussowitsch case 3: 606d71ae5a4SJacob Faibussowitsch DMPlex_Mult3D_Internal(A, 1, y, z); 607d71ae5a4SJacob Faibussowitsch break; 608ca3d3a14SMatthew G. Knepley } 6093ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 610ca3d3a14SMatthew G. Knepley } 611ca3d3a14SMatthew G. Knepley 612d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformField_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscInt f, PetscBool l2g, PetscScalar *a) 613d71ae5a4SJacob Faibussowitsch { 614ca3d3a14SMatthew G. Knepley PetscSection ts; 615ca3d3a14SMatthew G. Knepley const PetscScalar *ta, *tva; 616ca3d3a14SMatthew G. Knepley PetscInt dof; 617ca3d3a14SMatthew G. Knepley 618ca3d3a14SMatthew G. Knepley PetscFunctionBeginHot; 6199566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(tdm, &ts)); 6209566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(ts, p, f, &dof)); 6219566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(tv, &ta)); 6229566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(tdm, p, f, ta, &tva)); 623ca3d3a14SMatthew G. Knepley if (l2g) { 624ca3d3a14SMatthew G. Knepley switch (dof) { 625d71ae5a4SJacob Faibussowitsch case 4: 626d71ae5a4SJacob Faibussowitsch DMPlex_Mult2D_Internal(tva, 1, a, a); 627d71ae5a4SJacob Faibussowitsch break; 628d71ae5a4SJacob Faibussowitsch case 9: 629d71ae5a4SJacob Faibussowitsch DMPlex_Mult3D_Internal(tva, 1, a, a); 630d71ae5a4SJacob Faibussowitsch break; 631ca3d3a14SMatthew G. Knepley } 632ca3d3a14SMatthew G. Knepley } else { 633ca3d3a14SMatthew G. Knepley switch (dof) { 634d71ae5a4SJacob Faibussowitsch case 4: 635d71ae5a4SJacob Faibussowitsch DMPlex_MultTranspose2D_Internal(tva, 1, a, a); 636d71ae5a4SJacob Faibussowitsch break; 637d71ae5a4SJacob Faibussowitsch case 9: 638d71ae5a4SJacob Faibussowitsch DMPlex_MultTranspose3D_Internal(tva, 1, a, a); 639d71ae5a4SJacob Faibussowitsch break; 640ca3d3a14SMatthew G. Knepley } 641ca3d3a14SMatthew G. Knepley } 6429566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(tv, &ta)); 6433ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 644ca3d3a14SMatthew G. Knepley } 645ca3d3a14SMatthew G. Knepley 646d71ae5a4SJacob 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) 647d71ae5a4SJacob Faibussowitsch { 648ca3d3a14SMatthew G. Knepley PetscSection s, ts; 649ca3d3a14SMatthew G. Knepley const PetscScalar *ta, *tvaf, *tvag; 650ca3d3a14SMatthew G. Knepley PetscInt fdof, gdof, fpdof, gpdof; 651ca3d3a14SMatthew G. Knepley 652ca3d3a14SMatthew G. Knepley PetscFunctionBeginHot; 6539566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, &s)); 6549566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(tdm, &ts)); 6559566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, pf, f, &fpdof)); 6569566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, pg, g, &gpdof)); 6579566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(ts, pf, f, &fdof)); 6589566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(ts, pg, g, &gdof)); 6599566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(tv, &ta)); 6609566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(tdm, pf, f, ta, &tvaf)); 6619566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(tdm, pg, g, ta, &tvag)); 662ca3d3a14SMatthew G. Knepley if (l2g) { 663ca3d3a14SMatthew G. Knepley switch (fdof) { 664d71ae5a4SJacob Faibussowitsch case 4: 665d71ae5a4SJacob Faibussowitsch DMPlex_MatMult2D_Internal(tvaf, gpdof, lda, a, a); 666d71ae5a4SJacob Faibussowitsch break; 667d71ae5a4SJacob Faibussowitsch case 9: 668d71ae5a4SJacob Faibussowitsch DMPlex_MatMult3D_Internal(tvaf, gpdof, lda, a, a); 669d71ae5a4SJacob Faibussowitsch break; 670ca3d3a14SMatthew G. Knepley } 671ca3d3a14SMatthew G. Knepley switch (gdof) { 672d71ae5a4SJacob Faibussowitsch case 4: 673d71ae5a4SJacob Faibussowitsch DMPlex_MatMultTransposeLeft2D_Internal(tvag, fpdof, lda, a, a); 674d71ae5a4SJacob Faibussowitsch break; 675d71ae5a4SJacob Faibussowitsch case 9: 676d71ae5a4SJacob Faibussowitsch DMPlex_MatMultTransposeLeft3D_Internal(tvag, fpdof, lda, a, a); 677d71ae5a4SJacob Faibussowitsch break; 678ca3d3a14SMatthew G. Knepley } 679ca3d3a14SMatthew G. Knepley } else { 680ca3d3a14SMatthew G. Knepley switch (fdof) { 681d71ae5a4SJacob Faibussowitsch case 4: 682d71ae5a4SJacob Faibussowitsch DMPlex_MatMultTranspose2D_Internal(tvaf, gpdof, lda, a, a); 683d71ae5a4SJacob Faibussowitsch break; 684d71ae5a4SJacob Faibussowitsch case 9: 685d71ae5a4SJacob Faibussowitsch DMPlex_MatMultTranspose3D_Internal(tvaf, gpdof, lda, a, a); 686d71ae5a4SJacob Faibussowitsch break; 687ca3d3a14SMatthew G. Knepley } 688ca3d3a14SMatthew G. Knepley switch (gdof) { 689d71ae5a4SJacob Faibussowitsch case 4: 690d71ae5a4SJacob Faibussowitsch DMPlex_MatMultLeft2D_Internal(tvag, fpdof, lda, a, a); 691d71ae5a4SJacob Faibussowitsch break; 692d71ae5a4SJacob Faibussowitsch case 9: 693d71ae5a4SJacob Faibussowitsch DMPlex_MatMultLeft3D_Internal(tvag, fpdof, lda, a, a); 694d71ae5a4SJacob Faibussowitsch break; 695ca3d3a14SMatthew G. Knepley } 696ca3d3a14SMatthew G. Knepley } 6979566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(tv, &ta)); 6983ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 699ca3d3a14SMatthew G. Knepley } 700ca3d3a14SMatthew G. Knepley 701d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformPoint_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool fieldActive[], PetscBool l2g, PetscScalar *a) 702d71ae5a4SJacob Faibussowitsch { 703ca3d3a14SMatthew G. Knepley PetscSection s; 704ca3d3a14SMatthew G. Knepley PetscSection clSection; 705ca3d3a14SMatthew G. Knepley IS clPoints; 706ca3d3a14SMatthew G. Knepley const PetscInt *clp; 707ca3d3a14SMatthew G. Knepley PetscInt *points = NULL; 708ca3d3a14SMatthew G. Knepley PetscInt Nf, f, Np, cp, dof, d = 0; 709ca3d3a14SMatthew G. Knepley 710ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 7119566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, &s)); 7129566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(s, &Nf)); 71307218a29SMatthew G. Knepley PetscCall(DMPlexGetCompressedClosure(dm, s, p, 0, &Np, &points, &clSection, &clPoints, &clp)); 714ca3d3a14SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 715ca3d3a14SMatthew G. Knepley for (cp = 0; cp < Np * 2; cp += 2) { 7169566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, points[cp], f, &dof)); 717ca3d3a14SMatthew G. Knepley if (!dof) continue; 7189566063dSJacob Faibussowitsch if (fieldActive[f]) PetscCall(DMPlexBasisTransformField_Internal(dm, tdm, tv, points[cp], f, l2g, &a[d])); 719ca3d3a14SMatthew G. Knepley d += dof; 720ca3d3a14SMatthew G. Knepley } 721ca3d3a14SMatthew G. Knepley } 7229566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp)); 7233ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 724ca3d3a14SMatthew G. Knepley } 725ca3d3a14SMatthew G. Knepley 726d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformPointTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool l2g, PetscInt lda, PetscScalar *a) 727d71ae5a4SJacob Faibussowitsch { 728ca3d3a14SMatthew G. Knepley PetscSection s; 729ca3d3a14SMatthew G. Knepley PetscSection clSection; 730ca3d3a14SMatthew G. Knepley IS clPoints; 731ca3d3a14SMatthew G. Knepley const PetscInt *clp; 732ca3d3a14SMatthew G. Knepley PetscInt *points = NULL; 7338bdb3c71SMatthew G. Knepley PetscInt Nf, f, g, Np, cpf, cpg, fdof, gdof, r, c = 0; 734ca3d3a14SMatthew G. Knepley 735ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 7369566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, &s)); 7379566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(s, &Nf)); 73807218a29SMatthew G. Knepley PetscCall(DMPlexGetCompressedClosure(dm, s, p, 0, &Np, &points, &clSection, &clPoints, &clp)); 739ca3d3a14SMatthew G. Knepley for (f = 0, r = 0; f < Nf; ++f) { 740ca3d3a14SMatthew G. Knepley for (cpf = 0; cpf < Np * 2; cpf += 2) { 7419566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, points[cpf], f, &fdof)); 742ca3d3a14SMatthew G. Knepley for (g = 0, c = 0; g < Nf; ++g) { 743ca3d3a14SMatthew G. Knepley for (cpg = 0; cpg < Np * 2; cpg += 2) { 7449566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, points[cpg], g, &gdof)); 7459566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformFieldTensor_Internal(dm, tdm, tv, points[cpf], f, points[cpg], g, l2g, lda, &a[r * lda + c])); 746ca3d3a14SMatthew G. Knepley c += gdof; 747ca3d3a14SMatthew G. Knepley } 748ca3d3a14SMatthew G. Knepley } 74963a3b9bcSJacob Faibussowitsch PetscCheck(c == lda, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of columns %" PetscInt_FMT " should be %" PetscInt_FMT, c, lda); 750ca3d3a14SMatthew G. Knepley r += fdof; 751ca3d3a14SMatthew G. Knepley } 752ca3d3a14SMatthew G. Knepley } 75363a3b9bcSJacob Faibussowitsch PetscCheck(r == lda, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of rows %" PetscInt_FMT " should be %" PetscInt_FMT, c, lda); 7549566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp)); 7553ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 756ca3d3a14SMatthew G. Knepley } 757ca3d3a14SMatthew G. Knepley 758d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransform_Internal(DM dm, Vec lv, PetscBool l2g) 759d71ae5a4SJacob Faibussowitsch { 760ca3d3a14SMatthew G. Knepley DM tdm; 761ca3d3a14SMatthew G. Knepley Vec tv; 762ca3d3a14SMatthew G. Knepley PetscSection ts, s; 763ca3d3a14SMatthew G. Knepley const PetscScalar *ta; 764ca3d3a14SMatthew G. Knepley PetscScalar *a, *va; 765ca3d3a14SMatthew G. Knepley PetscInt pStart, pEnd, p, Nf, f; 766ca3d3a14SMatthew G. Knepley 767ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 7689566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 7699566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 7709566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(tdm, &ts)); 7719566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, &s)); 7729566063dSJacob Faibussowitsch PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 7739566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(s, &Nf)); 7749566063dSJacob Faibussowitsch PetscCall(VecGetArray(lv, &a)); 7759566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(tv, &ta)); 776ca3d3a14SMatthew G. Knepley for (p = pStart; p < pEnd; ++p) { 777ca3d3a14SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 7789566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, p, f, a, &va)); 7799566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformField_Internal(dm, tdm, tv, p, f, l2g, va)); 780ca3d3a14SMatthew G. Knepley } 781ca3d3a14SMatthew G. Knepley } 7829566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(lv, &a)); 7839566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(tv, &ta)); 7843ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 785ca3d3a14SMatthew G. Knepley } 786ca3d3a14SMatthew G. Knepley 787ca3d3a14SMatthew G. Knepley /*@ 788ca3d3a14SMatthew G. Knepley DMPlexGlobalToLocalBasis - Transform the values in the given local vector from the global basis to the local basis 789ca3d3a14SMatthew G. Knepley 790ca3d3a14SMatthew G. Knepley Input Parameters: 791a1cb98faSBarry Smith + dm - The `DM` 792ca3d3a14SMatthew G. Knepley - lv - A local vector with values in the global basis 793ca3d3a14SMatthew G. Knepley 7942fe279fdSBarry Smith Output Parameter: 795ca3d3a14SMatthew G. Knepley . lv - A local vector with values in the local basis 796ca3d3a14SMatthew G. Knepley 797ca3d3a14SMatthew G. Knepley Level: developer 798ca3d3a14SMatthew G. Knepley 799a1cb98faSBarry Smith Note: 800a1cb98faSBarry 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. 801a1cb98faSBarry Smith 8021cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexLocalToGlobalBasis()`, `DMGetLocalSection()`, `DMPlexCreateBasisRotation()` 803ca3d3a14SMatthew G. Knepley @*/ 804d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGlobalToLocalBasis(DM dm, Vec lv) 805d71ae5a4SJacob Faibussowitsch { 806ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 807ca3d3a14SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 808ca3d3a14SMatthew G. Knepley PetscValidHeaderSpecific(lv, VEC_CLASSID, 2); 8099566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransform_Internal(dm, lv, PETSC_FALSE)); 8103ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 811ca3d3a14SMatthew G. Knepley } 812ca3d3a14SMatthew G. Knepley 813ca3d3a14SMatthew G. Knepley /*@ 814ca3d3a14SMatthew G. Knepley DMPlexLocalToGlobalBasis - Transform the values in the given local vector from the local basis to the global basis 815ca3d3a14SMatthew G. Knepley 816ca3d3a14SMatthew G. Knepley Input Parameters: 817a1cb98faSBarry Smith + dm - The `DM` 818ca3d3a14SMatthew G. Knepley - lv - A local vector with values in the local basis 819ca3d3a14SMatthew G. Knepley 8202fe279fdSBarry Smith Output Parameter: 821ca3d3a14SMatthew G. Knepley . lv - A local vector with values in the global basis 822ca3d3a14SMatthew G. Knepley 823ca3d3a14SMatthew G. Knepley Level: developer 824ca3d3a14SMatthew G. Knepley 825a1cb98faSBarry Smith Note: 826a1cb98faSBarry 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. 827a1cb98faSBarry Smith 8281cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGlobalToLocalBasis()`, `DMGetLocalSection()`, `DMPlexCreateBasisRotation()` 829ca3d3a14SMatthew G. Knepley @*/ 830d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalToGlobalBasis(DM dm, Vec lv) 831d71ae5a4SJacob Faibussowitsch { 832ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 833ca3d3a14SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 834ca3d3a14SMatthew G. Knepley PetscValidHeaderSpecific(lv, VEC_CLASSID, 2); 8359566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransform_Internal(dm, lv, PETSC_TRUE)); 8363ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 837ca3d3a14SMatthew G. Knepley } 838ca3d3a14SMatthew G. Knepley 839ca3d3a14SMatthew G. Knepley /*@ 840ca3d3a14SMatthew G. Knepley DMPlexCreateBasisRotation - Create an internal transformation from the global basis, used to specify boundary conditions 841ca3d3a14SMatthew G. Knepley and global solutions, to a local basis, appropriate for discretization integrals and assembly. 842ca3d3a14SMatthew G. Knepley 843ca3d3a14SMatthew G. Knepley Input Parameters: 844a1cb98faSBarry Smith + dm - The `DM` 845ca3d3a14SMatthew G. Knepley . alpha - The first Euler angle, and in 2D the only one 846ca3d3a14SMatthew G. Knepley . beta - The second Euler angle 847f0fc11ceSJed Brown - gamma - The third Euler angle 848ca3d3a14SMatthew G. Knepley 849ca3d3a14SMatthew G. Knepley Level: developer 850ca3d3a14SMatthew G. Knepley 851a1cb98faSBarry Smith Note: 852a1cb98faSBarry Smith Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that 853a1cb98faSBarry 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 854a1cb98faSBarry Smith .vb 855a1cb98faSBarry 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. 856a1cb98faSBarry 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. 857a1cb98faSBarry Smith The XYZ system rotates a third time about the z axis by gamma. 858a1cb98faSBarry Smith .ve 859a1cb98faSBarry Smith 8601cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGlobalToLocalBasis()`, `DMPlexLocalToGlobalBasis()` 861ca3d3a14SMatthew G. Knepley @*/ 862d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateBasisRotation(DM dm, PetscReal alpha, PetscReal beta, PetscReal gamma) 863d71ae5a4SJacob Faibussowitsch { 864ca3d3a14SMatthew G. Knepley RotCtx *rc; 865ca3d3a14SMatthew G. Knepley PetscInt cdim; 866ca3d3a14SMatthew G. Knepley 867362febeeSStefano Zampini PetscFunctionBegin; 8689566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &cdim)); 8699566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(1, &rc)); 870ca3d3a14SMatthew G. Knepley dm->transformCtx = rc; 871ca3d3a14SMatthew G. Knepley dm->transformSetUp = DMPlexBasisTransformSetUp_Rotation_Internal; 872ca3d3a14SMatthew G. Knepley dm->transformDestroy = DMPlexBasisTransformDestroy_Rotation_Internal; 873ca3d3a14SMatthew G. Knepley dm->transformGetMatrix = DMPlexBasisTransformGetMatrix_Rotation_Internal; 874ca3d3a14SMatthew G. Knepley rc->dim = cdim; 875ca3d3a14SMatthew G. Knepley rc->alpha = alpha; 876ca3d3a14SMatthew G. Knepley rc->beta = beta; 877ca3d3a14SMatthew G. Knepley rc->gamma = gamma; 8789566063dSJacob Faibussowitsch PetscCall((*dm->transformSetUp)(dm, dm->transformCtx)); 8799566063dSJacob Faibussowitsch PetscCall(DMConstructBasisTransform_Internal(dm)); 8803ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 881ca3d3a14SMatthew G. Knepley } 882ca3d3a14SMatthew G. Knepley 883b278463cSMatthew G. Knepley /*@C 884ece3a9fcSMatthew G. Knepley DMPlexInsertBoundaryValuesEssential - Insert boundary values into a local vector using a function of the coordinates 885b278463cSMatthew G. Knepley 886b278463cSMatthew G. Knepley Input Parameters: 887a1cb98faSBarry Smith + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 888b278463cSMatthew G. Knepley . time - The time 889b278463cSMatthew G. Knepley . field - The field to constrain 8901c531cf8SMatthew G. Knepley . Nc - The number of constrained field components, or 0 for all components 89120f4b53cSBarry Smith . comps - An array of constrained component numbers, or `NULL` for all components 892a1cb98faSBarry Smith . label - The `DMLabel` defining constrained points 893a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points 894b278463cSMatthew G. Knepley . ids - An array of ids for constrained points 895b278463cSMatthew G. Knepley . func - A pointwise function giving boundary values 896b278463cSMatthew G. Knepley - ctx - An optional user context for bcFunc 897b278463cSMatthew G. Knepley 898b278463cSMatthew G. Knepley Output Parameter: 899b278463cSMatthew G. Knepley . locX - A local vector to receives the boundary values 900b278463cSMatthew G. Knepley 901b278463cSMatthew G. Knepley Level: developer 902b278463cSMatthew G. Knepley 9031cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLabel`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMPlexInsertBoundaryValuesEssentialBdField()`, `DMAddBoundary()` 904b278463cSMatthew G. Knepley @*/ 905d71ae5a4SJacob 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) 906d71ae5a4SJacob Faibussowitsch { 9070163fd50SMatthew G. Knepley PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx); 90855f2e967SMatthew G. Knepley void **ctxs; 909d7ddef95SMatthew G. Knepley PetscInt numFields; 910d7ddef95SMatthew G. Knepley 911d7ddef95SMatthew G. Knepley PetscFunctionBegin; 9129566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &numFields)); 9139566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs)); 914d7ddef95SMatthew G. Knepley funcs[field] = func; 915d7ddef95SMatthew G. Knepley ctxs[field] = ctx; 9169566063dSJacob Faibussowitsch PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numids, ids, Nc, comps, funcs, ctxs, INSERT_BC_VALUES, locX)); 9179566063dSJacob Faibussowitsch PetscCall(PetscFree2(funcs, ctxs)); 9183ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 919d7ddef95SMatthew G. Knepley } 920d7ddef95SMatthew G. Knepley 921b278463cSMatthew G. Knepley /*@C 922ece3a9fcSMatthew G. Knepley DMPlexInsertBoundaryValuesEssentialField - Insert boundary values into a local vector using a function of the coordinates and field data 923b278463cSMatthew G. Knepley 924b278463cSMatthew G. Knepley Input Parameters: 925a1cb98faSBarry Smith + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 926b278463cSMatthew G. Knepley . time - The time 927b278463cSMatthew G. Knepley . locU - A local vector with the input solution values 928b278463cSMatthew G. Knepley . field - The field to constrain 9291c531cf8SMatthew G. Knepley . Nc - The number of constrained field components, or 0 for all components 93020f4b53cSBarry Smith . comps - An array of constrained component numbers, or `NULL` for all components 931a1cb98faSBarry Smith . label - The `DMLabel` defining constrained points 932a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points 933b278463cSMatthew G. Knepley . ids - An array of ids for constrained points 934b278463cSMatthew G. Knepley . func - A pointwise function giving boundary values 935b278463cSMatthew G. Knepley - ctx - An optional user context for bcFunc 936b278463cSMatthew G. Knepley 937b278463cSMatthew G. Knepley Output Parameter: 938b278463cSMatthew G. Knepley . locX - A local vector to receives the boundary values 939b278463cSMatthew G. Knepley 940b278463cSMatthew G. Knepley Level: developer 941b278463cSMatthew G. Knepley 9421cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialBdField()`, `DMAddBoundary()` 943b278463cSMatthew G. Knepley @*/ 944d71ae5a4SJacob 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) 945d71ae5a4SJacob Faibussowitsch { 9469371c9d4SSatish 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[]); 947c60e475cSMatthew G. Knepley void **ctxs; 948c60e475cSMatthew G. Knepley PetscInt numFields; 949c60e475cSMatthew G. Knepley 950c60e475cSMatthew G. Knepley PetscFunctionBegin; 9519566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &numFields)); 9529566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs)); 953c60e475cSMatthew G. Knepley funcs[field] = func; 954c60e475cSMatthew G. Knepley ctxs[field] = ctx; 9559566063dSJacob Faibussowitsch PetscCall(DMProjectFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX)); 9569566063dSJacob Faibussowitsch PetscCall(PetscFree2(funcs, ctxs)); 9573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 958c60e475cSMatthew G. Knepley } 959c60e475cSMatthew G. Knepley 960b278463cSMatthew G. Knepley /*@C 961d5b43468SJose E. Roman DMPlexInsertBoundaryValuesEssentialBdField - Insert boundary values into a local vector using a function of the coordinates and boundary field data 962ece3a9fcSMatthew G. Knepley 96320f4b53cSBarry Smith Collective 964ece3a9fcSMatthew G. Knepley 965ece3a9fcSMatthew G. Knepley Input Parameters: 966a1cb98faSBarry Smith + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 967ece3a9fcSMatthew G. Knepley . time - The time 968ece3a9fcSMatthew G. Knepley . locU - A local vector with the input solution values 969ece3a9fcSMatthew G. Knepley . field - The field to constrain 970ece3a9fcSMatthew G. Knepley . Nc - The number of constrained field components, or 0 for all components 97120f4b53cSBarry Smith . comps - An array of constrained component numbers, or `NULL` for all components 972a1cb98faSBarry Smith . label - The `DMLabel` defining constrained points 973a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points 974ece3a9fcSMatthew G. Knepley . ids - An array of ids for constrained points 97520f4b53cSBarry Smith . func - A pointwise function giving boundary values, the calling sequence is given in `DMProjectBdFieldLabelLocal()` 97620f4b53cSBarry Smith - ctx - An optional user context for `func` 977ece3a9fcSMatthew G. Knepley 978ece3a9fcSMatthew G. Knepley Output Parameter: 979ece3a9fcSMatthew G. Knepley . locX - A local vector to receive the boundary values 980ece3a9fcSMatthew G. Knepley 981ece3a9fcSMatthew G. Knepley Level: developer 982ece3a9fcSMatthew G. Knepley 9831cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectBdFieldLabelLocal()`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMAddBoundary()` 984ece3a9fcSMatthew G. Knepley @*/ 985d71ae5a4SJacob 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) 986d71ae5a4SJacob Faibussowitsch { 9879371c9d4SSatish 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[]); 988ece3a9fcSMatthew G. Knepley void **ctxs; 989ece3a9fcSMatthew G. Knepley PetscInt numFields; 990ece3a9fcSMatthew G. Knepley 991ece3a9fcSMatthew G. Knepley PetscFunctionBegin; 9929566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &numFields)); 9939566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs)); 994ece3a9fcSMatthew G. Knepley funcs[field] = func; 995ece3a9fcSMatthew G. Knepley ctxs[field] = ctx; 9969566063dSJacob Faibussowitsch PetscCall(DMProjectBdFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX)); 9979566063dSJacob Faibussowitsch PetscCall(PetscFree2(funcs, ctxs)); 9983ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 999ece3a9fcSMatthew G. Knepley } 1000ece3a9fcSMatthew G. Knepley 1001ece3a9fcSMatthew G. Knepley /*@C 1002b278463cSMatthew G. Knepley DMPlexInsertBoundaryValuesRiemann - Insert boundary values into a local vector 1003b278463cSMatthew G. Knepley 1004b278463cSMatthew G. Knepley Input Parameters: 1005a1cb98faSBarry Smith + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 1006b278463cSMatthew G. Knepley . time - The time 1007b278463cSMatthew G. Knepley . faceGeometry - A vector with the FVM face geometry information 1008b278463cSMatthew G. Knepley . cellGeometry - A vector with the FVM cell geometry information 1009b278463cSMatthew G. Knepley . Grad - A vector with the FVM cell gradient information 1010b278463cSMatthew G. Knepley . field - The field to constrain 10111c531cf8SMatthew G. Knepley . Nc - The number of constrained field components, or 0 for all components 101220f4b53cSBarry Smith . comps - An array of constrained component numbers, or `NULL` for all components 1013a1cb98faSBarry Smith . label - The `DMLabel` defining constrained points 1014a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points 1015b278463cSMatthew G. Knepley . ids - An array of ids for constrained points 1016b278463cSMatthew G. Knepley . func - A pointwise function giving boundary values 1017b278463cSMatthew G. Knepley - ctx - An optional user context for bcFunc 1018b278463cSMatthew G. Knepley 1019b278463cSMatthew G. Knepley Output Parameter: 1020b278463cSMatthew G. Knepley . locX - A local vector to receives the boundary values 1021b278463cSMatthew G. Knepley 1022b278463cSMatthew G. Knepley Level: developer 1023b278463cSMatthew G. Knepley 1024a1cb98faSBarry Smith Note: 1025a1cb98faSBarry Smith This implementation currently ignores the numcomps/comps argument from `DMAddBoundary()` 1026a1cb98faSBarry Smith 10271cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMAddBoundary()` 1028b278463cSMatthew G. Knepley @*/ 1029d71ae5a4SJacob 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) 1030d71ae5a4SJacob Faibussowitsch { 103161f58d28SMatthew G. Knepley PetscDS prob; 1032da97024aSMatthew G. Knepley PetscSF sf; 1033d7ddef95SMatthew G. Knepley DM dmFace, dmCell, dmGrad; 103420369375SToby Isaac const PetscScalar *facegeom, *cellgeom = NULL, *grad; 1035da97024aSMatthew G. Knepley const PetscInt *leaves; 1036d7ddef95SMatthew G. Knepley PetscScalar *x, *fx; 1037520b3818SMatthew G. Knepley PetscInt dim, nleaves, loc, fStart, fEnd, pdim, i; 10383ba16761SJacob Faibussowitsch PetscErrorCode ierru = PETSC_SUCCESS; 1039d7ddef95SMatthew G. Knepley 1040d7ddef95SMatthew G. Knepley PetscFunctionBegin; 10419566063dSJacob Faibussowitsch PetscCall(DMGetPointSF(dm, &sf)); 10429566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL)); 1043da97024aSMatthew G. Knepley nleaves = PetscMax(0, nleaves); 10449566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 10459566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 10469566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 10479566063dSJacob Faibussowitsch PetscCall(VecGetDM(faceGeometry, &dmFace)); 10489566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 104920369375SToby Isaac if (cellGeometry) { 10509566063dSJacob Faibussowitsch PetscCall(VecGetDM(cellGeometry, &dmCell)); 10519566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 105220369375SToby Isaac } 1053d7ddef95SMatthew G. Knepley if (Grad) { 1054c0a6632aSMatthew G. Knepley PetscFV fv; 1055c0a6632aSMatthew G. Knepley 10569566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fv)); 10579566063dSJacob Faibussowitsch PetscCall(VecGetDM(Grad, &dmGrad)); 10589566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(Grad, &grad)); 10599566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 10609566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, pdim, MPIU_SCALAR, &fx)); 1061d7ddef95SMatthew G. Knepley } 10629566063dSJacob Faibussowitsch PetscCall(VecGetArray(locX, &x)); 1063d7ddef95SMatthew G. Knepley for (i = 0; i < numids; ++i) { 1064d7ddef95SMatthew G. Knepley IS faceIS; 1065d7ddef95SMatthew G. Knepley const PetscInt *faces; 1066d7ddef95SMatthew G. Knepley PetscInt numFaces, f; 1067d7ddef95SMatthew G. Knepley 10689566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, ids[i], &faceIS)); 1069d7ddef95SMatthew G. Knepley if (!faceIS) continue; /* No points with that id on this process */ 10709566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(faceIS, &numFaces)); 10719566063dSJacob Faibussowitsch PetscCall(ISGetIndices(faceIS, &faces)); 1072d7ddef95SMatthew G. Knepley for (f = 0; f < numFaces; ++f) { 1073d7ddef95SMatthew G. Knepley const PetscInt face = faces[f], *cells; 1074640bce14SSatish Balay PetscFVFaceGeom *fg; 1075d7ddef95SMatthew G. Knepley 1076d7ddef95SMatthew G. Knepley if ((face < fStart) || (face >= fEnd)) continue; /* Refinement adds non-faces to labels */ 10779566063dSJacob Faibussowitsch PetscCall(PetscFindInt(face, nleaves, (PetscInt *)leaves, &loc)); 1078da97024aSMatthew G. Knepley if (loc >= 0) continue; 10799566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 10809566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &cells)); 1081d7ddef95SMatthew G. Knepley if (Grad) { 1082640bce14SSatish Balay PetscFVCellGeom *cg; 1083640bce14SSatish Balay PetscScalar *cx, *cgrad; 1084d7ddef95SMatthew G. Knepley PetscScalar *xG; 1085d7ddef95SMatthew G. Knepley PetscReal dx[3]; 1086d7ddef95SMatthew G. Knepley PetscInt d; 1087d7ddef95SMatthew G. Knepley 10889566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cg)); 10899566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dm, cells[0], x, &cx)); 10909566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], grad, &cgrad)); 10919566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG)); 1092d7ddef95SMatthew G. Knepley DMPlex_WaxpyD_Internal(dim, -1, cg->centroid, fg->centroid, dx); 1093d7ddef95SMatthew G. Knepley for (d = 0; d < pdim; ++d) fx[d] = cx[d] + DMPlex_DotD_Internal(dim, &cgrad[d * dim], dx); 10949566063dSJacob Faibussowitsch PetscCall((*func)(time, fg->centroid, fg->normal, fx, xG, ctx)); 1095d7ddef95SMatthew G. Knepley } else { 1096640bce14SSatish Balay PetscScalar *xI; 1097d7ddef95SMatthew G. Knepley PetscScalar *xG; 1098d7ddef95SMatthew G. Knepley 10999566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dm, cells[0], x, &xI)); 11009566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG)); 1101e735a8a9SMatthew G. Knepley ierru = (*func)(time, fg->centroid, fg->normal, xI, xG, ctx); 1102e735a8a9SMatthew G. Knepley if (ierru) { 11039566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(faceIS, &faces)); 11049566063dSJacob Faibussowitsch PetscCall(ISDestroy(&faceIS)); 1105e735a8a9SMatthew G. Knepley goto cleanup; 1106e735a8a9SMatthew G. Knepley } 1107d7ddef95SMatthew G. Knepley } 1108d7ddef95SMatthew G. Knepley } 11099566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(faceIS, &faces)); 11109566063dSJacob Faibussowitsch PetscCall(ISDestroy(&faceIS)); 1111d7ddef95SMatthew G. Knepley } 1112e735a8a9SMatthew G. Knepley cleanup: 11139566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locX, &x)); 1114d7ddef95SMatthew G. Knepley if (Grad) { 11159566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, pdim, MPIU_SCALAR, &fx)); 11169566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(Grad, &grad)); 1117d7ddef95SMatthew G. Knepley } 11189566063dSJacob Faibussowitsch if (cellGeometry) PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 11199566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 11209566063dSJacob Faibussowitsch PetscCall(ierru); 11213ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1122d7ddef95SMatthew G. Knepley } 1123d7ddef95SMatthew G. Knepley 1124d71ae5a4SJacob Faibussowitsch static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 1125d71ae5a4SJacob Faibussowitsch { 11260c364540SMatthew G. Knepley PetscInt c; 11270c364540SMatthew G. Knepley for (c = 0; c < Nc; ++c) u[c] = 0.0; 11283ba16761SJacob Faibussowitsch return PETSC_SUCCESS; 11290c364540SMatthew G. Knepley } 11300c364540SMatthew G. Knepley 1131d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1132d71ae5a4SJacob Faibussowitsch { 11330c364540SMatthew G. Knepley PetscObject isZero; 1134e5e52638SMatthew G. Knepley PetscDS prob; 1135d7ddef95SMatthew G. Knepley PetscInt numBd, b; 113655f2e967SMatthew G. Knepley 113755f2e967SMatthew G. Knepley PetscFunctionBegin; 11389566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 11399566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 11409566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)locX, "__Vec_bc_zero__", &isZero)); 1141450c7a9fSMatthew G. Knepley PetscCall(PetscDSUpdateBoundaryLabels(prob, dm)); 114255f2e967SMatthew G. Knepley for (b = 0; b < numBd; ++b) { 114345480ffeSMatthew G. Knepley PetscWeakForm wf; 1144f971fd6bSMatthew G. Knepley DMBoundaryConditionType type; 114545480ffeSMatthew G. Knepley const char *name; 1146d7ddef95SMatthew G. Knepley DMLabel label; 11471c531cf8SMatthew G. Knepley PetscInt field, Nc; 11481c531cf8SMatthew G. Knepley const PetscInt *comps; 1149d7ddef95SMatthew G. Knepley PetscObject obj; 1150d7ddef95SMatthew G. Knepley PetscClassId id; 115145480ffeSMatthew G. Knepley void (*bvfunc)(void); 1152d7ddef95SMatthew G. Knepley PetscInt numids; 1153d7ddef95SMatthew G. Knepley const PetscInt *ids; 115455f2e967SMatthew G. Knepley void *ctx; 115555f2e967SMatthew G. Knepley 11569566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, &bvfunc, NULL, &ctx)); 1157f971fd6bSMatthew G. Knepley if (insertEssential != (type & DM_BC_ESSENTIAL)) continue; 11589566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 11599566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 1160d7ddef95SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 1161c60e475cSMatthew G. Knepley switch (type) { 1162c60e475cSMatthew G. Knepley /* for FEM, there is no insertion to be done for non-essential boundary conditions */ 11639371c9d4SSatish Balay case DM_BC_ESSENTIAL: { 11648434afd1SBarry Smith PetscSimplePointFn *func = (PetscSimplePointFn *)bvfunc; 116545480ffeSMatthew G. Knepley 116645480ffeSMatthew G. Knepley if (isZero) func = zero; 11679566063dSJacob Faibussowitsch PetscCall(DMPlexLabelAddCells(dm, label)); 11689566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, func, ctx, locX)); 11699566063dSJacob Faibussowitsch PetscCall(DMPlexLabelClearCells(dm, label)); 11709371c9d4SSatish Balay } break; 11719371c9d4SSatish Balay case DM_BC_ESSENTIAL_FIELD: { 117245480ffeSMatthew G. Knepley PetscPointFunc func = (PetscPointFunc)bvfunc; 117345480ffeSMatthew G. Knepley 11749566063dSJacob Faibussowitsch PetscCall(DMPlexLabelAddCells(dm, label)); 11759566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, func, ctx, locX)); 11769566063dSJacob Faibussowitsch PetscCall(DMPlexLabelClearCells(dm, label)); 11779371c9d4SSatish Balay } break; 1178d71ae5a4SJacob Faibussowitsch default: 1179d71ae5a4SJacob Faibussowitsch break; 1180c60e475cSMatthew G. Knepley } 1181d7ddef95SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 118245480ffeSMatthew G. Knepley { 118345480ffeSMatthew G. Knepley PetscErrorCode (*func)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *) = (PetscErrorCode (*)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *))bvfunc; 118445480ffeSMatthew G. Knepley 118543ea7facSMatthew G. Knepley if (!faceGeomFVM) continue; 11869566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValuesRiemann(dm, time, faceGeomFVM, cellGeomFVM, gradFVM, field, Nc, comps, label, numids, ids, func, ctx, locX)); 118745480ffeSMatthew G. Knepley } 118863a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 118955f2e967SMatthew G. Knepley } 11903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 119155f2e967SMatthew G. Knepley } 119255f2e967SMatthew G. Knepley 1193d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1194d71ae5a4SJacob Faibussowitsch { 119556cf3b9cSMatthew G. Knepley PetscObject isZero; 119656cf3b9cSMatthew G. Knepley PetscDS prob; 119756cf3b9cSMatthew G. Knepley PetscInt numBd, b; 119856cf3b9cSMatthew G. Knepley 119956cf3b9cSMatthew G. Knepley PetscFunctionBegin; 12003ba16761SJacob Faibussowitsch if (!locX) PetscFunctionReturn(PETSC_SUCCESS); 12019566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 12029566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 12039566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)locX, "__Vec_bc_zero__", &isZero)); 120456cf3b9cSMatthew G. Knepley for (b = 0; b < numBd; ++b) { 120545480ffeSMatthew G. Knepley PetscWeakForm wf; 120656cf3b9cSMatthew G. Knepley DMBoundaryConditionType type; 120745480ffeSMatthew G. Knepley const char *name; 120856cf3b9cSMatthew G. Knepley DMLabel label; 120956cf3b9cSMatthew G. Knepley PetscInt field, Nc; 121056cf3b9cSMatthew G. Knepley const PetscInt *comps; 121156cf3b9cSMatthew G. Knepley PetscObject obj; 121256cf3b9cSMatthew G. Knepley PetscClassId id; 121356cf3b9cSMatthew G. Knepley PetscInt numids; 121456cf3b9cSMatthew G. Knepley const PetscInt *ids; 121545480ffeSMatthew G. Knepley void (*bvfunc)(void); 121656cf3b9cSMatthew G. Knepley void *ctx; 121756cf3b9cSMatthew G. Knepley 12189566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, NULL, &bvfunc, &ctx)); 121956cf3b9cSMatthew G. Knepley if (insertEssential != (type & DM_BC_ESSENTIAL)) continue; 12209566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 12219566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 122256cf3b9cSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 122356cf3b9cSMatthew G. Knepley switch (type) { 122456cf3b9cSMatthew G. Knepley /* for FEM, there is no insertion to be done for non-essential boundary conditions */ 12259371c9d4SSatish Balay case DM_BC_ESSENTIAL: { 12268434afd1SBarry Smith PetscSimplePointFn *func_t = (PetscSimplePointFn *)bvfunc; 122745480ffeSMatthew G. Knepley 122845480ffeSMatthew G. Knepley if (isZero) func_t = zero; 12299566063dSJacob Faibussowitsch PetscCall(DMPlexLabelAddCells(dm, label)); 12309566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, func_t, ctx, locX)); 12319566063dSJacob Faibussowitsch PetscCall(DMPlexLabelClearCells(dm, label)); 12329371c9d4SSatish Balay } break; 12339371c9d4SSatish Balay case DM_BC_ESSENTIAL_FIELD: { 123445480ffeSMatthew G. Knepley PetscPointFunc func_t = (PetscPointFunc)bvfunc; 123545480ffeSMatthew G. Knepley 12369566063dSJacob Faibussowitsch PetscCall(DMPlexLabelAddCells(dm, label)); 12379566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, func_t, ctx, locX)); 12389566063dSJacob Faibussowitsch PetscCall(DMPlexLabelClearCells(dm, label)); 12399371c9d4SSatish Balay } break; 1240d71ae5a4SJacob Faibussowitsch default: 1241d71ae5a4SJacob Faibussowitsch break; 124256cf3b9cSMatthew G. Knepley } 124363a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 124456cf3b9cSMatthew G. Knepley } 12453ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 124656cf3b9cSMatthew G. Knepley } 124756cf3b9cSMatthew G. Knepley 1248f1d73a7aSMatthew G. Knepley /*@ 1249f1d73a7aSMatthew G. Knepley DMPlexInsertBoundaryValues - Puts coefficients which represent boundary values into the local solution vector 1250f1d73a7aSMatthew G. Knepley 1251ed808b8fSJed Brown Not Collective 1252ed808b8fSJed Brown 1253f1d73a7aSMatthew G. Knepley Input Parameters: 1254a1cb98faSBarry Smith + dm - The `DM` 1255f1d73a7aSMatthew G. Knepley . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions 1256f1d73a7aSMatthew G. Knepley . time - The time 1257f1d73a7aSMatthew G. Knepley . faceGeomFVM - Face geometry data for FV discretizations 1258f1d73a7aSMatthew G. Knepley . cellGeomFVM - Cell geometry data for FV discretizations 1259f1d73a7aSMatthew G. Knepley - gradFVM - Gradient reconstruction data for FV discretizations 1260f1d73a7aSMatthew G. Knepley 12612fe279fdSBarry Smith Output Parameter: 1262f1d73a7aSMatthew G. Knepley . locX - Solution updated with boundary values 1263f1d73a7aSMatthew G. Knepley 1264ed808b8fSJed Brown Level: intermediate 1265f1d73a7aSMatthew G. Knepley 12661cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunctionLabelLocal()`, `DMAddBoundary()` 1267f1d73a7aSMatthew G. Knepley @*/ 1268d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertBoundaryValues(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1269d71ae5a4SJacob Faibussowitsch { 1270f1d73a7aSMatthew G. Knepley PetscFunctionBegin; 1271f1d73a7aSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1272064a246eSJacob Faibussowitsch PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 1273ad540459SPierre Jolivet if (faceGeomFVM) PetscValidHeaderSpecific(faceGeomFVM, VEC_CLASSID, 5); 1274ad540459SPierre Jolivet if (cellGeomFVM) PetscValidHeaderSpecific(cellGeomFVM, VEC_CLASSID, 6); 1275ad540459SPierre Jolivet if (gradFVM) PetscValidHeaderSpecific(gradFVM, VEC_CLASSID, 7); 1276cac4c232SBarry Smith PetscTryMethod(dm, "DMPlexInsertBoundaryValues_C", (DM, PetscBool, Vec, PetscReal, Vec, Vec, Vec), (dm, insertEssential, locX, time, faceGeomFVM, cellGeomFVM, gradFVM)); 12773ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1278f1d73a7aSMatthew G. Knepley } 1279f1d73a7aSMatthew G. Knepley 128056cf3b9cSMatthew G. Knepley /*@ 1281a5b23f4aSJose E. Roman DMPlexInsertTimeDerivativeBoundaryValues - Puts coefficients which represent boundary values of the time derivative into the local solution vector 128256cf3b9cSMatthew G. Knepley 128356cf3b9cSMatthew G. Knepley Input Parameters: 1284a1cb98faSBarry Smith + dm - The `DM` 128556cf3b9cSMatthew G. Knepley . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions 128656cf3b9cSMatthew G. Knepley . time - The time 128756cf3b9cSMatthew G. Knepley . faceGeomFVM - Face geometry data for FV discretizations 128856cf3b9cSMatthew G. Knepley . cellGeomFVM - Cell geometry data for FV discretizations 128956cf3b9cSMatthew G. Knepley - gradFVM - Gradient reconstruction data for FV discretizations 129056cf3b9cSMatthew G. Knepley 12912fe279fdSBarry Smith Output Parameter: 129256cf3b9cSMatthew G. Knepley . locX_t - Solution updated with boundary values 129356cf3b9cSMatthew G. Knepley 129456cf3b9cSMatthew G. Knepley Level: developer 129556cf3b9cSMatthew G. Knepley 12961cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunctionLabelLocal()` 129756cf3b9cSMatthew G. Knepley @*/ 1298d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues(DM dm, PetscBool insertEssential, Vec locX_t, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1299d71ae5a4SJacob Faibussowitsch { 130056cf3b9cSMatthew G. Knepley PetscFunctionBegin; 130156cf3b9cSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1302ad540459SPierre Jolivet if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 3); 1303ad540459SPierre Jolivet if (faceGeomFVM) PetscValidHeaderSpecific(faceGeomFVM, VEC_CLASSID, 5); 1304ad540459SPierre Jolivet if (cellGeomFVM) PetscValidHeaderSpecific(cellGeomFVM, VEC_CLASSID, 6); 1305ad540459SPierre Jolivet if (gradFVM) PetscValidHeaderSpecific(gradFVM, VEC_CLASSID, 7); 13066c51210dSStefano Zampini PetscTryMethod(dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", (DM, PetscBool, Vec, PetscReal, Vec, Vec, Vec), (dm, insertEssential, locX_t, time, faceGeomFVM, cellGeomFVM, gradFVM)); 13073ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 130856cf3b9cSMatthew G. Knepley } 130956cf3b9cSMatthew G. Knepley 13105962854dSMatthew G. Knepley // Handle non-essential (e.g. outflow) boundary values 13115962854dSMatthew G. Knepley PetscErrorCode DMPlexInsertBoundaryValuesFVM(DM dm, PetscFV fv, Vec locX, PetscReal time, Vec *locGradient) 13125962854dSMatthew G. Knepley { 13135962854dSMatthew G. Knepley DM dmGrad; 13145962854dSMatthew G. Knepley Vec cellGeometryFVM, faceGeometryFVM, locGrad = NULL; 13155962854dSMatthew G. Knepley 13165962854dSMatthew G. Knepley PetscFunctionBegin; 13175962854dSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 13185962854dSMatthew G. Knepley PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 13195962854dSMatthew G. Knepley PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 13205962854dSMatthew G. Knepley if (locGradient) { 13215962854dSMatthew G. Knepley PetscAssertPointer(locGradient, 5); 13225962854dSMatthew G. Knepley *locGradient = NULL; 13235962854dSMatthew G. Knepley } 13245962854dSMatthew G. Knepley PetscCall(DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL)); 13255962854dSMatthew G. Knepley /* Reconstruct and limit cell gradients */ 13265962854dSMatthew G. Knepley PetscCall(DMPlexGetGradientDM(dm, fv, &dmGrad)); 13275962854dSMatthew G. Knepley if (dmGrad) { 13285962854dSMatthew G. Knepley Vec grad; 13295962854dSMatthew G. Knepley PetscInt fStart, fEnd; 13305962854dSMatthew G. Knepley 13315962854dSMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 13325962854dSMatthew G. Knepley PetscCall(DMGetGlobalVector(dmGrad, &grad)); 13335962854dSMatthew G. Knepley PetscCall(DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad)); 13345962854dSMatthew G. Knepley /* Communicate gradient values */ 13355962854dSMatthew G. Knepley PetscCall(DMGetLocalVector(dmGrad, &locGrad)); 13365962854dSMatthew G. Knepley PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad)); 13375962854dSMatthew G. Knepley PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad)); 13385962854dSMatthew G. Knepley PetscCall(DMRestoreGlobalVector(dmGrad, &grad)); 13395962854dSMatthew G. Knepley } 13405962854dSMatthew G. Knepley PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, time, faceGeometryFVM, cellGeometryFVM, locGrad)); 13415962854dSMatthew G. Knepley if (locGradient) *locGradient = locGrad; 13425962854dSMatthew G. Knepley else if (locGrad) PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 13435962854dSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 13445962854dSMatthew G. Knepley } 13455962854dSMatthew G. Knepley 1346d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2Diff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 1347d71ae5a4SJacob Faibussowitsch { 1348574a98acSMatthew G. Knepley Vec localX; 1349574a98acSMatthew G. Knepley 1350574a98acSMatthew G. Knepley PetscFunctionBegin; 13519566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 13529566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, localX, time, NULL, NULL, NULL)); 13539566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 13549566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 13559566063dSJacob Faibussowitsch PetscCall(DMPlexComputeL2DiffLocal(dm, time, funcs, ctxs, localX, diff)); 13569566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 13573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1358574a98acSMatthew G. Knepley } 1359574a98acSMatthew G. Knepley 1360574a98acSMatthew G. Knepley /*@C 136160225df5SJacob Faibussowitsch DMPlexComputeL2DiffLocal - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h. 1362574a98acSMatthew G. Knepley 136320f4b53cSBarry Smith Collective 1364c0f8e1fdSMatthew G. Knepley 1365574a98acSMatthew G. Knepley Input Parameters: 1366a1cb98faSBarry Smith + dm - The `DM` 1367574a98acSMatthew G. Knepley . time - The time 1368574a98acSMatthew G. Knepley . funcs - The functions to evaluate for each field component 136920f4b53cSBarry Smith . ctxs - Optional array of contexts to pass to each function, or `NULL`. 1370574a98acSMatthew G. Knepley - localX - The coefficient vector u_h, a local vector 1371574a98acSMatthew G. Knepley 1372574a98acSMatthew G. Knepley Output Parameter: 1373574a98acSMatthew G. Knepley . diff - The diff ||u - u_h||_2 1374574a98acSMatthew G. Knepley 1375574a98acSMatthew G. Knepley Level: developer 1376574a98acSMatthew G. Knepley 13771cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 1378574a98acSMatthew G. Knepley @*/ 1379d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeL2DiffLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec localX, PetscReal *diff) 1380d71ae5a4SJacob Faibussowitsch { 13810f09c10fSMatthew G. Knepley const PetscInt debug = ((DM_Plex *)dm->data)->printL2; 1382ca3d3a14SMatthew G. Knepley DM tdm; 1383ca3d3a14SMatthew G. Knepley Vec tv; 1384cb1e1211SMatthew G Knepley PetscSection section; 1385c5bbbd5bSMatthew G. Knepley PetscQuadrature quad; 13864bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 138715496722SMatthew G. Knepley PetscScalar *funcVal, *interpolant; 13884bee2e38SMatthew G. Knepley PetscReal *coords, *gcoords; 1389cb1e1211SMatthew G Knepley PetscReal localDiff = 0.0; 13907318780aSToby Isaac const PetscReal *quadWeights; 1391412e9a14SMatthew G. Knepley PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cellHeight, cStart, cEnd, c, field, fieldOffset; 1392ca3d3a14SMatthew G. Knepley PetscBool transform; 1393cb1e1211SMatthew G Knepley 1394cb1e1211SMatthew G Knepley PetscFunctionBegin; 13959566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 13969566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 13972a4e142eSMatthew G. Knepley fegeom.dimEmbed = coordDim; 13989566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 13999566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &numFields)); 14009566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 14019566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 14029566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 1403eae3dc7dSJacob Faibussowitsch PetscCheck(numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!"); 1404cb1e1211SMatthew G Knepley for (field = 0; field < numFields; ++field) { 140515496722SMatthew G. Knepley PetscObject obj; 140615496722SMatthew G. Knepley PetscClassId id; 1407c5bbbd5bSMatthew G. Knepley PetscInt Nc; 1408c5bbbd5bSMatthew G. Knepley 14099566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 14109566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 141115496722SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 141215496722SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 141315496722SMatthew G. Knepley 14149566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 14159566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 141615496722SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 141715496722SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 141815496722SMatthew G. Knepley 14199566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 14209566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 142163a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1422c5bbbd5bSMatthew G. Knepley numComponents += Nc; 1423cb1e1211SMatthew G Knepley } 14249566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights)); 142563a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 1426c9cb6370SYANG Zongze PetscCall(PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * (Nq + 1), &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ)); 14279566063dSJacob Faibussowitsch PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 14289566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 1429cb1e1211SMatthew G Knepley for (c = cStart; c < cEnd; ++c) { 1430a1e44745SMatthew G. Knepley PetscScalar *x = NULL; 1431cb1e1211SMatthew G Knepley PetscReal elemDiff = 0.0; 14329c3cf19fSMatthew G. Knepley PetscInt qc = 0; 1433cb1e1211SMatthew G Knepley 14349566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1435e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, c, 0, NULL, &x)); 1436cb1e1211SMatthew G Knepley 143715496722SMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 143815496722SMatthew G. Knepley PetscObject obj; 143915496722SMatthew G. Knepley PetscClassId id; 1440c110b1eeSGeoffrey Irving void *const ctx = ctxs ? ctxs[field] : NULL; 144115496722SMatthew G. Knepley PetscInt Nb, Nc, q, fc; 1442cb1e1211SMatthew G Knepley 14439566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 14449566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 14459371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 14469371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 14479371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 14489371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 14499371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 14509371c9d4SSatish Balay Nb = 1; 14519371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1452cb1e1211SMatthew G Knepley if (debug) { 1453cb1e1211SMatthew G Knepley char title[1024]; 145463a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field)); 14559566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, title, Nb, &x[fieldOffset])); 1456cb1e1211SMatthew G Knepley } 14577318780aSToby Isaac for (q = 0; q < Nq; ++q) { 14582a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 1459d0609cedSBarry Smith PetscErrorCode ierr; 14602a4e142eSMatthew G. Knepley 14612a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 14622a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 14632a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 14642a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 146563a3b9bcSJacob 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); 1466d3a7d86cSMatthew G. Knepley if (transform) { 1467d3a7d86cSMatthew G. Knepley gcoords = &coords[coordDim * Nq]; 14689566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim * q], PETSC_TRUE, coordDim, &coords[coordDim * q], gcoords, dm->transformCtx)); 1469d3a7d86cSMatthew G. Knepley } else { 1470d3a7d86cSMatthew G. Knepley gcoords = &coords[coordDim * q]; 1471d3a7d86cSMatthew G. Knepley } 14729566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(funcVal, Nc)); 1473ca3d3a14SMatthew G. Knepley ierr = (*funcs[field])(coordDim, time, gcoords, Nc, funcVal, ctx); 1474e735a8a9SMatthew G. Knepley if (ierr) { 14759566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 14769566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 14779566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1478e735a8a9SMatthew G. Knepley } 14799566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[coordDim * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 14809566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant)); 14819566063dSJacob Faibussowitsch else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant)); 14822df84da0SMatthew G. Knepley else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 148315496722SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1484beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 14859371c9d4SSatish Balay if (debug) 1486835f2295SStefano Zampini 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), 14879371c9d4SSatish Balay (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]), (double)PetscRealPart(interpolant[fc]), (double)PetscRealPart(funcVal[fc]))); 14884bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 1489cb1e1211SMatthew G Knepley } 1490cb1e1211SMatthew G Knepley } 14919c3cf19fSMatthew G. Knepley fieldOffset += Nb; 1492beaa55a6SMatthew G. Knepley qc += Nc; 1493cb1e1211SMatthew G Knepley } 14949566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 14959566063dSJacob Faibussowitsch if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff)); 1496cb1e1211SMatthew G Knepley localDiff += elemDiff; 1497cb1e1211SMatthew G Knepley } 14989566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1499462c564dSBarry Smith PetscCallMPI(MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 1500cb1e1211SMatthew G Knepley *diff = PetscSqrtReal(*diff); 15013ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1502cb1e1211SMatthew G Knepley } 1503cb1e1211SMatthew G Knepley 1504d71ae5a4SJacob 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) 1505d71ae5a4SJacob Faibussowitsch { 15060f09c10fSMatthew G. Knepley const PetscInt debug = ((DM_Plex *)dm->data)->printL2; 1507ca3d3a14SMatthew G. Knepley DM tdm; 1508cb1e1211SMatthew G Knepley PetscSection section; 150940e14135SMatthew G. Knepley PetscQuadrature quad; 1510ca3d3a14SMatthew G. Knepley Vec localX, tv; 15119c3cf19fSMatthew G. Knepley PetscScalar *funcVal, *interpolant; 15122a4e142eSMatthew G. Knepley const PetscReal *quadWeights; 15134bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 15144bee2e38SMatthew G. Knepley PetscReal *coords, *gcoords; 151540e14135SMatthew G. Knepley PetscReal localDiff = 0.0; 1516485ad865SMatthew G. Knepley PetscInt dim, coordDim, qNc = 0, Nq = 0, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset; 1517ca3d3a14SMatthew G. Knepley PetscBool transform; 1518cb1e1211SMatthew G Knepley 1519cb1e1211SMatthew G Knepley PetscFunctionBegin; 15209566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 15219566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 15224bee2e38SMatthew G. Knepley fegeom.dimEmbed = coordDim; 15239566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 15249566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &numFields)); 15259566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 15269566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 15279566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 15289566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 15299566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 15309566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 1531652b88e8SMatthew G. Knepley for (field = 0; field < numFields; ++field) { 15320f2d7e86SMatthew G. Knepley PetscFE fe; 153340e14135SMatthew G. Knepley PetscInt Nc; 1534652b88e8SMatthew G. Knepley 15359566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, (PetscObject *)&fe)); 15369566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 15379566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 153840e14135SMatthew G. Knepley numComponents += Nc; 1539652b88e8SMatthew G. Knepley } 15409566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights)); 154163a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 15429566063dSJacob Faibussowitsch /* PetscCall(DMProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX)); */ 1543c9cb6370SYANG 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)); 15449566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 154540e14135SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 154640e14135SMatthew G. Knepley PetscScalar *x = NULL; 154740e14135SMatthew G. Knepley PetscReal elemDiff = 0.0; 15489c3cf19fSMatthew G. Knepley PetscInt qc = 0; 1549652b88e8SMatthew G. Knepley 15509566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1551e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, c, 0, NULL, &x)); 155240e14135SMatthew G. Knepley 15539c3cf19fSMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 15540f2d7e86SMatthew G. Knepley PetscFE fe; 155551259fa3SMatthew G. Knepley void *const ctx = ctxs ? ctxs[field] : NULL; 15569c3cf19fSMatthew G. Knepley PetscInt Nb, Nc, q, fc; 155740e14135SMatthew G. Knepley 15589566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, (PetscObject *)&fe)); 15599566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 15609566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 156140e14135SMatthew G. Knepley if (debug) { 156240e14135SMatthew G. Knepley char title[1024]; 15639566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field)); 15649566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, title, Nb, &x[fieldOffset])); 1565652b88e8SMatthew G. Knepley } 15669c3cf19fSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 15672a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 1568d0609cedSBarry Smith PetscErrorCode ierr; 15692a4e142eSMatthew G. Knepley 15702a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 15712a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 15722a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 15732a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 15742df84da0SMatthew 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); 1575d3a7d86cSMatthew G. Knepley if (transform) { 1576d3a7d86cSMatthew G. Knepley gcoords = &coords[coordDim * Nq]; 15779566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim * q], PETSC_TRUE, coordDim, &coords[coordDim * q], gcoords, dm->transformCtx)); 1578d3a7d86cSMatthew G. Knepley } else { 1579d3a7d86cSMatthew G. Knepley gcoords = &coords[coordDim * q]; 1580d3a7d86cSMatthew G. Knepley } 15819566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(funcVal, Nc)); 15824bee2e38SMatthew G. Knepley ierr = (*funcs[field])(coordDim, time, gcoords, n, Nc, funcVal, ctx); 1583e735a8a9SMatthew G. Knepley if (ierr) { 15849566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 15859566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 15869566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, coords, fegeom.J, fegeom.invJ, interpolant, fegeom.detJ)); 1587e735a8a9SMatthew G. Knepley } 15889566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[coordDim * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 15899566063dSJacob Faibussowitsch PetscCall(PetscFEInterpolateGradient_Static(fe, 1, &x[fieldOffset], &qgeom, q, interpolant)); 15904bee2e38SMatthew G. Knepley /* Overwrite with the dot product if the normal is given */ 15914bee2e38SMatthew G. Knepley if (n) { 15924bee2e38SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 15934bee2e38SMatthew G. Knepley PetscScalar sum = 0.0; 15944bee2e38SMatthew G. Knepley PetscInt d; 15954bee2e38SMatthew G. Knepley for (d = 0; d < dim; ++d) sum += interpolant[fc * dim + d] * n[d]; 15964bee2e38SMatthew G. Knepley interpolant[fc] = sum; 15974bee2e38SMatthew G. Knepley } 15984bee2e38SMatthew G. Knepley } 15999c3cf19fSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1600beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 160163a3b9bcSJacob 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]))); 16024bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 160340e14135SMatthew G. Knepley } 160440e14135SMatthew G. Knepley } 16059c3cf19fSMatthew G. Knepley fieldOffset += Nb; 16069c3cf19fSMatthew G. Knepley qc += Nc; 160740e14135SMatthew G. Knepley } 16089566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 160963a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff)); 161040e14135SMatthew G. Knepley localDiff += elemDiff; 161140e14135SMatthew G. Knepley } 16129566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, coords, fegeom.J, fegeom.invJ, interpolant, fegeom.detJ)); 16139566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 1614462c564dSBarry Smith PetscCallMPI(MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 161540e14135SMatthew G. Knepley *diff = PetscSqrtReal(*diff); 16163ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1617cb1e1211SMatthew G Knepley } 1618cb1e1211SMatthew G Knepley 1619d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2FieldDiff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 1620d71ae5a4SJacob Faibussowitsch { 16210f09c10fSMatthew G. Knepley const PetscInt debug = ((DM_Plex *)dm->data)->printL2; 1622ca3d3a14SMatthew G. Knepley DM tdm; 1623083401c6SMatthew G. Knepley DMLabel depthLabel; 162473d901b8SMatthew G. Knepley PetscSection section; 1625ca3d3a14SMatthew G. Knepley Vec localX, tv; 162673d901b8SMatthew G. Knepley PetscReal *localDiff; 1627083401c6SMatthew G. Knepley PetscInt dim, depth, dE, Nf, f, Nds, s; 1628ca3d3a14SMatthew G. Knepley PetscBool transform; 1629835f2295SStefano Zampini PetscMPIInt Nfi; 163073d901b8SMatthew G. Knepley 163173d901b8SMatthew G. Knepley PetscFunctionBegin; 16329566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 16339566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &dE)); 16349566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 16359566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 16369566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 16379566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 16389566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 16399566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 16409566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 16419566063dSJacob Faibussowitsch PetscCall(DMLabelGetNumValues(depthLabel, &depth)); 1642083401c6SMatthew G. Knepley 16439566063dSJacob Faibussowitsch PetscCall(VecSet(localX, 0.0)); 16449566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 16459566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 16469566063dSJacob Faibussowitsch PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX)); 16479566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 16489566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(Nf, &localDiff)); 1649083401c6SMatthew G. Knepley for (s = 0; s < Nds; ++s) { 1650083401c6SMatthew G. Knepley PetscDS ds; 1651083401c6SMatthew G. Knepley DMLabel label; 1652083401c6SMatthew G. Knepley IS fieldIS, pointIS; 1653083401c6SMatthew G. Knepley const PetscInt *fields, *points = NULL; 1654083401c6SMatthew G. Knepley PetscQuadrature quad; 1655083401c6SMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 1656083401c6SMatthew G. Knepley PetscFEGeom fegeom; 1657083401c6SMatthew G. Knepley PetscReal *coords, *gcoords; 1658083401c6SMatthew G. Knepley PetscScalar *funcVal, *interpolant; 16595fedec97SMatthew G. Knepley PetscBool isCohesive; 1660083401c6SMatthew G. Knepley PetscInt qNc, Nq, totNc, cStart = 0, cEnd, c, dsNf; 166173d901b8SMatthew G. Knepley 166207218a29SMatthew G. Knepley PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL)); 16639566063dSJacob Faibussowitsch PetscCall(ISGetIndices(fieldIS, &fields)); 16649566063dSJacob Faibussowitsch PetscCall(PetscDSIsCohesive(ds, &isCohesive)); 16659566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &dsNf)); 16669566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalComponents(ds, &totNc)); 16679566063dSJacob Faibussowitsch PetscCall(PetscDSGetQuadrature(ds, &quad)); 16689566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 166963a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != totNc), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, totNc); 16709566063dSJacob Faibussowitsch PetscCall(PetscCalloc6(totNc, &funcVal, totNc, &interpolant, dE * (Nq + 1), &coords, Nq, &fegeom.detJ, dE * dE * Nq, &fegeom.J, dE * dE * Nq, &fegeom.invJ)); 1671083401c6SMatthew G. Knepley if (!label) { 16729566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1673083401c6SMatthew G. Knepley } else { 16749566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, 1, &pointIS)); 16759566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &cEnd)); 16769566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 1677083401c6SMatthew G. Knepley } 167873d901b8SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 1679083401c6SMatthew G. Knepley const PetscInt cell = points ? points[c] : c; 168073d901b8SMatthew G. Knepley PetscScalar *x = NULL; 16815fedec97SMatthew G. Knepley const PetscInt *cone; 16825fedec97SMatthew G. Knepley PetscInt qc = 0, fOff = 0, dep; 168373d901b8SMatthew G. Knepley 16849566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(depthLabel, cell, &dep)); 1685083401c6SMatthew G. Knepley if (dep != depth - 1) continue; 16865fedec97SMatthew G. Knepley if (isCohesive) { 16879566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cell, &cone)); 16889566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cone[0], quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 168996959cd1SMatthew G. Knepley } else { 16909566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 169196959cd1SMatthew G. Knepley } 1692e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, cell, 0, NULL, &x)); 16935fedec97SMatthew G. Knepley for (f = 0; f < dsNf; ++f) { 169415496722SMatthew G. Knepley PetscObject obj; 169515496722SMatthew G. Knepley PetscClassId id; 1696083401c6SMatthew G. Knepley void *const ctx = ctxs ? ctxs[fields[f]] : NULL; 169715496722SMatthew G. Knepley PetscInt Nb, Nc, q, fc; 169815496722SMatthew G. Knepley PetscReal elemDiff = 0.0; 16995fedec97SMatthew G. Knepley PetscBool cohesive; 170015496722SMatthew G. Knepley 17019566063dSJacob Faibussowitsch PetscCall(PetscDSGetCohesive(ds, f, &cohesive)); 17029566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 17039566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 17049371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 17059371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 17069371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 17079371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 17089371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 17099371c9d4SSatish Balay Nb = 1; 17109371c9d4SSatish Balay } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]); 1711c82db6dbSMatthew G. Knepley if (isCohesive && !cohesive) { 1712c82db6dbSMatthew G. Knepley fOff += Nb * 2; 1713c82db6dbSMatthew G. Knepley qc += Nc; 1714c82db6dbSMatthew G. Knepley continue; 1715c82db6dbSMatthew G. Knepley } 171673d901b8SMatthew G. Knepley if (debug) { 171773d901b8SMatthew G. Knepley char title[1024]; 171863a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, fields[f])); 17199566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(cell, title, Nb, &x[fOff])); 172073d901b8SMatthew G. Knepley } 17217318780aSToby Isaac for (q = 0; q < Nq; ++q) { 17222a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 1723d0609cedSBarry Smith PetscErrorCode ierr; 17242a4e142eSMatthew G. Knepley 17252a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 1726083401c6SMatthew G. Knepley qgeom.J = &fegeom.J[q * dE * dE]; 1727083401c6SMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * dE * dE]; 17282a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 172963a3b9bcSJacob 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); 1730d3a7d86cSMatthew G. Knepley if (transform) { 1731083401c6SMatthew G. Knepley gcoords = &coords[dE * Nq]; 17329566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[dE * q], PETSC_TRUE, dE, &coords[dE * q], gcoords, dm->transformCtx)); 1733d3a7d86cSMatthew G. Knepley } else { 1734083401c6SMatthew G. Knepley gcoords = &coords[dE * q]; 1735d3a7d86cSMatthew G. Knepley } 17362df84da0SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) funcVal[fc] = 0.; 1737083401c6SMatthew G. Knepley ierr = (*funcs[fields[f]])(dE, time, gcoords, Nc, funcVal, ctx); 1738e735a8a9SMatthew G. Knepley if (ierr) { 17399566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x)); 17409566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 17419566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1742e735a8a9SMatthew G. Knepley } 17439566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[dE * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 174496959cd1SMatthew G. Knepley /* Call once for each face, except for lagrange field */ 17459566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fOff], &qgeom, q, interpolant)); 17469566063dSJacob Faibussowitsch else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fOff], q, interpolant)); 174763a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]); 174815496722SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1749beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 17509371c9d4SSatish Balay if (debug) 1751835f2295SStefano Zampini 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), 17529371c9d4SSatish Balay (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]))); 17534bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 175473d901b8SMatthew G. Knepley } 175573d901b8SMatthew G. Knepley } 1756083401c6SMatthew G. Knepley fOff += Nb; 17579c3cf19fSMatthew G. Knepley qc += Nc; 1758083401c6SMatthew G. Knepley localDiff[fields[f]] += elemDiff; 175963a3b9bcSJacob 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]])); 176073d901b8SMatthew G. Knepley } 17619566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x)); 1762083401c6SMatthew G. Knepley } 1763083401c6SMatthew G. Knepley if (label) { 17649566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 17659566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 1766083401c6SMatthew G. Knepley } 17679566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(fieldIS, &fields)); 17689566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 176973d901b8SMatthew G. Knepley } 17709566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 1771835f2295SStefano Zampini PetscCall(PetscMPIIntCast(Nf, &Nfi)); 1772835f2295SStefano Zampini PetscCallMPI(MPIU_Allreduce(localDiff, diff, Nfi, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 17739566063dSJacob Faibussowitsch PetscCall(PetscFree(localDiff)); 1774083401c6SMatthew G. Knepley for (f = 0; f < Nf; ++f) diff[f] = PetscSqrtReal(diff[f]); 17753ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 177673d901b8SMatthew G. Knepley } 177773d901b8SMatthew G. Knepley 1778e729f68cSMatthew G. Knepley /*@C 1779e729f68cSMatthew 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. 1780e729f68cSMatthew G. Knepley 178120f4b53cSBarry Smith Collective 1782c0f8e1fdSMatthew G. Knepley 1783e729f68cSMatthew G. Knepley Input Parameters: 1784a1cb98faSBarry Smith + dm - The `DM` 17850163fd50SMatthew G. Knepley . time - The time 178620f4b53cSBarry Smith . funcs - The functions to evaluate for each field component: `NULL` means that component does not contribute to error calculation 178720f4b53cSBarry Smith . ctxs - Optional array of contexts to pass to each function, or `NULL`. 1788e729f68cSMatthew G. Knepley - X - The coefficient vector u_h 1789e729f68cSMatthew G. Knepley 1790e729f68cSMatthew G. Knepley Output Parameter: 179120f4b53cSBarry Smith . D - A `Vec` which holds the difference ||u - u_h||_2 for each cell 1792e729f68cSMatthew G. Knepley 1793e729f68cSMatthew G. Knepley Level: developer 1794e729f68cSMatthew G. Knepley 17951cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 1796e729f68cSMatthew G. Knepley @*/ 1797d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeL2DiffVec(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, Vec D) 1798d71ae5a4SJacob Faibussowitsch { 1799e729f68cSMatthew G. Knepley PetscSection section; 1800e729f68cSMatthew G. Knepley PetscQuadrature quad; 1801e729f68cSMatthew G. Knepley Vec localX; 18024bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 1803e729f68cSMatthew G. Knepley PetscScalar *funcVal, *interpolant; 18044bee2e38SMatthew G. Knepley PetscReal *coords; 1805e729f68cSMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 1806485ad865SMatthew G. Knepley PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, c, field, fieldOffset; 1807e729f68cSMatthew G. Knepley 1808e729f68cSMatthew G. Knepley PetscFunctionBegin; 18099566063dSJacob Faibussowitsch PetscCall(VecSet(D, 0.0)); 18109566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 18119566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 18129566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 18139566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &numFields)); 18149566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 18159566063dSJacob Faibussowitsch PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX)); 18169566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 18179566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 1818e729f68cSMatthew G. Knepley for (field = 0; field < numFields; ++field) { 1819e729f68cSMatthew G. Knepley PetscObject obj; 1820e729f68cSMatthew G. Knepley PetscClassId id; 1821e729f68cSMatthew G. Knepley PetscInt Nc; 1822e729f68cSMatthew G. Knepley 18239566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 18249566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 1825e729f68cSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 1826e729f68cSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 1827e729f68cSMatthew G. Knepley 18289566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 18299566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 1830e729f68cSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 1831e729f68cSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 1832e729f68cSMatthew G. Knepley 18339566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 18349566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 183563a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1836e729f68cSMatthew G. Knepley numComponents += Nc; 1837e729f68cSMatthew G. Knepley } 18389566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 183963a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 18409566063dSJacob Faibussowitsch PetscCall(PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * Nq, &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ)); 18419566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1842e729f68cSMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 1843e729f68cSMatthew G. Knepley PetscScalar *x = NULL; 18446f288a59SMatthew G. Knepley PetscScalar elemDiff = 0.0; 18459c3cf19fSMatthew G. Knepley PetscInt qc = 0; 1846e729f68cSMatthew G. Knepley 18479566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1848e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, c, 0, NULL, &x)); 1849e729f68cSMatthew G. Knepley 1850e729f68cSMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 1851e729f68cSMatthew G. Knepley PetscObject obj; 1852e729f68cSMatthew G. Knepley PetscClassId id; 1853e729f68cSMatthew G. Knepley void *const ctx = ctxs ? ctxs[field] : NULL; 1854e729f68cSMatthew G. Knepley PetscInt Nb, Nc, q, fc; 1855e729f68cSMatthew G. Knepley 18569566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 18579566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 18589371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 18599371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 18609371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 18619371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 18629371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 18639371c9d4SSatish Balay Nb = 1; 18649371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 186523f34ed2SToby Isaac if (funcs[field]) { 18667318780aSToby Isaac for (q = 0; q < Nq; ++q) { 18672a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 18682a4e142eSMatthew G. Knepley 18692a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 18702a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 18712a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 18722a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 187363a3b9bcSJacob 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); 18749566063dSJacob Faibussowitsch PetscCall((*funcs[field])(coordDim, time, &coords[q * coordDim], Nc, funcVal, ctx)); 1875c3e24edfSBarry Smith #if defined(needs_fix_with_return_code_argument) 1876e735a8a9SMatthew G. Knepley if (ierr) { 18779566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 18789566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 18799566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 1880e735a8a9SMatthew G. Knepley } 1881c3e24edfSBarry Smith #endif 18829566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant)); 18839566063dSJacob Faibussowitsch else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant)); 188463a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1885e729f68cSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1886beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 18874bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 1888e729f68cSMatthew G. Knepley } 1889e729f68cSMatthew G. Knepley } 189023f34ed2SToby Isaac } 1891beaa55a6SMatthew G. Knepley fieldOffset += Nb; 18929c3cf19fSMatthew G. Knepley qc += Nc; 1893e729f68cSMatthew G. Knepley } 18949566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 18959566063dSJacob Faibussowitsch PetscCall(VecSetValue(D, c - cStart, elemDiff, INSERT_VALUES)); 1896e729f68cSMatthew G. Knepley } 18979566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 18989566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 18999566063dSJacob Faibussowitsch PetscCall(VecSqrtAbs(D)); 19003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1901e729f68cSMatthew G. Knepley } 1902e729f68cSMatthew G. Knepley 19035f0b18bfSMatthew G. Knepley /*@ 19042353bfffSMatthew G. Knepley DMPlexComputeL2FluxDiffVecLocal - This function computes the integral of the difference between the gradient of field `f`in `u` and field `mf` in `mu` 19052353bfffSMatthew G. Knepley 19062353bfffSMatthew G. Knepley Collective 19072353bfffSMatthew G. Knepley 19082353bfffSMatthew G. Knepley Input Parameters: 19092353bfffSMatthew G. Knepley + lu - The local `Vec` containing the primal solution 19102353bfffSMatthew G. Knepley . f - The field number for the potential 19112353bfffSMatthew G. Knepley . lmu - The local `Vec` containing the mixed solution 19122353bfffSMatthew G. Knepley - mf - The field number for the flux 19132353bfffSMatthew G. Knepley 19142353bfffSMatthew G. Knepley Output Parameter: 19152353bfffSMatthew G. Knepley . eFlux - A global `Vec` which holds $||\nabla u_f - \mu_{mf}||$ 19162353bfffSMatthew G. Knepley 19172353bfffSMatthew G. Knepley Level: advanced 19182353bfffSMatthew G. Knepley 19192353bfffSMatthew G. Knepley Notes: 19202353bfffSMatthew G. Knepley We assume that the `DM` for each solution has the same topology, geometry, and quadrature. 19212353bfffSMatthew G. Knepley 19222353bfffSMatthew G. Knepley This is usually used to get an error estimate for the primal solution, using the flux from a mixed solution. 19232353bfffSMatthew G. Knepley 19242353bfffSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeL2FluxDiffVec()`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 19252353bfffSMatthew G. Knepley @*/ 19262353bfffSMatthew G. Knepley PetscErrorCode DMPlexComputeL2FluxDiffVecLocal(Vec lu, PetscInt f, Vec lmu, PetscInt mf, Vec eFlux) 19272353bfffSMatthew G. Knepley { 19282353bfffSMatthew G. Knepley DM dm, mdm, edm; 19292353bfffSMatthew G. Knepley PetscFE fe, mfe; 19302353bfffSMatthew G. Knepley PetscFEGeom fegeom; 19312353bfffSMatthew G. Knepley PetscQuadrature quad; 19322353bfffSMatthew G. Knepley const PetscReal *quadWeights; 19332353bfffSMatthew G. Knepley PetscReal *coords; 19342353bfffSMatthew G. Knepley PetscScalar *interpolant, *minterpolant, *earray; 19352353bfffSMatthew G. Knepley PetscInt cdim, mcdim, cStart, cEnd, Nc, mNc, qNc, Nq; 19362353bfffSMatthew G. Knepley MPI_Comm comm; 19372353bfffSMatthew G. Knepley 19382353bfffSMatthew G. Knepley PetscFunctionBegin; 19392353bfffSMatthew G. Knepley PetscCall(VecGetDM(lu, &dm)); 19402353bfffSMatthew G. Knepley PetscCall(VecGetDM(lmu, &mdm)); 19412353bfffSMatthew G. Knepley PetscCall(VecGetDM(eFlux, &edm)); 19422353bfffSMatthew G. Knepley PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 19432353bfffSMatthew G. Knepley PetscCall(VecSet(eFlux, 0.0)); 19442353bfffSMatthew G. Knepley 19452353bfffSMatthew G. Knepley // Check if the both problems are on the same mesh 19462353bfffSMatthew G. Knepley PetscCall(DMGetCoordinateDim(dm, &cdim)); 19472353bfffSMatthew G. Knepley PetscCall(DMGetCoordinateDim(mdm, &mcdim)); 19482353bfffSMatthew G. Knepley PetscCheck(cdim == mcdim, comm, PETSC_ERR_ARG_SIZ, "primal coordinate Dim %" PetscInt_FMT " != %" PetscInt_FMT " mixed coordinate Dim", cdim, mcdim); 19492353bfffSMatthew G. Knepley fegeom.dimEmbed = cdim; 19502353bfffSMatthew G. Knepley 19512353bfffSMatthew G. Knepley PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe)); 19522353bfffSMatthew G. Knepley PetscCall(DMGetField(mdm, mf, NULL, (PetscObject *)&mfe)); 19532353bfffSMatthew G. Knepley PetscCall(PetscFEGetNumComponents(fe, &Nc)); 19542353bfffSMatthew G. Knepley PetscCall(PetscFEGetNumComponents(mfe, &mNc)); 19552353bfffSMatthew G. Knepley PetscCall(PetscFEGetQuadrature(fe, &quad)); 19562353bfffSMatthew G. Knepley PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights)); 19572353bfffSMatthew G. Knepley PetscCheck(qNc == 1 || qNc == mNc, comm, PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, mNc); 19582353bfffSMatthew G. Knepley 19592353bfffSMatthew G. Knepley PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 19602353bfffSMatthew G. Knepley PetscCall(VecGetArrayWrite(eFlux, &earray)); 19612353bfffSMatthew G. Knepley PetscCall(PetscMalloc6(Nc * cdim, &interpolant, mNc * cdim, &minterpolant, cdim * (Nq + 1), &coords, cdim * cdim * Nq, &fegeom.J, cdim * cdim * Nq, &fegeom.invJ, Nq, &fegeom.detJ)); 19622353bfffSMatthew G. Knepley for (PetscInt c = cStart; c < cEnd; ++c) { 19632353bfffSMatthew G. Knepley PetscScalar *x = NULL; 19642353bfffSMatthew G. Knepley PetscScalar *mx = NULL; 19652353bfffSMatthew G. Knepley PetscScalar *eval = NULL; 19662353bfffSMatthew G. Knepley PetscReal fluxElemDiff = 0.0; 19672353bfffSMatthew G. Knepley 19682353bfffSMatthew G. Knepley PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 19692353bfffSMatthew G. Knepley PetscCall(DMPlexVecGetClosure(dm, NULL, lu, c, NULL, &x)); 19702353bfffSMatthew G. Knepley PetscCall(DMPlexVecGetClosure(mdm, NULL, lmu, c, NULL, &mx)); 19712353bfffSMatthew G. Knepley 19722353bfffSMatthew G. Knepley for (PetscInt q = 0; q < Nq; ++q) { 19732353bfffSMatthew G. Knepley PetscFEGeom qgeom; 19742353bfffSMatthew G. Knepley 19752353bfffSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 19762353bfffSMatthew G. Knepley qgeom.J = &fegeom.J[q * cdim * cdim]; 19772353bfffSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * cdim * cdim]; 19782353bfffSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 19792353bfffSMatthew G. Knepley 19802353bfffSMatthew 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); 19812353bfffSMatthew G. Knepley 19822353bfffSMatthew G. Knepley PetscCall(PetscFEInterpolate_Static(mfe, &mx[0], &qgeom, q, minterpolant)); 19832353bfffSMatthew G. Knepley PetscCall(PetscFEInterpolateGradient_Static(fe, 1, &x[0], &qgeom, q, interpolant)); 19842353bfffSMatthew G. Knepley 19852353bfffSMatthew G. Knepley /* Now take the elementwise difference and store that in a vector. */ 19862353bfffSMatthew G. Knepley for (PetscInt fc = 0; fc < mNc; ++fc) { 19872353bfffSMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : fc)]; 19882353bfffSMatthew G. Knepley fluxElemDiff += PetscSqr(PetscRealPart(interpolant[fc] - minterpolant[fc])) * wt * fegeom.detJ[q]; 19892353bfffSMatthew G. Knepley } 19902353bfffSMatthew G. Knepley } 19912353bfffSMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(dm, NULL, lu, c, NULL, &x)); 19922353bfffSMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(mdm, NULL, lmu, c, NULL, &mx)); 19932353bfffSMatthew G. Knepley PetscCall(DMPlexPointGlobalRef(edm, c, earray, (void *)&eval)); 19942353bfffSMatthew G. Knepley if (eval) eval[0] = fluxElemDiff; 19952353bfffSMatthew G. Knepley } 19962353bfffSMatthew G. Knepley PetscCall(PetscFree6(interpolant, minterpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 19972353bfffSMatthew G. Knepley PetscCall(VecRestoreArrayWrite(eFlux, &earray)); 19982353bfffSMatthew G. Knepley 19992353bfffSMatthew G. Knepley PetscCall(VecAssemblyBegin(eFlux)); 20002353bfffSMatthew G. Knepley PetscCall(VecAssemblyEnd(eFlux)); 20012353bfffSMatthew G. Knepley PetscCall(VecSqrtAbs(eFlux)); 20022353bfffSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 20032353bfffSMatthew G. Knepley } 20042353bfffSMatthew G. Knepley 20052353bfffSMatthew G. Knepley /*@ 20062353bfffSMatthew G. Knepley DMPlexComputeL2FluxDiffVec - This function computes the integral of the difference between the gradient of field `f`in `u` and field `mf` in `mu` 20072353bfffSMatthew G. Knepley 20082353bfffSMatthew G. Knepley Collective 20092353bfffSMatthew G. Knepley 20102353bfffSMatthew G. Knepley Input Parameters: 20112353bfffSMatthew G. Knepley + u - The global `Vec` containing the primal solution 20122353bfffSMatthew G. Knepley . f - The field number for the potential 20132353bfffSMatthew G. Knepley . mu - The global `Vec` containing the mixed solution 20142353bfffSMatthew G. Knepley - mf - The field number for the flux 20152353bfffSMatthew G. Knepley 20162353bfffSMatthew G. Knepley Output Parameter: 20172353bfffSMatthew G. Knepley . eFlux - A global `Vec` which holds $||\nabla u_f - \mu_{mf}||$ 20182353bfffSMatthew G. Knepley 20192353bfffSMatthew G. Knepley Level: advanced 20202353bfffSMatthew G. Knepley 20212353bfffSMatthew G. Knepley Notes: 20222353bfffSMatthew G. Knepley We assume that the `DM` for each solution has the same topology, geometry, and quadrature. 20232353bfffSMatthew G. Knepley 20242353bfffSMatthew G. Knepley This is usually used to get an error estimate for the primal solution, using the flux from a mixed solution. 20252353bfffSMatthew G. Knepley 20262353bfffSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeL2FluxDiffVecLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 20272353bfffSMatthew G. Knepley @*/ 20282353bfffSMatthew G. Knepley PetscErrorCode DMPlexComputeL2FluxDiffVec(Vec u, PetscInt f, Vec mu, PetscInt mf, Vec eFlux) 20292353bfffSMatthew G. Knepley { 20302353bfffSMatthew G. Knepley DM dm, mdm; 20312353bfffSMatthew G. Knepley Vec lu, lmu; 20322353bfffSMatthew G. Knepley 20332353bfffSMatthew G. Knepley PetscFunctionBegin; 20342353bfffSMatthew G. Knepley PetscCall(VecGetDM(u, &dm)); 20352353bfffSMatthew G. Knepley PetscCall(DMGetLocalVector(dm, &lu)); 20362353bfffSMatthew G. Knepley PetscCall(DMGlobalToLocal(dm, u, INSERT_VALUES, lu)); 20372353bfffSMatthew G. Knepley PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, lu, 0.0, NULL, NULL, NULL)); 20382353bfffSMatthew G. Knepley 20392353bfffSMatthew G. Knepley PetscCall(VecGetDM(mu, &mdm)); 20402353bfffSMatthew G. Knepley PetscCall(DMGetLocalVector(mdm, &lmu)); 20412353bfffSMatthew G. Knepley PetscCall(DMGlobalToLocal(mdm, mu, INSERT_VALUES, lmu)); 20422353bfffSMatthew G. Knepley PetscCall(DMPlexInsertBoundaryValues(mdm, PETSC_TRUE, lmu, 0.0, NULL, NULL, NULL)); 20432353bfffSMatthew G. Knepley 20442353bfffSMatthew G. Knepley PetscCall(DMPlexComputeL2FluxDiffVecLocal(lu, f, lmu, mf, eFlux)); 20452353bfffSMatthew G. Knepley 20462353bfffSMatthew G. Knepley PetscCall(DMRestoreLocalVector(dm, &lu)); 20472353bfffSMatthew G. Knepley PetscCall(DMRestoreLocalVector(mdm, &lmu)); 20482353bfffSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 20492353bfffSMatthew G. Knepley } 20502353bfffSMatthew G. Knepley 20512353bfffSMatthew G. Knepley /*@ 205220f4b53cSBarry Smith DMPlexComputeClementInterpolant - This function computes the L2 projection of the cellwise values of a function u onto P1 20535f0b18bfSMatthew G. Knepley 205420f4b53cSBarry Smith Collective 20555f0b18bfSMatthew G. Knepley 20565f0b18bfSMatthew G. Knepley Input Parameters: 2057a1cb98faSBarry Smith + dm - The `DM` 20585f0b18bfSMatthew G. Knepley - locX - The coefficient vector u_h 20595f0b18bfSMatthew G. Knepley 20605f0b18bfSMatthew G. Knepley Output Parameter: 2061a1cb98faSBarry Smith . locC - A `Vec` which holds the Clement interpolant of the function 20625f0b18bfSMatthew G. Knepley 20635f0b18bfSMatthew G. Knepley Level: developer 20645f0b18bfSMatthew G. Knepley 2065a1cb98faSBarry Smith Note: 2066a1cb98faSBarry 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 2067a1cb98faSBarry Smith 20681cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 20695f0b18bfSMatthew G. Knepley @*/ 2070d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeClementInterpolant(DM dm, Vec locX, Vec locC) 2071d71ae5a4SJacob Faibussowitsch { 20725f0b18bfSMatthew G. Knepley PetscInt debug = ((DM_Plex *)dm->data)->printFEM; 20735f0b18bfSMatthew G. Knepley DM dmc; 20745f0b18bfSMatthew G. Knepley PetscQuadrature quad; 20755f0b18bfSMatthew G. Knepley PetscScalar *interpolant, *valsum; 20765f0b18bfSMatthew G. Knepley PetscFEGeom fegeom; 20775f0b18bfSMatthew G. Knepley PetscReal *coords; 20785f0b18bfSMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 20795f0b18bfSMatthew G. Knepley PetscInt dim, cdim, Nf, f, Nc = 0, Nq, qNc, cStart, cEnd, vStart, vEnd, v; 20805f0b18bfSMatthew G. Knepley 20815f0b18bfSMatthew G. Knepley PetscFunctionBegin; 20829566063dSJacob Faibussowitsch PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite)); 20839566063dSJacob Faibussowitsch PetscCall(VecGetDM(locC, &dmc)); 20849566063dSJacob Faibussowitsch PetscCall(VecSet(locC, 0.0)); 20859566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 20869566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &cdim)); 20875f0b18bfSMatthew G. Knepley fegeom.dimEmbed = cdim; 20889566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 20895f0b18bfSMatthew G. Knepley PetscCheck(Nf > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!"); 20905f0b18bfSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 20915f0b18bfSMatthew G. Knepley PetscObject obj; 20925f0b18bfSMatthew G. Knepley PetscClassId id; 20935f0b18bfSMatthew G. Knepley PetscInt fNc; 20945f0b18bfSMatthew G. Knepley 20959566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, f, NULL, &obj)); 20969566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 20975f0b18bfSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 20985f0b18bfSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 20995f0b18bfSMatthew G. Knepley 21009566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 21019566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &fNc)); 21025f0b18bfSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 21035f0b18bfSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 21045f0b18bfSMatthew G. Knepley 21059566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 21069566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &fNc)); 210763a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 21085f0b18bfSMatthew G. Knepley Nc += fNc; 21095f0b18bfSMatthew G. Knepley } 21109566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 211163a3b9bcSJacob Faibussowitsch PetscCheck(qNc == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " > 1", qNc); 21129566063dSJacob Faibussowitsch PetscCall(PetscMalloc6(Nc * 2, &valsum, Nc, &interpolant, cdim * Nq, &coords, Nq, &fegeom.detJ, cdim * cdim * Nq, &fegeom.J, cdim * cdim * Nq, &fegeom.invJ)); 21139566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 21149566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 21155f0b18bfSMatthew G. Knepley for (v = vStart; v < vEnd; ++v) { 21165f0b18bfSMatthew G. Knepley PetscScalar volsum = 0.0; 21175f0b18bfSMatthew G. Knepley PetscInt *star = NULL; 21185f0b18bfSMatthew G. Knepley PetscInt starSize, st, fc; 21195f0b18bfSMatthew G. Knepley 21209566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(valsum, Nc)); 21219566063dSJacob Faibussowitsch PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 21225f0b18bfSMatthew G. Knepley for (st = 0; st < starSize * 2; st += 2) { 21235f0b18bfSMatthew G. Knepley const PetscInt cell = star[st]; 21245f0b18bfSMatthew G. Knepley PetscScalar *val = &valsum[Nc]; 21255f0b18bfSMatthew G. Knepley PetscScalar *x = NULL; 21265f0b18bfSMatthew G. Knepley PetscReal vol = 0.0; 21275f0b18bfSMatthew G. Knepley PetscInt foff = 0; 21285f0b18bfSMatthew G. Knepley 21295f0b18bfSMatthew G. Knepley if ((cell < cStart) || (cell >= cEnd)) continue; 21309566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 21319566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x)); 21325f0b18bfSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 21335f0b18bfSMatthew G. Knepley PetscObject obj; 21345f0b18bfSMatthew G. Knepley PetscClassId id; 21355f0b18bfSMatthew G. Knepley PetscInt Nb, fNc, q; 21365f0b18bfSMatthew G. Knepley 21379566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(val, Nc)); 21389566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, f, NULL, &obj)); 21399566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 21409371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 21419371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &fNc)); 21429371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 21439371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 21449371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &fNc)); 21459371c9d4SSatish Balay Nb = 1; 21469371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 21475f0b18bfSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 21485f0b18bfSMatthew G. Knepley const PetscReal wt = quadWeights[q] * fegeom.detJ[q]; 21495f0b18bfSMatthew G. Knepley PetscFEGeom qgeom; 21505f0b18bfSMatthew G. Knepley 21515f0b18bfSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 21525f0b18bfSMatthew G. Knepley qgeom.J = &fegeom.J[q * cdim * cdim]; 21535f0b18bfSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * cdim * cdim]; 21545f0b18bfSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 215563a3b9bcSJacob 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); 21569566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[foff], &qgeom, q, interpolant)); 215763a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 21585f0b18bfSMatthew G. Knepley for (fc = 0; fc < fNc; ++fc) val[foff + fc] += interpolant[fc] * wt; 21595f0b18bfSMatthew G. Knepley vol += wt; 21605f0b18bfSMatthew G. Knepley } 21615f0b18bfSMatthew G. Knepley foff += Nb; 21625f0b18bfSMatthew G. Knepley } 21639566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x)); 21645f0b18bfSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) valsum[fc] += val[fc]; 21655f0b18bfSMatthew G. Knepley volsum += vol; 21665f0b18bfSMatthew G. Knepley if (debug) { 21679566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " value: [", v, cell)); 21685f0b18bfSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 21699566063dSJacob Faibussowitsch if (fc) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 21709566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(val[fc]))); 21715f0b18bfSMatthew G. Knepley } 21729566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n")); 21735f0b18bfSMatthew G. Knepley } 21745f0b18bfSMatthew G. Knepley } 21755f0b18bfSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) valsum[fc] /= volsum; 21769566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 21779566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dmc, NULL, locC, v, valsum, INSERT_VALUES)); 21785f0b18bfSMatthew G. Knepley } 21799566063dSJacob Faibussowitsch PetscCall(PetscFree6(valsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 21803ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 21815f0b18bfSMatthew G. Knepley } 21825f0b18bfSMatthew G. Knepley 21835f0b18bfSMatthew G. Knepley /*@ 218420f4b53cSBarry Smith DMPlexComputeGradientClementInterpolant - This function computes the L2 projection of the cellwise gradient of a function u onto P1 21851555c271SMatthew G. Knepley 218620f4b53cSBarry Smith Collective 2187c0f8e1fdSMatthew G. Knepley 21881555c271SMatthew G. Knepley Input Parameters: 2189a1cb98faSBarry Smith + dm - The `DM` 21905f0b18bfSMatthew G. Knepley - locX - The coefficient vector u_h 21911555c271SMatthew G. Knepley 21921555c271SMatthew G. Knepley Output Parameter: 2193a1cb98faSBarry Smith . locC - A `Vec` which holds the Clement interpolant of the gradient 21941555c271SMatthew G. Knepley 21951555c271SMatthew G. Knepley Level: developer 21961555c271SMatthew G. Knepley 2197a1cb98faSBarry Smith Note: 2198a1cb98faSBarry 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 2199a1cb98faSBarry Smith 22001cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 22011555c271SMatthew G. Knepley @*/ 2202d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeGradientClementInterpolant(DM dm, Vec locX, Vec locC) 2203d71ae5a4SJacob Faibussowitsch { 2204db1066baSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 2205db1066baSMatthew G. Knepley PetscInt debug = mesh->printFEM; 22061555c271SMatthew G. Knepley DM dmC; 22071555c271SMatthew G. Knepley PetscQuadrature quad; 22081555c271SMatthew G. Knepley PetscScalar *interpolant, *gradsum; 22094bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 22104bee2e38SMatthew G. Knepley PetscReal *coords; 22111555c271SMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 2212485ad865SMatthew G. Knepley PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, vStart, vEnd, v, field, fieldOffset; 22131555c271SMatthew G. Knepley 22141555c271SMatthew G. Knepley PetscFunctionBegin; 22159566063dSJacob Faibussowitsch PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite)); 22169566063dSJacob Faibussowitsch PetscCall(VecGetDM(locC, &dmC)); 22179566063dSJacob Faibussowitsch PetscCall(VecSet(locC, 0.0)); 22189566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 22199566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 22204bee2e38SMatthew G. Knepley fegeom.dimEmbed = coordDim; 22219566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &numFields)); 22225f80ce2aSJacob Faibussowitsch PetscCheck(numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!"); 22231555c271SMatthew G. Knepley for (field = 0; field < numFields; ++field) { 22241555c271SMatthew G. Knepley PetscObject obj; 22251555c271SMatthew G. Knepley PetscClassId id; 22261555c271SMatthew G. Knepley PetscInt Nc; 22271555c271SMatthew G. Knepley 22289566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 22299566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 22301555c271SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 22311555c271SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 22321555c271SMatthew G. Knepley 22339566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 22349566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 22351555c271SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 22361555c271SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 22371555c271SMatthew G. Knepley 22389566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 22399566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 224063a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 22411555c271SMatthew G. Knepley numComponents += Nc; 22421555c271SMatthew G. Knepley } 22439566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 224463a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 22459566063dSJacob 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)); 22469566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 22479566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 22481555c271SMatthew G. Knepley for (v = vStart; v < vEnd; ++v) { 22491555c271SMatthew G. Knepley PetscScalar volsum = 0.0; 22501555c271SMatthew G. Knepley PetscInt *star = NULL; 22511555c271SMatthew G. Knepley PetscInt starSize, st, d, fc; 22521555c271SMatthew G. Knepley 22539566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(gradsum, coordDim * numComponents)); 22549566063dSJacob Faibussowitsch PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 22551555c271SMatthew G. Knepley for (st = 0; st < starSize * 2; st += 2) { 22561555c271SMatthew G. Knepley const PetscInt cell = star[st]; 22571555c271SMatthew G. Knepley PetscScalar *grad = &gradsum[coordDim * numComponents]; 22581555c271SMatthew G. Knepley PetscScalar *x = NULL; 22591555c271SMatthew G. Knepley PetscReal vol = 0.0; 22601555c271SMatthew G. Knepley 22611555c271SMatthew G. Knepley if ((cell < cStart) || (cell >= cEnd)) continue; 22629566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 22639566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x)); 22641555c271SMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 22651555c271SMatthew G. Knepley PetscObject obj; 22661555c271SMatthew G. Knepley PetscClassId id; 22671555c271SMatthew G. Knepley PetscInt Nb, Nc, q, qc = 0; 22681555c271SMatthew G. Knepley 22699566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(grad, coordDim * numComponents)); 22709566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 22719566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 22729371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 22739371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 22749371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 22759371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 22769371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 22779371c9d4SSatish Balay Nb = 1; 22789371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 22791555c271SMatthew G. Knepley for (q = 0; q < Nq; ++q) { 22802a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 22812a4e142eSMatthew G. Knepley 22822a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 22832a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 22842a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 22852a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 228663a3b9bcSJacob 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); 22879566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolateGradient_Static((PetscFE)obj, 1, &x[fieldOffset], &qgeom, q, interpolant)); 228863a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 22891555c271SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 229053d2db2dSJoe Wallwork const PetscReal wt = quadWeights[q * qNc + qc]; 22911555c271SMatthew G. Knepley 22924bee2e38SMatthew G. Knepley for (d = 0; d < coordDim; ++d) grad[fc * coordDim + d] += interpolant[fc * dim + d] * wt * fegeom.detJ[q]; 22931555c271SMatthew G. Knepley } 22944bee2e38SMatthew G. Knepley vol += quadWeights[q * qNc] * fegeom.detJ[q]; 22951555c271SMatthew G. Knepley } 22961555c271SMatthew G. Knepley fieldOffset += Nb; 22971555c271SMatthew G. Knepley qc += Nc; 22981555c271SMatthew G. Knepley } 22999566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x)); 2300f8527842SMatthew G. Knepley for (fc = 0; fc < numComponents; ++fc) { 2301ad540459SPierre Jolivet for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] += grad[fc * coordDim + d]; 2302f8527842SMatthew G. Knepley } 2303f8527842SMatthew G. Knepley volsum += vol; 2304db1066baSMatthew G. Knepley if (debug) { 23059566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " gradient: [", v, cell)); 23061555c271SMatthew G. Knepley for (fc = 0; fc < numComponents; ++fc) { 23071555c271SMatthew G. Knepley for (d = 0; d < coordDim; ++d) { 23089566063dSJacob Faibussowitsch if (fc || d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 23099566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(grad[fc * coordDim + d]))); 23101555c271SMatthew G. Knepley } 23111555c271SMatthew G. Knepley } 23129566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n")); 2313db1066baSMatthew G. Knepley } 23141555c271SMatthew G. Knepley } 23151555c271SMatthew G. Knepley for (fc = 0; fc < numComponents; ++fc) { 23161555c271SMatthew G. Knepley for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] /= volsum; 23171555c271SMatthew G. Knepley } 23189566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 23199566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dmC, NULL, locC, v, gradsum, INSERT_VALUES)); 23201555c271SMatthew G. Knepley } 23219566063dSJacob Faibussowitsch PetscCall(PetscFree6(gradsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 23223ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 23231555c271SMatthew G. Knepley } 23241555c271SMatthew G. Knepley 23256493148fSStefano Zampini PetscErrorCode DMPlexComputeIntegral_Internal(DM dm, Vec locX, PetscInt cStart, PetscInt cEnd, PetscScalar *cintegral, void *user) 2326d71ae5a4SJacob Faibussowitsch { 2327cbf8eb3cSStefano Zampini DM dmAux = NULL, plexA = NULL; 232861aaff12SToby Isaac PetscDS prob, probAux = NULL; 232973d901b8SMatthew G. Knepley PetscSection section, sectionAux; 23306493148fSStefano Zampini Vec locA; 2331c330f8ffSToby Isaac PetscInt dim, numCells = cEnd - cStart, c, f; 2332c330f8ffSToby Isaac PetscBool useFVM = PETSC_FALSE; 2333338f77d5SMatthew G. Knepley /* DS */ 2334338f77d5SMatthew G. Knepley PetscInt Nf, totDim, *uOff, *uOff_x, numConstants; 2335338f77d5SMatthew G. Knepley PetscInt NfAux, totDimAux, *aOff; 23368e3a54c0SPierre Jolivet PetscScalar *u, *a = NULL; 2337338f77d5SMatthew G. Knepley const PetscScalar *constants; 2338338f77d5SMatthew G. Knepley /* Geometry */ 2339c330f8ffSToby Isaac PetscFEGeom *cgeomFEM; 2340338f77d5SMatthew G. Knepley DM dmGrad; 2341c330f8ffSToby Isaac PetscQuadrature affineQuad = NULL; 2342338f77d5SMatthew G. Knepley Vec cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL; 2343b5a3613cSMatthew G. Knepley PetscFVCellGeom *cgeomFVM; 2344338f77d5SMatthew G. Knepley const PetscScalar *lgrad; 2345b7260050SToby Isaac PetscInt maxDegree; 2346c330f8ffSToby Isaac DMField coordField; 2347c330f8ffSToby Isaac IS cellIS; 234873d901b8SMatthew G. Knepley 234973d901b8SMatthew G. Knepley PetscFunctionBegin; 23509566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 23519566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 23529566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 23539566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 2354338f77d5SMatthew G. Knepley /* Determine which discretizations we have */ 2355b5a3613cSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 2356b5a3613cSMatthew G. Knepley PetscObject obj; 2357b5a3613cSMatthew G. Knepley PetscClassId id; 2358b5a3613cSMatthew G. Knepley 23599566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 23609566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 2361338f77d5SMatthew G. Knepley if (id == PETSCFV_CLASSID) useFVM = PETSC_TRUE; 2362338f77d5SMatthew G. Knepley } 2363338f77d5SMatthew G. Knepley /* Read DS information */ 23649566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 23659566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(prob, &uOff)); 23669566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x)); 23679566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PETSC_COMM_SELF, numCells, cStart, 1, &cellIS)); 23689566063dSJacob Faibussowitsch PetscCall(PetscDSGetConstants(prob, &numConstants, &constants)); 2369338f77d5SMatthew G. Knepley /* Read Auxiliary DS information */ 23709566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 23719a2a23afSMatthew G. Knepley if (locA) { 23729566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 2373cbf8eb3cSStefano Zampini PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 23749566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 23759566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(probAux, &NfAux)); 23769566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 23779566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 23789566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(probAux, &aOff)); 2379338f77d5SMatthew G. Knepley } 2380338f77d5SMatthew G. Knepley /* Allocate data arrays */ 23819566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(numCells * totDim, &u)); 23829566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 2383338f77d5SMatthew G. Knepley /* Read out geometry */ 23849566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 23859566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 2386b7260050SToby Isaac if (maxDegree <= 1) { 23879566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 238848a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &cgeomFEM)); 2389b5a3613cSMatthew G. Knepley } 2390b5a3613cSMatthew G. Knepley if (useFVM) { 2391338f77d5SMatthew G. Knepley PetscFV fv = NULL; 2392b5a3613cSMatthew G. Knepley Vec grad; 2393b5a3613cSMatthew G. Knepley PetscInt fStart, fEnd; 2394b5a3613cSMatthew G. Knepley PetscBool compGrad; 2395b5a3613cSMatthew G. Knepley 2396338f77d5SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 2397338f77d5SMatthew G. Knepley PetscObject obj; 2398338f77d5SMatthew G. Knepley PetscClassId id; 2399338f77d5SMatthew G. Knepley 24009566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 24019566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 24029371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 24039371c9d4SSatish Balay fv = (PetscFV)obj; 24049371c9d4SSatish Balay break; 24059371c9d4SSatish Balay } 2406338f77d5SMatthew G. Knepley } 24079566063dSJacob Faibussowitsch PetscCall(PetscFVGetComputeGradients(fv, &compGrad)); 24089566063dSJacob Faibussowitsch PetscCall(PetscFVSetComputeGradients(fv, PETSC_TRUE)); 24099566063dSJacob Faibussowitsch PetscCall(DMPlexComputeGeometryFVM(dm, &cellGeometryFVM, &faceGeometryFVM)); 24109566063dSJacob Faibussowitsch PetscCall(DMPlexComputeGradientFVM(dm, fv, faceGeometryFVM, cellGeometryFVM, &dmGrad)); 24119566063dSJacob Faibussowitsch PetscCall(PetscFVSetComputeGradients(fv, compGrad)); 24129566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM)); 2413b5a3613cSMatthew G. Knepley /* Reconstruct and limit cell gradients */ 24149566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 24159566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmGrad, &grad)); 24169566063dSJacob Faibussowitsch PetscCall(DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad)); 2417b5a3613cSMatthew G. Knepley /* Communicate gradient values */ 24189566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dmGrad, &locGrad)); 24199566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad)); 24209566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad)); 24219566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmGrad, &grad)); 2422b5a3613cSMatthew G. Knepley /* Handle non-essential (e.g. outflow) boundary values */ 24239566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, 0.0, faceGeometryFVM, cellGeometryFVM, locGrad)); 24249566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locGrad, &lgrad)); 2425b5a3613cSMatthew G. Knepley } 2426338f77d5SMatthew G. Knepley /* Read out data from inputs */ 242773d901b8SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 242873d901b8SMatthew G. Knepley PetscScalar *x = NULL; 242973d901b8SMatthew G. Knepley PetscInt i; 243073d901b8SMatthew G. Knepley 24319566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, locX, c, NULL, &x)); 24320f2d7e86SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i]; 24339566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, locX, c, NULL, &x)); 243473d901b8SMatthew G. Knepley if (dmAux) { 2435cbf8eb3cSStefano Zampini PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, c, NULL, &x)); 24360f2d7e86SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i]; 2437cbf8eb3cSStefano Zampini PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, c, NULL, &x)); 243873d901b8SMatthew G. Knepley } 243973d901b8SMatthew G. Knepley } 2440338f77d5SMatthew G. Knepley /* Do integration for each field */ 244173d901b8SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 2442c1f031eeSMatthew G. Knepley PetscObject obj; 2443c1f031eeSMatthew G. Knepley PetscClassId id; 2444c1f031eeSMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 244573d901b8SMatthew G. Knepley 24469566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 24479566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 2448c1f031eeSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 2449c1f031eeSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 2450c1f031eeSMatthew G. Knepley PetscQuadrature q; 2451c330f8ffSToby Isaac PetscFEGeom *chunkGeom = NULL; 2452c1f031eeSMatthew G. Knepley PetscInt Nq, Nb; 2453c1f031eeSMatthew G. Knepley 24549566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 24559566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 24569566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL)); 24579566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 2458c1f031eeSMatthew G. Knepley blockSize = Nb * Nq; 245973d901b8SMatthew G. Knepley batchSize = numBlocks * blockSize; 24609566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 246173d901b8SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 246273d901b8SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 246373d901b8SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 246473d901b8SMatthew G. Knepley offset = numCells - Nr; 246548a46eb9SPierre Jolivet if (!affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, q, PETSC_FALSE, &cgeomFEM)); 24669566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 24679566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrate(prob, f, Ne, chunkGeom, u, probAux, a, cintegral)); 24689566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &chunkGeom)); 24698e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrate(prob, f, Nr, chunkGeom, &u[offset * totDim], probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), &cintegral[offset * Nf])); 24709566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &chunkGeom)); 247148a46eb9SPierre Jolivet if (!affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM)); 2472c1f031eeSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 2473c1f031eeSMatthew G. Knepley PetscInt foff; 2474420e96edSMatthew G. Knepley PetscPointFunc obj_func; 2475c1f031eeSMatthew G. Knepley 24769566063dSJacob Faibussowitsch PetscCall(PetscDSGetObjective(prob, f, &obj_func)); 24779566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, f, &foff)); 2478c1f031eeSMatthew G. Knepley if (obj_func) { 2479c1f031eeSMatthew G. Knepley for (c = 0; c < numCells; ++c) { 2480b5a3613cSMatthew G. Knepley PetscScalar *u_x; 2481d627b919SMatthew G. Knepley PetscScalar lint = 0.; 2482b5a3613cSMatthew G. Knepley 24839566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, c, lgrad, &u_x)); 248455bffe1bSPierre Jolivet obj_func(dim, Nf, NfAux, uOff, uOff_x, &u[totDim * c + foff], NULL, u_x, aOff, NULL, PetscSafePointerPlusOffset(a, totDimAux * c), NULL, NULL, 0.0, cgeomFVM[c].centroid, numConstants, constants, &lint); 2485338f77d5SMatthew G. Knepley cintegral[c * Nf + f] += PetscRealPart(lint) * cgeomFVM[c].volume; 248673d901b8SMatthew G. Knepley } 2487c1f031eeSMatthew G. Knepley } 248863a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 2489c1f031eeSMatthew G. Knepley } 2490338f77d5SMatthew G. Knepley /* Cleanup data arrays */ 2491b5a3613cSMatthew G. Knepley if (useFVM) { 24929566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(locGrad, &lgrad)); 24939566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM)); 24949566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 24959566063dSJacob Faibussowitsch PetscCall(VecDestroy(&faceGeometryFVM)); 24969566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cellGeometryFVM)); 24979566063dSJacob Faibussowitsch PetscCall(DMDestroy(&dmGrad)); 2498b5a3613cSMatthew G. Knepley } 24999566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscFree(a)); 2500cbf8eb3cSStefano Zampini PetscCall(DMDestroy(&plexA)); 25019566063dSJacob Faibussowitsch PetscCall(PetscFree(u)); 2502338f77d5SMatthew G. Knepley /* Cleanup */ 250348a46eb9SPierre Jolivet if (affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM)); 25049566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 25059566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cellIS)); 25063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2507338f77d5SMatthew G. Knepley } 2508338f77d5SMatthew G. Knepley 2509338f77d5SMatthew G. Knepley /*@ 2510338f77d5SMatthew G. Knepley DMPlexComputeIntegralFEM - Form the integral over the domain from the global input X using pointwise functions specified by the user 2511338f77d5SMatthew G. Knepley 2512338f77d5SMatthew G. Knepley Input Parameters: 2513338f77d5SMatthew G. Knepley + dm - The mesh 2514338f77d5SMatthew G. Knepley . X - Global input vector 2515338f77d5SMatthew G. Knepley - user - The user context 2516338f77d5SMatthew G. Knepley 2517338f77d5SMatthew G. Knepley Output Parameter: 2518338f77d5SMatthew G. Knepley . integral - Integral for each field 2519338f77d5SMatthew G. Knepley 2520338f77d5SMatthew G. Knepley Level: developer 2521338f77d5SMatthew G. Knepley 25221cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()` 2523338f77d5SMatthew G. Knepley @*/ 2524d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscScalar *integral, void *user) 2525d71ae5a4SJacob Faibussowitsch { 2526cbf8eb3cSStefano Zampini PetscInt printFEM; 2527b8feb594SMatthew G. Knepley PetscScalar *cintegral, *lintegral; 2528412e9a14SMatthew G. Knepley PetscInt Nf, f, cellHeight, cStart, cEnd, cell; 25296493148fSStefano Zampini Vec locX; 2530835f2295SStefano Zampini PetscMPIInt Nfi; 2531338f77d5SMatthew G. Knepley 2532338f77d5SMatthew G. Knepley PetscFunctionBegin; 2533338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2534338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 25354f572ea9SToby Isaac PetscAssertPointer(integral, 3); 25369566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 2537cbf8eb3cSStefano Zampini PetscCall(DMPlexConvertPlex(dm, &dm, PETSC_TRUE)); 25389566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 25399566063dSJacob Faibussowitsch PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 25409566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 2541338f77d5SMatthew G. Knepley /* TODO Introduce a loop over large chunks (right now this is a single chunk) */ 25429566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &lintegral, (cEnd - cStart) * Nf, &cintegral)); 25436493148fSStefano Zampini /* Get local solution with boundary values */ 25446493148fSStefano Zampini PetscCall(DMGetLocalVector(dm, &locX)); 25456493148fSStefano Zampini PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 25466493148fSStefano Zampini PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 25476493148fSStefano Zampini PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 25486493148fSStefano Zampini PetscCall(DMPlexComputeIntegral_Internal(dm, locX, cStart, cEnd, cintegral, user)); 25496493148fSStefano Zampini PetscCall(DMRestoreLocalVector(dm, &locX)); 2550cbf8eb3cSStefano Zampini printFEM = ((DM_Plex *)dm->data)->printFEM; 2551338f77d5SMatthew G. Knepley /* Sum up values */ 2552338f77d5SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 2553338f77d5SMatthew G. Knepley const PetscInt c = cell - cStart; 2554338f77d5SMatthew G. Knepley 2555cbf8eb3cSStefano Zampini if (printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf])); 2556b8feb594SMatthew G. Knepley for (f = 0; f < Nf; ++f) lintegral[f] += cintegral[c * Nf + f]; 2557338f77d5SMatthew G. Knepley } 2558835f2295SStefano Zampini PetscCall(PetscMPIIntCast(Nf, &Nfi)); 2559835f2295SStefano Zampini PetscCallMPI(MPIU_Allreduce(lintegral, integral, Nfi, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 2560cbf8eb3cSStefano Zampini if (printFEM) { 25619566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Integral:")); 25629566063dSJacob Faibussowitsch for (f = 0; f < Nf; ++f) PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), " %g", (double)PetscRealPart(integral[f]))); 25639566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "\n")); 256473d901b8SMatthew G. Knepley } 25659566063dSJacob Faibussowitsch PetscCall(PetscFree2(lintegral, cintegral)); 25669566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 2567cbf8eb3cSStefano Zampini PetscCall(DMDestroy(&dm)); 25683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2569338f77d5SMatthew G. Knepley } 2570338f77d5SMatthew G. Knepley 2571338f77d5SMatthew G. Knepley /*@ 2572338f77d5SMatthew G. Knepley DMPlexComputeCellwiseIntegralFEM - Form the vector of cellwise integrals F from the global input X using pointwise functions specified by the user 2573338f77d5SMatthew G. Knepley 2574338f77d5SMatthew G. Knepley Input Parameters: 2575338f77d5SMatthew G. Knepley + dm - The mesh 2576338f77d5SMatthew G. Knepley . X - Global input vector 2577338f77d5SMatthew G. Knepley - user - The user context 2578338f77d5SMatthew G. Knepley 2579338f77d5SMatthew G. Knepley Output Parameter: 258060225df5SJacob Faibussowitsch . F - Cellwise integrals for each field 2581338f77d5SMatthew G. Knepley 2582338f77d5SMatthew G. Knepley Level: developer 2583338f77d5SMatthew G. Knepley 25841cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()` 2585338f77d5SMatthew G. Knepley @*/ 2586d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellwiseIntegralFEM(DM dm, Vec X, Vec F, void *user) 2587d71ae5a4SJacob Faibussowitsch { 2588cbf8eb3cSStefano Zampini PetscInt printFEM; 2589338f77d5SMatthew G. Knepley DM dmF; 25909c8ab049SStefano Zampini PetscSection sectionF = NULL; 2591338f77d5SMatthew G. Knepley PetscScalar *cintegral, *af; 25929c8ab049SStefano Zampini PetscInt Nf, f, cellHeight, cStart, cEnd, cell, n; 25936493148fSStefano Zampini Vec locX; 2594338f77d5SMatthew G. Knepley 2595338f77d5SMatthew G. Knepley PetscFunctionBegin; 2596338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2597338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2598338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(F, VEC_CLASSID, 3); 25999566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 2600cbf8eb3cSStefano Zampini PetscCall(DMPlexConvertPlex(dm, &dm, PETSC_TRUE)); 26019566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 26029566063dSJacob Faibussowitsch PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 26039566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 2604338f77d5SMatthew G. Knepley /* TODO Introduce a loop over large chunks (right now this is a single chunk) */ 26059566063dSJacob Faibussowitsch PetscCall(PetscCalloc1((cEnd - cStart) * Nf, &cintegral)); 26066493148fSStefano Zampini /* Get local solution with boundary values */ 26076493148fSStefano Zampini PetscCall(DMGetLocalVector(dm, &locX)); 26086493148fSStefano Zampini PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 26096493148fSStefano Zampini PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 26106493148fSStefano Zampini PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 26116493148fSStefano Zampini PetscCall(DMPlexComputeIntegral_Internal(dm, locX, cStart, cEnd, cintegral, user)); 26126493148fSStefano Zampini PetscCall(DMRestoreLocalVector(dm, &locX)); 2613338f77d5SMatthew G. Knepley /* Put values in F */ 26149566063dSJacob Faibussowitsch PetscCall(VecGetArray(F, &af)); 26159c8ab049SStefano Zampini PetscCall(VecGetDM(F, &dmF)); 26169c8ab049SStefano Zampini if (dmF) PetscCall(DMGetLocalSection(dmF, §ionF)); 26179c8ab049SStefano Zampini PetscCall(VecGetLocalSize(F, &n)); 26189c8ab049SStefano Zampini PetscCheck(n >= (cEnd - cStart) * Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Vector size %" PetscInt_FMT " < %" PetscInt_FMT, n, (cEnd - cStart) * Nf); 2619cbf8eb3cSStefano Zampini printFEM = ((DM_Plex *)dm->data)->printFEM; 2620338f77d5SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 2621338f77d5SMatthew G. Knepley const PetscInt c = cell - cStart; 26229c8ab049SStefano Zampini PetscInt dof = Nf, off = c * Nf; 2623338f77d5SMatthew G. Knepley 2624cbf8eb3cSStefano Zampini if (printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf])); 26259c8ab049SStefano Zampini if (sectionF) { 26269566063dSJacob Faibussowitsch PetscCall(PetscSectionGetDof(sectionF, cell, &dof)); 26279566063dSJacob Faibussowitsch PetscCall(PetscSectionGetOffset(sectionF, cell, &off)); 26289c8ab049SStefano Zampini } 262963a3b9bcSJacob Faibussowitsch PetscCheck(dof == Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cell dofs %" PetscInt_FMT " != %" PetscInt_FMT, dof, Nf); 2630338f77d5SMatthew G. Knepley for (f = 0; f < Nf; ++f) af[off + f] = cintegral[c * Nf + f]; 2631338f77d5SMatthew G. Knepley } 26329566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(F, &af)); 26339566063dSJacob Faibussowitsch PetscCall(PetscFree(cintegral)); 26349566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 2635cbf8eb3cSStefano Zampini PetscCall(DMDestroy(&dm)); 26363ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 263773d901b8SMatthew G. Knepley } 263873d901b8SMatthew G. Knepley 263979ab67a3SMatthew G. Knepley static PetscErrorCode DMPlexComputeBdIntegral_Internal(DM dm, Vec locX, IS pointIS, 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[]), PetscScalar *fintegral, void *user) 2640d71ae5a4SJacob Faibussowitsch { 26419b6f715bSMatthew G. Knepley DM plex = NULL, plexA = NULL; 2642a6e0b375SMatthew G. Knepley DMEnclosureType encAux; 26439b6f715bSMatthew G. Knepley PetscDS prob, probAux = NULL; 26449b6f715bSMatthew G. Knepley PetscSection section, sectionAux = NULL; 26459b6f715bSMatthew G. Knepley Vec locA = NULL; 26469b6f715bSMatthew G. Knepley DMField coordField; 26479b6f715bSMatthew G. Knepley PetscInt Nf, totDim, *uOff, *uOff_x; 26489b6f715bSMatthew G. Knepley PetscInt NfAux = 0, totDimAux = 0, *aOff = NULL; 26499b6f715bSMatthew G. Knepley PetscScalar *u, *a = NULL; 265064c72086SMatthew G. Knepley const PetscScalar *constants; 26519b6f715bSMatthew G. Knepley PetscInt numConstants, f; 265264c72086SMatthew G. Knepley 265364c72086SMatthew G. Knepley PetscFunctionBegin; 26549566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 26559566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 26569566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 26579566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 26589566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &Nf)); 265964c72086SMatthew G. Knepley /* Determine which discretizations we have */ 26609b6f715bSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 266164c72086SMatthew G. Knepley PetscObject obj; 266264c72086SMatthew G. Knepley PetscClassId id; 266364c72086SMatthew G. Knepley 26649566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 26659566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 266663a3b9bcSJacob Faibussowitsch PetscCheck(id != PETSCFV_CLASSID, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Not supported for FVM (field %" PetscInt_FMT ")", f); 266764c72086SMatthew G. Knepley } 266864c72086SMatthew G. Knepley /* Read DS information */ 26699566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 26709566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(prob, &uOff)); 26719566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x)); 26729566063dSJacob Faibussowitsch PetscCall(PetscDSGetConstants(prob, &numConstants, &constants)); 267364c72086SMatthew G. Knepley /* Read Auxiliary DS information */ 26749566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 26759b6f715bSMatthew G. Knepley if (locA) { 26769b6f715bSMatthew G. Knepley DM dmAux; 26779b6f715bSMatthew G. Knepley 26789566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 26799566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 26809566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 26819566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 26829566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(probAux, &NfAux)); 26839566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 26849566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 26859566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(probAux, &aOff)); 268664c72086SMatthew G. Knepley } 26879b6f715bSMatthew G. Knepley /* Integrate over points */ 26889b6f715bSMatthew G. Knepley { 26899b6f715bSMatthew G. Knepley PetscFEGeom *fgeom, *chunkGeom = NULL; 2690b7260050SToby Isaac PetscInt maxDegree; 26919b6f715bSMatthew G. Knepley PetscQuadrature qGeom = NULL; 26929b6f715bSMatthew G. Knepley const PetscInt *points; 26939b6f715bSMatthew G. Knepley PetscInt numFaces, face, Nq, field; 26949b6f715bSMatthew G. Knepley PetscInt numChunks, chunkSize, chunk, Nr, offset; 269564c72086SMatthew G. Knepley 26969566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 26979566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 269832603206SJames Wright PetscCall(PetscCalloc2(numFaces * totDim, &u, (locA ? (size_t)numFaces * totDimAux : 0), &a)); 26999566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 270079ab67a3SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 270179ab67a3SMatthew G. Knepley const PetscInt point = points[face], *support; 270279ab67a3SMatthew G. Knepley PetscScalar *x = NULL; 270379ab67a3SMatthew G. Knepley 270479ab67a3SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, point, &support)); 270579ab67a3SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 270679ab67a3SMatthew G. Knepley for (PetscInt i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 270779ab67a3SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 270879ab67a3SMatthew G. Knepley if (locA) { 270979ab67a3SMatthew G. Knepley PetscInt subp; 271079ab67a3SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 271179ab67a3SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 271279ab67a3SMatthew G. Knepley for (PetscInt i = 0; i < totDimAux; ++i) a[f * totDimAux + i] = x[i]; 271379ab67a3SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 271479ab67a3SMatthew G. Knepley } 271579ab67a3SMatthew G. Knepley } 271664c72086SMatthew G. Knepley for (field = 0; field < Nf; ++field) { 271764c72086SMatthew G. Knepley PetscFE fe; 271864c72086SMatthew G. Knepley 27199566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fe)); 27209566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 27219b6f715bSMatthew G. Knepley if (!qGeom) { 27229566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 27239566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 27249b6f715bSMatthew G. Knepley } 27259566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 27269566063dSJacob Faibussowitsch PetscCall(DMPlexGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 27279b6f715bSMatthew G. Knepley /* Get blocking */ 27289b6f715bSMatthew G. Knepley { 27299b6f715bSMatthew G. Knepley PetscQuadrature q; 27309b6f715bSMatthew G. Knepley PetscInt numBatches, batchSize, numBlocks, blockSize; 27319b6f715bSMatthew G. Knepley PetscInt Nq, Nb; 27329b6f715bSMatthew G. Knepley 27339566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 27349566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 27359566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL)); 27369566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 273764c72086SMatthew G. Knepley blockSize = Nb * Nq; 273864c72086SMatthew G. Knepley batchSize = numBlocks * blockSize; 27399b6f715bSMatthew G. Knepley chunkSize = numBatches * batchSize; 27409566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 27419b6f715bSMatthew G. Knepley numChunks = numFaces / chunkSize; 27429b6f715bSMatthew G. Knepley Nr = numFaces % chunkSize; 274364c72086SMatthew G. Knepley offset = numFaces - Nr; 274464c72086SMatthew G. Knepley } 27459b6f715bSMatthew G. Knepley /* Do integration for each field */ 27469b6f715bSMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 27479566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, chunk * chunkSize, (chunk + 1) * chunkSize, &chunkGeom)); 274879ab67a3SMatthew G. Knepley PetscCall(PetscFEIntegrateBd(prob, field, funcs[field], chunkSize, chunkGeom, &u[chunk * chunkSize * totDim], probAux, PetscSafePointerPlusOffset(a, chunk * chunkSize * totDimAux), &fintegral[chunk * chunkSize * Nf])); 27499566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom)); 275064c72086SMatthew G. Knepley } 27519566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 275279ab67a3SMatthew G. Knepley PetscCall(PetscFEIntegrateBd(prob, field, funcs[field], Nr, chunkGeom, &u[offset * totDim], probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), &fintegral[offset * Nf])); 27539566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 275464c72086SMatthew G. Knepley /* Cleanup data arrays */ 27559566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 27569566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 275779ab67a3SMatthew G. Knepley } 27589566063dSJacob Faibussowitsch PetscCall(PetscFree2(u, a)); 27599566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 276064c72086SMatthew G. Knepley } 27619566063dSJacob Faibussowitsch if (plex) PetscCall(DMDestroy(&plex)); 27629566063dSJacob Faibussowitsch if (plexA) PetscCall(DMDestroy(&plexA)); 27633ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 27649b6f715bSMatthew G. Knepley } 27659b6f715bSMatthew G. Knepley 276660225df5SJacob Faibussowitsch /*@C 27679b6f715bSMatthew G. Knepley DMPlexComputeBdIntegral - Form the integral over the specified boundary from the global input X using pointwise functions specified by the user 27689b6f715bSMatthew G. Knepley 27699b6f715bSMatthew G. Knepley Input Parameters: 27709b6f715bSMatthew G. Knepley + dm - The mesh 27719b6f715bSMatthew G. Knepley . X - Global input vector 2772a1cb98faSBarry Smith . label - The boundary `DMLabel` 2773a1cb98faSBarry Smith . numVals - The number of label values to use, or `PETSC_DETERMINE` for all values 2774a1cb98faSBarry Smith . vals - The label values to use, or NULL for all values 277579ab67a3SMatthew G. Knepley . funcs - The functions to integrate along the boundary for each field 27769b6f715bSMatthew G. Knepley - user - The user context 27779b6f715bSMatthew G. Knepley 27789b6f715bSMatthew G. Knepley Output Parameter: 27799b6f715bSMatthew G. Knepley . integral - Integral for each field 27809b6f715bSMatthew G. Knepley 27819b6f715bSMatthew G. Knepley Level: developer 27829b6f715bSMatthew G. Knepley 27831cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeIntegralFEM()`, `DMPlexComputeBdResidualFEM()` 27849b6f715bSMatthew G. Knepley @*/ 278579ab67a3SMatthew G. Knepley PetscErrorCode DMPlexComputeBdIntegral(DM dm, Vec X, DMLabel label, PetscInt numVals, const PetscInt vals[], 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[]), PetscScalar *integral, void *user) 2786d71ae5a4SJacob Faibussowitsch { 27879b6f715bSMatthew G. Knepley Vec locX; 27889b6f715bSMatthew G. Knepley PetscSection section; 27899b6f715bSMatthew G. Knepley DMLabel depthLabel; 27909b6f715bSMatthew G. Knepley IS facetIS; 27919b6f715bSMatthew G. Knepley PetscInt dim, Nf, f, v; 27929b6f715bSMatthew G. Knepley 27939b6f715bSMatthew G. Knepley PetscFunctionBegin; 27949b6f715bSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 27959b6f715bSMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2796292bffcbSToby Isaac PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3); 27974f572ea9SToby Isaac if (vals) PetscAssertPointer(vals, 5); 27984f572ea9SToby Isaac PetscAssertPointer(integral, 7); 27999566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 28009566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 28019566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 28029566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 28039566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 28049566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &Nf)); 28059b6f715bSMatthew G. Knepley /* Get local solution with boundary values */ 28069566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &locX)); 28079566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 28089566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 28099566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 28109b6f715bSMatthew G. Knepley /* Loop over label values */ 28119566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(integral, Nf)); 28129b6f715bSMatthew G. Knepley for (v = 0; v < numVals; ++v) { 28139b6f715bSMatthew G. Knepley IS pointIS; 28149b6f715bSMatthew G. Knepley PetscInt numFaces, face; 28159b6f715bSMatthew G. Knepley PetscScalar *fintegral; 28169b6f715bSMatthew G. Knepley 28179566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, vals[v], &pointIS)); 28189b6f715bSMatthew G. Knepley if (!pointIS) continue; /* No points with that id on this process */ 28199b6f715bSMatthew G. Knepley { 28209b6f715bSMatthew G. Knepley IS isectIS; 28219b6f715bSMatthew G. Knepley 28229b6f715bSMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 28239566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 28249566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 28259b6f715bSMatthew G. Knepley pointIS = isectIS; 28269b6f715bSMatthew G. Knepley } 28279566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 28289566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(numFaces * Nf, &fintegral)); 282979ab67a3SMatthew G. Knepley PetscCall(DMPlexComputeBdIntegral_Internal(dm, locX, pointIS, funcs, fintegral, user)); 28309b6f715bSMatthew G. Knepley /* Sum point contributions into integral */ 28319371c9d4SSatish Balay for (f = 0; f < Nf; ++f) 28329371c9d4SSatish Balay for (face = 0; face < numFaces; ++face) integral[f] += fintegral[face * Nf + f]; 28339566063dSJacob Faibussowitsch PetscCall(PetscFree(fintegral)); 28349566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 28359b6f715bSMatthew G. Knepley } 28369566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &locX)); 28379566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 28389566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 28393ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 284064c72086SMatthew G. Knepley } 284164c72086SMatthew G. Knepley 2842d69c5d34SMatthew G. Knepley /*@ 28430318f8a0SStefano Zampini DMPlexComputeInterpolatorNested - Form the local portion of the interpolation matrix from the coarse `DM` to a uniformly refined `DM`. 2844d69c5d34SMatthew G. Knepley 2845d69c5d34SMatthew G. Knepley Input Parameters: 2846cf51de39SMatthew G. Knepley + dmc - The coarse mesh 2847cf51de39SMatthew G. Knepley . dmf - The fine mesh 2848cf51de39SMatthew G. Knepley . isRefined - Flag indicating regular refinement, rather than the same topology 2849d69c5d34SMatthew G. Knepley - user - The user context 2850d69c5d34SMatthew G. Knepley 2851d69c5d34SMatthew G. Knepley Output Parameter: 2852934789fcSMatthew G. Knepley . In - The interpolation matrix 2853d69c5d34SMatthew G. Knepley 2854d69c5d34SMatthew G. Knepley Level: developer 2855d69c5d34SMatthew G. Knepley 2856ae3cf2c1SStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorGeneral()` 2857d69c5d34SMatthew G. Knepley @*/ 2858d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, PetscBool isRefined, Mat In, void *user) 2859d71ae5a4SJacob Faibussowitsch { 2860d69c5d34SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmc->data; 2861d69c5d34SMatthew G. Knepley const char *name = "Interpolator"; 2862d69c5d34SMatthew G. Knepley PetscFE *feRef; 286397c42addSMatthew G. Knepley PetscFV *fvRef; 2864d69c5d34SMatthew G. Knepley PetscSection fsection, fglobalSection; 2865d69c5d34SMatthew G. Knepley PetscSection csection, cglobalSection; 2866d69c5d34SMatthew G. Knepley PetscScalar *elemMat; 2867485ad865SMatthew G. Knepley PetscInt dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, c; 28682ea9c922SToby Isaac PetscInt cTotDim = 0, rTotDim = 0; 2869d69c5d34SMatthew G. Knepley 2870d69c5d34SMatthew G. Knepley PetscFunctionBegin; 28719566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 28729566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dmf, &dim)); 28739566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 28749566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &fglobalSection)); 28759566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 28769566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &cglobalSection)); 28779566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(fsection, &Nf)); 28789566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd)); 28799566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &feRef, Nf, &fvRef)); 2880d69c5d34SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 28812ea9c922SToby Isaac PetscObject obj, objc; 28822ea9c922SToby Isaac PetscClassId id, idc; 28832ea9c922SToby Isaac PetscInt rNb = 0, Nc = 0, cNb = 0; 2884d69c5d34SMatthew G. Knepley 28859566063dSJacob Faibussowitsch PetscCall(DMGetField(dmf, f, NULL, &obj)); 28869566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 288797c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 288897c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 288997c42addSMatthew G. Knepley 2890cf51de39SMatthew G. Knepley if (isRefined) { 28919566063dSJacob Faibussowitsch PetscCall(PetscFERefine(fe, &feRef[f])); 2892cf51de39SMatthew G. Knepley } else { 28939566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)fe)); 2894cf51de39SMatthew G. Knepley feRef[f] = fe; 2895cf51de39SMatthew G. Knepley } 28969566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feRef[f], &rNb)); 28979566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 289897c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 289997c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 290097c42addSMatthew G. Knepley PetscDualSpace Q; 290197c42addSMatthew G. Knepley 2902cf51de39SMatthew G. Knepley if (isRefined) { 29039566063dSJacob Faibussowitsch PetscCall(PetscFVRefine(fv, &fvRef[f])); 2904cf51de39SMatthew G. Knepley } else { 29059566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)fv)); 2906cf51de39SMatthew G. Knepley fvRef[f] = fv; 2907cf51de39SMatthew G. Knepley } 29089566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[f], &Q)); 29099566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &rNb)); 29109566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 29119566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 291297c42addSMatthew G. Knepley } 29139566063dSJacob Faibussowitsch PetscCall(DMGetField(dmc, f, NULL, &objc)); 29149566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(objc, &idc)); 29152ea9c922SToby Isaac if (idc == PETSCFE_CLASSID) { 29162ea9c922SToby Isaac PetscFE fe = (PetscFE)objc; 29172ea9c922SToby Isaac 29189566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cNb)); 29192ea9c922SToby Isaac } else if (id == PETSCFV_CLASSID) { 29202ea9c922SToby Isaac PetscFV fv = (PetscFV)obj; 29212ea9c922SToby Isaac PetscDualSpace Q; 29222ea9c922SToby Isaac 29239566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 29249566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &cNb)); 2925d69c5d34SMatthew G. Knepley } 29262ea9c922SToby Isaac rTotDim += rNb; 29272ea9c922SToby Isaac cTotDim += cNb; 29282ea9c922SToby Isaac } 29299566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(rTotDim * cTotDim, &elemMat)); 29309566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, rTotDim * cTotDim)); 2931d69c5d34SMatthew G. Knepley for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) { 2932d69c5d34SMatthew G. Knepley PetscDualSpace Qref; 2933d69c5d34SMatthew G. Knepley PetscQuadrature f; 2934d69c5d34SMatthew G. Knepley const PetscReal *qpoints, *qweights; 2935d69c5d34SMatthew G. Knepley PetscReal *points; 2936d69c5d34SMatthew G. Knepley PetscInt npoints = 0, Nc, Np, fpdim, i, k, p, d; 2937d69c5d34SMatthew G. Knepley 2938d69c5d34SMatthew G. Knepley /* Compose points from all dual basis functionals */ 293997c42addSMatthew G. Knepley if (feRef[fieldI]) { 29409566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feRef[fieldI], &Qref)); 29419566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feRef[fieldI], &Nc)); 294297c42addSMatthew G. Knepley } else { 29439566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[fieldI], &Qref)); 29449566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvRef[fieldI], &Nc)); 294597c42addSMatthew G. Knepley } 29469566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Qref, &fpdim)); 2947d69c5d34SMatthew G. Knepley for (i = 0; i < fpdim; ++i) { 29489566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 29499566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL)); 2950d69c5d34SMatthew G. Knepley npoints += Np; 2951d69c5d34SMatthew G. Knepley } 29529566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(npoints * dim, &points)); 2953d69c5d34SMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 29549566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 29559566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL)); 29569371c9d4SSatish Balay for (p = 0; p < Np; ++p, ++k) 29579371c9d4SSatish Balay for (d = 0; d < dim; ++d) points[k * dim + d] = qpoints[p * dim + d]; 2958d69c5d34SMatthew G. Knepley } 2959d69c5d34SMatthew G. Knepley 2960d69c5d34SMatthew G. Knepley for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) { 296197c42addSMatthew G. Knepley PetscObject obj; 296297c42addSMatthew G. Knepley PetscClassId id; 29639c3cf19fSMatthew G. Knepley PetscInt NcJ = 0, cpdim = 0, j, qNc; 2964d69c5d34SMatthew G. Knepley 29659566063dSJacob Faibussowitsch PetscCall(DMGetField(dmc, fieldJ, NULL, &obj)); 29669566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 296797c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 296897c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 2969ef0bb6c7SMatthew G. Knepley PetscTabulation T = NULL; 2970d69c5d34SMatthew G. Knepley 2971d69c5d34SMatthew G. Knepley /* Evaluate basis at points */ 29729566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &NcJ)); 29739566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cpdim)); 2974ffe73a53SMatthew G. Knepley /* For now, fields only interpolate themselves */ 2975ffe73a53SMatthew G. Knepley if (fieldI == fieldJ) { 297663a3b9bcSJacob 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); 29779566063dSJacob Faibussowitsch PetscCall(PetscFECreateTabulation(fe, 1, npoints, points, 0, &T)); 2978d69c5d34SMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 29799566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 29809566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights)); 298163a3b9bcSJacob 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); 2982d69c5d34SMatthew G. Knepley for (p = 0; p < Np; ++p, ++k) { 298336a6d9c0SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 2984d172c84bSMatthew G. Knepley /* 2985d172c84bSMatthew G. Knepley cTotDim: Total columns in element interpolation matrix, sum of number of dual basis functionals in each field 2986d172c84bSMatthew G. Knepley offsetI, offsetJ: Offsets into the larger element interpolation matrix for different fields 2987d172c84bSMatthew G. Knepley fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals 2988d172c84bSMatthew G. Knepley qNC, Nc, Ncj, c: Number of components in this field 2989d172c84bSMatthew G. Knepley Np, p: Number of quad points in the fine grid functional i 2990d172c84bSMatthew G. Knepley k: i*Np + p, overall point number for the interpolation 2991d172c84bSMatthew G. Knepley */ 2992ef0bb6c7SMatthew 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]; 299336a6d9c0SMatthew G. Knepley } 2994d69c5d34SMatthew G. Knepley } 2995d69c5d34SMatthew G. Knepley } 29969566063dSJacob Faibussowitsch PetscCall(PetscTabulationDestroy(&T)); 2997ffe73a53SMatthew G. Knepley } 299897c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 299997c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 300097c42addSMatthew G. Knepley 300197c42addSMatthew G. Knepley /* Evaluate constant function at points */ 30029566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &NcJ)); 300397c42addSMatthew G. Knepley cpdim = 1; 300497c42addSMatthew G. Knepley /* For now, fields only interpolate themselves */ 300597c42addSMatthew G. Knepley if (fieldI == fieldJ) { 300663a3b9bcSJacob 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); 300797c42addSMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 30089566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 30099566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights)); 301063a3b9bcSJacob 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); 301197c42addSMatthew G. Knepley for (p = 0; p < Np; ++p, ++k) { 301297c42addSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3013458eb97cSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[(offsetI + i) * cTotDim + offsetJ + j] += 1.0 * qweights[p * qNc + c]; 301497c42addSMatthew G. Knepley } 301597c42addSMatthew G. Knepley } 301697c42addSMatthew G. Knepley } 301797c42addSMatthew G. Knepley } 301897c42addSMatthew G. Knepley } 3019d172c84bSMatthew G. Knepley offsetJ += cpdim; 3020d69c5d34SMatthew G. Knepley } 3021d172c84bSMatthew G. Knepley offsetI += fpdim; 30229566063dSJacob Faibussowitsch PetscCall(PetscFree(points)); 3023d69c5d34SMatthew G. Knepley } 30249566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat)); 30257f5b169aSMatthew G. Knepley /* Preallocate matrix */ 30267f5b169aSMatthew G. Knepley { 3027c094ef40SMatthew G. Knepley Mat preallocator; 3028c094ef40SMatthew G. Knepley PetscScalar *vals; 3029c094ef40SMatthew G. Knepley PetscInt *cellCIndices, *cellFIndices; 3030c094ef40SMatthew G. Knepley PetscInt locRows, locCols, cell; 30317f5b169aSMatthew G. Knepley 30329566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(In, &locRows, &locCols)); 30339566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &preallocator)); 30349566063dSJacob Faibussowitsch PetscCall(MatSetType(preallocator, MATPREALLOCATOR)); 30359566063dSJacob Faibussowitsch PetscCall(MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE)); 30369566063dSJacob Faibussowitsch PetscCall(MatSetUp(preallocator)); 30379566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(rTotDim * cTotDim, &vals, cTotDim, &cellCIndices, rTotDim, &cellFIndices)); 30387f5b169aSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 3039cf51de39SMatthew G. Knepley if (isRefined) { 30409566063dSJacob Faibussowitsch PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices)); 30419566063dSJacob Faibussowitsch PetscCall(MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES)); 3042cf51de39SMatthew G. Knepley } else { 3043e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, PETSC_FALSE, dmc, csection, cglobalSection, PETSC_FALSE, preallocator, cell, vals, INSERT_VALUES)); 3044cf51de39SMatthew G. Knepley } 30457f5b169aSMatthew G. Knepley } 30469566063dSJacob Faibussowitsch PetscCall(PetscFree3(vals, cellCIndices, cellFIndices)); 30479566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY)); 30489566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY)); 30499566063dSJacob Faibussowitsch PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In)); 30509566063dSJacob Faibussowitsch PetscCall(MatDestroy(&preallocator)); 30517f5b169aSMatthew G. Knepley } 30527f5b169aSMatthew G. Knepley /* Fill matrix */ 30539566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(In)); 3054d69c5d34SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 3055cf51de39SMatthew G. Knepley if (isRefined) { 30569566063dSJacob Faibussowitsch PetscCall(DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES)); 3057cf51de39SMatthew G. Knepley } else { 3058e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, PETSC_FALSE, dmc, csection, cglobalSection, PETSC_FALSE, In, c, elemMat, INSERT_VALUES)); 3059cf51de39SMatthew G. Knepley } 3060d69c5d34SMatthew G. Knepley } 30619566063dSJacob Faibussowitsch for (f = 0; f < Nf; ++f) PetscCall(PetscFEDestroy(&feRef[f])); 30629566063dSJacob Faibussowitsch PetscCall(PetscFree2(feRef, fvRef)); 30639566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 30649566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY)); 30659566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY)); 30669318fe57SMatthew G. Knepley if (mesh->printFEM > 1) { 30679566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name)); 30682ce66baaSPierre Jolivet PetscCall(MatFilter(In, 1.0e-10, PETSC_FALSE, PETSC_FALSE)); 30699566063dSJacob Faibussowitsch PetscCall(MatView(In, NULL)); 3070d69c5d34SMatthew G. Knepley } 30719566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 30723ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3073d69c5d34SMatthew G. Knepley } 30746c73c22cSMatthew G. Knepley 3075d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user) 3076d71ae5a4SJacob Faibussowitsch { 3077bd041c0cSMatthew G. Knepley SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_SUP, "Laziness"); 3078bd041c0cSMatthew G. Knepley } 3079bd041c0cSMatthew G. Knepley 308068132eb9SMatthew G. Knepley /*@ 30810318f8a0SStefano Zampini DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix from the coarse `DM` to a non-nested fine `DM`. 308268132eb9SMatthew G. Knepley 308368132eb9SMatthew G. Knepley Input Parameters: 308468132eb9SMatthew G. Knepley + dmf - The fine mesh 308568132eb9SMatthew G. Knepley . dmc - The coarse mesh 308668132eb9SMatthew G. Knepley - user - The user context 308768132eb9SMatthew G. Knepley 308868132eb9SMatthew G. Knepley Output Parameter: 308968132eb9SMatthew G. Knepley . In - The interpolation matrix 309068132eb9SMatthew G. Knepley 309168132eb9SMatthew G. Knepley Level: developer 309268132eb9SMatthew G. Knepley 3093ae3cf2c1SStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()` 309468132eb9SMatthew G. Knepley @*/ 3095d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user) 3096d71ae5a4SJacob Faibussowitsch { 309764e98e1dSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmf->data; 309864e98e1dSMatthew G. Knepley const char *name = "Interpolator"; 30994ef9d792SMatthew G. Knepley PetscDS prob; 3100a0806964SMatthew G. Knepley Mat interp; 3101a0806964SMatthew G. Knepley PetscSection fsection, globalFSection; 3102a0806964SMatthew G. Knepley PetscSection csection, globalCSection; 3103a0806964SMatthew G. Knepley PetscInt locRows, locCols; 31044ef9d792SMatthew G. Knepley PetscReal *x, *v0, *J, *invJ, detJ; 31054ef9d792SMatthew G. Knepley PetscReal *v0c, *Jc, *invJc, detJc; 31064ef9d792SMatthew G. Knepley PetscScalar *elemMat; 3107a0806964SMatthew G. Knepley PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell, s; 31084ef9d792SMatthew G. Knepley 31094ef9d792SMatthew G. Knepley PetscFunctionBegin; 31109566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 31119566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dmc, &dim)); 31129566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 31139566063dSJacob Faibussowitsch PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL)); 31149566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 31159566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ)); 31169566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc)); 31179566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 31189566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 31199566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 31209566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 3121a0806964SMatthew G. Knepley PetscCall(DMPlexGetSimplexOrBoxCells(dmf, 0, &cStart, &cEnd)); 31229566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 31239566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totDim, &elemMat)); 31244ef9d792SMatthew G. Knepley 3125a0806964SMatthew G. Knepley PetscCall(MatGetLocalSize(In, &locRows, &locCols)); 3126a0806964SMatthew G. Knepley PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &interp)); 3127a0806964SMatthew G. Knepley PetscCall(MatSetType(interp, MATPREALLOCATOR)); 3128a0806964SMatthew G. Knepley PetscCall(MatSetSizes(interp, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE)); 3129a0806964SMatthew G. Knepley PetscCall(MatSetUp(interp)); 3130a0806964SMatthew G. Knepley for (s = 0; s < 2; ++s) { 31314ef9d792SMatthew G. Knepley for (field = 0; field < Nf; ++field) { 31324ef9d792SMatthew G. Knepley PetscObject obj; 31334ef9d792SMatthew G. Knepley PetscClassId id; 3134c0d7054bSMatthew G. Knepley PetscDualSpace Q = NULL; 3135ef0bb6c7SMatthew G. Knepley PetscTabulation T = NULL; 31364ef9d792SMatthew G. Knepley PetscQuadrature f; 31374ef9d792SMatthew G. Knepley const PetscReal *qpoints, *qweights; 3138d0f6233fSMatthew G. Knepley PetscInt Nc, qNc, Np, fpdim, off, i, d; 31394ef9d792SMatthew G. Knepley 3140d0f6233fSMatthew G. Knepley PetscCall(PetscDSGetFieldOffset(prob, field, &off)); 31419566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 31429566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 31434ef9d792SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 31444ef9d792SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 31454ef9d792SMatthew G. Knepley 31469566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(fe, &Q)); 31479566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 3148a0806964SMatthew G. Knepley if (s) PetscCall(PetscFECreateTabulation(fe, 1, 1, x, 0, &T)); 31494ef9d792SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 31504ef9d792SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 31514ef9d792SMatthew G. Knepley 31529566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 31534ef9d792SMatthew G. Knepley Nc = 1; 315463a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 31559566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &fpdim)); 31564ef9d792SMatthew G. Knepley /* For each fine grid cell */ 31574ef9d792SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 31584ef9d792SMatthew G. Knepley PetscInt *findices, *cindices; 31594ef9d792SMatthew G. Knepley PetscInt numFIndices, numCIndices; 31604ef9d792SMatthew G. Knepley 31619566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 31629566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 3163d0f6233fSMatthew 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); 31644ef9d792SMatthew G. Knepley for (i = 0; i < fpdim; ++i) { 31654ef9d792SMatthew G. Knepley Vec pointVec; 31664ef9d792SMatthew G. Knepley PetscScalar *pV; 316712111d7cSToby Isaac PetscSF coarseCellSF = NULL; 31683a93e3b7SToby Isaac const PetscSFNode *coarseCells; 3169d0f6233fSMatthew G. Knepley PetscInt numCoarseCells, cpdim, row = findices[i + off], q, c, j; 31704ef9d792SMatthew G. Knepley 31714ef9d792SMatthew G. Knepley /* Get points from the dual basis functional quadrature */ 31729566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Q, i, &f)); 31739566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights)); 317463a3b9bcSJacob 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); 31759566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Np * dim, &pointVec)); 31769566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 31779566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 31784ef9d792SMatthew G. Knepley for (q = 0; q < Np; ++q) { 3179c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3180c330f8ffSToby Isaac 31814ef9d792SMatthew G. Knepley /* Transform point to real space */ 3182c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 31834ef9d792SMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 31844ef9d792SMatthew G. Knepley } 31859566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 31864ef9d792SMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 31871555c271SMatthew G. Knepley /* OPT: Read this out from preallocation information */ 31889566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 31894ef9d792SMatthew G. Knepley /* Update preallocation info */ 31909566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 31915f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Np, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 31929566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 31934ef9d792SMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 3194826eb36dSMatthew G. Knepley PetscReal pVReal[3]; 3195c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3196826eb36dSMatthew G. Knepley 31979566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3198a0806964SMatthew G. Knepley if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetDimension((PetscFE)obj, &cpdim)); 3199a0806964SMatthew G. Knepley else cpdim = 1; 3200a0806964SMatthew G. Knepley 3201a0806964SMatthew G. Knepley if (s) { 32024ef9d792SMatthew G. Knepley /* Transform points from real space to coarse reference space */ 32039566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc)); 3204e2d86523SMatthew G. Knepley for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]); 3205c330f8ffSToby Isaac CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 32064ef9d792SMatthew G. Knepley 32074ef9d792SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 32084ef9d792SMatthew G. Knepley /* Evaluate coarse basis on contained point */ 3209a0806964SMatthew G. Knepley PetscCall(PetscFEComputeTabulation((PetscFE)obj, 1, x, 0, T)); 32109566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 32114ef9d792SMatthew G. Knepley /* Get elemMat entries by multiplying by weight */ 32124ef9d792SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3213ef0bb6c7SMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j * Nc + c] * qweights[ccell * qNc + c]; 32144ef9d792SMatthew G. Knepley } 32154ef9d792SMatthew G. Knepley } else { 32164ef9d792SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 32179c3cf19fSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * qweights[ccell * qNc + c]; 32184ef9d792SMatthew G. Knepley } 32194ef9d792SMatthew G. Knepley } 32209566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 3221a0806964SMatthew G. Knepley } 3222a0806964SMatthew G. Knepley /* Update interpolator */ 3223d0f6233fSMatthew G. Knepley PetscCheck(numCIndices == totDim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, totDim); 3224a0806964SMatthew G. Knepley PetscCall(MatSetValues(interp, 1, &row, cpdim, &cindices[off], elemMat, INSERT_VALUES)); 32259566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 32264ef9d792SMatthew G. Knepley } 32279566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 32289566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 32299566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 32304ef9d792SMatthew G. Knepley } 32319566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 32324ef9d792SMatthew G. Knepley } 3233a0806964SMatthew G. Knepley if (s && id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T)); 3234a0806964SMatthew G. Knepley } 3235a0806964SMatthew G. Knepley if (!s) { 3236a0806964SMatthew G. Knepley PetscCall(MatAssemblyBegin(interp, MAT_FINAL_ASSEMBLY)); 3237a0806964SMatthew G. Knepley PetscCall(MatAssemblyEnd(interp, MAT_FINAL_ASSEMBLY)); 3238a0806964SMatthew G. Knepley PetscCall(MatPreallocatorPreallocate(interp, PETSC_TRUE, In)); 3239a0806964SMatthew G. Knepley PetscCall(MatDestroy(&interp)); 3240a0806964SMatthew G. Knepley interp = In; 3241a0806964SMatthew G. Knepley } 32424ef9d792SMatthew G. Knepley } 32439566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0, J, invJ)); 32449566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0c, Jc, invJc)); 32459566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 32469566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY)); 32479566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY)); 32489566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 32493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 32504ef9d792SMatthew G. Knepley } 32514ef9d792SMatthew G. Knepley 325246fa42a0SMatthew G. Knepley /*@ 32530318f8a0SStefano Zampini DMPlexComputeMassMatrixGeneral - Form the local portion of the mass matrix from the coarse `DM` to a non-nested fine `DM`. 3254bd041c0cSMatthew G. Knepley 3255bd041c0cSMatthew G. Knepley Input Parameters: 3256bd041c0cSMatthew G. Knepley + dmf - The fine mesh 3257bd041c0cSMatthew G. Knepley . dmc - The coarse mesh 3258bd041c0cSMatthew G. Knepley - user - The user context 3259bd041c0cSMatthew G. Knepley 3260bd041c0cSMatthew G. Knepley Output Parameter: 3261bd041c0cSMatthew G. Knepley . mass - The mass matrix 3262bd041c0cSMatthew G. Knepley 3263bd041c0cSMatthew G. Knepley Level: developer 3264bd041c0cSMatthew G. Knepley 3265ae3cf2c1SStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeMassMatrixNested()`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeInterpolatorGeneral()` 3266bd041c0cSMatthew G. Knepley @*/ 3267d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, void *user) 3268d71ae5a4SJacob Faibussowitsch { 3269bd041c0cSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmf->data; 3270bd041c0cSMatthew G. Knepley const char *name = "Mass Matrix"; 3271bd041c0cSMatthew G. Knepley PetscDS prob; 3272bd041c0cSMatthew G. Knepley PetscSection fsection, csection, globalFSection, globalCSection; 3273e8f14785SLisandro Dalcin PetscHSetIJ ht; 3274bd041c0cSMatthew G. Knepley PetscLayout rLayout; 3275bd041c0cSMatthew G. Knepley PetscInt *dnz, *onz; 3276bd041c0cSMatthew G. Knepley PetscInt locRows, rStart, rEnd; 3277bd041c0cSMatthew G. Knepley PetscReal *x, *v0, *J, *invJ, detJ; 3278bd041c0cSMatthew G. Knepley PetscReal *v0c, *Jc, *invJc, detJc; 3279bd041c0cSMatthew G. Knepley PetscScalar *elemMat; 3280bd041c0cSMatthew G. Knepley PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell; 3281bd041c0cSMatthew G. Knepley 3282bd041c0cSMatthew G. Knepley PetscFunctionBegin; 32839566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dmc, &dim)); 32849566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 32859566063dSJacob Faibussowitsch PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL)); 32869566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 32879566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ)); 32889566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc)); 32899566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 32909566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 32919566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 32929566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 32939566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd)); 32949566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 32959566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totDim, &elemMat)); 3296bd041c0cSMatthew G. Knepley 32979566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mass, &locRows, NULL)); 32989566063dSJacob Faibussowitsch PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)mass), &rLayout)); 32999566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(rLayout, locRows)); 33009566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetBlockSize(rLayout, 1)); 33019566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(rLayout)); 33029566063dSJacob Faibussowitsch PetscCall(PetscLayoutGetRange(rLayout, &rStart, &rEnd)); 33039566063dSJacob Faibussowitsch PetscCall(PetscLayoutDestroy(&rLayout)); 33049566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz)); 33059566063dSJacob Faibussowitsch PetscCall(PetscHSetIJCreate(&ht)); 3306bd041c0cSMatthew G. Knepley for (field = 0; field < Nf; ++field) { 3307bd041c0cSMatthew G. Knepley PetscObject obj; 3308bd041c0cSMatthew G. Knepley PetscClassId id; 3309bd041c0cSMatthew G. Knepley PetscQuadrature quad; 3310bd041c0cSMatthew G. Knepley const PetscReal *qpoints; 3311bd041c0cSMatthew G. Knepley PetscInt Nq, Nc, i, d; 3312bd041c0cSMatthew G. Knepley 33139566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 33149566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 33159566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad)); 33169566063dSJacob Faibussowitsch else PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad)); 33179566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL)); 3318bd041c0cSMatthew G. Knepley /* For each fine grid cell */ 3319bd041c0cSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 3320bd041c0cSMatthew G. Knepley Vec pointVec; 3321bd041c0cSMatthew G. Knepley PetscScalar *pV; 3322bd041c0cSMatthew G. Knepley PetscSF coarseCellSF = NULL; 3323bd041c0cSMatthew G. Knepley const PetscSFNode *coarseCells; 3324bd041c0cSMatthew G. Knepley PetscInt numCoarseCells, q, c; 3325bd041c0cSMatthew G. Knepley PetscInt *findices, *cindices; 3326bd041c0cSMatthew G. Knepley PetscInt numFIndices, numCIndices; 3327bd041c0cSMatthew G. Knepley 33289566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 33299566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 3330bd041c0cSMatthew G. Knepley /* Get points from the quadrature */ 33319566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec)); 33329566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 33339566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 3334bd041c0cSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 3335c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3336c330f8ffSToby Isaac 3337bd041c0cSMatthew G. Knepley /* Transform point to real space */ 3338c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 3339bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 3340bd041c0cSMatthew G. Knepley } 33419566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 3342bd041c0cSMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 33439566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 33449566063dSJacob Faibussowitsch PetscCall(PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view")); 3345bd041c0cSMatthew G. Knepley /* Update preallocation info */ 33469566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 33475f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 3348bd041c0cSMatthew G. Knepley { 3349e8f14785SLisandro Dalcin PetscHashIJKey key; 3350e8f14785SLisandro Dalcin PetscBool missing; 3351bd041c0cSMatthew G. Knepley 3352bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 3353e8f14785SLisandro Dalcin key.i = findices[i]; 3354e8f14785SLisandro Dalcin if (key.i >= 0) { 3355bd041c0cSMatthew G. Knepley /* Get indices for coarse elements */ 3356bd041c0cSMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 33579566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3358bd041c0cSMatthew G. Knepley for (c = 0; c < numCIndices; ++c) { 3359e8f14785SLisandro Dalcin key.j = cindices[c]; 3360e8f14785SLisandro Dalcin if (key.j < 0) continue; 33619566063dSJacob Faibussowitsch PetscCall(PetscHSetIJQueryAdd(ht, key, &missing)); 3362bd041c0cSMatthew G. Knepley if (missing) { 3363e8f14785SLisandro Dalcin if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i - rStart]; 3364e8f14785SLisandro Dalcin else ++onz[key.i - rStart]; 3365bd041c0cSMatthew G. Knepley } 3366bd041c0cSMatthew G. Knepley } 33679566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3368bd041c0cSMatthew G. Knepley } 3369bd041c0cSMatthew G. Knepley } 3370bd041c0cSMatthew G. Knepley } 3371bd041c0cSMatthew G. Knepley } 33729566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 33739566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 33749566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3375bd041c0cSMatthew G. Knepley } 3376bd041c0cSMatthew G. Knepley } 33779566063dSJacob Faibussowitsch PetscCall(PetscHSetIJDestroy(&ht)); 33789566063dSJacob Faibussowitsch PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL)); 33799566063dSJacob Faibussowitsch PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE)); 33809566063dSJacob Faibussowitsch PetscCall(PetscFree2(dnz, onz)); 3381bd041c0cSMatthew G. Knepley for (field = 0; field < Nf; ++field) { 3382bd041c0cSMatthew G. Knepley PetscObject obj; 3383bd041c0cSMatthew G. Knepley PetscClassId id; 3384ef0bb6c7SMatthew G. Knepley PetscTabulation T, Tfine; 3385bd041c0cSMatthew G. Knepley PetscQuadrature quad; 3386bd041c0cSMatthew G. Knepley const PetscReal *qpoints, *qweights; 3387bd041c0cSMatthew G. Knepley PetscInt Nq, Nc, i, d; 3388bd041c0cSMatthew G. Knepley 33899566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 33909566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 3391ef0bb6c7SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 33929566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad)); 33939566063dSJacob Faibussowitsch PetscCall(PetscFEGetCellTabulation((PetscFE)obj, 1, &Tfine)); 33949566063dSJacob Faibussowitsch PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, 1, x, 0, &T)); 3395ef0bb6c7SMatthew G. Knepley } else { 33969566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad)); 3397ef0bb6c7SMatthew G. Knepley } 33989566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights)); 3399bd041c0cSMatthew G. Knepley /* For each fine grid cell */ 3400bd041c0cSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 3401bd041c0cSMatthew G. Knepley Vec pointVec; 3402bd041c0cSMatthew G. Knepley PetscScalar *pV; 3403bd041c0cSMatthew G. Knepley PetscSF coarseCellSF = NULL; 3404bd041c0cSMatthew G. Knepley const PetscSFNode *coarseCells; 3405bd041c0cSMatthew G. Knepley PetscInt numCoarseCells, cpdim, q, c, j; 3406bd041c0cSMatthew G. Knepley PetscInt *findices, *cindices; 3407bd041c0cSMatthew G. Knepley PetscInt numFIndices, numCIndices; 3408bd041c0cSMatthew G. Knepley 34099566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 34109566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 3411bd041c0cSMatthew G. Knepley /* Get points from the quadrature */ 34129566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec)); 34139566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 34149566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 3415bd041c0cSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 3416c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3417c330f8ffSToby Isaac 3418bd041c0cSMatthew G. Knepley /* Transform point to real space */ 3419c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 3420bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 3421bd041c0cSMatthew G. Knepley } 34229566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 3423bd041c0cSMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 34249566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 3425bd041c0cSMatthew G. Knepley /* Update matrix */ 34269566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 34275f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 34289566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 3429bd041c0cSMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 3430bd041c0cSMatthew G. Knepley PetscReal pVReal[3]; 3431c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3432c330f8ffSToby Isaac 34339566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3434bd041c0cSMatthew G. Knepley /* Transform points from real space to coarse reference space */ 34359566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc)); 3436bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]); 3437c330f8ffSToby Isaac CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 3438bd041c0cSMatthew G. Knepley 3439bd041c0cSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 3440bd041c0cSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 3441bd041c0cSMatthew G. Knepley 3442bd041c0cSMatthew G. Knepley /* Evaluate coarse basis on contained point */ 34439566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cpdim)); 34449566063dSJacob Faibussowitsch PetscCall(PetscFEComputeTabulation(fe, 1, x, 0, T)); 3445bd041c0cSMatthew G. Knepley /* Get elemMat entries by multiplying by weight */ 3446bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 34479566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 3448bd041c0cSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3449ef0bb6c7SMatthew 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; 3450bd041c0cSMatthew G. Knepley } 3451bd041c0cSMatthew G. Knepley /* Update interpolator */ 34529566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 345363a3b9bcSJacob Faibussowitsch PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim); 34549566063dSJacob Faibussowitsch PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES)); 3455bd041c0cSMatthew G. Knepley } 3456bd041c0cSMatthew G. Knepley } else { 3457bd041c0cSMatthew G. Knepley cpdim = 1; 3458bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 34599566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 3460bd041c0cSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3461bd041c0cSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * 1.0 * qweights[ccell * Nc + c] * detJ; 3462bd041c0cSMatthew G. Knepley } 3463bd041c0cSMatthew G. Knepley /* Update interpolator */ 34649566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 346563a3b9bcSJacob 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)); 346663a3b9bcSJacob Faibussowitsch PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim); 34679566063dSJacob Faibussowitsch PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES)); 3468bd041c0cSMatthew G. Knepley } 3469bd041c0cSMatthew G. Knepley } 34709566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3471bd041c0cSMatthew G. Knepley } 34729566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 34739566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 34749566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 34759566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3476bd041c0cSMatthew G. Knepley } 34779566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T)); 3478bd041c0cSMatthew G. Knepley } 34799566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0, J, invJ)); 34809566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0c, Jc, invJc)); 34819566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 34829566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY)); 34839566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY)); 34843ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3485bd041c0cSMatthew G. Knepley } 3486bd041c0cSMatthew G. Knepley 3487bd041c0cSMatthew G. Knepley /*@ 348846fa42a0SMatthew G. Knepley DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns 348946fa42a0SMatthew G. Knepley 349046fa42a0SMatthew G. Knepley Input Parameters: 349146fa42a0SMatthew G. Knepley + dmc - The coarse mesh 349260225df5SJacob Faibussowitsch . dmf - The fine mesh 349346fa42a0SMatthew G. Knepley - user - The user context 349446fa42a0SMatthew G. Knepley 349546fa42a0SMatthew G. Knepley Output Parameter: 349646fa42a0SMatthew G. Knepley . sc - The mapping 349746fa42a0SMatthew G. Knepley 349846fa42a0SMatthew G. Knepley Level: developer 349946fa42a0SMatthew G. Knepley 3500ae3cf2c1SStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()` 350146fa42a0SMatthew G. Knepley @*/ 3502d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user) 3503d71ae5a4SJacob Faibussowitsch { 3504e9d4ef1bSMatthew G. Knepley PetscDS prob; 35057c927364SMatthew G. Knepley PetscFE *feRef; 350697c42addSMatthew G. Knepley PetscFV *fvRef; 35077c927364SMatthew G. Knepley Vec fv, cv; 35087c927364SMatthew G. Knepley IS fis, cis; 35097c927364SMatthew G. Knepley PetscSection fsection, fglobalSection, csection, cglobalSection; 35107c927364SMatthew G. Knepley PetscInt *cmap, *cellCIndices, *cellFIndices, *cindices, *findices; 3511485ad865SMatthew G. Knepley PetscInt cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, c, dim, d, startC, endC, offsetC, offsetF, m; 35126f3d3cbcSMatthew G. Knepley PetscBool *needAvg; 35137c927364SMatthew G. Knepley 35147c927364SMatthew G. Knepley PetscFunctionBegin; 35159566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InjectorFEM, dmc, dmf, 0, 0)); 35169566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dmf, &dim)); 35179566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 35189566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &fglobalSection)); 35199566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 35209566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &cglobalSection)); 35219566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(fsection, &Nf)); 35229566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd)); 35239566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 35249566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(Nf, &feRef, Nf, &fvRef, Nf, &needAvg)); 35257c927364SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 352697c42addSMatthew G. Knepley PetscObject obj; 352797c42addSMatthew G. Knepley PetscClassId id; 3528aa7890ccSMatthew G. Knepley PetscInt fNb = 0, Nc = 0; 35297c927364SMatthew G. Knepley 35309566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 35319566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 353297c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 353397c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 35346f3d3cbcSMatthew G. Knepley PetscSpace sp; 35359b2fc754SMatthew G. Knepley PetscInt maxDegree; 353697c42addSMatthew G. Knepley 35379566063dSJacob Faibussowitsch PetscCall(PetscFERefine(fe, &feRef[f])); 35389566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feRef[f], &fNb)); 35399566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 35409566063dSJacob Faibussowitsch PetscCall(PetscFEGetBasisSpace(fe, &sp)); 35419566063dSJacob Faibussowitsch PetscCall(PetscSpaceGetDegree(sp, NULL, &maxDegree)); 35429b2fc754SMatthew G. Knepley if (!maxDegree) needAvg[f] = PETSC_TRUE; 354397c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 354497c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 354597c42addSMatthew G. Knepley PetscDualSpace Q; 354697c42addSMatthew G. Knepley 35479566063dSJacob Faibussowitsch PetscCall(PetscFVRefine(fv, &fvRef[f])); 35489566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[f], &Q)); 35499566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &fNb)); 35509566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 35516f3d3cbcSMatthew G. Knepley needAvg[f] = PETSC_TRUE; 355297c42addSMatthew G. Knepley } 3553d172c84bSMatthew G. Knepley fTotDim += fNb; 35547c927364SMatthew G. Knepley } 35559566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &cTotDim)); 35569566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(cTotDim, &cmap)); 35577c927364SMatthew G. Knepley for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) { 35587c927364SMatthew G. Knepley PetscFE feC; 355997c42addSMatthew G. Knepley PetscFV fvC; 35607c927364SMatthew G. Knepley PetscDualSpace QF, QC; 3561d172c84bSMatthew G. Knepley PetscInt order = -1, NcF, NcC, fpdim, cpdim; 35627c927364SMatthew G. Knepley 356397c42addSMatthew G. Knepley if (feRef[field]) { 35649566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&feC)); 35659566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feC, &NcC)); 35669566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feRef[field], &NcF)); 35679566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feRef[field], &QF)); 35689566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetOrder(QF, &order)); 35699566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QF, &fpdim)); 35709566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feC, &QC)); 35719566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QC, &cpdim)); 357297c42addSMatthew G. Knepley } else { 35739566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fvC)); 35749566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvC, &NcC)); 35759566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvRef[field], &NcF)); 35769566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[field], &QF)); 35779566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QF, &fpdim)); 35789566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvC, &QC)); 35799566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QC, &cpdim)); 358097c42addSMatthew G. Knepley } 358163a3b9bcSJacob 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); 35827c927364SMatthew G. Knepley for (c = 0; c < cpdim; ++c) { 35837c927364SMatthew G. Knepley PetscQuadrature cfunc; 3584d172c84bSMatthew G. Knepley const PetscReal *cqpoints, *cqweights; 3585d172c84bSMatthew G. Knepley PetscInt NqcC, NpC; 358697c42addSMatthew G. Knepley PetscBool found = PETSC_FALSE; 35877c927364SMatthew G. Knepley 35889566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(QC, c, &cfunc)); 35899566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights)); 359063a3b9bcSJacob 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); 35911dca8a05SBarry Smith PetscCheck(NpC == 1 || !feRef[field], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments"); 35927c927364SMatthew G. Knepley for (f = 0; f < fpdim; ++f) { 35937c927364SMatthew G. Knepley PetscQuadrature ffunc; 3594d172c84bSMatthew G. Knepley const PetscReal *fqpoints, *fqweights; 35957c927364SMatthew G. Knepley PetscReal sum = 0.0; 3596d172c84bSMatthew G. Knepley PetscInt NqcF, NpF; 35977c927364SMatthew G. Knepley 35989566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(QF, f, &ffunc)); 35999566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights)); 360063a3b9bcSJacob 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); 36017c927364SMatthew G. Knepley if (NpC != NpF) continue; 36027c927364SMatthew G. Knepley for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]); 36037c927364SMatthew G. Knepley if (sum > 1.0e-9) continue; 3604d172c84bSMatthew G. Knepley for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d] * fqweights[d]); 3605d172c84bSMatthew G. Knepley if (sum < 1.0e-9) continue; 3606d172c84bSMatthew G. Knepley cmap[offsetC + c] = offsetF + f; 360797c42addSMatthew G. Knepley found = PETSC_TRUE; 36087c927364SMatthew G. Knepley break; 36097c927364SMatthew G. Knepley } 361097c42addSMatthew G. Knepley if (!found) { 361197c42addSMatthew G. Knepley /* TODO We really want the average here, but some asshole put VecScatter in the interface */ 3612d172c84bSMatthew G. Knepley if (fvRef[field] || (feRef[field] && order == 0)) { 3613d172c84bSMatthew G. Knepley cmap[offsetC + c] = offsetF + 0; 361497c42addSMatthew G. Knepley } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection"); 361597c42addSMatthew G. Knepley } 36167c927364SMatthew G. Knepley } 3617d172c84bSMatthew G. Knepley offsetC += cpdim; 3618d172c84bSMatthew G. Knepley offsetF += fpdim; 36197c927364SMatthew G. Knepley } 36209371c9d4SSatish Balay for (f = 0; f < Nf; ++f) { 36219371c9d4SSatish Balay PetscCall(PetscFEDestroy(&feRef[f])); 36229371c9d4SSatish Balay PetscCall(PetscFVDestroy(&fvRef[f])); 36239371c9d4SSatish Balay } 36249566063dSJacob Faibussowitsch PetscCall(PetscFree3(feRef, fvRef, needAvg)); 36257c927364SMatthew G. Knepley 36269566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmf, &fv)); 36279566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmc, &cv)); 36289566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(cv, &startC, &endC)); 36299566063dSJacob Faibussowitsch PetscCall(PetscSectionGetConstrainedStorageSize(cglobalSection, &m)); 36309566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(cTotDim, &cellCIndices, fTotDim, &cellFIndices)); 36319566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &cindices)); 36329566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &findices)); 36337c927364SMatthew G. Knepley for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1; 36347c927364SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 36359566063dSJacob Faibussowitsch PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices)); 36367c927364SMatthew G. Knepley for (d = 0; d < cTotDim; ++d) { 36370bd915a7SMatthew G. Knepley if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue; 3638d2457c26SMatthew 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]]); 36397c927364SMatthew G. Knepley cindices[cellCIndices[d] - startC] = cellCIndices[d]; 36407c927364SMatthew G. Knepley findices[cellCIndices[d] - startC] = cellFIndices[cmap[d]]; 36417c927364SMatthew G. Knepley } 36427c927364SMatthew G. Knepley } 36439566063dSJacob Faibussowitsch PetscCall(PetscFree(cmap)); 36449566063dSJacob Faibussowitsch PetscCall(PetscFree2(cellCIndices, cellFIndices)); 36457c927364SMatthew G. Knepley 36469566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis)); 36479566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis)); 36489566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(cv, cis, fv, fis, sc)); 36499566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cis)); 36509566063dSJacob Faibussowitsch PetscCall(ISDestroy(&fis)); 36519566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmf, &fv)); 36529566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmc, &cv)); 36539566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InjectorFEM, dmc, dmf, 0, 0)); 36543ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3655cb1e1211SMatthew G Knepley } 3656a1cf66bbSMatthew G. Knepley 36572f856554SMatthew G. Knepley /*@C 36582f856554SMatthew G. Knepley DMPlexGetCellFields - Retrieve the field values values for a chunk of cells 36592f856554SMatthew G. Knepley 36602f856554SMatthew G. Knepley Input Parameters: 3661a1cb98faSBarry Smith + dm - The `DM` 36622f856554SMatthew G. Knepley . cellIS - The cells to include 36632f856554SMatthew G. Knepley . locX - A local vector with the solution fields 36642f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 36652f856554SMatthew G. Knepley - locA - A local vector with auxiliary fields, or NULL 36662f856554SMatthew G. Knepley 36672f856554SMatthew G. Knepley Output Parameters: 36682f856554SMatthew G. Knepley + u - The field coefficients 36692f856554SMatthew G. Knepley . u_t - The fields derivative coefficients 36702f856554SMatthew G. Knepley - a - The auxiliary field coefficients 36712f856554SMatthew G. Knepley 36722f856554SMatthew G. Knepley Level: developer 36732f856554SMatthew G. Knepley 36741cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 36752f856554SMatthew G. Knepley @*/ 3676d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3677d71ae5a4SJacob Faibussowitsch { 36782f856554SMatthew G. Knepley DM plex, plexA = NULL; 3679a6e0b375SMatthew G. Knepley DMEnclosureType encAux; 36802f856554SMatthew G. Knepley PetscSection section, sectionAux; 36812f856554SMatthew G. Knepley PetscDS prob; 36822f856554SMatthew G. Knepley const PetscInt *cells; 36832f856554SMatthew G. Knepley PetscInt cStart, cEnd, numCells, totDim, totDimAux, c; 36842f856554SMatthew G. Knepley 36852f856554SMatthew G. Knepley PetscFunctionBegin; 36862f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3687064a246eSJacob Faibussowitsch PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 3688ad540459SPierre Jolivet if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 4); 3689ad540459SPierre Jolivet if (locA) PetscValidHeaderSpecific(locA, VEC_CLASSID, 5); 36904f572ea9SToby Isaac PetscAssertPointer(u, 6); 36914f572ea9SToby Isaac PetscAssertPointer(u_t, 7); 36924f572ea9SToby Isaac PetscAssertPointer(a, 8); 36939566063dSJacob Faibussowitsch PetscCall(DMPlexConvertPlex(dm, &plex, PETSC_FALSE)); 36949566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 36959566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 369607218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL)); 36979566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 36982f856554SMatthew G. Knepley if (locA) { 36992f856554SMatthew G. Knepley DM dmAux; 37002f856554SMatthew G. Knepley PetscDS probAux; 37012f856554SMatthew G. Knepley 37029566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 37039566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 37049566063dSJacob Faibussowitsch PetscCall(DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE)); 37059566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 37069566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 37079566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 37082f856554SMatthew G. Knepley } 37092f856554SMatthew G. Knepley numCells = cEnd - cStart; 37109566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u)); 37119371c9d4SSatish Balay if (locX_t) PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u_t)); 3712ad540459SPierre Jolivet else *u_t = NULL; 37139371c9d4SSatish Balay if (locA) PetscCall(DMGetWorkArray(dm, numCells * totDimAux, MPIU_SCALAR, a)); 3714ad540459SPierre Jolivet else *a = NULL; 37152f856554SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 37162f856554SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 37172f856554SMatthew G. Knepley const PetscInt cind = c - cStart; 37182f856554SMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a; 37192f856554SMatthew G. Knepley PetscInt i; 37202f856554SMatthew G. Knepley 37219566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x)); 37222f856554SMatthew G. Knepley for (i = 0; i < totDim; ++i) ul[cind * totDim + i] = x[i]; 37239566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x)); 37242f856554SMatthew G. Knepley if (locX_t) { 37259566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t)); 37262f856554SMatthew G. Knepley for (i = 0; i < totDim; ++i) ul_t[cind * totDim + i] = x_t[i]; 37279566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t)); 37282f856554SMatthew G. Knepley } 37292f856554SMatthew G. Knepley if (locA) { 37302f856554SMatthew G. Knepley PetscInt subcell; 37319566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell)); 37329566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x)); 37332f856554SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) al[cind * totDimAux + i] = x[i]; 37349566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x)); 37352f856554SMatthew G. Knepley } 37362f856554SMatthew G. Knepley } 37379566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 37389566063dSJacob Faibussowitsch if (locA) PetscCall(DMDestroy(&plexA)); 37399566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 37403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 37412f856554SMatthew G. Knepley } 37422f856554SMatthew G. Knepley 37432f856554SMatthew G. Knepley /*@C 37442f856554SMatthew G. Knepley DMPlexRestoreCellFields - Restore the field values values for a chunk of cells 37452f856554SMatthew G. Knepley 37462f856554SMatthew G. Knepley Input Parameters: 3747a1cb98faSBarry Smith + dm - The `DM` 37482f856554SMatthew G. Knepley . cellIS - The cells to include 37492f856554SMatthew G. Knepley . locX - A local vector with the solution fields 37502f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 37512f856554SMatthew G. Knepley - locA - A local vector with auxiliary fields, or NULL 37522f856554SMatthew G. Knepley 37532f856554SMatthew G. Knepley Output Parameters: 37542f856554SMatthew G. Knepley + u - The field coefficients 37552f856554SMatthew G. Knepley . u_t - The fields derivative coefficients 37562f856554SMatthew G. Knepley - a - The auxiliary field coefficients 37572f856554SMatthew G. Knepley 37582f856554SMatthew G. Knepley Level: developer 37592f856554SMatthew G. Knepley 37601cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 37612f856554SMatthew G. Knepley @*/ 3762d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3763d71ae5a4SJacob Faibussowitsch { 37642f856554SMatthew G. Knepley PetscFunctionBegin; 37659566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u)); 37669566063dSJacob Faibussowitsch if (locX_t) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t)); 37679566063dSJacob Faibussowitsch if (locA) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a)); 37683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 37692f856554SMatthew G. Knepley } 37702f856554SMatthew G. Knepley 3771a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexGetHybridCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3772d71ae5a4SJacob Faibussowitsch { 377307218a29SMatthew G. Knepley DM plex, plexA = NULL; 377407218a29SMatthew G. Knepley DMEnclosureType encAux; 377507218a29SMatthew G. Knepley PetscSection section, sectionAux; 377607218a29SMatthew G. Knepley PetscDS ds, dsIn; 37776528b96dSMatthew G. Knepley const PetscInt *cells; 377807218a29SMatthew G. Knepley PetscInt cStart, cEnd, numCells, c, totDim, totDimAux, Nf, f; 37796528b96dSMatthew G. Knepley 37806528b96dSMatthew G. Knepley PetscFunctionBegin; 378107218a29SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 378207218a29SMatthew G. Knepley PetscValidHeaderSpecific(cellIS, IS_CLASSID, 2); 378307218a29SMatthew G. Knepley PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 378407218a29SMatthew G. Knepley if (locX_t) { PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 4); } 378507218a29SMatthew G. Knepley if (locA) { PetscValidHeaderSpecific(locA, VEC_CLASSID, 5); } 37864f572ea9SToby Isaac PetscAssertPointer(u, 6); 37874f572ea9SToby Isaac PetscAssertPointer(u_t, 7); 37884f572ea9SToby Isaac PetscAssertPointer(a, 8); 378907218a29SMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 379007218a29SMatthew G. Knepley numCells = cEnd - cStart; 379107218a29SMatthew G. Knepley PetscCall(DMPlexConvertPlex(dm, &plex, PETSC_FALSE)); 379207218a29SMatthew G. Knepley PetscCall(DMGetLocalSection(dm, §ion)); 379307218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn)); 379407218a29SMatthew G. Knepley PetscCall(PetscDSGetNumFields(dsIn, &Nf)); 379507218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsIn, &totDim)); 379607218a29SMatthew G. Knepley if (locA) { 379707218a29SMatthew G. Knepley DM dmAux; 379807218a29SMatthew G. Knepley PetscDS probAux; 379907218a29SMatthew G. Knepley 380007218a29SMatthew G. Knepley PetscCall(VecGetDM(locA, &dmAux)); 380107218a29SMatthew G. Knepley PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 380207218a29SMatthew G. Knepley PetscCall(DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE)); 380307218a29SMatthew G. Knepley PetscCall(DMGetLocalSection(dmAux, §ionAux)); 380407218a29SMatthew G. Knepley PetscCall(DMGetDS(dmAux, &probAux)); 380507218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 380607218a29SMatthew G. Knepley } 380707218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u)); 380807218a29SMatthew G. Knepley if (locX_t) PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u_t)); 380907218a29SMatthew G. Knepley else { 381007218a29SMatthew G. Knepley *u_t = NULL; 381107218a29SMatthew G. Knepley } 381207218a29SMatthew G. Knepley if (locA) PetscCall(DMGetWorkArray(dm, numCells * totDimAux, MPIU_SCALAR, a)); 381307218a29SMatthew G. Knepley else { 381407218a29SMatthew G. Knepley *a = NULL; 381507218a29SMatthew G. Knepley } 381607218a29SMatthew G. Knepley // Loop over cohesive cells 381707218a29SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 381807218a29SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 381907218a29SMatthew G. Knepley const PetscInt cind = c - cStart; 382074a0c561SMatthew G. Knepley PetscScalar *xf = NULL, *xc = NULL, *x = NULL, *xf_t = NULL, *xc_t = NULL; 38218e3a54c0SPierre Jolivet PetscScalar *ul = &(*u)[cind * totDim], *ul_t = PetscSafePointerPlusOffset(*u_t, cind * totDim); 382207218a29SMatthew G. Knepley const PetscInt *cone, *ornt; 382307218a29SMatthew G. Knepley PetscInt Nx = 0, Nxf, s; 382407218a29SMatthew G. Knepley 382507218a29SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cell, &cone)); 382607218a29SMatthew G. Knepley PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt)); 382707218a29SMatthew G. Knepley // Put in cohesive unknowns 382807218a29SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, &Nxf, &xf)); 382974a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &xf_t)); 383007218a29SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 383107218a29SMatthew G. Knepley PetscInt fdofIn, foff, foffIn; 383207218a29SMatthew G. Knepley PetscBool cohesive; 383307218a29SMatthew G. Knepley 383407218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(dsIn, f, &cohesive)); 383507218a29SMatthew G. Knepley if (!cohesive) continue; 383607218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsIn, f, &fdofIn)); 383707218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldOffsetCohesive(ds, f, &foff)); 383807218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldOffsetCohesive(dsIn, f, &foffIn)); 383907218a29SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul[foffIn + i] = xf[foff + i]; 384074a0c561SMatthew G. Knepley if (locX_t) 384174a0c561SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul_t[foffIn + i] = xf_t[foff + i]; 384207218a29SMatthew G. Knepley Nx += fdofIn; 384307218a29SMatthew G. Knepley } 384407218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, &Nxf, &xf)); 384574a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &xf_t)); 384607218a29SMatthew G. Knepley // Loop over sides of surface 384707218a29SMatthew G. Knepley for (s = 0; s < 2; ++s) { 384807218a29SMatthew G. Knepley const PetscInt *support; 384907218a29SMatthew G. Knepley const PetscInt face = cone[s]; 385007218a29SMatthew G. Knepley PetscInt ssize, ncell, Nxc; 385107218a29SMatthew G. Knepley 385207218a29SMatthew G. Knepley // I don't think I need the face to have 0 orientation in the hybrid cell 385307218a29SMatthew 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]); 385407218a29SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, face, &support)); 385507218a29SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, face, &ssize)); 385607218a29SMatthew G. Knepley if (support[0] == cell) ncell = support[1]; 385707218a29SMatthew G. Knepley else if (support[1] == cell) ncell = support[0]; 385807218a29SMatthew 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); 385907218a29SMatthew G. Knepley // Get closure of both face and cell, stick in cell for normal fields and face for cohesive fields 386007218a29SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plex, section, locX, ncell, &Nxc, &xc)); 386174a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecGetClosure(plex, section, locX_t, ncell, NULL, &xc_t)); 386207218a29SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 386307218a29SMatthew G. Knepley PetscInt fdofIn, foffIn; 386407218a29SMatthew G. Knepley PetscBool cohesive; 386507218a29SMatthew G. Knepley 386607218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(dsIn, f, &cohesive)); 386707218a29SMatthew G. Knepley if (cohesive) continue; 386807218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsIn, f, &fdofIn)); 386907218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldOffsetCohesive(dsIn, f, &foffIn)); 387007218a29SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul[foffIn + s * fdofIn + i] = xc[foffIn + i]; 387174a0c561SMatthew G. Knepley if (locX_t) 387274a0c561SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul_t[foffIn + s * fdofIn + i] = xc_t[foffIn + i]; 387307218a29SMatthew G. Knepley Nx += fdofIn; 387407218a29SMatthew G. Knepley } 387507218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plex, section, locX, ncell, &Nxc, &xc)); 387674a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, ncell, NULL, &xc_t)); 387707218a29SMatthew G. Knepley } 387807218a29SMatthew 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); 387907218a29SMatthew G. Knepley 388007218a29SMatthew G. Knepley if (locA) { 388107218a29SMatthew G. Knepley PetscScalar *al = &(*a)[cind * totDimAux]; 388207218a29SMatthew G. Knepley PetscInt subcell; 388307218a29SMatthew G. Knepley 388407218a29SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell)); 388507218a29SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, &Nx, &x)); 388607218a29SMatthew 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); 388707218a29SMatthew G. Knepley for (PetscInt i = 0; i < totDimAux; ++i) al[i] = x[i]; 388807218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, &Nx, &x)); 388907218a29SMatthew G. Knepley } 389007218a29SMatthew G. Knepley } 389107218a29SMatthew G. Knepley PetscCall(DMDestroy(&plex)); 389207218a29SMatthew G. Knepley PetscCall(DMDestroy(&plexA)); 389307218a29SMatthew G. Knepley PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 389407218a29SMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 389507218a29SMatthew G. Knepley } 389607218a29SMatthew G. Knepley 389707218a29SMatthew G. Knepley /* 38983e2b0218SMatthew G. Knepley DMPlexGetHybridFields - Get the field values for the negative side (s = 0) and positive side (s = 1) of the interface 389907218a29SMatthew G. Knepley 390007218a29SMatthew G. Knepley Input Parameters: 390107218a29SMatthew G. Knepley + dm - The full domain DM 390207218a29SMatthew G. Knepley . dmX - An array of DM for the field, say an auxiliary DM, indexed by s 390307218a29SMatthew G. Knepley . dsX - An array of PetscDS for the field, indexed by s 390407218a29SMatthew G. Knepley . cellIS - The interface cells for which we want values 390507218a29SMatthew G. Knepley . locX - An array of local vectors with the field values, indexed by s 390607218a29SMatthew G. Knepley - useCell - Flag to have values come from neighboring cell rather than endcap face 390707218a29SMatthew G. Knepley 390807218a29SMatthew G. Knepley Output Parameter: 390907218a29SMatthew G. Knepley . x - An array of field values, indexed by s 391007218a29SMatthew G. Knepley 391107218a29SMatthew G. Knepley Note: 391276fbde31SPierre Jolivet The arrays in `x` will be allocated using `DMGetWorkArray()`, and must be returned using `DMPlexRestoreHybridFields()`. 391307218a29SMatthew G. Knepley 391407218a29SMatthew G. Knepley Level: advanced 391507218a29SMatthew G. Knepley 391676fbde31SPierre Jolivet .seealso: `DMPlexRestoreHybridFields()`, `DMGetWorkArray()` 391707218a29SMatthew G. Knepley */ 391807218a29SMatthew G. Knepley static PetscErrorCode DMPlexGetHybridFields(DM dm, DM dmX[], PetscDS dsX[], IS cellIS, Vec locX[], PetscBool useCell, PetscScalar *x[]) 391907218a29SMatthew G. Knepley { 392007218a29SMatthew G. Knepley DM plexX[2]; 392107218a29SMatthew G. Knepley DMEnclosureType encX[2]; 392207218a29SMatthew G. Knepley PetscSection sectionX[2]; 392307218a29SMatthew G. Knepley const PetscInt *cells; 392407218a29SMatthew G. Knepley PetscInt cStart, cEnd, numCells, c, s, totDimX[2]; 392507218a29SMatthew G. Knepley 392607218a29SMatthew G. Knepley PetscFunctionBegin; 39274f572ea9SToby Isaac PetscAssertPointer(locX, 5); 392807218a29SMatthew G. Knepley if (!locX[0] || !locX[1]) PetscFunctionReturn(PETSC_SUCCESS); 39294f572ea9SToby Isaac PetscAssertPointer(dmX, 2); 39304f572ea9SToby Isaac PetscAssertPointer(dsX, 3); 393107218a29SMatthew G. Knepley PetscValidHeaderSpecific(cellIS, IS_CLASSID, 4); 39324f572ea9SToby Isaac PetscAssertPointer(x, 7); 39339566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 39346528b96dSMatthew G. Knepley numCells = cEnd - cStart; 3935148442b3SMatthew G. Knepley for (s = 0; s < 2; ++s) { 393607218a29SMatthew G. Knepley PetscValidHeaderSpecific(dmX[s], DM_CLASSID, 2); 393707218a29SMatthew G. Knepley PetscValidHeaderSpecific(dsX[s], PETSCDS_CLASSID, 3); 393807218a29SMatthew G. Knepley PetscValidHeaderSpecific(locX[s], VEC_CLASSID, 5); 393907218a29SMatthew G. Knepley PetscCall(DMPlexConvertPlex(dmX[s], &plexX[s], PETSC_FALSE)); 394007218a29SMatthew G. Knepley PetscCall(DMGetEnclosureRelation(dmX[s], dm, &encX[s])); 394107218a29SMatthew G. Knepley PetscCall(DMGetLocalSection(dmX[s], §ionX[s])); 394207218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsX[s], &totDimX[s])); 394307218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dmX[s], numCells * totDimX[s], MPIU_SCALAR, &x[s])); 394404c51a94SMatthew G. Knepley } 3945148442b3SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 39466528b96dSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 39476528b96dSMatthew G. Knepley const PetscInt cind = c - cStart; 39486528b96dSMatthew G. Knepley const PetscInt *cone, *ornt; 39496528b96dSMatthew G. Knepley 39509566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cell, &cone)); 39519566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt)); 395207218a29SMatthew 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]); 3953148442b3SMatthew G. Knepley for (s = 0; s < 2; ++s) { 395407218a29SMatthew G. Knepley const PetscInt tdX = totDimX[s]; 395507218a29SMatthew G. Knepley PetscScalar *closure = NULL, *xl = &x[s][cind * tdX]; 395607218a29SMatthew G. Knepley PetscInt face = cone[s], point = face, subpoint, Nx, i; 395707218a29SMatthew G. Knepley 395807218a29SMatthew G. Knepley if (useCell) { 39595fedec97SMatthew G. Knepley const PetscInt *support; 396007218a29SMatthew G. Knepley PetscInt ssize; 39616528b96dSMatthew G. Knepley 396207218a29SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, face, &support)); 396307218a29SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, face, &ssize)); 396407218a29SMatthew 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); 396507218a29SMatthew G. Knepley if (support[0] == cell) point = support[1]; 396607218a29SMatthew G. Knepley else if (support[1] == cell) point = support[0]; 396707218a29SMatthew 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); 396807218a29SMatthew G. Knepley } 396907218a29SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(plexX[s], dm, encX[s], point, &subpoint)); 3970e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(plexX[s], sectionX[s], PETSC_FALSE, locX[s], subpoint, ornt[s], &Nx, &closure)); 397107218a29SMatthew 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); 397207218a29SMatthew G. Knepley for (i = 0; i < Nx; ++i) xl[i] = closure[i]; 397307218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plexX[s], sectionX[s], locX[s], subpoint, &Nx, &closure)); 39746528b96dSMatthew G. Knepley } 39756528b96dSMatthew G. Knepley } 397607218a29SMatthew G. Knepley for (s = 0; s < 2; ++s) PetscCall(DMDestroy(&plexX[s])); 39779566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 39783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 39796528b96dSMatthew G. Knepley } 39806528b96dSMatthew G. Knepley 398107218a29SMatthew G. Knepley static PetscErrorCode DMPlexRestoreHybridFields(DM dm, DM dmX[], PetscDS dsX[], IS cellIS, Vec locX[], PetscBool useCell, PetscScalar *x[]) 3982d71ae5a4SJacob Faibussowitsch { 39836528b96dSMatthew G. Knepley PetscFunctionBegin; 398407218a29SMatthew G. Knepley if (!locX[0] || !locX[1]) PetscFunctionReturn(PETSC_SUCCESS); 398507218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dmX[0], 0, MPIU_SCALAR, &x[0])); 398607218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dmX[1], 0, MPIU_SCALAR, &x[1])); 39873ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 39886528b96dSMatthew G. Knepley } 39896528b96dSMatthew G. Knepley 39902f856554SMatthew G. Knepley /*@C 39912f856554SMatthew G. Knepley DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces 39922f856554SMatthew G. Knepley 39932f856554SMatthew G. Knepley Input Parameters: 3994a1cb98faSBarry Smith + dm - The `DM` 39952f856554SMatthew G. Knepley . fStart - The first face to include 39962f856554SMatthew G. Knepley . fEnd - The first face to exclude 39972f856554SMatthew G. Knepley . locX - A local vector with the solution fields 39982f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 39992f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 40002f856554SMatthew G. Knepley . cellGeometry - A local vector with cell geometry 400160225df5SJacob Faibussowitsch - locGrad - A local vector with field gradients, or NULL 40022f856554SMatthew G. Knepley 40032f856554SMatthew G. Knepley Output Parameters: 40042f856554SMatthew G. Knepley + Nface - The number of faces with field values 40052f856554SMatthew G. Knepley . uL - The field values at the left side of the face 40062f856554SMatthew G. Knepley - uR - The field values at the right side of the face 40072f856554SMatthew G. Knepley 40082f856554SMatthew G. Knepley Level: developer 40092f856554SMatthew G. Knepley 40101cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()` 40112f856554SMatthew G. Knepley @*/ 4012d71ae5a4SJacob 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) 4013d71ae5a4SJacob Faibussowitsch { 40142f856554SMatthew G. Knepley DM dmFace, dmCell, dmGrad = NULL; 40152f856554SMatthew G. Knepley PetscSection section; 40162f856554SMatthew G. Knepley PetscDS prob; 40172f856554SMatthew G. Knepley DMLabel ghostLabel; 40182f856554SMatthew G. Knepley const PetscScalar *facegeom, *cellgeom, *x, *lgrad; 40192f856554SMatthew G. Knepley PetscBool *isFE; 40202f856554SMatthew G. Knepley PetscInt dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face; 40212f856554SMatthew G. Knepley 40222f856554SMatthew G. Knepley PetscFunctionBegin; 40232f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 40242f856554SMatthew G. Knepley PetscValidHeaderSpecific(locX, VEC_CLASSID, 4); 4025ad540459SPierre Jolivet if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 5); 40262f856554SMatthew G. Knepley PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 6); 40272f856554SMatthew G. Knepley PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 7); 4028ad540459SPierre Jolivet if (locGrad) PetscValidHeaderSpecific(locGrad, VEC_CLASSID, 8); 40294f572ea9SToby Isaac PetscAssertPointer(uL, 10); 40304f572ea9SToby Isaac PetscAssertPointer(uR, 11); 40319566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 40329566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 40339566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 40349566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 40359566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalComponents(prob, &Nc)); 40369566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nf, &isFE)); 40372f856554SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 40382f856554SMatthew G. Knepley PetscObject obj; 40392f856554SMatthew G. Knepley PetscClassId id; 40402f856554SMatthew G. Knepley 40419566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 40429566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 40439371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 40449371c9d4SSatish Balay isFE[f] = PETSC_TRUE; 40459371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 40469371c9d4SSatish Balay isFE[f] = PETSC_FALSE; 40479371c9d4SSatish Balay } else { 40489371c9d4SSatish Balay isFE[f] = PETSC_FALSE; 40499371c9d4SSatish Balay } 40502f856554SMatthew G. Knepley } 40519566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 40529566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locX, &x)); 40539566063dSJacob Faibussowitsch PetscCall(VecGetDM(faceGeometry, &dmFace)); 40549566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 40559566063dSJacob Faibussowitsch PetscCall(VecGetDM(cellGeometry, &dmCell)); 40569566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 40572f856554SMatthew G. Knepley if (locGrad) { 40589566063dSJacob Faibussowitsch PetscCall(VecGetDM(locGrad, &dmGrad)); 40599566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locGrad, &lgrad)); 40602f856554SMatthew G. Knepley } 40619566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uL)); 40629566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uR)); 40632f856554SMatthew G. Knepley /* Right now just eat the extra work for FE (could make a cell loop) */ 40642f856554SMatthew G. Knepley for (face = fStart, iface = 0; face < fEnd; ++face) { 40652f856554SMatthew G. Knepley const PetscInt *cells; 40662f856554SMatthew G. Knepley PetscFVFaceGeom *fg; 40672f856554SMatthew G. Knepley PetscFVCellGeom *cgL, *cgR; 40682f856554SMatthew G. Knepley PetscScalar *xL, *xR, *gL, *gR; 40692f856554SMatthew G. Knepley PetscScalar *uLl = *uL, *uRl = *uR; 40702f856554SMatthew G. Knepley PetscInt ghost, nsupp, nchild; 40712f856554SMatthew G. Knepley 40729566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 40739566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 40749566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 40752f856554SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 40769566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 40779566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &cells)); 40789566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL)); 40799566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR)); 40802f856554SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 40812f856554SMatthew G. Knepley PetscInt off; 40822f856554SMatthew G. Knepley 40839566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffset(prob, f, &off)); 40842f856554SMatthew G. Knepley if (isFE[f]) { 40852f856554SMatthew G. Knepley const PetscInt *cone; 40862f856554SMatthew G. Knepley PetscInt comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d; 40872f856554SMatthew G. Knepley 40882f856554SMatthew G. Knepley xL = xR = NULL; 40899566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldComponents(section, f, &comp)); 4090835f2295SStefano Zampini PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, &xL)); 4091835f2295SStefano Zampini PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, &xR)); 40929566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cells[0], &cone)); 40939566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, cells[0], &coneSizeL)); 40949371c9d4SSatish Balay for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL) 40959371c9d4SSatish Balay if (cone[faceLocL] == face) break; 40969566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cells[1], &cone)); 40979566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, cells[1], &coneSizeR)); 40989371c9d4SSatish Balay for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR) 40999371c9d4SSatish Balay if (cone[faceLocR] == face) break; 41001dca8a05SBarry 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]); 41012f856554SMatthew G. Knepley /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */ 41022f856554SMatthew G. Knepley /* TODO: this is a hack that might not be right for nonconforming */ 41032f856554SMatthew G. Knepley if (faceLocL < coneSizeL) { 41049566063dSJacob Faibussowitsch PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface * Nc + off])); 41059566063dSJacob Faibussowitsch if (rdof == ldof && faceLocR < coneSizeR) PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off])); 41062f856554SMatthew G. Knepley else { 41079371c9d4SSatish Balay for (d = 0; d < comp; ++d) uRl[iface * Nc + off + d] = uLl[iface * Nc + off + d]; 41089371c9d4SSatish Balay } 41099371c9d4SSatish Balay } else { 41109566063dSJacob Faibussowitsch PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off])); 41119566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldComponents(section, f, &comp)); 41122f856554SMatthew G. Knepley for (d = 0; d < comp; ++d) uLl[iface * Nc + off + d] = uRl[iface * Nc + off + d]; 41132f856554SMatthew G. Knepley } 4114835f2295SStefano Zampini PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, &xL)); 4115835f2295SStefano Zampini PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, &xR)); 41162f856554SMatthew G. Knepley } else { 41172f856554SMatthew G. Knepley PetscFV fv; 41182f856554SMatthew G. Knepley PetscInt numComp, c; 41192f856554SMatthew G. Knepley 41209566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, (PetscObject *)&fv)); 41219566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &numComp)); 41229566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL)); 41239566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR)); 41242f856554SMatthew G. Knepley if (dmGrad) { 41252f856554SMatthew G. Knepley PetscReal dxL[3], dxR[3]; 41262f856554SMatthew G. Knepley 41279566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL)); 41289566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR)); 41292f856554SMatthew G. Knepley DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL); 41302f856554SMatthew G. Knepley DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR); 41312f856554SMatthew G. Knepley for (c = 0; c < numComp; ++c) { 41322f856554SMatthew G. Knepley uLl[iface * Nc + off + c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c * dim], dxL); 41332f856554SMatthew G. Knepley uRl[iface * Nc + off + c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c * dim], dxR); 41342f856554SMatthew G. Knepley } 41352f856554SMatthew G. Knepley } else { 41362f856554SMatthew G. Knepley for (c = 0; c < numComp; ++c) { 41372f856554SMatthew G. Knepley uLl[iface * Nc + off + c] = xL[c]; 41382f856554SMatthew G. Knepley uRl[iface * Nc + off + c] = xR[c]; 41392f856554SMatthew G. Knepley } 41402f856554SMatthew G. Knepley } 41412f856554SMatthew G. Knepley } 41422f856554SMatthew G. Knepley } 41432f856554SMatthew G. Knepley ++iface; 41442f856554SMatthew G. Knepley } 41452f856554SMatthew G. Knepley *Nface = iface; 41469566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(locX, &x)); 41479566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 41489566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 414948a46eb9SPierre Jolivet if (locGrad) PetscCall(VecRestoreArrayRead(locGrad, &lgrad)); 41509566063dSJacob Faibussowitsch PetscCall(PetscFree(isFE)); 41513ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 41522f856554SMatthew G. Knepley } 41532f856554SMatthew G. Knepley 41542f856554SMatthew G. Knepley /*@C 41552f856554SMatthew G. Knepley DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces 41562f856554SMatthew G. Knepley 41572f856554SMatthew G. Knepley Input Parameters: 4158a1cb98faSBarry Smith + dm - The `DM` 41592f856554SMatthew G. Knepley . fStart - The first face to include 41602f856554SMatthew G. Knepley . fEnd - The first face to exclude 41612f856554SMatthew G. Knepley . locX - A local vector with the solution fields 41622f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 41632f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 41642f856554SMatthew G. Knepley . cellGeometry - A local vector with cell geometry 416560225df5SJacob Faibussowitsch - locGrad - A local vector with field gradients, or NULL 41662f856554SMatthew G. Knepley 41672f856554SMatthew G. Knepley Output Parameters: 41682f856554SMatthew G. Knepley + Nface - The number of faces with field values 41692f856554SMatthew G. Knepley . uL - The field values at the left side of the face 41702f856554SMatthew G. Knepley - uR - The field values at the right side of the face 41712f856554SMatthew G. Knepley 41722f856554SMatthew G. Knepley Level: developer 41732f856554SMatthew G. Knepley 41741cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 41752f856554SMatthew G. Knepley @*/ 4176d71ae5a4SJacob 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) 4177d71ae5a4SJacob Faibussowitsch { 41782f856554SMatthew G. Knepley PetscFunctionBegin; 41799566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL)); 41809566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR)); 41813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 41822f856554SMatthew G. Knepley } 41832f856554SMatthew G. Knepley 41842f856554SMatthew G. Knepley /*@C 41852f856554SMatthew G. Knepley DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces 41862f856554SMatthew G. Knepley 41872f856554SMatthew G. Knepley Input Parameters: 4188a1cb98faSBarry Smith + dm - The `DM` 41892f856554SMatthew G. Knepley . fStart - The first face to include 41902f856554SMatthew G. Knepley . fEnd - The first face to exclude 41912f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 41922f856554SMatthew G. Knepley - cellGeometry - A local vector with cell geometry 41932f856554SMatthew G. Knepley 41942f856554SMatthew G. Knepley Output Parameters: 41952f856554SMatthew G. Knepley + Nface - The number of faces with field values 41962f856554SMatthew G. Knepley . fgeom - The extract the face centroid and normal 41972f856554SMatthew G. Knepley - vol - The cell volume 41982f856554SMatthew G. Knepley 41992f856554SMatthew G. Knepley Level: developer 42002f856554SMatthew G. Knepley 42011cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()` 42022f856554SMatthew G. Knepley @*/ 4203d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 4204d71ae5a4SJacob Faibussowitsch { 42052f856554SMatthew G. Knepley DM dmFace, dmCell; 42062f856554SMatthew G. Knepley DMLabel ghostLabel; 42072f856554SMatthew G. Knepley const PetscScalar *facegeom, *cellgeom; 42082f856554SMatthew G. Knepley PetscInt dim, numFaces = fEnd - fStart, iface, face; 42092f856554SMatthew G. Knepley 42102f856554SMatthew G. Knepley PetscFunctionBegin; 42112f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 42122f856554SMatthew G. Knepley PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 4); 42132f856554SMatthew G. Knepley PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 5); 42144f572ea9SToby Isaac PetscAssertPointer(fgeom, 7); 42154f572ea9SToby Isaac PetscAssertPointer(vol, 8); 42169566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 42179566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 42189566063dSJacob Faibussowitsch PetscCall(VecGetDM(faceGeometry, &dmFace)); 42199566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 42209566063dSJacob Faibussowitsch PetscCall(VecGetDM(cellGeometry, &dmCell)); 42219566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 42229566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(numFaces, fgeom)); 42239566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * 2, MPIU_SCALAR, vol)); 42242f856554SMatthew G. Knepley for (face = fStart, iface = 0; face < fEnd; ++face) { 42252f856554SMatthew G. Knepley const PetscInt *cells; 42262f856554SMatthew G. Knepley PetscFVFaceGeom *fg; 42272f856554SMatthew G. Knepley PetscFVCellGeom *cgL, *cgR; 42282f856554SMatthew G. Knepley PetscFVFaceGeom *fgeoml = *fgeom; 42292f856554SMatthew G. Knepley PetscReal *voll = *vol; 42302f856554SMatthew G. Knepley PetscInt ghost, d, nchild, nsupp; 42312f856554SMatthew G. Knepley 42329566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 42339566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 42349566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 42352f856554SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 42369566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 42379566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &cells)); 42389566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL)); 42399566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR)); 42402f856554SMatthew G. Knepley for (d = 0; d < dim; ++d) { 42412f856554SMatthew G. Knepley fgeoml[iface].centroid[d] = fg->centroid[d]; 42422f856554SMatthew G. Knepley fgeoml[iface].normal[d] = fg->normal[d]; 42432f856554SMatthew G. Knepley } 42442f856554SMatthew G. Knepley voll[iface * 2 + 0] = cgL->volume; 42452f856554SMatthew G. Knepley voll[iface * 2 + 1] = cgR->volume; 42462f856554SMatthew G. Knepley ++iface; 42472f856554SMatthew G. Knepley } 42482f856554SMatthew G. Knepley *Nface = iface; 42499566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 42509566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 42513ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 42522f856554SMatthew G. Knepley } 42532f856554SMatthew G. Knepley 42542f856554SMatthew G. Knepley /*@C 42552f856554SMatthew G. Knepley DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces 42562f856554SMatthew G. Knepley 42572f856554SMatthew G. Knepley Input Parameters: 4258a1cb98faSBarry Smith + dm - The `DM` 42592f856554SMatthew G. Knepley . fStart - The first face to include 42602f856554SMatthew G. Knepley . fEnd - The first face to exclude 42612f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 42622f856554SMatthew G. Knepley - cellGeometry - A local vector with cell geometry 42632f856554SMatthew G. Knepley 42642f856554SMatthew G. Knepley Output Parameters: 42652f856554SMatthew G. Knepley + Nface - The number of faces with field values 42662f856554SMatthew G. Knepley . fgeom - The extract the face centroid and normal 42672f856554SMatthew G. Knepley - vol - The cell volume 42682f856554SMatthew G. Knepley 42692f856554SMatthew G. Knepley Level: developer 42702f856554SMatthew G. Knepley 42711cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 42722f856554SMatthew G. Knepley @*/ 4273d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 4274d71ae5a4SJacob Faibussowitsch { 42752f856554SMatthew G. Knepley PetscFunctionBegin; 42769566063dSJacob Faibussowitsch PetscCall(PetscFree(*fgeom)); 42779566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_REAL, vol)); 42783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 42792f856554SMatthew G. Knepley } 42802f856554SMatthew G. Knepley 4281d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 4282d71ae5a4SJacob Faibussowitsch { 4283a1cf66bbSMatthew G. Knepley char composeStr[33] = {0}; 4284a1cf66bbSMatthew G. Knepley PetscObjectId id; 4285a1cf66bbSMatthew G. Knepley PetscContainer container; 4286a1cf66bbSMatthew G. Knepley 4287a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 42889566063dSJacob Faibussowitsch PetscCall(PetscObjectGetId((PetscObject)quad, &id)); 428963a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%" PetscInt64_FMT "\n", id)); 42909566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)pointIS, composeStr, (PetscObject *)&container)); 4291a1cf66bbSMatthew G. Knepley if (container) { 42929566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(container, (void **)geom)); 4293a1cf66bbSMatthew G. Knepley } else { 42949566063dSJacob Faibussowitsch PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom)); 42959566063dSJacob Faibussowitsch PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container)); 42969566063dSJacob Faibussowitsch PetscCall(PetscContainerSetPointer(container, (void *)*geom)); 429749abdd8aSBarry Smith PetscCall(PetscContainerSetCtxDestroy(container, PetscContainerCtxDestroy_PetscFEGeom)); 42989566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)pointIS, composeStr, (PetscObject)container)); 42999566063dSJacob Faibussowitsch PetscCall(PetscContainerDestroy(&container)); 4300a1cf66bbSMatthew G. Knepley } 43013ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4302a1cf66bbSMatthew G. Knepley } 4303a1cf66bbSMatthew G. Knepley 4304d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 4305d71ae5a4SJacob Faibussowitsch { 4306a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 4307a1cf66bbSMatthew G. Knepley *geom = NULL; 43083ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4309a1cf66bbSMatthew G. Knepley } 4310a1cf66bbSMatthew G. Knepley 4311d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user) 4312d71ae5a4SJacob Faibussowitsch { 431392d50984SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 431492d50984SMatthew G. Knepley const char *name = "Residual"; 431592d50984SMatthew G. Knepley DM dmAux = NULL; 431692d50984SMatthew G. Knepley DMLabel ghostLabel = NULL; 431792d50984SMatthew G. Knepley PetscDS prob = NULL; 431892d50984SMatthew G. Knepley PetscDS probAux = NULL; 431992d50984SMatthew G. Knepley PetscBool useFEM = PETSC_FALSE; 432092d50984SMatthew G. Knepley PetscBool isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 432192d50984SMatthew G. Knepley DMField coordField = NULL; 4322c0006e53SPatrick Farrell Vec locA; 4323c0006e53SPatrick Farrell PetscScalar *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL; 432492d50984SMatthew G. Knepley IS chunkIS; 432592d50984SMatthew G. Knepley const PetscInt *cells; 432692d50984SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 4327364207b6SKarl Rupp PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd; 43281690c2aeSBarry Smith PetscInt maxDegree = PETSC_INT_MAX; 432906ad1575SMatthew G. Knepley PetscFormKey key; 433092d50984SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 433192d50984SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 433292d50984SMatthew G. Knepley 433392d50984SMatthew G. Knepley PetscFunctionBegin; 43349566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 433592d50984SMatthew G. Knepley /* FEM+FVM */ 433692d50984SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 43379566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 43389566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 43399566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 43409566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 43419566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 434292d50984SMatthew G. Knepley if (locA) { 43439566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 43449566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 43459566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 434692d50984SMatthew G. Knepley } 434792d50984SMatthew G. Knepley /* 2: Get geometric data */ 434892d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 434992d50984SMatthew G. Knepley PetscObject obj; 435092d50984SMatthew G. Knepley PetscClassId id; 435192d50984SMatthew G. Knepley PetscBool fimp; 435292d50984SMatthew G. Knepley 43539566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 435492d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 43559566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 43569566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 4357ad540459SPierre Jolivet if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE; 43585f80ce2aSJacob Faibussowitsch PetscCheck(id != PETSCFV_CLASSID, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Use of FVM with PCPATCH not yet implemented"); 435992d50984SMatthew G. Knepley } 436092d50984SMatthew G. Knepley if (useFEM) { 43619566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 43629566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 436392d50984SMatthew G. Knepley if (maxDegree <= 1) { 43649566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 436548a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 436692d50984SMatthew G. Knepley } else { 43679566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 436892d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 436992d50984SMatthew G. Knepley PetscObject obj; 437092d50984SMatthew G. Knepley PetscClassId id; 437192d50984SMatthew G. Knepley PetscBool fimp; 437292d50984SMatthew G. Knepley 43739566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 437492d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 43759566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 43769566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 437792d50984SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 437892d50984SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 437992d50984SMatthew G. Knepley 43809566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 43819566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 43829566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 438392d50984SMatthew G. Knepley } 438492d50984SMatthew G. Knepley } 438592d50984SMatthew G. Knepley } 438692d50984SMatthew G. Knepley } 438792d50984SMatthew G. Knepley /* Loop over chunks */ 43889566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 43899566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 43909566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS)); 439192d50984SMatthew G. Knepley numCells = cEnd - cStart; 439292d50984SMatthew G. Knepley numChunks = 1; 439392d50984SMatthew G. Knepley cellChunkSize = numCells / numChunks; 439492d50984SMatthew G. Knepley numChunks = PetscMin(1, numCells); 43956528b96dSMatthew G. Knepley key.label = NULL; 43966528b96dSMatthew G. Knepley key.value = 0; 439706ad1575SMatthew G. Knepley key.part = 0; 439892d50984SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 4399c0006e53SPatrick Farrell PetscScalar *elemVec, *fluxL = NULL, *fluxR = NULL; 4400c0006e53SPatrick Farrell PetscReal *vol = NULL; 4401c0006e53SPatrick Farrell PetscFVFaceGeom *fgeom = NULL; 440292d50984SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 4403c0006e53SPatrick Farrell PetscInt numFaces = 0; 440492d50984SMatthew G. Knepley 440592d50984SMatthew G. Knepley /* Extract field coefficients */ 440692d50984SMatthew G. Knepley if (useFEM) { 44079566063dSJacob Faibussowitsch PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells)); 44089566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 44099566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 44109566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numCells * totDim)); 441192d50984SMatthew G. Knepley } 441292d50984SMatthew 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 */ 441392d50984SMatthew G. Knepley /* Loop over fields */ 441492d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 441592d50984SMatthew G. Knepley PetscObject obj; 441692d50984SMatthew G. Knepley PetscClassId id; 441792d50984SMatthew G. Knepley PetscBool fimp; 441892d50984SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 441992d50984SMatthew G. Knepley 44206528b96dSMatthew G. Knepley key.field = f; 44219566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 442292d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 44239566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 44249566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 442592d50984SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 442692d50984SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 442792d50984SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 442892d50984SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 442992d50984SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 443092d50984SMatthew G. Knepley PetscInt Nq, Nb; 443192d50984SMatthew G. Knepley 44329566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 44339566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 44349566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 443592d50984SMatthew G. Knepley blockSize = Nb; 443692d50984SMatthew G. Knepley batchSize = numBlocks * blockSize; 44379566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 443892d50984SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 443992d50984SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 444092d50984SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 444192d50984SMatthew G. Knepley offset = numCells - Nr; 444292d50984SMatthew G. Knepley /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 444392d50984SMatthew 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) */ 44449566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom)); 44459566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateResidual(prob, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec)); 44469566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom)); 44478e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateResidual(prob, key, Nr, chunkGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, &a[offset * totDimAux], t, &elemVec[offset * totDim])); 44489566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom)); 444992d50984SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 445092d50984SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 445192d50984SMatthew G. Knepley 445292d50984SMatthew G. Knepley Ne = numFaces; 445392d50984SMatthew G. Knepley /* Riemann solve over faces (need fields at face centroids) */ 445492d50984SMatthew G. Knepley /* We need to evaluate FE fields at those coordinates */ 44559566063dSJacob Faibussowitsch PetscCall(PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR)); 445663a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 445792d50984SMatthew G. Knepley } 445892d50984SMatthew G. Knepley /* Loop over domain */ 445992d50984SMatthew G. Knepley if (useFEM) { 446092d50984SMatthew G. Knepley /* Add elemVec to locX */ 446192d50984SMatthew G. Knepley for (c = cS; c < cE; ++c) { 446292d50984SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 446392d50984SMatthew G. Knepley const PetscInt cind = c - cStart; 446492d50984SMatthew G. Knepley 44659566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim])); 446692d50984SMatthew G. Knepley if (ghostLabel) { 446792d50984SMatthew G. Knepley PetscInt ghostVal; 446892d50984SMatthew G. Knepley 44699566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 447092d50984SMatthew G. Knepley if (ghostVal > 0) continue; 447192d50984SMatthew G. Knepley } 44729566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES)); 447392d50984SMatthew G. Knepley } 447492d50984SMatthew G. Knepley } 447592d50984SMatthew G. Knepley /* Handle time derivative */ 447692d50984SMatthew G. Knepley if (locX_t) { 447792d50984SMatthew G. Knepley PetscScalar *x_t, *fa; 447892d50984SMatthew G. Knepley 44799566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 44809566063dSJacob Faibussowitsch PetscCall(VecGetArray(locX_t, &x_t)); 448192d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 448292d50984SMatthew G. Knepley PetscFV fv; 448392d50984SMatthew G. Knepley PetscObject obj; 448492d50984SMatthew G. Knepley PetscClassId id; 448592d50984SMatthew G. Knepley PetscInt pdim, d; 448692d50984SMatthew G. Knepley 44879566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 44889566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 448992d50984SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 449092d50984SMatthew G. Knepley fv = (PetscFV)obj; 44919566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 449292d50984SMatthew G. Knepley for (c = cS; c < cE; ++c) { 449392d50984SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 449492d50984SMatthew G. Knepley PetscScalar *u_t, *r; 449592d50984SMatthew G. Knepley 449692d50984SMatthew G. Knepley if (ghostLabel) { 449792d50984SMatthew G. Knepley PetscInt ghostVal; 449892d50984SMatthew G. Knepley 44999566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 450092d50984SMatthew G. Knepley if (ghostVal > 0) continue; 450192d50984SMatthew G. Knepley } 45029566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t)); 45039566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r)); 450492d50984SMatthew G. Knepley for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 450592d50984SMatthew G. Knepley } 450692d50984SMatthew G. Knepley } 45079566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locX_t, &x_t)); 45089566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 450992d50984SMatthew G. Knepley } 451092d50984SMatthew G. Knepley if (useFEM) { 45119566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 45129566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 451392d50984SMatthew G. Knepley } 451492d50984SMatthew G. Knepley } 45159566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISDestroy(&chunkIS)); 45169566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 451792d50984SMatthew G. Knepley /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */ 451892d50984SMatthew G. Knepley if (useFEM) { 451992d50984SMatthew G. Knepley if (maxDegree <= 1) { 45209566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 45219566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 452292d50984SMatthew G. Knepley } else { 452392d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 45249566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 45259566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&quads[f])); 452692d50984SMatthew G. Knepley } 45279566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 452892d50984SMatthew G. Knepley } 452992d50984SMatthew G. Knepley } 45309566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 45313ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 453292d50984SMatthew G. Knepley } 453392d50984SMatthew G. Knepley 4534a1cf66bbSMatthew G. Knepley /* 4535a1cf66bbSMatthew 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 4536a1cf66bbSMatthew G. Knepley 4537a1cf66bbSMatthew G. Knepley X - The local solution vector 4538a5b23f4aSJose E. Roman X_t - The local solution time derivative vector, or NULL 4539a1cf66bbSMatthew G. Knepley */ 4540d71ae5a4SJacob 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) 4541d71ae5a4SJacob Faibussowitsch { 4542a1cf66bbSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 4543a1cf66bbSMatthew G. Knepley const char *name = "Jacobian", *nameP = "JacobianPre"; 4544a1cf66bbSMatthew G. Knepley DM dmAux = NULL; 4545a1cf66bbSMatthew G. Knepley PetscDS prob, probAux = NULL; 4546a1cf66bbSMatthew G. Knepley PetscSection sectionAux = NULL; 4547a1cf66bbSMatthew G. Knepley Vec A; 4548a1cf66bbSMatthew G. Knepley DMField coordField; 4549a1cf66bbSMatthew G. Knepley PetscFEGeom *cgeomFEM; 4550a1cf66bbSMatthew G. Knepley PetscQuadrature qGeom = NULL; 4551a1cf66bbSMatthew G. Knepley Mat J = Jac, JP = JacP; 4552a1cf66bbSMatthew G. Knepley PetscScalar *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL; 4553e432b41dSStefano Zampini PetscBool hasJac, hasPrec, hasDyn, assembleJac, *isFE, hasFV = PETSC_FALSE; 4554a1cf66bbSMatthew G. Knepley const PetscInt *cells; 455506ad1575SMatthew G. Knepley PetscFormKey key; 45569b2fc754SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0; 4557a1cf66bbSMatthew G. Knepley 4558a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 45599566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(cellIS, &numCells)); 45609566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 45619566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 45629566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 45639566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &A)); 45649a2a23afSMatthew G. Knepley if (A) { 45659566063dSJacob Faibussowitsch PetscCall(VecGetDM(A, &dmAux)); 45669566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 45679566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 4568a1cf66bbSMatthew G. Knepley } 4569a1cf66bbSMatthew G. Knepley /* Get flags */ 45709566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 45719566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE)); 4572a1cf66bbSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 4573a1cf66bbSMatthew G. Knepley PetscObject disc; 4574a1cf66bbSMatthew G. Knepley PetscClassId id; 45759566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, &disc)); 45769566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(disc, &id)); 45779371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 45789371c9d4SSatish Balay isFE[fieldI] = PETSC_TRUE; 45799371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 45809371c9d4SSatish Balay hasFV = PETSC_TRUE; 45819371c9d4SSatish Balay isFE[fieldI] = PETSC_FALSE; 45829371c9d4SSatish Balay } 4583a1cf66bbSMatthew G. Knepley } 45849566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobian(prob, &hasJac)); 45859566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec)); 45869566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 4587a1cf66bbSMatthew G. Knepley assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE; 4588a1cf66bbSMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 45899566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); /* No allocated space for FV stuff, so ignore the zero entries */ 45909566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 45919566063dSJacob Faibussowitsch if (probAux) PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 4592a1cf66bbSMatthew G. Knepley /* Compute batch sizes */ 4593a1cf66bbSMatthew G. Knepley if (isFE[0]) { 4594a1cf66bbSMatthew G. Knepley PetscFE fe; 4595a1cf66bbSMatthew G. Knepley PetscQuadrature q; 4596a1cf66bbSMatthew G. Knepley PetscInt numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb; 4597a1cf66bbSMatthew G. Knepley 45989566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe)); 45999566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 46009566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL)); 46019566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 46029566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 4603a1cf66bbSMatthew G. Knepley blockSize = Nb * numQuadPoints; 4604a1cf66bbSMatthew G. Knepley batchSize = numBlocks * blockSize; 4605a1cf66bbSMatthew G. Knepley chunkSize = numBatches * batchSize; 4606a1cf66bbSMatthew G. Knepley numChunks = numCells / chunkSize + numCells % chunkSize; 46079566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 4608a1cf66bbSMatthew G. Knepley } else { 4609a1cf66bbSMatthew G. Knepley chunkSize = numCells; 4610a1cf66bbSMatthew G. Knepley numChunks = 1; 4611a1cf66bbSMatthew G. Knepley } 4612a1cf66bbSMatthew G. Knepley /* Get work space */ 4613a1cf66bbSMatthew 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; 46149566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work)); 46159566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(work, wsz)); 4616a1cf66bbSMatthew G. Knepley off = 0; 4617a1cf66bbSMatthew G. Knepley u = X ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL; 4618a1cf66bbSMatthew G. Knepley u_t = X_t ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL; 4619a1cf66bbSMatthew G. Knepley a = dmAux ? (sz = chunkSize * totDimAux, off += sz, work + off - sz) : NULL; 4620a1cf66bbSMatthew G. Knepley elemMat = hasJac ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 4621a1cf66bbSMatthew G. Knepley elemMatP = hasPrec ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 4622a1cf66bbSMatthew G. Knepley elemMatD = hasDyn ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 462363a3b9bcSJacob Faibussowitsch PetscCheck(off == wsz, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %" PetscInt_FMT " should be %" PetscInt_FMT, off, wsz); 4624a1cf66bbSMatthew G. Knepley /* Setup geometry */ 46259566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 46269566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 46279566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 4628a1cf66bbSMatthew G. Knepley if (!qGeom) { 4629a1cf66bbSMatthew G. Knepley PetscFE fe; 4630a1cf66bbSMatthew G. Knepley 46319566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe)); 46329566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 46339566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 4634a1cf66bbSMatthew G. Knepley } 46359566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 4636a1cf66bbSMatthew G. Knepley /* Compute volume integrals */ 46379566063dSJacob Faibussowitsch if (assembleJac) PetscCall(MatZeroEntries(J)); 46389566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(JP)); 46396528b96dSMatthew G. Knepley key.label = NULL; 46406528b96dSMatthew G. Knepley key.value = 0; 464106ad1575SMatthew G. Knepley key.part = 0; 4642a1cf66bbSMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) { 4643a1cf66bbSMatthew G. Knepley const PetscInt Ncell = PetscMin(chunkSize, numCells - offCell); 4644a1cf66bbSMatthew G. Knepley PetscInt c; 4645a1cf66bbSMatthew G. Knepley 4646a1cf66bbSMatthew G. Knepley /* Extract values */ 4647a1cf66bbSMatthew G. Knepley for (c = 0; c < Ncell; ++c) { 4648a1cf66bbSMatthew G. Knepley const PetscInt cell = cells ? cells[c + offCell] : c + offCell; 4649a1cf66bbSMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 4650a1cf66bbSMatthew G. Knepley PetscInt i; 4651a1cf66bbSMatthew G. Knepley 4652a1cf66bbSMatthew G. Knepley if (X) { 46539566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x)); 4654a1cf66bbSMatthew G. Knepley for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i]; 46559566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x)); 4656a1cf66bbSMatthew G. Knepley } 4657a1cf66bbSMatthew G. Knepley if (X_t) { 46589566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t)); 4659a1cf66bbSMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[c * totDim + i] = x_t[i]; 46609566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t)); 4661a1cf66bbSMatthew G. Knepley } 4662a1cf66bbSMatthew G. Knepley if (dmAux) { 46639566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x)); 4664a1cf66bbSMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i]; 46659566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x)); 4666a1cf66bbSMatthew G. Knepley } 4667a1cf66bbSMatthew G. Knepley } 4668a1cf66bbSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 4669a1cf66bbSMatthew G. Knepley PetscFE fe; 46709566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 4671a1cf66bbSMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 46726528b96dSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 46739566063dSJacob Faibussowitsch if (hasJac) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat)); 46749566063dSJacob Faibussowitsch if (hasPrec) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP)); 46759566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD)); 4676a1cf66bbSMatthew G. Knepley } 4677a1cf66bbSMatthew G. Knepley /* For finite volume, add the identity */ 4678a1cf66bbSMatthew G. Knepley if (!isFE[fieldI]) { 4679a1cf66bbSMatthew G. Knepley PetscFV fv; 4680a1cf66bbSMatthew G. Knepley PetscInt eOffset = 0, Nc, fc, foff; 4681a1cf66bbSMatthew G. Knepley 46829566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, fieldI, &foff)); 46839566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv)); 46849566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 4685a1cf66bbSMatthew G. Knepley for (c = 0; c < chunkSize; ++c, eOffset += totDim * totDim) { 4686a1cf66bbSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 4687a1cf66bbSMatthew G. Knepley const PetscInt i = foff + fc; 4688ad540459SPierre Jolivet if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0; 4689ad540459SPierre Jolivet if (hasPrec) elemMatP[eOffset + i * totDim + i] = 1.0; 4690a1cf66bbSMatthew G. Knepley } 4691a1cf66bbSMatthew G. Knepley } 4692a1cf66bbSMatthew G. Knepley } 4693a1cf66bbSMatthew G. Knepley } 4694a1cf66bbSMatthew G. Knepley /* Add contribution from X_t */ 46959371c9d4SSatish Balay if (hasDyn) { 46969371c9d4SSatish Balay for (c = 0; c < chunkSize * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 46979371c9d4SSatish Balay } 4698a1cf66bbSMatthew G. Knepley /* Insert values into matrix */ 4699a1cf66bbSMatthew G. Knepley for (c = 0; c < Ncell; ++c) { 4700a1cf66bbSMatthew G. Knepley const PetscInt cell = cells ? cells[c + offCell] : c + offCell; 4701a1cf66bbSMatthew G. Knepley if (mesh->printFEM > 1) { 47029566063dSJacob Faibussowitsch if (hasJac) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[(c - cStart) * totDim * totDim])); 47039566063dSJacob Faibussowitsch if (hasPrec) PetscCall(DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c - cStart) * totDim * totDim])); 4704a1cf66bbSMatthew G. Knepley } 4705e8e188d2SZach Atkins if (assembleJac) PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES)); 4706e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, JP, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES)); 4707a1cf66bbSMatthew G. Knepley } 4708a1cf66bbSMatthew G. Knepley } 4709a1cf66bbSMatthew G. Knepley /* Cleanup */ 47109566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 47119566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 47129566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE)); 47139566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE)); 47149566063dSJacob 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)); 4715a1cf66bbSMatthew G. Knepley /* Compute boundary integrals */ 47169566063dSJacob Faibussowitsch /* PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx)); */ 4717a1cf66bbSMatthew G. Knepley /* Assemble matrix */ 47189371c9d4SSatish Balay if (assembleJac) { 47199371c9d4SSatish Balay PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY)); 47209371c9d4SSatish Balay PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY)); 47219371c9d4SSatish Balay } 47229371c9d4SSatish Balay PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY)); 47239371c9d4SSatish Balay PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 47249566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 47253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4726a1cf66bbSMatthew G. Knepley } 47273e9753d6SMatthew G. Knepley 47284ee01570SBarry Smith /* FEM Assembly Function */ 47293e9753d6SMatthew G. Knepley 4730d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMConvertPlex_Internal(DM dm, DM *plex, PetscBool copy) 4731d71ae5a4SJacob Faibussowitsch { 47323e9753d6SMatthew G. Knepley PetscBool isPlex; 47333e9753d6SMatthew G. Knepley 47343e9753d6SMatthew G. Knepley PetscFunctionBegin; 47359566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex)); 47363e9753d6SMatthew G. Knepley if (isPlex) { 47373e9753d6SMatthew G. Knepley *plex = dm; 47389566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)dm)); 47393e9753d6SMatthew G. Knepley } else { 47409566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex)); 47413e9753d6SMatthew G. Knepley if (!*plex) { 47429566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, plex)); 47439566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex)); 47443e9753d6SMatthew G. Knepley } else { 47459566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)*plex)); 47463e9753d6SMatthew G. Knepley } 4747cbf8eb3cSStefano Zampini if (copy) PetscCall(DMCopyAuxiliaryVec(dm, *plex)); 47483e9753d6SMatthew G. Knepley } 47493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 47503e9753d6SMatthew G. Knepley } 47513e9753d6SMatthew G. Knepley 47523e9753d6SMatthew G. Knepley /*@ 47533e9753d6SMatthew G. Knepley DMPlexGetGeometryFVM - Return precomputed geometric data 47543e9753d6SMatthew G. Knepley 475520f4b53cSBarry Smith Collective 47563e9753d6SMatthew G. Knepley 47573e9753d6SMatthew G. Knepley Input Parameter: 4758a1cb98faSBarry Smith . dm - The `DM` 47593e9753d6SMatthew G. Knepley 47603e9753d6SMatthew G. Knepley Output Parameters: 47613e9753d6SMatthew G. Knepley + facegeom - The values precomputed from face geometry 47623e9753d6SMatthew G. Knepley . cellgeom - The values precomputed from cell geometry 47633e9753d6SMatthew G. Knepley - minRadius - The minimum radius over the mesh of an inscribed sphere in a cell 47643e9753d6SMatthew G. Knepley 47653e9753d6SMatthew G. Knepley Level: developer 47663e9753d6SMatthew G. Knepley 47671cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMTSSetRHSFunctionLocal()` 47683e9753d6SMatthew G. Knepley @*/ 4769d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGeometryFVM(DM dm, Vec *facegeom, Vec *cellgeom, PetscReal *minRadius) 4770d71ae5a4SJacob Faibussowitsch { 47713e9753d6SMatthew G. Knepley DM plex; 47723e9753d6SMatthew G. Knepley 47733e9753d6SMatthew G. Knepley PetscFunctionBegin; 47743e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 47759566063dSJacob Faibussowitsch PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE)); 47769566063dSJacob Faibussowitsch PetscCall(DMPlexGetDataFVM(plex, NULL, cellgeom, facegeom, NULL)); 47779566063dSJacob Faibussowitsch if (minRadius) PetscCall(DMPlexGetMinRadius(plex, minRadius)); 47789566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 47793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 47803e9753d6SMatthew G. Knepley } 47813e9753d6SMatthew G. Knepley 47823e9753d6SMatthew G. Knepley /*@ 47833e9753d6SMatthew G. Knepley DMPlexGetGradientDM - Return gradient data layout 47843e9753d6SMatthew G. Knepley 478520f4b53cSBarry Smith Collective 47863e9753d6SMatthew G. Knepley 47873e9753d6SMatthew G. Knepley Input Parameters: 4788a1cb98faSBarry Smith + dm - The `DM` 478920f4b53cSBarry Smith - fv - The `PetscFV` 47903e9753d6SMatthew G. Knepley 47913e9753d6SMatthew G. Knepley Output Parameter: 47923e9753d6SMatthew G. Knepley . dmGrad - The layout for gradient values 47933e9753d6SMatthew G. Knepley 47943e9753d6SMatthew G. Knepley Level: developer 47953e9753d6SMatthew G. Knepley 47961cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetGeometryFVM()` 47973e9753d6SMatthew G. Knepley @*/ 4798d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGradientDM(DM dm, PetscFV fv, DM *dmGrad) 4799d71ae5a4SJacob Faibussowitsch { 48003e9753d6SMatthew G. Knepley DM plex; 48013e9753d6SMatthew G. Knepley PetscBool computeGradients; 48023e9753d6SMatthew G. Knepley 48033e9753d6SMatthew G. Knepley PetscFunctionBegin; 48043e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 48053e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 48064f572ea9SToby Isaac PetscAssertPointer(dmGrad, 3); 48079566063dSJacob Faibussowitsch PetscCall(PetscFVGetComputeGradients(fv, &computeGradients)); 48089371c9d4SSatish Balay if (!computeGradients) { 48099371c9d4SSatish Balay *dmGrad = NULL; 48103ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 48119371c9d4SSatish Balay } 48129566063dSJacob Faibussowitsch PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE)); 48139566063dSJacob Faibussowitsch PetscCall(DMPlexGetDataFVM(plex, fv, NULL, NULL, dmGrad)); 48149566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 48153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 48163e9753d6SMatthew G. Knepley } 48173e9753d6SMatthew G. Knepley 4818d71ae5a4SJacob 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) 4819d71ae5a4SJacob Faibussowitsch { 48203e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 48213e9753d6SMatthew G. Knepley DM plex = NULL, plexA = NULL; 4822673019faSMatthew G. Knepley const char *name = "BdResidual"; 48233e9753d6SMatthew G. Knepley DMEnclosureType encAux; 48243e9753d6SMatthew G. Knepley PetscDS prob, probAux = NULL; 48253e9753d6SMatthew G. Knepley PetscSection section, sectionAux = NULL; 48263e9753d6SMatthew G. Knepley Vec locA = NULL; 48273e9753d6SMatthew G. Knepley PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemVec = NULL; 48283e9753d6SMatthew G. Knepley PetscInt totDim, totDimAux = 0; 48293e9753d6SMatthew G. Knepley 48303e9753d6SMatthew G. Knepley PetscFunctionBegin; 48319566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 48329566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 48339566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 48349566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 48359566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA)); 48363e9753d6SMatthew G. Knepley if (locA) { 48373e9753d6SMatthew G. Knepley DM dmAux; 48383e9753d6SMatthew G. Knepley 48399566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 48409566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 48419566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 48429566063dSJacob Faibussowitsch PetscCall(DMGetDS(plexA, &probAux)); 48439566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 48449566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexA, §ionAux)); 48453e9753d6SMatthew G. Knepley } 48460c290148SMatthew G. Knepley { 48473e9753d6SMatthew G. Knepley PetscFEGeom *fgeom; 48483e9753d6SMatthew G. Knepley PetscInt maxDegree; 48493e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 48503e9753d6SMatthew G. Knepley IS pointIS; 48513e9753d6SMatthew G. Knepley const PetscInt *points; 48523e9753d6SMatthew G. Knepley PetscInt numFaces, face, Nq; 48533e9753d6SMatthew G. Knepley 48549566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS)); 48550c290148SMatthew G. Knepley if (!pointIS) goto end; /* No points with that id on this process */ 48563e9753d6SMatthew G. Knepley { 48573e9753d6SMatthew G. Knepley IS isectIS; 48583e9753d6SMatthew G. Knepley 48593e9753d6SMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 48609566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 48619566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 48623e9753d6SMatthew G. Knepley pointIS = isectIS; 48633e9753d6SMatthew G. Knepley } 48649566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 48659566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 486632603206SJames Wright PetscCall(PetscMalloc4(numFaces * totDim, &u, (locX_t ? (size_t)numFaces * totDim : 0), &u_t, numFaces * totDim, &elemVec, (locA ? (size_t)numFaces * totDimAux : 0), &a)); 48679566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 486848a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 48693e9753d6SMatthew G. Knepley if (!qGeom) { 48703e9753d6SMatthew G. Knepley PetscFE fe; 48713e9753d6SMatthew G. Knepley 48729566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe)); 48739566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 48749566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 48753e9753d6SMatthew G. Knepley } 48769566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 48779566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 48783e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 4879f15274beSMatthew Knepley const PetscInt point = points[face], *support; 48803e9753d6SMatthew G. Knepley PetscScalar *x = NULL; 4881f15274beSMatthew Knepley PetscInt i; 48823e9753d6SMatthew G. Knepley 48839566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, point, &support)); 48849566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 48853e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 48869566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 48873e9753d6SMatthew G. Knepley if (locX_t) { 48889566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x)); 48893e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i]; 48909566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x)); 48913e9753d6SMatthew G. Knepley } 48923e9753d6SMatthew G. Knepley if (locA) { 48933e9753d6SMatthew G. Knepley PetscInt subp; 48943e9753d6SMatthew G. Knepley 48959566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 48969566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 48973e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i]; 48989566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 48993e9753d6SMatthew G. Knepley } 49003e9753d6SMatthew G. Knepley } 49019566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numFaces * totDim)); 49023e9753d6SMatthew G. Knepley { 49033e9753d6SMatthew G. Knepley PetscFE fe; 49043e9753d6SMatthew G. Knepley PetscInt Nb; 49053e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 49063e9753d6SMatthew G. Knepley /* Conforming batches */ 49073e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 49083e9753d6SMatthew G. Knepley /* Remainder */ 49093e9753d6SMatthew G. Knepley PetscInt Nr, offset; 49103e9753d6SMatthew G. Knepley 49119566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe)); 49129566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 49139566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 49143e9753d6SMatthew G. Knepley /* TODO: documentation is unclear about what is going on with these numbers: how should Nb / Nq factor in ? */ 49153e9753d6SMatthew G. Knepley blockSize = Nb; 49163e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 49179566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 49183e9753d6SMatthew G. Knepley numChunks = numFaces / (numBatches * batchSize); 49193e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 49203e9753d6SMatthew G. Knepley Nr = numFaces % (numBatches * batchSize); 49213e9753d6SMatthew G. Knepley offset = numFaces - Nr; 49229566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom)); 49239566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBdResidual(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec)); 49249566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom)); 49259566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 49268e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateBdResidual(prob, wf, key, Nr, chunkGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, &elemVec[offset * totDim])); 49279566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 49283e9753d6SMatthew G. Knepley } 49293e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 49303e9753d6SMatthew G. Knepley const PetscInt point = points[face], *support; 49313e9753d6SMatthew G. Knepley 4932673019faSMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(point, name, totDim, &elemVec[face * totDim])); 49339566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(plex, point, &support)); 49349566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(plex, NULL, locF, support[0], &elemVec[face * totDim], ADD_ALL_VALUES)); 49353e9753d6SMatthew G. Knepley } 49369566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 49379566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 49389566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 49399566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 49409566063dSJacob Faibussowitsch PetscCall(PetscFree4(u, u_t, elemVec, a)); 49413e9753d6SMatthew G. Knepley } 49420c290148SMatthew G. Knepley end: 4943673019faSMatthew G. Knepley if (mesh->printFEM) { 4944673019faSMatthew G. Knepley PetscSection s; 4945673019faSMatthew G. Knepley Vec locFbc; 4946673019faSMatthew G. Knepley PetscInt pStart, pEnd, maxDof; 4947673019faSMatthew G. Knepley PetscScalar *zeroes; 4948673019faSMatthew G. Knepley 4949673019faSMatthew G. Knepley PetscCall(DMGetLocalSection(dm, &s)); 4950673019faSMatthew G. Knepley PetscCall(VecDuplicate(locF, &locFbc)); 4951673019faSMatthew G. Knepley PetscCall(VecCopy(locF, locFbc)); 4952673019faSMatthew G. Knepley PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 4953673019faSMatthew G. Knepley PetscCall(PetscSectionGetMaxDof(s, &maxDof)); 4954673019faSMatthew G. Knepley PetscCall(PetscCalloc1(maxDof, &zeroes)); 4955673019faSMatthew G. Knepley for (PetscInt p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, s, p, zeroes, INSERT_BC_VALUES)); 4956673019faSMatthew G. Knepley PetscCall(PetscFree(zeroes)); 4957673019faSMatthew G. Knepley PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc)); 4958673019faSMatthew G. Knepley PetscCall(VecDestroy(&locFbc)); 4959673019faSMatthew G. Knepley } 49609566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 49619566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plexA)); 49623ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 49633e9753d6SMatthew G. Knepley } 49643e9753d6SMatthew G. Knepley 4965d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeBdResidualSingle(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF) 4966d71ae5a4SJacob Faibussowitsch { 49673e9753d6SMatthew G. Knepley DMField coordField; 49683e9753d6SMatthew G. Knepley DMLabel depthLabel; 49693e9753d6SMatthew G. Knepley IS facetIS; 49703e9753d6SMatthew G. Knepley PetscInt dim; 49713e9753d6SMatthew G. Knepley 49723e9753d6SMatthew G. Knepley PetscFunctionBegin; 49739566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 49749566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 49759566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 49769566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 49779566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS)); 49789566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 49793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 49803e9753d6SMatthew G. Knepley } 49813e9753d6SMatthew G. Knepley 4982a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexComputeBdResidual_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4983d71ae5a4SJacob Faibussowitsch { 49843e9753d6SMatthew G. Knepley PetscDS prob; 49853e9753d6SMatthew G. Knepley PetscInt numBd, bd; 49863e9753d6SMatthew G. Knepley DMField coordField = NULL; 49873e9753d6SMatthew G. Knepley IS facetIS = NULL; 49883e9753d6SMatthew G. Knepley DMLabel depthLabel; 49893e9753d6SMatthew G. Knepley PetscInt dim; 49903e9753d6SMatthew G. Knepley 49913e9753d6SMatthew G. Knepley PetscFunctionBegin; 49929566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 49939566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 49949566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 49959566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 49969566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 49973e9753d6SMatthew G. Knepley for (bd = 0; bd < numBd; ++bd) { 499845480ffeSMatthew G. Knepley PetscWeakForm wf; 49993e9753d6SMatthew G. Knepley DMBoundaryConditionType type; 50003e9753d6SMatthew G. Knepley DMLabel label; 50013e9753d6SMatthew G. Knepley const PetscInt *values; 50020c290148SMatthew G. Knepley PetscInt field, numValues, v; 50033e9753d6SMatthew G. Knepley PetscObject obj; 50043e9753d6SMatthew G. Knepley PetscClassId id; 50050c290148SMatthew G. Knepley PetscFormKey key; 50063e9753d6SMatthew G. Knepley 50079566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &field, NULL, NULL, NULL, NULL, NULL)); 50083d3e5d66SMatthew G. Knepley if (type & DM_BC_ESSENTIAL) continue; 50099566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 50109566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 50113d3e5d66SMatthew G. Knepley if (id != PETSCFE_CLASSID) continue; 50123e9753d6SMatthew G. Knepley if (!facetIS) { 50133e9753d6SMatthew G. Knepley DMLabel depthLabel; 50143e9753d6SMatthew G. Knepley PetscInt dim; 50153e9753d6SMatthew G. Knepley 50169566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 50179566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 50189566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 50193e9753d6SMatthew G. Knepley } 50209566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 50210c290148SMatthew G. Knepley for (v = 0; v < numValues; ++v) { 50220c290148SMatthew G. Knepley key.label = label; 50230c290148SMatthew G. Knepley key.value = values[v]; 50240c290148SMatthew G. Knepley key.field = field; 50250c290148SMatthew G. Knepley key.part = 0; 50269566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS)); 50270c290148SMatthew G. Knepley } 50283e9753d6SMatthew G. Knepley } 50299566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 50303ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 50313e9753d6SMatthew G. Knepley } 50323e9753d6SMatthew G. Knepley 5033d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 5034d71ae5a4SJacob Faibussowitsch { 50353e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 50363e9753d6SMatthew G. Knepley const char *name = "Residual"; 50373e9753d6SMatthew G. Knepley DM dmAux = NULL; 50383e9753d6SMatthew G. Knepley DM dmGrad = NULL; 50393e9753d6SMatthew G. Knepley DMLabel ghostLabel = NULL; 50406528b96dSMatthew G. Knepley PetscDS ds = NULL; 50416528b96dSMatthew G. Knepley PetscDS dsAux = NULL; 50423e9753d6SMatthew G. Knepley PetscSection section = NULL; 50433e9753d6SMatthew G. Knepley PetscBool useFEM = PETSC_FALSE; 50443e9753d6SMatthew G. Knepley PetscBool useFVM = PETSC_FALSE; 50453e9753d6SMatthew G. Knepley PetscBool isImplicit = (locX_t || time == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 50463e9753d6SMatthew G. Knepley PetscFV fvm = NULL; 50473e9753d6SMatthew G. Knepley DMField coordField = NULL; 50485962854dSMatthew G. Knepley Vec locA, cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL; 50493e9753d6SMatthew G. Knepley PetscScalar *u = NULL, *u_t, *a, *uL, *uR; 50503e9753d6SMatthew G. Knepley IS chunkIS; 50513e9753d6SMatthew G. Knepley const PetscInt *cells; 50523e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 50533e9753d6SMatthew G. Knepley PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, faceChunkSize, chunk, fStart, fEnd; 50541690c2aeSBarry Smith PetscInt maxDegree = PETSC_INT_MAX; 50553e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 50563e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 50573e9753d6SMatthew G. Knepley 50583e9753d6SMatthew G. Knepley PetscFunctionBegin; 50599566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 50603cc88e6aSStefano Zampini if (!cellIS) goto end; 50613cc88e6aSStefano Zampini PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 50623cc88e6aSStefano Zampini if (cStart >= cEnd) goto end; 50633e9753d6SMatthew G. Knepley /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 50643e9753d6SMatthew G. Knepley /* TODO The FVM geometry is over-manipulated. Make the precalc functions return exactly what we need */ 50653e9753d6SMatthew G. Knepley /* FEM+FVM */ 50669566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 50673e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 50689566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 50699566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 507007218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, NULL)); 50719566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 50729566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 50739566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA)); 50743e9753d6SMatthew G. Knepley if (locA) { 50753e9753d6SMatthew G. Knepley PetscInt subcell; 50769566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 50771059d808SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(dmAux, dm, DM_ENC_UNKNOWN, cells ? cells[cStart] : cStart, &subcell)); 507807218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux, subcell, &dsAux, NULL)); 50799566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux)); 50803e9753d6SMatthew G. Knepley } 50813e9753d6SMatthew G. Knepley /* 2: Get geometric data */ 50823e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 50833e9753d6SMatthew G. Knepley PetscObject obj; 50843e9753d6SMatthew G. Knepley PetscClassId id; 50853e9753d6SMatthew G. Knepley PetscBool fimp; 50863e9753d6SMatthew G. Knepley 50879566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 50883e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 50899566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 50909566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 5091ad540459SPierre Jolivet if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE; 50929371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 50939371c9d4SSatish Balay useFVM = PETSC_TRUE; 50949371c9d4SSatish Balay fvm = (PetscFV)obj; 50959371c9d4SSatish Balay } 50963e9753d6SMatthew G. Knepley } 50973e9753d6SMatthew G. Knepley if (useFEM) { 50989566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 50999566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 51003e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 51019566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 510248a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 51033e9753d6SMatthew G. Knepley } else { 51049566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 51053e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 51063e9753d6SMatthew G. Knepley PetscObject obj; 51073e9753d6SMatthew G. Knepley PetscClassId id; 51083e9753d6SMatthew G. Knepley PetscBool fimp; 51093e9753d6SMatthew G. Knepley 51109566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 51113e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 51129566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 51139566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 51143e9753d6SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 51153e9753d6SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 51163e9753d6SMatthew G. Knepley 51179566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 51189566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 51199566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 51203e9753d6SMatthew G. Knepley } 51213e9753d6SMatthew G. Knepley } 51223e9753d6SMatthew G. Knepley } 51233e9753d6SMatthew G. Knepley } 51245962854dSMatthew G. Knepley // Handle non-essential (e.g. outflow) boundary values 51253e9753d6SMatthew G. Knepley if (useFVM) { 51265962854dSMatthew G. Knepley PetscCall(DMPlexInsertBoundaryValuesFVM(dm, fvm, locX, time, &locGrad)); 51279566063dSJacob Faibussowitsch PetscCall(DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL)); 51289566063dSJacob Faibussowitsch PetscCall(DMPlexGetGradientDM(dm, fvm, &dmGrad)); 51293e9753d6SMatthew G. Knepley } 51303e9753d6SMatthew G. Knepley /* Loop over chunks */ 51319566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS)); 51323e9753d6SMatthew G. Knepley numCells = cEnd - cStart; 51333e9753d6SMatthew G. Knepley numChunks = 1; 51343e9753d6SMatthew G. Knepley cellChunkSize = numCells / numChunks; 51353e9753d6SMatthew G. Knepley faceChunkSize = (fEnd - fStart) / numChunks; 51363e9753d6SMatthew G. Knepley numChunks = PetscMin(1, numCells); 51373e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 51383e9753d6SMatthew G. Knepley PetscScalar *elemVec, *fluxL, *fluxR; 51393e9753d6SMatthew G. Knepley PetscReal *vol; 51403e9753d6SMatthew G. Knepley PetscFVFaceGeom *fgeom; 51413e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 51423e9753d6SMatthew G. Knepley PetscInt fS = fStart + chunk * faceChunkSize, fE = PetscMin(fS + faceChunkSize, fEnd), numFaces = 0, face; 51433e9753d6SMatthew G. Knepley 51443e9753d6SMatthew G. Knepley /* Extract field coefficients */ 51453e9753d6SMatthew G. Knepley if (useFEM) { 51469566063dSJacob Faibussowitsch PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells)); 51479566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 51489566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 51499566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numCells * totDim)); 51503e9753d6SMatthew G. Knepley } 51513e9753d6SMatthew G. Knepley if (useFVM) { 51529566063dSJacob Faibussowitsch PetscCall(DMPlexGetFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR)); 51539566063dSJacob Faibussowitsch PetscCall(DMPlexGetFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol)); 51549566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL)); 51559566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR)); 51569566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(fluxL, numFaces * totDim)); 51579566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(fluxR, numFaces * totDim)); 51583e9753d6SMatthew G. Knepley } 51593e9753d6SMatthew 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 */ 51603e9753d6SMatthew G. Knepley /* Loop over fields */ 51613e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 51623e9753d6SMatthew G. Knepley PetscObject obj; 51633e9753d6SMatthew G. Knepley PetscClassId id; 51643e9753d6SMatthew G. Knepley PetscBool fimp; 51653e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 51663e9753d6SMatthew G. Knepley 51676528b96dSMatthew G. Knepley key.field = f; 51689566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 51693e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 51709566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 51719566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 51723e9753d6SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 51733e9753d6SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 51743e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 51753e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 51763e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 51773e9753d6SMatthew G. Knepley PetscInt Nq, Nb; 51783e9753d6SMatthew G. Knepley 51799566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 51809566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 51819566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 51823e9753d6SMatthew G. Knepley blockSize = Nb; 51833e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 51849566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 51853e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 51863e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 51873e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 51883e9753d6SMatthew G. Knepley offset = numCells - Nr; 51893e9753d6SMatthew G. Knepley /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 51903e9753d6SMatthew 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) */ 51919566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom)); 51929566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateResidual(ds, key, Ne, chunkGeom, u, u_t, dsAux, a, t, elemVec)); 51939566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom)); 51948e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateResidual(ds, key, Nr, chunkGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), dsAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, &elemVec[offset * totDim])); 51959566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom)); 51963e9753d6SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 51973e9753d6SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 51983e9753d6SMatthew G. Knepley 51993e9753d6SMatthew G. Knepley Ne = numFaces; 52003e9753d6SMatthew G. Knepley /* Riemann solve over faces (need fields at face centroids) */ 52013e9753d6SMatthew G. Knepley /* We need to evaluate FE fields at those coordinates */ 52029566063dSJacob Faibussowitsch PetscCall(PetscFVIntegrateRHSFunction(fv, ds, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR)); 520363a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 52043e9753d6SMatthew G. Knepley } 52053e9753d6SMatthew G. Knepley /* Loop over domain */ 52063e9753d6SMatthew G. Knepley if (useFEM) { 52073e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 52083e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 52093e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 52103e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 52113e9753d6SMatthew G. Knepley 52129566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim])); 52133e9753d6SMatthew G. Knepley if (ghostLabel) { 52143e9753d6SMatthew G. Knepley PetscInt ghostVal; 52153e9753d6SMatthew G. Knepley 52169566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 52173e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 52183e9753d6SMatthew G. Knepley } 52199566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES)); 52203e9753d6SMatthew G. Knepley } 52213e9753d6SMatthew G. Knepley } 52223e9753d6SMatthew G. Knepley if (useFVM) { 52233e9753d6SMatthew G. Knepley PetscScalar *fa; 52243e9753d6SMatthew G. Knepley PetscInt iface; 52253e9753d6SMatthew G. Knepley 52269566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 52273e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 52283e9753d6SMatthew G. Knepley PetscFV fv; 52293e9753d6SMatthew G. Knepley PetscObject obj; 52303e9753d6SMatthew G. Knepley PetscClassId id; 52315962854dSMatthew G. Knepley PetscInt cdim, foff, pdim; 52323e9753d6SMatthew G. Knepley 52335962854dSMatthew G. Knepley PetscCall(DMGetCoordinateDim(dm, &cdim)); 52349566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 52359566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(ds, f, &foff)); 52369566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 52373e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 52383e9753d6SMatthew G. Knepley fv = (PetscFV)obj; 52399566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 52403e9753d6SMatthew G. Knepley /* Accumulate fluxes to cells */ 52413e9753d6SMatthew G. Knepley for (face = fS, iface = 0; face < fE; ++face) { 52423e9753d6SMatthew G. Knepley const PetscInt *scells; 52433e9753d6SMatthew G. Knepley PetscScalar *fL = NULL, *fR = NULL; 52443e9753d6SMatthew G. Knepley PetscInt ghost, d, nsupp, nchild; 52453e9753d6SMatthew G. Knepley 52469566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 52479566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 52489566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 52493e9753d6SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 52509566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &scells)); 52519566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, scells[0], &ghost)); 52529566063dSJacob Faibussowitsch if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[0], f, fa, &fL)); 52539566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, scells[1], &ghost)); 52549566063dSJacob Faibussowitsch if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[1], f, fa, &fR)); 52555962854dSMatthew G. Knepley if (mesh->printFVM > 1) { 52565962854dSMatthew G. Knepley PetscCall(DMPrintCellVectorReal(face, "Residual: normal", cdim, fgeom[iface].normal)); 52575962854dSMatthew G. Knepley PetscCall(DMPrintCellVector(face, "Residual: left state", pdim, &uL[iface * totDim + foff])); 52585962854dSMatthew G. Knepley PetscCall(DMPrintCellVector(face, "Residual: right state", pdim, &uR[iface * totDim + foff])); 52595962854dSMatthew G. Knepley PetscCall(DMPrintCellVector(face, "Residual: left flux", pdim, &fluxL[iface * totDim + foff])); 52605962854dSMatthew G. Knepley PetscCall(DMPrintCellVector(face, "Residual: right flux", pdim, &fluxR[iface * totDim + foff])); 52615962854dSMatthew G. Knepley } 52623e9753d6SMatthew G. Knepley for (d = 0; d < pdim; ++d) { 52633e9753d6SMatthew G. Knepley if (fL) fL[d] -= fluxL[iface * totDim + foff + d]; 52643e9753d6SMatthew G. Knepley if (fR) fR[d] += fluxR[iface * totDim + foff + d]; 52653e9753d6SMatthew G. Knepley } 52663e9753d6SMatthew G. Knepley ++iface; 52673e9753d6SMatthew G. Knepley } 52683e9753d6SMatthew G. Knepley } 52699566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 52703e9753d6SMatthew G. Knepley } 52713e9753d6SMatthew G. Knepley /* Handle time derivative */ 52723e9753d6SMatthew G. Knepley if (locX_t) { 52733e9753d6SMatthew G. Knepley PetscScalar *x_t, *fa; 52743e9753d6SMatthew G. Knepley 52759566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 52769566063dSJacob Faibussowitsch PetscCall(VecGetArray(locX_t, &x_t)); 52773e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 52783e9753d6SMatthew G. Knepley PetscFV fv; 52793e9753d6SMatthew G. Knepley PetscObject obj; 52803e9753d6SMatthew G. Knepley PetscClassId id; 52813e9753d6SMatthew G. Knepley PetscInt pdim, d; 52823e9753d6SMatthew G. Knepley 52839566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 52849566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 52853e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 52863e9753d6SMatthew G. Knepley fv = (PetscFV)obj; 52879566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 52883e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 52893e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 52903e9753d6SMatthew G. Knepley PetscScalar *u_t, *r; 52913e9753d6SMatthew G. Knepley 52923e9753d6SMatthew G. Knepley if (ghostLabel) { 52933e9753d6SMatthew G. Knepley PetscInt ghostVal; 52943e9753d6SMatthew G. Knepley 52959566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 52963e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 52973e9753d6SMatthew G. Knepley } 52989566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t)); 52999566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r)); 53003e9753d6SMatthew G. Knepley for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 53013e9753d6SMatthew G. Knepley } 53023e9753d6SMatthew G. Knepley } 53039566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locX_t, &x_t)); 53049566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 53053e9753d6SMatthew G. Knepley } 53063e9753d6SMatthew G. Knepley if (useFEM) { 53079566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 53089566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 53093e9753d6SMatthew G. Knepley } 53103e9753d6SMatthew G. Knepley if (useFVM) { 53119566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR)); 53129566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol)); 53139566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL)); 53149566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR)); 53159566063dSJacob Faibussowitsch if (dmGrad) PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 53163e9753d6SMatthew G. Knepley } 53173e9753d6SMatthew G. Knepley } 53189566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISDestroy(&chunkIS)); 53199566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 53203e9753d6SMatthew G. Knepley 53213e9753d6SMatthew G. Knepley if (useFEM) { 53229566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Internal(dm, locX, locX_t, t, locF, user)); 53233e9753d6SMatthew G. Knepley 53243e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 53259566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 53269566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 53273e9753d6SMatthew G. Knepley } else { 53283e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 53299566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 53309566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&quads[f])); 53313e9753d6SMatthew G. Knepley } 53329566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 53333e9753d6SMatthew G. Knepley } 53343e9753d6SMatthew G. Knepley } 53353e9753d6SMatthew G. Knepley 53363e9753d6SMatthew G. Knepley /* FEM */ 53373e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 53383e9753d6SMatthew G. Knepley /* 2: Get geometric data */ 53393e9753d6SMatthew G. Knepley /* 3: Handle boundary values */ 53403e9753d6SMatthew G. Knepley /* 4: Loop over domain */ 53413e9753d6SMatthew G. Knepley /* Extract coefficients */ 53423e9753d6SMatthew G. Knepley /* Loop over fields */ 53433e9753d6SMatthew G. Knepley /* Set tiling for FE*/ 53443e9753d6SMatthew G. Knepley /* Integrate FE residual to get elemVec */ 53453e9753d6SMatthew G. Knepley /* Loop over subdomain */ 53463e9753d6SMatthew G. Knepley /* Loop over quad points */ 53473e9753d6SMatthew G. Knepley /* Transform coords to real space */ 53483e9753d6SMatthew G. Knepley /* Evaluate field and aux fields at point */ 53493e9753d6SMatthew G. Knepley /* Evaluate residual at point */ 53503e9753d6SMatthew G. Knepley /* Transform residual to real space */ 53513e9753d6SMatthew G. Knepley /* Add residual to elemVec */ 53523e9753d6SMatthew G. Knepley /* Loop over domain */ 53533e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 53543e9753d6SMatthew G. Knepley 53553e9753d6SMatthew G. Knepley /* FVM */ 53563e9753d6SMatthew G. Knepley /* Get geometric data */ 53573e9753d6SMatthew G. Knepley /* If using gradients */ 53583e9753d6SMatthew G. Knepley /* Compute gradient data */ 53593e9753d6SMatthew G. Knepley /* Loop over domain faces */ 53603e9753d6SMatthew G. Knepley /* Count computational faces */ 53613e9753d6SMatthew G. Knepley /* Reconstruct cell gradient */ 53623e9753d6SMatthew G. Knepley /* Loop over domain cells */ 53633e9753d6SMatthew G. Knepley /* Limit cell gradients */ 53643e9753d6SMatthew G. Knepley /* Handle boundary values */ 53653e9753d6SMatthew G. Knepley /* Loop over domain faces */ 53663e9753d6SMatthew G. Knepley /* Read out field, centroid, normal, volume for each side of face */ 53673e9753d6SMatthew G. Knepley /* Riemann solve over faces */ 53683e9753d6SMatthew G. Knepley /* Loop over domain faces */ 53693e9753d6SMatthew G. Knepley /* Accumulate fluxes to cells */ 53703e9753d6SMatthew G. Knepley /* TODO Change printFEM to printDisc here */ 53713e9753d6SMatthew G. Knepley if (mesh->printFEM) { 53723e9753d6SMatthew G. Knepley Vec locFbc; 53733e9753d6SMatthew G. Knepley PetscInt pStart, pEnd, p, maxDof; 53743e9753d6SMatthew G. Knepley PetscScalar *zeroes; 53753e9753d6SMatthew G. Knepley 53769566063dSJacob Faibussowitsch PetscCall(VecDuplicate(locF, &locFbc)); 53779566063dSJacob Faibussowitsch PetscCall(VecCopy(locF, locFbc)); 53789566063dSJacob Faibussowitsch PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 53799566063dSJacob Faibussowitsch PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 53809566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(maxDof, &zeroes)); 538148a46eb9SPierre Jolivet for (p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES)); 53829566063dSJacob Faibussowitsch PetscCall(PetscFree(zeroes)); 53839566063dSJacob Faibussowitsch PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc)); 53849566063dSJacob Faibussowitsch PetscCall(VecDestroy(&locFbc)); 53853e9753d6SMatthew G. Knepley } 53863cc88e6aSStefano Zampini end: 53879566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 53883ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 53893e9753d6SMatthew G. Knepley } 53903e9753d6SMatthew G. Knepley 53916528b96dSMatthew G. Knepley /* 53926528b96dSMatthew G. Knepley 1) Allow multiple kernels for BdResidual for hybrid DS 53936528b96dSMatthew G. Knepley 53946528b96dSMatthew G. Knepley DONE 2) Get out dsAux for either side at the same time as cohesive cell dsAux 53956528b96dSMatthew G. Knepley 53966528b96dSMatthew G. Knepley DONE 3) Change DMGetCellFields() to get different aux data a[] for each side 53976528b96dSMatthew G. Knepley - I think I just need to replace a[] with the closure from each face 53986528b96dSMatthew G. Knepley 53996528b96dSMatthew G. Knepley 4) Run both kernels for each non-hybrid field with correct dsAux, and then hybrid field as before 54006528b96dSMatthew G. Knepley */ 5401d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Hybrid_Internal(DM dm, PetscFormKey key[], IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 5402d71ae5a4SJacob Faibussowitsch { 54033e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 54043e9753d6SMatthew G. Knepley const char *name = "Hybrid Residual"; 540504c51a94SMatthew G. Knepley DM dmAux[3] = {NULL, NULL, NULL}; 54063e9753d6SMatthew G. Knepley DMLabel ghostLabel = NULL; 54076528b96dSMatthew G. Knepley PetscDS ds = NULL; 540807218a29SMatthew G. Knepley PetscDS dsIn = NULL; 54096528b96dSMatthew G. Knepley PetscDS dsAux[3] = {NULL, NULL, NULL}; 541004c51a94SMatthew G. Knepley Vec locA[3] = {NULL, NULL, NULL}; 541107218a29SMatthew G. Knepley DM dmScale[3] = {NULL, NULL, NULL}; 541207218a29SMatthew G. Knepley PetscDS dsScale[3] = {NULL, NULL, NULL}; 541307218a29SMatthew G. Knepley Vec locS[3] = {NULL, NULL, NULL}; 54143e9753d6SMatthew G. Knepley PetscSection section = NULL; 54153e9753d6SMatthew G. Knepley DMField coordField = NULL; 541607218a29SMatthew G. Knepley PetscScalar *a[3] = {NULL, NULL, NULL}; 541707218a29SMatthew G. Knepley PetscScalar *s[3] = {NULL, NULL, NULL}; 5418b2ab40e6SMatthew G. Knepley PetscScalar *u = NULL, *u_t; 541907218a29SMatthew G. Knepley PetscScalar *elemVecNeg, *elemVecPos, *elemVecCoh; 54203e9753d6SMatthew G. Knepley IS chunkIS; 54213e9753d6SMatthew G. Knepley const PetscInt *cells; 54223e9753d6SMatthew G. Knepley PetscInt *faces; 54233e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 54243e2b0218SMatthew G. Knepley PetscInt Nf, f, totDim, totDimIn, totDimAux[3], totDimScale[3], numChunks, cellChunkSize, chunk; 54251690c2aeSBarry Smith PetscInt maxDegree = PETSC_INT_MAX; 54263e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 54273e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 54283e9753d6SMatthew G. Knepley 54293e9753d6SMatthew G. Knepley PetscFunctionBegin; 54303cc88e6aSStefano Zampini PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 54313cc88e6aSStefano Zampini if (!cellIS) goto end; 5432437e83fbSMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5433437e83fbSMatthew G. Knepley PetscCall(ISGetLocalSize(cellIS, &numCells)); 54343cc88e6aSStefano Zampini if (cStart >= cEnd) goto end; 54355fedec97SMatthew G. Knepley if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) { 54365fedec97SMatthew G. Knepley const char *name; 54379566063dSJacob Faibussowitsch PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name)); 543863a3b9bcSJacob 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); 54395fedec97SMatthew G. Knepley } 54403e9753d6SMatthew G. Knepley /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 54413e9753d6SMatthew G. Knepley /* FEM */ 54423e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 5443b98a7184SJames Wright PetscCall(DMGetLocalSection(dm, §ion)); 54449566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 544507218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn)); 54469566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 54479566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 544807218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsIn, &totDimIn)); 54499566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2])); 545004c51a94SMatthew G. Knepley if (locA[2]) { 54511059d808SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 54521059d808SMatthew G. Knepley 54539566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA[2], &dmAux[2])); 545407218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2], NULL)); 54559566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2])); 54566528b96dSMatthew G. Knepley { 54576528b96dSMatthew G. Knepley const PetscInt *cone; 54586528b96dSMatthew G. Knepley PetscInt c; 54596528b96dSMatthew G. Knepley 54601059d808SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 54616528b96dSMatthew G. Knepley for (c = 0; c < 2; ++c) { 54626528b96dSMatthew G. Knepley const PetscInt *support; 54636528b96dSMatthew G. Knepley PetscInt ssize, s; 54646528b96dSMatthew G. Knepley 54659566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 54669566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 54671059d808SMatthew 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); 54681059d808SMatthew G. Knepley if (support[0] == cellStart) s = 1; 54691059d808SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 54701059d808SMatthew 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); 54719566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c])); 5472c75bfeddSPierre 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); 54739566063dSJacob Faibussowitsch if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c])); 5474ad540459SPierre Jolivet else dmAux[c] = dmAux[2]; 547507218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c], NULL)); 54769566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c])); 54776528b96dSMatthew G. Knepley } 54786528b96dSMatthew G. Knepley } 54793e9753d6SMatthew G. Knepley } 548007218a29SMatthew G. Knepley /* Handle mass matrix scaling 548107218a29SMatthew G. Knepley The field in key[2] is the field to be scaled, and the scaling field is the first in the dsScale */ 548207218a29SMatthew G. Knepley PetscCall(DMGetAuxiliaryVec(dm, key[2].label, -key[2].value, key[2].part, &locS[2])); 548307218a29SMatthew G. Knepley if (locS[2]) { 54843e2b0218SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 548507218a29SMatthew G. Knepley PetscInt Nb, Nbs; 548607218a29SMatthew G. Knepley 548707218a29SMatthew G. Knepley PetscCall(VecGetDM(locS[2], &dmScale[2])); 54883e2b0218SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[2], cellStart, &dsScale[2], NULL)); 54893e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[2], &totDimScale[2])); 549007218a29SMatthew G. Knepley // BRAD: This is not set correctly 549107218a29SMatthew G. Knepley key[2].field = 2; 549207218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, key[2].field, &Nb)); 549307218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsScale[2], 0, &Nbs)); 549407218a29SMatthew 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); 54953e2b0218SMatthew G. Knepley { 54963e2b0218SMatthew G. Knepley const PetscInt *cone; 54973e2b0218SMatthew G. Knepley PetscInt c; 54983e2b0218SMatthew G. Knepley 54993e2b0218SMatthew G. Knepley locS[1] = locS[0] = locS[2]; 55003e2b0218SMatthew G. Knepley dmScale[1] = dmScale[0] = dmScale[2]; 55013e2b0218SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 55023e2b0218SMatthew G. Knepley for (c = 0; c < 2; ++c) { 55033e2b0218SMatthew G. Knepley const PetscInt *support; 55043e2b0218SMatthew G. Knepley PetscInt ssize, s; 55053e2b0218SMatthew G. Knepley 55063e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 55073e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 55083e2b0218SMatthew 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); 55093e2b0218SMatthew G. Knepley if (support[0] == cellStart) s = 1; 55103e2b0218SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 55113e2b0218SMatthew 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); 55123e2b0218SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[c], support[s], &dsScale[c], NULL)); 55133e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[c], &totDimScale[c])); 55143e2b0218SMatthew G. Knepley } 55153e2b0218SMatthew G. Knepley } 551607218a29SMatthew G. Knepley } 55173e9753d6SMatthew G. Knepley /* 2: Setup geometric data */ 55189566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 55199566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 55203e9753d6SMatthew G. Knepley if (maxDegree > 1) { 55219566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 55223e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 55233e9753d6SMatthew G. Knepley PetscFE fe; 55243e9753d6SMatthew G. Knepley 55259566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 55263e9753d6SMatthew G. Knepley if (fe) { 55279566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 55289566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 55293e9753d6SMatthew G. Knepley } 55303e9753d6SMatthew G. Knepley } 55313e9753d6SMatthew G. Knepley } 55323e9753d6SMatthew G. Knepley /* Loop over chunks */ 55333e9753d6SMatthew G. Knepley cellChunkSize = numCells; 55343e9753d6SMatthew G. Knepley numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize); 553507218a29SMatthew G. Knepley PetscCall(PetscCalloc1(2 * cellChunkSize, &faces)); 553607218a29SMatthew G. Knepley PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS)); 55373e9753d6SMatthew G. Knepley /* Extract field coefficients */ 55383e9753d6SMatthew G. Knepley /* NOTE This needs the end cap faces to have identical orientations */ 553907218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 554007218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 55413e2b0218SMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s)); 554207218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecNeg)); 554307218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecPos)); 554407218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecCoh)); 55453e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 55463e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 55473e9753d6SMatthew G. Knepley 554807218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemVecNeg, cellChunkSize * totDim)); 554907218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemVecPos, cellChunkSize * totDim)); 555007218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemVecCoh, cellChunkSize * totDim)); 55513e9753d6SMatthew G. Knepley /* Get faces */ 55523e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 55533e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 55543e9753d6SMatthew G. Knepley const PetscInt *cone; 55559566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cell, &cone)); 555607218a29SMatthew G. Knepley faces[(c - cS) * 2 + 0] = cone[0]; 555707218a29SMatthew G. Knepley faces[(c - cS) * 2 + 1] = cone[1]; 55583e9753d6SMatthew G. Knepley } 555907218a29SMatthew G. Knepley PetscCall(ISGeneralSetIndices(chunkIS, 2 * cellChunkSize, faces, PETSC_USE_POINTER)); 55603e9753d6SMatthew G. Knepley /* Get geometric data */ 55613e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 55629566063dSJacob Faibussowitsch if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad)); 55639566063dSJacob Faibussowitsch if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom)); 55643e9753d6SMatthew G. Knepley } else { 55653e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 55669566063dSJacob Faibussowitsch if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f])); 55673e9753d6SMatthew G. Knepley } 55683e9753d6SMatthew G. Knepley } 55693e9753d6SMatthew G. Knepley /* Loop over fields */ 55703e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 55713e9753d6SMatthew G. Knepley PetscFE fe; 55723e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 5573148442b3SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 55743e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 55753e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 55765fedec97SMatthew G. Knepley PetscBool isCohesiveField; 55773e9753d6SMatthew G. Knepley 55789566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 55793e9753d6SMatthew G. Knepley if (!fe) continue; 55809566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 55819566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 55829566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 55833e9753d6SMatthew G. Knepley blockSize = Nb; 55843e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 55859566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 55863e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 55873e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 55883e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 55893e9753d6SMatthew G. Knepley offset = numCells - Nr; 559007218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, 0, offset * 2, &chunkGeom)); 559107218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, offset * 2, numCells * 2, &remGeom)); 55929566063dSJacob Faibussowitsch PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField)); 55935fedec97SMatthew G. Knepley chunkGeom->isCohesive = remGeom->isCohesive = PETSC_TRUE; 55946528b96dSMatthew G. Knepley key[0].field = f; 55956528b96dSMatthew G. Knepley key[1].field = f; 55965fedec97SMatthew G. Knepley key[2].field = f; 559707218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, elemVecNeg)); 55988e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[0], 0, Nr, remGeom, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[0], PetscSafePointerPlusOffset(a[0], offset * totDimAux[0]), t, &elemVecNeg[offset * totDim])); 559907218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, elemVecPos)); 56008e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[1], 1, Nr, remGeom, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[1], PetscSafePointerPlusOffset(a[1], offset * totDimAux[1]), t, &elemVecPos[offset * totDim])); 560107218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, elemVecCoh)); 56028e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[2], 2, Nr, remGeom, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[2], PetscSafePointerPlusOffset(a[2], offset * totDimAux[2]), t, &elemVecCoh[offset * totDim])); 56039566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom)); 56049566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom)); 56053e9753d6SMatthew G. Knepley } 56063e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 56073e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 56083e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 56093e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 561007218a29SMatthew G. Knepley PetscInt i; 56113e9753d6SMatthew G. Knepley 561207218a29SMatthew G. Knepley /* Scale element values */ 561307218a29SMatthew G. Knepley if (locS[0]) { 56143e2b0218SMatthew G. Knepley PetscInt Nb, off = cind * totDim, soff = cind * totDimScale[0]; 561507218a29SMatthew G. Knepley PetscBool cohesive; 561607218a29SMatthew G. Knepley 561707218a29SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 561807218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, f, &Nb)); 561907218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(ds, f, &cohesive)); 562007218a29SMatthew G. Knepley if (f == key[2].field) { 562107218a29SMatthew G. Knepley PetscCheck(cohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Scaling should not happen for face fields"); 562207218a29SMatthew G. Knepley // No cohesive scaling field is currently input 562307218a29SMatthew 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]; 562407218a29SMatthew G. Knepley off += Nb; 562507218a29SMatthew G. Knepley } else { 562607218a29SMatthew G. Knepley const PetscInt N = cohesive ? Nb : Nb * 2; 562707218a29SMatthew G. Knepley 562807218a29SMatthew G. Knepley for (i = 0; i < N; ++i) elemVecCoh[off + i] += elemVecNeg[off + i] + elemVecPos[off + i]; 562907218a29SMatthew G. Knepley off += N; 563007218a29SMatthew G. Knepley } 563107218a29SMatthew G. Knepley } 563207218a29SMatthew G. Knepley } else { 563307218a29SMatthew G. Knepley for (i = cind * totDim; i < (cind + 1) * totDim; ++i) elemVecCoh[i] += elemVecNeg[i] + elemVecPos[i]; 563407218a29SMatthew G. Knepley } 563507218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVecCoh[cind * totDim])); 56363e9753d6SMatthew G. Knepley if (ghostLabel) { 56373e9753d6SMatthew G. Knepley PetscInt ghostVal; 56383e9753d6SMatthew G. Knepley 56399566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 56403e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 56413e9753d6SMatthew G. Knepley } 564207218a29SMatthew G. Knepley PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVecCoh[cind * totDim], ADD_ALL_VALUES)); 56433e9753d6SMatthew G. Knepley } 56443e9753d6SMatthew G. Knepley } 56459566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 564607218a29SMatthew G. Knepley PetscCall(DMPlexRestoreHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 56473e2b0218SMatthew G. Knepley PetscCall(DMPlexRestoreHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s)); 564807218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecNeg)); 564907218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecPos)); 565007218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecCoh)); 56519566063dSJacob Faibussowitsch PetscCall(PetscFree(faces)); 56529566063dSJacob Faibussowitsch PetscCall(ISDestroy(&chunkIS)); 56539566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 56543e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 56559566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 56569566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 56573e9753d6SMatthew G. Knepley } else { 56583e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 56599566063dSJacob Faibussowitsch if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 56609566063dSJacob Faibussowitsch if (quads) PetscCall(PetscQuadratureDestroy(&quads[f])); 56613e9753d6SMatthew G. Knepley } 56629566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 56633e9753d6SMatthew G. Knepley } 566485cc2951SMatthew G. Knepley if (mesh->printFEM) { 566585cc2951SMatthew G. Knepley Vec locFbc; 566685cc2951SMatthew G. Knepley PetscInt pStart, pEnd, p, maxDof; 566785cc2951SMatthew G. Knepley PetscScalar *zeroes; 566885cc2951SMatthew G. Knepley 566985cc2951SMatthew G. Knepley PetscCall(VecDuplicate(locF, &locFbc)); 567085cc2951SMatthew G. Knepley PetscCall(VecCopy(locF, locFbc)); 567185cc2951SMatthew G. Knepley PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 567285cc2951SMatthew G. Knepley PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 567385cc2951SMatthew G. Knepley PetscCall(PetscCalloc1(maxDof, &zeroes)); 567485cc2951SMatthew G. Knepley for (p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES)); 567585cc2951SMatthew G. Knepley PetscCall(PetscFree(zeroes)); 567685cc2951SMatthew G. Knepley PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc)); 567785cc2951SMatthew G. Knepley PetscCall(VecDestroy(&locFbc)); 567885cc2951SMatthew G. Knepley } 56793cc88e6aSStefano Zampini end: 56809566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 56813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 56823e9753d6SMatthew G. Knepley } 56833e9753d6SMatthew G. Knepley 5684a4e35b19SJacob 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) 5685d71ae5a4SJacob Faibussowitsch { 56863e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 56873e9753d6SMatthew G. Knepley DM plex = NULL, plexA = NULL, tdm; 56883e9753d6SMatthew G. Knepley DMEnclosureType encAux; 5689be62b2b4SMatthew G. Knepley PetscDS ds, dsAux = NULL; 56903e9753d6SMatthew G. Knepley PetscSection section, sectionAux = NULL; 5691e432b41dSStefano Zampini PetscSection globalSection; 56923e9753d6SMatthew G. Knepley Vec locA = NULL, tv; 5693be62b2b4SMatthew G. Knepley PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL; 56943e9753d6SMatthew G. Knepley PetscInt v; 56953e9753d6SMatthew G. Knepley PetscInt Nf, totDim, totDimAux = 0; 5696be62b2b4SMatthew G. Knepley PetscBool hasJac = PETSC_FALSE, hasPrec = PETSC_FALSE, transform; 56973e9753d6SMatthew G. Knepley 56983e9753d6SMatthew G. Knepley PetscFunctionBegin; 56999566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 57009566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 57019566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 57029566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 5703be62b2b4SMatthew G. Knepley PetscCall(DMGetDS(dm, &ds)); 5704be62b2b4SMatthew G. Knepley PetscCall(PetscDSGetNumFields(ds, &Nf)); 5705be62b2b4SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 570621a4fad8SMatthew G. Knepley PetscCall(PetscWeakFormHasBdJacobian(wf, &hasJac)); 570721a4fad8SMatthew G. Knepley PetscCall(PetscWeakFormHasBdJacobianPreconditioner(wf, &hasPrec)); 570821a4fad8SMatthew G. Knepley if (!hasJac && !hasPrec) PetscFunctionReturn(PETSC_SUCCESS); 570921a4fad8SMatthew G. Knepley PetscCall(DMConvert(dm, DMPLEX, &plex)); 57109566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, label, values[0], 0, &locA)); 57113e9753d6SMatthew G. Knepley if (locA) { 57123e9753d6SMatthew G. Knepley DM dmAux; 57133e9753d6SMatthew G. Knepley 57149566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 57159566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 57169566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 5717be62b2b4SMatthew G. Knepley PetscCall(DMGetDS(plexA, &dsAux)); 5718be62b2b4SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux)); 57199566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexA, §ionAux)); 57203e9753d6SMatthew G. Knepley } 57213e9753d6SMatthew G. Knepley 57229566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 57233e9753d6SMatthew G. Knepley for (v = 0; v < numValues; ++v) { 57243e9753d6SMatthew G. Knepley PetscFEGeom *fgeom; 57253e9753d6SMatthew G. Knepley PetscInt maxDegree; 57263e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 57273e9753d6SMatthew G. Knepley IS pointIS; 57283e9753d6SMatthew G. Knepley const PetscInt *points; 572906ad1575SMatthew G. Knepley PetscFormKey key; 57303e9753d6SMatthew G. Knepley PetscInt numFaces, face, Nq; 57313e9753d6SMatthew G. Knepley 573245480ffeSMatthew G. Knepley key.label = label; 573345480ffeSMatthew G. Knepley key.value = values[v]; 573406ad1575SMatthew G. Knepley key.part = 0; 57359566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS)); 57363e9753d6SMatthew G. Knepley if (!pointIS) continue; /* No points with that id on this process */ 57373e9753d6SMatthew G. Knepley { 57383e9753d6SMatthew G. Knepley IS isectIS; 57393e9753d6SMatthew G. Knepley 57403e9753d6SMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a prior if one is a superset of the other */ 57419566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 57429566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 57433e9753d6SMatthew G. Knepley pointIS = isectIS; 57443e9753d6SMatthew G. Knepley } 57459566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 57469566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 574732603206SJames Wright PetscCall(PetscMalloc5(numFaces * totDim, &u, (locX_t ? (size_t)numFaces * totDim : 0), &u_t, (hasJac ? (size_t)numFaces * totDim * totDim : 0), &elemMat, (hasPrec ? (size_t)numFaces * totDim * totDim : 0), &elemMatP, (locA ? (size_t)numFaces * totDimAux : 0), &a)); 57489566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 574948a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 57503e9753d6SMatthew G. Knepley if (!qGeom) { 57513e9753d6SMatthew G. Knepley PetscFE fe; 57523e9753d6SMatthew G. Knepley 5753be62b2b4SMatthew G. Knepley PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&fe)); 57549566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 57559566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 57563e9753d6SMatthew G. Knepley } 57579566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 57589566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 57593e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 5760f15274beSMatthew Knepley const PetscInt point = points[face], *support; 57613e9753d6SMatthew G. Knepley PetscScalar *x = NULL; 5762f15274beSMatthew Knepley PetscInt i; 57633e9753d6SMatthew G. Knepley 57649566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, point, &support)); 57659566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 57663e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 57679566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 57683e9753d6SMatthew G. Knepley if (locX_t) { 57699566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x)); 57703e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i]; 57719566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x)); 57723e9753d6SMatthew G. Knepley } 57733e9753d6SMatthew G. Knepley if (locA) { 57743e9753d6SMatthew G. Knepley PetscInt subp; 57759566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 57769566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 57773e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i]; 57789566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 57793e9753d6SMatthew G. Knepley } 57803e9753d6SMatthew G. Knepley } 578121a4fad8SMatthew G. Knepley if (elemMat) PetscCall(PetscArrayzero(elemMat, numFaces * totDim * totDim)); 578221a4fad8SMatthew G. Knepley if (elemMatP) PetscCall(PetscArrayzero(elemMatP, numFaces * totDim * totDim)); 57833e9753d6SMatthew G. Knepley { 57843e9753d6SMatthew G. Knepley PetscFE fe; 57853e9753d6SMatthew G. Knepley PetscInt Nb; 57863e9753d6SMatthew G. Knepley /* Conforming batches */ 57873e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 57883e9753d6SMatthew G. Knepley /* Remainder */ 57893e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 57903e9753d6SMatthew G. Knepley PetscInt fieldJ, Nr, offset; 57913e9753d6SMatthew G. Knepley 5792be62b2b4SMatthew G. Knepley PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&fe)); 57939566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 57949566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 57953e9753d6SMatthew G. Knepley blockSize = Nb; 57963e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 57979566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 57983e9753d6SMatthew G. Knepley numChunks = numFaces / (numBatches * batchSize); 57993e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 58003e9753d6SMatthew G. Knepley Nr = numFaces % (numBatches * batchSize); 58013e9753d6SMatthew G. Knepley offset = numFaces - Nr; 58029566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom)); 58033e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 580445480ffeSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 5805be62b2b4SMatthew G. Knepley if (hasJac) PetscCall(PetscFEIntegrateBdJacobian(ds, wf, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, dsAux, a, t, X_tShift, elemMat)); 5806be62b2b4SMatthew G. Knepley if (hasPrec) PetscCall(PetscFEIntegrateBdJacobian(ds, wf, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, dsAux, a, t, X_tShift, elemMatP)); 58073e9753d6SMatthew G. Knepley } 58089566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 58093e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 581045480ffeSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 5811be62b2b4SMatthew G. Knepley if (hasJac) 58128e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateBdJacobian(ds, wf, PETSCFE_JACOBIAN, key, Nr, chunkGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), dsAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMat[offset * totDim * totDim])); 5813be62b2b4SMatthew G. Knepley if (hasPrec) 58148e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateBdJacobian(ds, wf, PETSCFE_JACOBIAN_PRE, key, Nr, chunkGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), dsAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMatP[offset * totDim * totDim])); 58153e9753d6SMatthew G. Knepley } 58169566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 58173e9753d6SMatthew G. Knepley } 58183e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 58193e9753d6SMatthew G. Knepley const PetscInt point = points[face], *support; 58203e9753d6SMatthew G. Knepley 58213e9753d6SMatthew G. Knepley /* Transform to global basis before insertion in Jacobian */ 58229566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(plex, point, &support)); 582321a4fad8SMatthew G. Knepley if (hasJac && transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMat[face * totDim * totDim])); 582421a4fad8SMatthew G. Knepley if (hasPrec && transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMatP[face * totDim * totDim])); 5825be62b2b4SMatthew G. Knepley if (hasPrec) { 5826be62b2b4SMatthew G. Knepley if (hasJac) { 58279566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face * totDim * totDim])); 582821a4fad8SMatthew G. Knepley PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, Jac, support[0], &elemMat[face * totDim * totDim], ADD_VALUES)); 58293e9753d6SMatthew G. Knepley } 5830be62b2b4SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMatP[face * totDim * totDim])); 5831be62b2b4SMatthew G. Knepley PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, JacP, support[0], &elemMatP[face * totDim * totDim], ADD_VALUES)); 5832be62b2b4SMatthew G. Knepley } else { 5833be62b2b4SMatthew G. Knepley if (hasJac) { 5834be62b2b4SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face * totDim * totDim])); 583521a4fad8SMatthew G. Knepley PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, Jac, support[0], &elemMat[face * totDim * totDim], ADD_VALUES)); 5836be62b2b4SMatthew G. Knepley } 5837be62b2b4SMatthew G. Knepley } 5838be62b2b4SMatthew G. Knepley } 58399566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 58409566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 58419566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 58429566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 5843be62b2b4SMatthew G. Knepley PetscCall(PetscFree5(u, u_t, elemMat, elemMatP, a)); 58443e9753d6SMatthew G. Knepley } 58459566063dSJacob Faibussowitsch if (plex) PetscCall(DMDestroy(&plex)); 58469566063dSJacob Faibussowitsch if (plexA) PetscCall(DMDestroy(&plexA)); 58473ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 58483e9753d6SMatthew G. Knepley } 58493e9753d6SMatthew G. Knepley 5850d71ae5a4SJacob 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) 5851d71ae5a4SJacob Faibussowitsch { 58523e9753d6SMatthew G. Knepley DMField coordField; 58533e9753d6SMatthew G. Knepley DMLabel depthLabel; 58543e9753d6SMatthew G. Knepley IS facetIS; 58553e9753d6SMatthew G. Knepley PetscInt dim; 58563e9753d6SMatthew G. Knepley 58573e9753d6SMatthew G. Knepley PetscFunctionBegin; 58589566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 58599566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 58609566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 58619566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 58629566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, field, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS)); 58639566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 58643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 58653e9753d6SMatthew G. Knepley } 58663e9753d6SMatthew G. Knepley 5867a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexComputeBdJacobian_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP, void *user) 5868d71ae5a4SJacob Faibussowitsch { 58693e9753d6SMatthew G. Knepley PetscDS prob; 58703e9753d6SMatthew G. Knepley PetscInt dim, numBd, bd; 58713e9753d6SMatthew G. Knepley DMLabel depthLabel; 58723e9753d6SMatthew G. Knepley DMField coordField = NULL; 58733e9753d6SMatthew G. Knepley IS facetIS; 58743e9753d6SMatthew G. Knepley 58753e9753d6SMatthew G. Knepley PetscFunctionBegin; 58769566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 58779566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 58789566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 58799566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 58809566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 58819566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 58823e9753d6SMatthew G. Knepley for (bd = 0; bd < numBd; ++bd) { 588345480ffeSMatthew G. Knepley PetscWeakForm wf; 58843e9753d6SMatthew G. Knepley DMBoundaryConditionType type; 58853e9753d6SMatthew G. Knepley DMLabel label; 58863e9753d6SMatthew G. Knepley const PetscInt *values; 58873e9753d6SMatthew G. Knepley PetscInt fieldI, numValues; 58883e9753d6SMatthew G. Knepley PetscObject obj; 58893e9753d6SMatthew G. Knepley PetscClassId id; 58903e9753d6SMatthew G. Knepley 58919566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &fieldI, NULL, NULL, NULL, NULL, NULL)); 58923d3e5d66SMatthew G. Knepley if (type & DM_BC_ESSENTIAL) continue; 58939566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, &obj)); 58949566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 58953d3e5d66SMatthew G. Knepley if (id != PETSCFE_CLASSID) continue; 58969566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, fieldI, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS)); 58973e9753d6SMatthew G. Knepley } 58989566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 58993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 59003e9753d6SMatthew G. Knepley } 59013e9753d6SMatthew G. Knepley 5902d71ae5a4SJacob 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) 5903d71ae5a4SJacob Faibussowitsch { 59043e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 59053e9753d6SMatthew G. Knepley const char *name = "Jacobian"; 59069a2a23afSMatthew G. Knepley DM dmAux = NULL, plex, tdm; 59073e9753d6SMatthew G. Knepley DMEnclosureType encAux; 59083e9753d6SMatthew G. Knepley Vec A, tv; 59093e9753d6SMatthew G. Knepley DMField coordField; 59103e9753d6SMatthew G. Knepley PetscDS prob, probAux = NULL; 5911e432b41dSStefano Zampini PetscSection section, globalSection, sectionAux; 59123e9753d6SMatthew G. Knepley PetscScalar *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL; 59133e9753d6SMatthew G. Knepley const PetscInt *cells; 59143e9753d6SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ; 591528351e22SJed Brown PetscInt totDim, totDimAux = 0, cStart, cEnd, numCells, c; 5916e04ae0b4SMatthew G. Knepley PetscBool hasJac = PETSC_FALSE, hasPrec = PETSC_FALSE, hasDyn, hasFV = PETSC_FALSE, transform; 59173e9753d6SMatthew G. Knepley 59183e9753d6SMatthew G. Knepley PetscFunctionBegin; 5919af18b51aSmarkadams4 PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 5920ae3cf2c1SStefano Zampini PetscCall(DMGetLocalSection(dm, §ion)); 5921ae3cf2c1SStefano Zampini PetscCall(DMGetGlobalSection(dm, &globalSection)); 5922ae3cf2c1SStefano Zampini PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A)); 5923ae3cf2c1SStefano Zampini if (A) { 5924ae3cf2c1SStefano Zampini PetscCall(VecGetDM(A, &dmAux)); 5925ae3cf2c1SStefano Zampini PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 5926ae3cf2c1SStefano Zampini PetscCall(DMConvert(dmAux, DMPLEX, &plex)); 5927ae3cf2c1SStefano Zampini PetscCall(DMGetLocalSection(plex, §ionAux)); 5928ae3cf2c1SStefano Zampini PetscCall(DMGetDS(dmAux, &probAux)); 5929ae3cf2c1SStefano Zampini PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 5930ae3cf2c1SStefano Zampini } 5931ae3cf2c1SStefano Zampini PetscCall(DMGetCoordinateField(dm, &coordField)); 5932e04ae0b4SMatthew G. Knepley if (!cellIS) goto end; 59339566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5934437e83fbSMatthew G. Knepley PetscCall(ISGetLocalSize(cellIS, &numCells)); 5935437e83fbSMatthew G. Knepley if (cStart >= cEnd) goto end; 59369566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 59379566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 59389566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 593907218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL)); 59409566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 59419566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 59429566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobian(prob, &hasJac)); 59439566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec)); 59443e9753d6SMatthew G. Knepley /* user passed in the same matrix, avoid double contributions and 59453e9753d6SMatthew G. Knepley only assemble the Jacobian */ 59463e9753d6SMatthew G. Knepley if (hasJac && Jac == JacP) hasPrec = PETSC_FALSE; 59479566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 59483e9753d6SMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 594932603206SJames Wright PetscCall(PetscMalloc5(numCells * totDim, &u, (X_t ? (size_t)numCells * totDim : 0), &u_t, (hasJac ? (size_t)numCells * totDim * totDim : 0), &elemMat, (hasPrec ? (size_t)numCells * totDim * totDim : 0), &elemMatP, (hasDyn ? (size_t)numCells * totDim * totDim : 0), &elemMatD)); 59509566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 59513e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 59523e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 59533e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 59543e9753d6SMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 59553e9753d6SMatthew G. Knepley PetscInt i; 59563e9753d6SMatthew G. Knepley 59579566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x)); 59583e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i]; 59599566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x)); 59603e9753d6SMatthew G. Knepley if (X_t) { 59619566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t)); 59623e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i]; 59639566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t)); 59643e9753d6SMatthew G. Knepley } 59653e9753d6SMatthew G. Knepley if (dmAux) { 59663e9753d6SMatthew G. Knepley PetscInt subcell; 59679566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell)); 59689566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x)); 59693e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i]; 59709566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x)); 59713e9753d6SMatthew G. Knepley } 59723e9753d6SMatthew G. Knepley } 59739566063dSJacob Faibussowitsch if (hasJac) PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim)); 59749566063dSJacob Faibussowitsch if (hasPrec) PetscCall(PetscArrayzero(elemMatP, numCells * totDim * totDim)); 59759566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim)); 59763e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 59773e9753d6SMatthew G. Knepley PetscClassId id; 59783e9753d6SMatthew G. Knepley PetscFE fe; 59793e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 59803e9753d6SMatthew G. Knepley PetscInt Nb; 59813e9753d6SMatthew G. Knepley /* Conforming batches */ 59823e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 59833e9753d6SMatthew G. Knepley /* Remainder */ 59843e9753d6SMatthew G. Knepley PetscInt Nr, offset, Nq; 59853e9753d6SMatthew G. Knepley PetscInt maxDegree; 59863e9753d6SMatthew G. Knepley PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 59873e9753d6SMatthew G. Knepley 59889566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 59899566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 59909371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 59919371c9d4SSatish Balay hasFV = PETSC_TRUE; 59929371c9d4SSatish Balay continue; 59939371c9d4SSatish Balay } 59949566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 59959566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 59969566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 599748a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 59983e9753d6SMatthew G. Knepley if (!qGeom) { 59999566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 60009566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 60013e9753d6SMatthew G. Knepley } 60029566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 60039566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 60043e9753d6SMatthew G. Knepley blockSize = Nb; 60053e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 60069566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 60073e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 60083e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 60093e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 60103e9753d6SMatthew G. Knepley offset = numCells - Nr; 60119566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 60129566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom)); 60133e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 60146528b96dSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 60153e9753d6SMatthew G. Knepley if (hasJac) { 60169566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 60178e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMat[offset * totDim * totDim])); 60183e9753d6SMatthew G. Knepley } 60193e9753d6SMatthew G. Knepley if (hasPrec) { 60209566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP)); 60218e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Nr, remGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMatP[offset * totDim * totDim])); 60223e9753d6SMatthew G. Knepley } 60233e9753d6SMatthew G. Knepley if (hasDyn) { 60249566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD)); 60258e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMatD[offset * totDim * totDim])); 60263e9753d6SMatthew G. Knepley } 60273e9753d6SMatthew G. Knepley } 60289566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom)); 60299566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom)); 60309566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 60319566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 60323e9753d6SMatthew G. Knepley } 60333e9753d6SMatthew G. Knepley /* Add contribution from X_t */ 60349371c9d4SSatish Balay if (hasDyn) { 60359371c9d4SSatish Balay for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 60369371c9d4SSatish Balay } 60373e9753d6SMatthew G. Knepley if (hasFV) { 60383e9753d6SMatthew G. Knepley PetscClassId id; 60393e9753d6SMatthew G. Knepley PetscFV fv; 60403e9753d6SMatthew G. Knepley PetscInt offsetI, NcI, NbI = 1, fc, f; 60413e9753d6SMatthew G. Knepley 60423e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 60439566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv)); 60449566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, fieldI, &offsetI)); 60459566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId((PetscObject)fv, &id)); 60463e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 60472f86f8c5SMatthew G. Knepley /* Put in the weighted identity */ 60489566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &NcI)); 60493e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 60503e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 60513e9753d6SMatthew G. Knepley const PetscInt eOffset = cind * totDim * totDim; 60522f86f8c5SMatthew G. Knepley PetscReal vol; 60532f86f8c5SMatthew G. Knepley 60542f86f8c5SMatthew G. Knepley PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 60553e9753d6SMatthew G. Knepley for (fc = 0; fc < NcI; ++fc) { 60563e9753d6SMatthew G. Knepley for (f = 0; f < NbI; ++f) { 60573e9753d6SMatthew G. Knepley const PetscInt i = offsetI + f * NcI + fc; 60583e9753d6SMatthew G. Knepley if (hasPrec) { 60592f86f8c5SMatthew G. Knepley if (hasJac) elemMat[eOffset + i * totDim + i] = vol; 60602f86f8c5SMatthew G. Knepley elemMatP[eOffset + i * totDim + i] = vol; 60619371c9d4SSatish Balay } else { 60622f86f8c5SMatthew G. Knepley elemMat[eOffset + i * totDim + i] = vol; 60639371c9d4SSatish Balay } 60643e9753d6SMatthew G. Knepley } 60653e9753d6SMatthew G. Knepley } 60663e9753d6SMatthew G. Knepley } 60673e9753d6SMatthew G. Knepley } 60683e9753d6SMatthew G. Knepley /* No allocated space for FV stuff, so ignore the zero entries */ 60699566063dSJacob Faibussowitsch PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); 60703e9753d6SMatthew G. Knepley } 60713e9753d6SMatthew G. Knepley /* Insert values into matrix */ 60723e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 60733e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 60743e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 60753e9753d6SMatthew G. Knepley 60763e9753d6SMatthew G. Knepley /* Transform to global basis before insertion in Jacobian */ 60779566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind * totDim * totDim])); 60783e9753d6SMatthew G. Knepley if (hasPrec) { 60793e9753d6SMatthew G. Knepley if (hasJac) { 60809566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 6081e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMat[cind * totDim * totDim], ADD_VALUES)); 60823e9753d6SMatthew G. Knepley } 60839566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind * totDim * totDim])); 6084be62b2b4SMatthew G. Knepley PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, JacP, cell, &elemMatP[cind * totDim * totDim], ADD_VALUES)); 60853e9753d6SMatthew G. Knepley } else { 60863e9753d6SMatthew G. Knepley if (hasJac) { 60879566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 6088e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, JacP, cell, &elemMat[cind * totDim * totDim], ADD_VALUES)); 60893e9753d6SMatthew G. Knepley } 60903e9753d6SMatthew G. Knepley } 60913e9753d6SMatthew G. Knepley } 60929566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 60939566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE)); 60949566063dSJacob Faibussowitsch PetscCall(PetscFree5(u, u_t, elemMat, elemMatP, elemMatD)); 60953e9753d6SMatthew G. Knepley if (dmAux) { 60969566063dSJacob Faibussowitsch PetscCall(PetscFree(a)); 60979566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 60983e9753d6SMatthew G. Knepley } 60993e9753d6SMatthew G. Knepley /* Compute boundary integrals */ 61009566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, user)); 61013e9753d6SMatthew G. Knepley /* Assemble matrix */ 61029371c9d4SSatish Balay end: { 6103e04ae0b4SMatthew G. Knepley PetscBool assOp = hasJac && hasPrec ? PETSC_TRUE : PETSC_FALSE, gassOp; 6104e04ae0b4SMatthew G. Knepley 6105462c564dSBarry Smith PetscCallMPI(MPIU_Allreduce(&assOp, &gassOp, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 61063e9753d6SMatthew G. Knepley if (hasJac && hasPrec) { 61079566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY)); 61089566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY)); 61093e9753d6SMatthew G. Knepley } 6110e04ae0b4SMatthew G. Knepley } 61119566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY)); 61129566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 61139566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 61143ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 61153e9753d6SMatthew G. Knepley } 61163e9753d6SMatthew G. Knepley 6117d71ae5a4SJacob 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) 6118d71ae5a4SJacob Faibussowitsch { 61193e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 61203e9753d6SMatthew G. Knepley const char *name = "Hybrid Jacobian"; 6121148442b3SMatthew G. Knepley DM dmAux[3] = {NULL, NULL, NULL}; 6122148442b3SMatthew G. Knepley DMLabel ghostLabel = NULL; 61233e9753d6SMatthew G. Knepley DM plex = NULL; 61243e9753d6SMatthew G. Knepley DM plexA = NULL; 6125148442b3SMatthew G. Knepley PetscDS ds = NULL; 612607218a29SMatthew G. Knepley PetscDS dsIn = NULL; 6127148442b3SMatthew G. Knepley PetscDS dsAux[3] = {NULL, NULL, NULL}; 6128148442b3SMatthew G. Knepley Vec locA[3] = {NULL, NULL, NULL}; 612907218a29SMatthew G. Knepley DM dmScale[3] = {NULL, NULL, NULL}; 613007218a29SMatthew G. Knepley PetscDS dsScale[3] = {NULL, NULL, NULL}; 613107218a29SMatthew G. Knepley Vec locS[3] = {NULL, NULL, NULL}; 61323e9753d6SMatthew G. Knepley PetscSection section = NULL; 6133148442b3SMatthew G. Knepley PetscSection sectionAux[3] = {NULL, NULL, NULL}; 61343e9753d6SMatthew G. Knepley DMField coordField = NULL; 613507218a29SMatthew G. Knepley PetscScalar *a[3] = {NULL, NULL, NULL}; 613607218a29SMatthew G. Knepley PetscScalar *s[3] = {NULL, NULL, NULL}; 613707218a29SMatthew G. Knepley PetscScalar *u = NULL, *u_t; 613807218a29SMatthew G. Knepley PetscScalar *elemMatNeg, *elemMatPos, *elemMatCoh; 613907218a29SMatthew G. Knepley PetscScalar *elemMatNegP, *elemMatPosP, *elemMatCohP; 6140e432b41dSStefano Zampini PetscSection globalSection; 61413e9753d6SMatthew G. Knepley IS chunkIS; 61423e9753d6SMatthew G. Knepley const PetscInt *cells; 61433e9753d6SMatthew G. Knepley PetscInt *faces; 61443e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 61453e2b0218SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ, totDim, totDimIn, totDimAux[3], totDimScale[3], numChunks, cellChunkSize, chunk; 61461690c2aeSBarry Smith PetscInt maxDegree = PETSC_INT_MAX; 61473e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 61483e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 6149e432b41dSStefano Zampini PetscBool hasBdJac, hasBdPrec; 61503e9753d6SMatthew G. Knepley 61513e9753d6SMatthew G. Knepley PetscFunctionBegin; 61523cc88e6aSStefano Zampini PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 61533cc88e6aSStefano Zampini if (!cellIS) goto end; 6154437e83fbSMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 6155437e83fbSMatthew G. Knepley PetscCall(ISGetLocalSize(cellIS, &numCells)); 61563cc88e6aSStefano Zampini if (cStart >= cEnd) goto end; 61575fedec97SMatthew G. Knepley if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) { 61585fedec97SMatthew G. Knepley const char *name; 61599566063dSJacob Faibussowitsch PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name)); 616063a3b9bcSJacob 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); 61615fedec97SMatthew G. Knepley } 61629566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 6163b98a7184SJames Wright PetscCall(DMGetLocalSection(dm, §ion)); 61649566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 61659566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 616607218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn)); 61679566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 61689566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 616907218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsIn, &totDimIn)); 61709566063dSJacob Faibussowitsch PetscCall(PetscDSHasBdJacobian(ds, &hasBdJac)); 61719566063dSJacob Faibussowitsch PetscCall(PetscDSHasBdJacobianPreconditioner(ds, &hasBdPrec)); 61729566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2])); 6173148442b3SMatthew G. Knepley if (locA[2]) { 61741059d808SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 61751059d808SMatthew G. Knepley 61769566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA[2], &dmAux[2])); 61779566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux[2], DMPLEX, &plexA)); 6178b98a7184SJames Wright PetscCall(DMGetLocalSection(dmAux[2], §ionAux[2])); 617907218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2], NULL)); 61809566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2])); 6181148442b3SMatthew G. Knepley { 6182148442b3SMatthew G. Knepley const PetscInt *cone; 6183148442b3SMatthew G. Knepley PetscInt c; 6184148442b3SMatthew G. Knepley 61851059d808SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 6186148442b3SMatthew G. Knepley for (c = 0; c < 2; ++c) { 6187148442b3SMatthew G. Knepley const PetscInt *support; 6188148442b3SMatthew G. Knepley PetscInt ssize, s; 6189148442b3SMatthew G. Knepley 61909566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 61919566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 61921059d808SMatthew 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); 61931059d808SMatthew G. Knepley if (support[0] == cellStart) s = 1; 61941059d808SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 61951059d808SMatthew 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); 61969566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c])); 61979566063dSJacob Faibussowitsch if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c])); 6198ad540459SPierre Jolivet else dmAux[c] = dmAux[2]; 619907218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c], NULL)); 62009566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c])); 6201148442b3SMatthew G. Knepley } 6202148442b3SMatthew G. Knepley } 62033e9753d6SMatthew G. Knepley } 620407218a29SMatthew G. Knepley /* Handle mass matrix scaling 620507218a29SMatthew G. Knepley The field in key[2] is the field to be scaled, and the scaling field is the first in the dsScale */ 620607218a29SMatthew G. Knepley PetscCall(DMGetAuxiliaryVec(dm, key[2].label, -key[2].value, key[2].part, &locS[2])); 620707218a29SMatthew G. Knepley if (locS[2]) { 62083e2b0218SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 620907218a29SMatthew G. Knepley PetscInt Nb, Nbs; 621007218a29SMatthew G. Knepley 621107218a29SMatthew G. Knepley PetscCall(VecGetDM(locS[2], &dmScale[2])); 621207218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[2], cells ? cells[cStart] : cStart, &dsScale[2], NULL)); 62133e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[2], &totDimScale[2])); 621407218a29SMatthew G. Knepley // BRAD: This is not set correctly 621507218a29SMatthew G. Knepley key[2].field = 2; 621607218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, key[2].field, &Nb)); 621707218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsScale[2], 0, &Nbs)); 621807218a29SMatthew 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); 62193e2b0218SMatthew G. Knepley { 62203e2b0218SMatthew G. Knepley const PetscInt *cone; 62213e2b0218SMatthew G. Knepley PetscInt c; 62223e2b0218SMatthew G. Knepley 62233e2b0218SMatthew G. Knepley locS[1] = locS[0] = locS[2]; 62243e2b0218SMatthew G. Knepley dmScale[1] = dmScale[0] = dmScale[2]; 62253e2b0218SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 62263e2b0218SMatthew G. Knepley for (c = 0; c < 2; ++c) { 62273e2b0218SMatthew G. Knepley const PetscInt *support; 62283e2b0218SMatthew G. Knepley PetscInt ssize, s; 62293e2b0218SMatthew G. Knepley 62303e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 62313e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 62323e2b0218SMatthew 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); 62333e2b0218SMatthew G. Knepley if (support[0] == cellStart) s = 1; 62343e2b0218SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 62353e2b0218SMatthew 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); 62363e2b0218SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[c], support[s], &dsScale[c], NULL)); 62373e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[c], &totDimScale[c])); 62383e2b0218SMatthew G. Knepley } 62393e2b0218SMatthew G. Knepley } 624007218a29SMatthew G. Knepley } 624107218a29SMatthew G. Knepley /* 2: Setup geometric data */ 62429566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 62439566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 62443e9753d6SMatthew G. Knepley if (maxDegree > 1) { 62453e9753d6SMatthew G. Knepley PetscInt f; 62469566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 62473e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 62483e9753d6SMatthew G. Knepley PetscFE fe; 62493e9753d6SMatthew G. Knepley 62509566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 62513e9753d6SMatthew G. Knepley if (fe) { 62529566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 62539566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 62543e9753d6SMatthew G. Knepley } 62553e9753d6SMatthew G. Knepley } 62563e9753d6SMatthew G. Knepley } 625707218a29SMatthew G. Knepley /* Loop over chunks */ 62583e9753d6SMatthew G. Knepley cellChunkSize = numCells; 62593e9753d6SMatthew G. Knepley numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize); 626007218a29SMatthew G. Knepley PetscCall(PetscCalloc1(2 * cellChunkSize, &faces)); 6261a4158a15SMatthew G. Knepley PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 1 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS)); 626207218a29SMatthew G. Knepley /* Extract field coefficients */ 626307218a29SMatthew G. Knepley /* NOTE This needs the end cap faces to have identical orientations */ 626407218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 626507218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 62668bf0a22dSMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s)); 626707218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNeg)); 626807218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPos)); 626907218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCoh)); 627007218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNegP)); 627107218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPosP)); 627207218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCohP)); 62733e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 62743e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 62753e9753d6SMatthew G. Knepley 627607218a29SMatthew G. Knepley if (hasBdJac) { 627707218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatNeg, cellChunkSize * totDim * totDim)); 627807218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatPos, cellChunkSize * totDim * totDim)); 627907218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatCoh, cellChunkSize * totDim * totDim)); 628007218a29SMatthew G. Knepley } 628107218a29SMatthew G. Knepley if (hasBdPrec) { 628207218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatNegP, cellChunkSize * totDim * totDim)); 628307218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatPosP, cellChunkSize * totDim * totDim)); 628407218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatCohP, cellChunkSize * totDim * totDim)); 628507218a29SMatthew G. Knepley } 62863e9753d6SMatthew G. Knepley /* Get faces */ 62873e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 62883e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 62893e9753d6SMatthew G. Knepley const PetscInt *cone; 62909566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(plex, cell, &cone)); 629107218a29SMatthew G. Knepley faces[(c - cS) * 2 + 0] = cone[0]; 629207218a29SMatthew G. Knepley faces[(c - cS) * 2 + 1] = cone[1]; 62933e9753d6SMatthew G. Knepley } 629407218a29SMatthew G. Knepley PetscCall(ISGeneralSetIndices(chunkIS, 2 * cellChunkSize, faces, PETSC_USE_POINTER)); 62953e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 62969566063dSJacob Faibussowitsch if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad)); 62979566063dSJacob Faibussowitsch if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom)); 62983e9753d6SMatthew G. Knepley } else { 62993e9753d6SMatthew G. Knepley PetscInt f; 63003e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 63019566063dSJacob Faibussowitsch if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f])); 63023e9753d6SMatthew G. Knepley } 63033e9753d6SMatthew G. Knepley } 63043e9753d6SMatthew G. Knepley 63053e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 63063e9753d6SMatthew G. Knepley PetscFE feI; 63073e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[fieldI]; 63083e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 63093e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[fieldI]; 63103e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 63115fedec97SMatthew G. Knepley PetscBool isCohesiveField; 63123e9753d6SMatthew G. Knepley 63139566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&feI)); 63143e9753d6SMatthew G. Knepley if (!feI) continue; 63159566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(feI, NULL, &numBlocks, NULL, &numBatches)); 63169566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 63179566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feI, &Nb)); 63183e9753d6SMatthew G. Knepley blockSize = Nb; 63193e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 63209566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(feI, blockSize, numBlocks, batchSize, numBatches)); 63213e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 63223e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 63233e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 63243e9753d6SMatthew G. Knepley offset = numCells - Nr; 632507218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, 0, offset * 2, &chunkGeom)); 632607218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, offset * 2, numCells * 2, &remGeom)); 63279566063dSJacob Faibussowitsch PetscCall(PetscDSGetCohesive(ds, fieldI, &isCohesiveField)); 63283e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 63293e9753d6SMatthew G. Knepley PetscFE feJ; 63303e9753d6SMatthew G. Knepley 63319566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *)&feJ)); 63323e9753d6SMatthew G. Knepley if (!feJ) continue; 6333148442b3SMatthew G. Knepley key[0].field = fieldI * Nf + fieldJ; 6334148442b3SMatthew G. Knepley key[1].field = fieldI * Nf + fieldJ; 63355fedec97SMatthew G. Knepley key[2].field = fieldI * Nf + fieldJ; 6336148442b3SMatthew G. Knepley if (hasBdJac) { 633707218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMatNeg)); 63388e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[0], 0, Nr, remGeom, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[0], PetscSafePointerPlusOffset(a[0], offset * totDimAux[0]), t, X_tShift, &elemMatNeg[offset * totDim * totDim])); 633907218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMatPos)); 63408e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[1], 1, Nr, remGeom, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[1], PetscSafePointerPlusOffset(a[1], offset * totDimAux[1]), t, X_tShift, &elemMatPos[offset * totDim * totDim])); 6341148442b3SMatthew G. Knepley } 6342148442b3SMatthew G. Knepley if (hasBdPrec) { 634307218a29SMatthew 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)); 63448e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[0], 0, Nr, remGeom, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[0], &a[0][offset * totDimAux[0]], t, X_tShift, &elemMatNegP[offset * totDim * totDim])); 634507218a29SMatthew 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)); 63468e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[1], 1, Nr, remGeom, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[1], &a[1][offset * totDimAux[1]], t, X_tShift, &elemMatPosP[offset * totDim * totDim])); 6347148442b3SMatthew G. Knepley } 63485fedec97SMatthew G. Knepley if (hasBdJac) { 634907218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMatCoh)); 63508e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[2], 2, Nr, remGeom, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[2], PetscSafePointerPlusOffset(a[2], offset * totDimAux[2]), t, X_tShift, &elemMatCoh[offset * totDim * totDim])); 6351148442b3SMatthew G. Knepley } 63525fedec97SMatthew G. Knepley if (hasBdPrec) { 635307218a29SMatthew 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)); 63548e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[2], 2, Nr, remGeom, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[2], &a[2][offset * totDimAux[2]], t, X_tShift, &elemMatCohP[offset * totDim * totDim])); 63553e9753d6SMatthew G. Knepley } 63563e9753d6SMatthew G. Knepley } 63579566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom)); 63589566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom)); 63593e9753d6SMatthew G. Knepley } 63603e9753d6SMatthew G. Knepley /* Insert values into matrix */ 63613e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 63623e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 636307218a29SMatthew G. Knepley const PetscInt cind = c - cS, coff = cind * totDim * totDim; 636407218a29SMatthew G. Knepley PetscInt i, j; 63653e9753d6SMatthew G. Knepley 636607218a29SMatthew G. Knepley /* Scale element values */ 636707218a29SMatthew G. Knepley if (locS[0]) { 63683e2b0218SMatthew G. Knepley PetscInt Nb, soff = cind * totDimScale[0], off = 0; 636907218a29SMatthew G. Knepley PetscBool cohesive; 637007218a29SMatthew G. Knepley 637107218a29SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 637207218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, fieldI, &Nb)); 637307218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(ds, fieldI, &cohesive)); 637407218a29SMatthew G. Knepley 637507218a29SMatthew G. Knepley if (fieldI == key[2].field) { 637607218a29SMatthew G. Knepley PetscCheck(cohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Scaling should not happen for face fields"); 63778bf0a22dSMatthew G. Knepley for (i = 0; i < Nb; ++i) { 637807218a29SMatthew 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]; 63798bf0a22dSMatthew G. Knepley if (hasBdPrec) 63808bf0a22dSMatthew 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]; 63818bf0a22dSMatthew G. Knepley } 638207218a29SMatthew G. Knepley off += Nb; 638307218a29SMatthew G. Knepley } else { 638407218a29SMatthew G. Knepley const PetscInt N = cohesive ? Nb : Nb * 2; 638507218a29SMatthew G. Knepley 63868bf0a22dSMatthew G. Knepley for (i = 0; i < N; ++i) { 638707218a29SMatthew 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]; 63888bf0a22dSMatthew G. Knepley if (hasBdPrec) 63898bf0a22dSMatthew 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]; 63908bf0a22dSMatthew G. Knepley } 639107218a29SMatthew G. Knepley off += N; 639207218a29SMatthew G. Knepley } 639307218a29SMatthew G. Knepley } 639407218a29SMatthew G. Knepley } else { 639507218a29SMatthew G. Knepley for (i = 0; i < totDim * totDim; ++i) elemMatCoh[coff + i] += elemMatNeg[coff + i] + elemMatPos[coff + i]; 63968bf0a22dSMatthew G. Knepley if (hasBdPrec) 63978bf0a22dSMatthew G. Knepley for (i = 0; i < totDim * totDim; ++i) elemMatCohP[coff + i] += elemMatNegP[coff + i] + elemMatPosP[coff + i]; 639807218a29SMatthew G. Knepley } 63993e9753d6SMatthew G. Knepley if (hasBdPrec) { 64003e9753d6SMatthew G. Knepley if (hasBdJac) { 640107218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCoh[cind * totDim * totDim])); 6402e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMatCoh[cind * totDim * totDim], ADD_VALUES)); 64033e9753d6SMatthew G. Knepley } 640407218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCohP[cind * totDim * totDim])); 640507218a29SMatthew G. Knepley PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMatCohP[cind * totDim * totDim], ADD_VALUES)); 64063e9753d6SMatthew G. Knepley } else if (hasBdJac) { 640707218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCoh[cind * totDim * totDim])); 6408e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, JacP, cell, &elemMatCoh[cind * totDim * totDim], ADD_VALUES)); 64093e9753d6SMatthew G. Knepley } 64103e9753d6SMatthew G. Knepley } 64113e9753d6SMatthew G. Knepley } 64129566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 641307218a29SMatthew G. Knepley PetscCall(DMPlexRestoreHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 641407218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNeg)); 641507218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPos)); 641607218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCoh)); 641707218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNegP)); 641807218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPosP)); 641907218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCohP)); 64209566063dSJacob Faibussowitsch PetscCall(PetscFree(faces)); 64219566063dSJacob Faibussowitsch PetscCall(ISDestroy(&chunkIS)); 64229566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 64233e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 64249566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 64259566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 64263e9753d6SMatthew G. Knepley } else { 64273e9753d6SMatthew G. Knepley PetscInt f; 64283e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 64299566063dSJacob Faibussowitsch if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 64309566063dSJacob Faibussowitsch if (quads) PetscCall(PetscQuadratureDestroy(&quads[f])); 64313e9753d6SMatthew G. Knepley } 64329566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 64333e9753d6SMatthew G. Knepley } 64349566063dSJacob Faibussowitsch if (dmAux[2]) PetscCall(DMDestroy(&plexA)); 64359566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 64363cc88e6aSStefano Zampini end: 64379566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 64383ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 64393e9753d6SMatthew G. Knepley } 64408e3a2eefSMatthew G. Knepley 64418e3a2eefSMatthew G. Knepley /* 64428e3a2eefSMatthew 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. 64438e3a2eefSMatthew G. Knepley 64448e3a2eefSMatthew G. Knepley Input Parameters: 64458e3a2eefSMatthew G. Knepley + dm - The mesh 6446baca6076SPierre Jolivet . key - The PetscWeakFormKey indicating where integration should happen 644706ad1575SMatthew G. Knepley . cellIS - The cells to integrate over 64488e3a2eefSMatthew G. Knepley . t - The time 6449145b44c9SPierre Jolivet . X_tShift - The multiplier for the Jacobian with respect to X_t 64508e3a2eefSMatthew G. Knepley . X - Local solution vector 64518e3a2eefSMatthew G. Knepley . X_t - Time-derivative of the local solution vector 64528e3a2eefSMatthew G. Knepley . Y - Local input vector 645306ad1575SMatthew G. Knepley - user - the user context 64548e3a2eefSMatthew G. Knepley 64558e3a2eefSMatthew G. Knepley Output Parameter: 64568e3a2eefSMatthew G. Knepley . Z - Local output vector 64578e3a2eefSMatthew G. Knepley 64588e3a2eefSMatthew G. Knepley Note: 64598e3a2eefSMatthew G. Knepley We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator, 64608e3a2eefSMatthew G. Knepley like a GPU, or vectorize on a multicore machine. 64618e3a2eefSMatthew G. Knepley */ 6462d71ae5a4SJacob 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) 6463d71ae5a4SJacob Faibussowitsch { 64648e3a2eefSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 64658e3a2eefSMatthew G. Knepley const char *name = "Jacobian"; 64668e3a2eefSMatthew G. Knepley DM dmAux = NULL, plex, plexAux = NULL; 64678e3a2eefSMatthew G. Knepley DMEnclosureType encAux; 64688e3a2eefSMatthew G. Knepley Vec A; 64698e3a2eefSMatthew G. Knepley DMField coordField; 64708e3a2eefSMatthew G. Knepley PetscDS prob, probAux = NULL; 64718e3a2eefSMatthew G. Knepley PetscQuadrature quad; 64728e3a2eefSMatthew G. Knepley PetscSection section, globalSection, sectionAux; 64738e3a2eefSMatthew G. Knepley PetscScalar *elemMat, *elemMatD, *u, *u_t, *a = NULL, *y, *z; 64748e3a2eefSMatthew G. Knepley const PetscInt *cells; 64758e3a2eefSMatthew G. Knepley PetscInt Nf, fieldI, fieldJ; 64768e3a2eefSMatthew G. Knepley PetscInt totDim, totDimAux = 0, cStart, cEnd, numCells, c; 64778e3a2eefSMatthew G. Knepley PetscBool hasDyn; 64788e3a2eefSMatthew G. Knepley 64798e3a2eefSMatthew G. Knepley PetscFunctionBegin; 64809566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 64819566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 64829566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(cellIS, &numCells)); 64839566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 64849566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 64859566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 648607218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL)); 64879566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 64889566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 64899566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 64908e3a2eefSMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 64919566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A)); 64928e3a2eefSMatthew G. Knepley if (A) { 64939566063dSJacob Faibussowitsch PetscCall(VecGetDM(A, &dmAux)); 64949566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 64959566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexAux)); 64969566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexAux, §ionAux)); 64979566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 64989566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 64998e3a2eefSMatthew G. Knepley } 65009566063dSJacob Faibussowitsch PetscCall(VecSet(Z, 0.0)); 650132603206SJames Wright PetscCall(PetscMalloc6(numCells * totDim, &u, (X_t ? (size_t)numCells * totDim : 0), &u_t, numCells * totDim * totDim, &elemMat, (hasDyn ? (size_t)numCells * totDim * totDim : 0), &elemMatD, numCells * totDim, &y, totDim, &z)); 65029566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 65039566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 65048e3a2eefSMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 65058e3a2eefSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 65068e3a2eefSMatthew G. Knepley const PetscInt cind = c - cStart; 65078e3a2eefSMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 65088e3a2eefSMatthew G. Knepley PetscInt i; 65098e3a2eefSMatthew G. Knepley 65109566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, X, cell, NULL, &x)); 65118e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i]; 65129566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, X, cell, NULL, &x)); 65138e3a2eefSMatthew G. Knepley if (X_t) { 65149566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, X_t, cell, NULL, &x_t)); 65158e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i]; 65169566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, X_t, cell, NULL, &x_t)); 65178e3a2eefSMatthew G. Knepley } 65188e3a2eefSMatthew G. Knepley if (dmAux) { 65198e3a2eefSMatthew G. Knepley PetscInt subcell; 65209566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell)); 65219566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexAux, sectionAux, A, subcell, NULL, &x)); 65228e3a2eefSMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i]; 65239566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexAux, sectionAux, A, subcell, NULL, &x)); 65248e3a2eefSMatthew G. Knepley } 65259566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, Y, cell, NULL, &x)); 65268e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) y[cind * totDim + i] = x[i]; 65279566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, Y, cell, NULL, &x)); 65288e3a2eefSMatthew G. Knepley } 65299566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim)); 65309566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim)); 65318e3a2eefSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 65328e3a2eefSMatthew G. Knepley PetscFE fe; 65338e3a2eefSMatthew G. Knepley PetscInt Nb; 65348e3a2eefSMatthew G. Knepley /* Conforming batches */ 65358e3a2eefSMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 65368e3a2eefSMatthew G. Knepley /* Remainder */ 65378e3a2eefSMatthew G. Knepley PetscInt Nr, offset, Nq; 65388e3a2eefSMatthew G. Knepley PetscQuadrature qGeom = NULL; 65398e3a2eefSMatthew G. Knepley PetscInt maxDegree; 65408e3a2eefSMatthew G. Knepley PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 65418e3a2eefSMatthew G. Knepley 65429566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 65439566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 65449566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 65459566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 65469566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 65479566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 65488e3a2eefSMatthew G. Knepley if (!qGeom) { 65499566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 65509566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 65518e3a2eefSMatthew G. Knepley } 65529566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 65539566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 65548e3a2eefSMatthew G. Knepley blockSize = Nb; 65558e3a2eefSMatthew G. Knepley batchSize = numBlocks * blockSize; 65569566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 65578e3a2eefSMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 65588e3a2eefSMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 65598e3a2eefSMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 65608e3a2eefSMatthew G. Knepley offset = numCells - Nr; 65619566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 65629566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom)); 65638e3a2eefSMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 65648e3a2eefSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 65659566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 65668e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMat[offset * totDim * totDim])); 65678e3a2eefSMatthew G. Knepley if (hasDyn) { 65689566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD)); 65698e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, &a[offset * totDimAux], t, X_tShift, &elemMatD[offset * totDim * totDim])); 65708e3a2eefSMatthew G. Knepley } 65718e3a2eefSMatthew G. Knepley } 65729566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom)); 65739566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom)); 65749566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 65759566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 65768e3a2eefSMatthew G. Knepley } 65778e3a2eefSMatthew G. Knepley if (hasDyn) { 65788e3a2eefSMatthew G. Knepley for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 65798e3a2eefSMatthew G. Knepley } 65808e3a2eefSMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 65818e3a2eefSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 65828e3a2eefSMatthew G. Knepley const PetscInt cind = c - cStart; 65836497c311SBarry Smith const PetscBLASInt one = 1; 65846497c311SBarry Smith PetscBLASInt M; 65858e3a2eefSMatthew G. Knepley const PetscScalar a = 1.0, b = 0.0; 65868e3a2eefSMatthew G. Knepley 65876497c311SBarry Smith PetscCall(PetscBLASIntCast(totDim, &M)); 6588792fecdfSBarry Smith PetscCallBLAS("BLASgemv", BLASgemv_("N", &M, &M, &a, &elemMat[cind * totDim * totDim], &M, &y[cind * totDim], &one, &b, z, &one)); 65898e3a2eefSMatthew G. Knepley if (mesh->printFEM > 1) { 65909566063dSJacob Faibussowitsch PetscCall(DMPrintCellMatrix(c, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 65919566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, "Y", totDim, &y[cind * totDim])); 65929566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, "Z", totDim, z)); 65938e3a2eefSMatthew G. Knepley } 65949566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, Z, cell, z, ADD_VALUES)); 65958e3a2eefSMatthew G. Knepley } 65969566063dSJacob Faibussowitsch PetscCall(PetscFree6(u, u_t, elemMat, elemMatD, y, z)); 65978e3a2eefSMatthew G. Knepley if (mesh->printFEM) { 65989566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)Z), "Z:\n")); 65999566063dSJacob Faibussowitsch PetscCall(VecView(Z, NULL)); 66008e3a2eefSMatthew G. Knepley } 66011059d808SMatthew G. Knepley PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 66029566063dSJacob Faibussowitsch PetscCall(PetscFree(a)); 66039566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plexAux)); 66049566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 66059566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 66063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 66078e3a2eefSMatthew G. Knepley } 6608d52c2f21SMatthew G. Knepley 6609d52c2f21SMatthew G. Knepley static void f0_1(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]) 6610d52c2f21SMatthew G. Knepley { 6611d52c2f21SMatthew G. Knepley f0[0] = u[0]; 6612d52c2f21SMatthew G. Knepley } 6613d52c2f21SMatthew G. Knepley 6614d52c2f21SMatthew G. Knepley static void f0_x(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]) 6615d52c2f21SMatthew G. Knepley { 6616d52c2f21SMatthew G. Knepley f0[0] = x[(int)PetscRealPart(constants[0])] * u[0]; 6617d52c2f21SMatthew G. Knepley } 6618d52c2f21SMatthew G. Knepley 6619d52c2f21SMatthew G. Knepley static void f0_x2(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]) 6620d52c2f21SMatthew G. Knepley { 6621d52c2f21SMatthew G. Knepley PetscInt d; 6622d52c2f21SMatthew G. Knepley 6623d52c2f21SMatthew G. Knepley f0[0] = 0.0; 6624d52c2f21SMatthew G. Knepley for (d = 0; d < dim; ++d) f0[0] += PetscSqr(x[d]) * u[0]; 6625d52c2f21SMatthew G. Knepley } 6626d52c2f21SMatthew G. Knepley 6627d52c2f21SMatthew G. Knepley /*@ 6628d52c2f21SMatthew G. Knepley DMPlexComputeMoments - Compute the first three moments for a field 6629d52c2f21SMatthew G. Knepley 6630d52c2f21SMatthew G. Knepley Noncollective 6631d52c2f21SMatthew G. Knepley 6632d52c2f21SMatthew G. Knepley Input Parameters: 6633d52c2f21SMatthew G. Knepley + dm - the `DMPLEX` 6634d52c2f21SMatthew G. Knepley - u - the field 6635d52c2f21SMatthew G. Knepley 6636d52c2f21SMatthew G. Knepley Output Parameter: 6637d52c2f21SMatthew G. Knepley . moments - the field moments 6638d52c2f21SMatthew G. Knepley 6639d52c2f21SMatthew G. Knepley Level: intermediate 6640d52c2f21SMatthew G. Knepley 6641d52c2f21SMatthew G. Knepley Note: 6642*17314648SMatthew G. Knepley The `moments` array should be of length cdim + 2, where cdim is the number of components for the coordinate field. 6643d52c2f21SMatthew G. Knepley 6644d52c2f21SMatthew G. Knepley .seealso: `DM`, `DMPLEX`, `DMSwarmComputeMoments()` 6645d52c2f21SMatthew G. Knepley @*/ 6646d52c2f21SMatthew G. Knepley PetscErrorCode DMPlexComputeMoments(DM dm, Vec u, PetscReal moments[]) 6647d52c2f21SMatthew G. Knepley { 6648d52c2f21SMatthew G. Knepley PetscDS ds; 6649d52c2f21SMatthew G. Knepley PetscScalar mom, constants[1]; 6650d52c2f21SMatthew G. Knepley const PetscScalar *oldConstants; 6651*17314648SMatthew G. Knepley PetscInt cdim, Nf, field = 0, Ncon; 6652d52c2f21SMatthew G. Knepley MPI_Comm comm; 6653d52c2f21SMatthew G. Knepley void *user; 6654d52c2f21SMatthew G. Knepley 6655d52c2f21SMatthew G. Knepley PetscFunctionBeginUser; 6656d52c2f21SMatthew G. Knepley PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 6657*17314648SMatthew G. Knepley PetscCall(DMGetCoordinateDim(dm, &cdim)); 6658d52c2f21SMatthew G. Knepley PetscCall(DMGetApplicationContext(dm, &user)); 6659d52c2f21SMatthew G. Knepley PetscCall(DMGetDS(dm, &ds)); 6660d52c2f21SMatthew G. Knepley PetscCall(PetscDSGetNumFields(ds, &Nf)); 6661d52c2f21SMatthew G. Knepley PetscCall(PetscDSGetConstants(ds, &Ncon, &oldConstants)); 6662d52c2f21SMatthew G. Knepley PetscCheck(Nf == 1, comm, PETSC_ERR_ARG_WRONG, "We currently only support 1 field, not %" PetscInt_FMT, Nf); 6663d52c2f21SMatthew G. Knepley PetscCall(PetscDSSetObjective(ds, field, &f0_1)); 6664d52c2f21SMatthew G. Knepley PetscCall(DMPlexComputeIntegralFEM(dm, u, &mom, user)); 6665d52c2f21SMatthew G. Knepley moments[0] = PetscRealPart(mom); 6666*17314648SMatthew G. Knepley for (PetscInt c = 0; c < cdim; ++c) { 6667d52c2f21SMatthew G. Knepley constants[0] = c; 6668*17314648SMatthew G. Knepley PetscCall(PetscDSSetConstants(ds, 1, constants)); 6669d52c2f21SMatthew G. Knepley PetscCall(PetscDSSetObjective(ds, field, &f0_x)); 6670d52c2f21SMatthew G. Knepley PetscCall(DMPlexComputeIntegralFEM(dm, u, &mom, user)); 6671d52c2f21SMatthew G. Knepley moments[c + 1] = PetscRealPart(mom); 6672d52c2f21SMatthew G. Knepley } 6673d52c2f21SMatthew G. Knepley PetscCall(PetscDSSetObjective(ds, field, &f0_x2)); 6674d52c2f21SMatthew G. Knepley PetscCall(DMPlexComputeIntegralFEM(dm, u, &mom, user)); 6675*17314648SMatthew G. Knepley moments[cdim + 1] = PetscRealPart(mom); 6676d52c2f21SMatthew G. Knepley PetscCall(PetscDSSetConstants(ds, Ncon, (PetscScalar *)oldConstants)); 6677d52c2f21SMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 6678d52c2f21SMatthew G. Knepley } 6679