117314648SMatthew G. Knepley #include "petscdm.h" 217314648SMatthew 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; 162973d901b8SMatthew G. Knepley 163073d901b8SMatthew G. Knepley PetscFunctionBegin; 16319566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 16329566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &dE)); 16339566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 16349566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 16359566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 16369566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 16379566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 16389566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 16399566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 16409566063dSJacob Faibussowitsch PetscCall(DMLabelGetNumValues(depthLabel, &depth)); 1641083401c6SMatthew G. Knepley 16429566063dSJacob Faibussowitsch PetscCall(VecSet(localX, 0.0)); 16439566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 16449566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 16459566063dSJacob Faibussowitsch PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX)); 16469566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 16479566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(Nf, &localDiff)); 1648083401c6SMatthew G. Knepley for (s = 0; s < Nds; ++s) { 1649083401c6SMatthew G. Knepley PetscDS ds; 1650083401c6SMatthew G. Knepley DMLabel label; 1651083401c6SMatthew G. Knepley IS fieldIS, pointIS; 1652083401c6SMatthew G. Knepley const PetscInt *fields, *points = NULL; 1653083401c6SMatthew G. Knepley PetscQuadrature quad; 1654083401c6SMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 1655083401c6SMatthew G. Knepley PetscFEGeom fegeom; 1656083401c6SMatthew G. Knepley PetscReal *coords, *gcoords; 1657083401c6SMatthew G. Knepley PetscScalar *funcVal, *interpolant; 16585fedec97SMatthew G. Knepley PetscBool isCohesive; 1659083401c6SMatthew G. Knepley PetscInt qNc, Nq, totNc, cStart = 0, cEnd, c, dsNf; 166073d901b8SMatthew G. Knepley 166107218a29SMatthew G. Knepley PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL)); 16629566063dSJacob Faibussowitsch PetscCall(ISGetIndices(fieldIS, &fields)); 16639566063dSJacob Faibussowitsch PetscCall(PetscDSIsCohesive(ds, &isCohesive)); 16649566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &dsNf)); 16659566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalComponents(ds, &totNc)); 16669566063dSJacob Faibussowitsch PetscCall(PetscDSGetQuadrature(ds, &quad)); 16679566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 166863a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != totNc), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, totNc); 16699566063dSJacob Faibussowitsch PetscCall(PetscCalloc6(totNc, &funcVal, totNc, &interpolant, dE * (Nq + 1), &coords, Nq, &fegeom.detJ, dE * dE * Nq, &fegeom.J, dE * dE * Nq, &fegeom.invJ)); 1670083401c6SMatthew G. Knepley if (!label) { 16719566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1672083401c6SMatthew G. Knepley } else { 16739566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, 1, &pointIS)); 16749566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &cEnd)); 16759566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 1676083401c6SMatthew G. Knepley } 167773d901b8SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 1678083401c6SMatthew G. Knepley const PetscInt cell = points ? points[c] : c; 167973d901b8SMatthew G. Knepley PetscScalar *x = NULL; 16805fedec97SMatthew G. Knepley const PetscInt *cone; 16815fedec97SMatthew G. Knepley PetscInt qc = 0, fOff = 0, dep; 168273d901b8SMatthew G. Knepley 16839566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(depthLabel, cell, &dep)); 1684083401c6SMatthew G. Knepley if (dep != depth - 1) continue; 16855fedec97SMatthew G. Knepley if (isCohesive) { 16869566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cell, &cone)); 16879566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cone[0], quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 168896959cd1SMatthew G. Knepley } else { 16899566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 169096959cd1SMatthew G. Knepley } 1691e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, cell, 0, NULL, &x)); 16925fedec97SMatthew G. Knepley for (f = 0; f < dsNf; ++f) { 169315496722SMatthew G. Knepley PetscObject obj; 169415496722SMatthew G. Knepley PetscClassId id; 1695083401c6SMatthew G. Knepley void *const ctx = ctxs ? ctxs[fields[f]] : NULL; 169615496722SMatthew G. Knepley PetscInt Nb, Nc, q, fc; 169715496722SMatthew G. Knepley PetscReal elemDiff = 0.0; 16985fedec97SMatthew G. Knepley PetscBool cohesive; 169915496722SMatthew G. Knepley 17009566063dSJacob Faibussowitsch PetscCall(PetscDSGetCohesive(ds, f, &cohesive)); 17019566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 17029566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 17039371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 17049371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 17059371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 17069371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 17079371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 17089371c9d4SSatish Balay Nb = 1; 17099371c9d4SSatish Balay } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]); 1710c82db6dbSMatthew G. Knepley if (isCohesive && !cohesive) { 1711c82db6dbSMatthew G. Knepley fOff += Nb * 2; 1712c82db6dbSMatthew G. Knepley qc += Nc; 1713c82db6dbSMatthew G. Knepley continue; 1714c82db6dbSMatthew G. Knepley } 171573d901b8SMatthew G. Knepley if (debug) { 171673d901b8SMatthew G. Knepley char title[1024]; 171763a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, fields[f])); 17189566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(cell, title, Nb, &x[fOff])); 171973d901b8SMatthew G. Knepley } 17207318780aSToby Isaac for (q = 0; q < Nq; ++q) { 17212a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 1722d0609cedSBarry Smith PetscErrorCode ierr; 17232a4e142eSMatthew G. Knepley 17242a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 1725083401c6SMatthew G. Knepley qgeom.J = &fegeom.J[q * dE * dE]; 1726083401c6SMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * dE * dE]; 17272a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 172863a3b9bcSJacob 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); 1729d3a7d86cSMatthew G. Knepley if (transform) { 1730083401c6SMatthew G. Knepley gcoords = &coords[dE * Nq]; 17319566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[dE * q], PETSC_TRUE, dE, &coords[dE * q], gcoords, dm->transformCtx)); 1732d3a7d86cSMatthew G. Knepley } else { 1733083401c6SMatthew G. Knepley gcoords = &coords[dE * q]; 1734d3a7d86cSMatthew G. Knepley } 17352df84da0SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) funcVal[fc] = 0.; 1736083401c6SMatthew G. Knepley ierr = (*funcs[fields[f]])(dE, time, gcoords, Nc, funcVal, ctx); 1737e735a8a9SMatthew G. Knepley if (ierr) { 17389566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x)); 17399566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 17409566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1741e735a8a9SMatthew G. Knepley } 17429566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[dE * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 174396959cd1SMatthew G. Knepley /* Call once for each face, except for lagrange field */ 17449566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fOff], &qgeom, q, interpolant)); 17459566063dSJacob Faibussowitsch else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fOff], q, interpolant)); 174663a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]); 174715496722SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1748beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 17499371c9d4SSatish Balay if (debug) 1750835f2295SStefano 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), 17519371c9d4SSatish Balay (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]))); 17524bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 175373d901b8SMatthew G. Knepley } 175473d901b8SMatthew G. Knepley } 1755083401c6SMatthew G. Knepley fOff += Nb; 17569c3cf19fSMatthew G. Knepley qc += Nc; 1757083401c6SMatthew G. Knepley localDiff[fields[f]] += elemDiff; 175863a3b9bcSJacob 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]])); 175973d901b8SMatthew G. Knepley } 17609566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x)); 1761083401c6SMatthew G. Knepley } 1762083401c6SMatthew G. Knepley if (label) { 17639566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 17649566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 1765083401c6SMatthew G. Knepley } 17669566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(fieldIS, &fields)); 17679566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 176873d901b8SMatthew G. Knepley } 17699566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 1770*e91c04dfSPierre Jolivet PetscCallMPI(MPIU_Allreduce(localDiff, diff, Nf, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 17719566063dSJacob Faibussowitsch PetscCall(PetscFree(localDiff)); 1772083401c6SMatthew G. Knepley for (f = 0; f < Nf; ++f) diff[f] = PetscSqrtReal(diff[f]); 17733ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 177473d901b8SMatthew G. Knepley } 177573d901b8SMatthew G. Knepley 1776e729f68cSMatthew G. Knepley /*@C 1777e729f68cSMatthew 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. 1778e729f68cSMatthew G. Knepley 177920f4b53cSBarry Smith Collective 1780c0f8e1fdSMatthew G. Knepley 1781e729f68cSMatthew G. Knepley Input Parameters: 1782a1cb98faSBarry Smith + dm - The `DM` 17830163fd50SMatthew G. Knepley . time - The time 178420f4b53cSBarry Smith . funcs - The functions to evaluate for each field component: `NULL` means that component does not contribute to error calculation 178520f4b53cSBarry Smith . ctxs - Optional array of contexts to pass to each function, or `NULL`. 1786e729f68cSMatthew G. Knepley - X - The coefficient vector u_h 1787e729f68cSMatthew G. Knepley 1788e729f68cSMatthew G. Knepley Output Parameter: 178920f4b53cSBarry Smith . D - A `Vec` which holds the difference ||u - u_h||_2 for each cell 1790e729f68cSMatthew G. Knepley 1791e729f68cSMatthew G. Knepley Level: developer 1792e729f68cSMatthew G. Knepley 17931cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 1794e729f68cSMatthew G. Knepley @*/ 1795d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeL2DiffVec(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, Vec D) 1796d71ae5a4SJacob Faibussowitsch { 1797e729f68cSMatthew G. Knepley PetscSection section; 1798e729f68cSMatthew G. Knepley PetscQuadrature quad; 1799e729f68cSMatthew G. Knepley Vec localX; 18004bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 1801e729f68cSMatthew G. Knepley PetscScalar *funcVal, *interpolant; 18024bee2e38SMatthew G. Knepley PetscReal *coords; 1803e729f68cSMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 1804485ad865SMatthew G. Knepley PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, c, field, fieldOffset; 1805e729f68cSMatthew G. Knepley 1806e729f68cSMatthew G. Knepley PetscFunctionBegin; 18079566063dSJacob Faibussowitsch PetscCall(VecSet(D, 0.0)); 18089566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 18099566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 18109566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 18119566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &numFields)); 18129566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 18139566063dSJacob Faibussowitsch PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX)); 18149566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 18159566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 1816e729f68cSMatthew G. Knepley for (field = 0; field < numFields; ++field) { 1817e729f68cSMatthew G. Knepley PetscObject obj; 1818e729f68cSMatthew G. Knepley PetscClassId id; 1819e729f68cSMatthew G. Knepley PetscInt Nc; 1820e729f68cSMatthew G. Knepley 18219566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 18229566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 1823e729f68cSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 1824e729f68cSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 1825e729f68cSMatthew G. Knepley 18269566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 18279566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 1828e729f68cSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 1829e729f68cSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 1830e729f68cSMatthew G. Knepley 18319566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 18329566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 183363a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1834e729f68cSMatthew G. Knepley numComponents += Nc; 1835e729f68cSMatthew G. Knepley } 18369566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 183763a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 18389566063dSJacob Faibussowitsch PetscCall(PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * Nq, &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ)); 18399566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1840e729f68cSMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 1841e729f68cSMatthew G. Knepley PetscScalar *x = NULL; 18426f288a59SMatthew G. Knepley PetscScalar elemDiff = 0.0; 18439c3cf19fSMatthew G. Knepley PetscInt qc = 0; 1844e729f68cSMatthew G. Knepley 18459566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1846e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, c, 0, NULL, &x)); 1847e729f68cSMatthew G. Knepley 1848e729f68cSMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 1849e729f68cSMatthew G. Knepley PetscObject obj; 1850e729f68cSMatthew G. Knepley PetscClassId id; 1851e729f68cSMatthew G. Knepley void *const ctx = ctxs ? ctxs[field] : NULL; 1852e729f68cSMatthew G. Knepley PetscInt Nb, Nc, q, fc; 1853e729f68cSMatthew G. Knepley 18549566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 18559566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 18569371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 18579371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 18589371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 18599371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 18609371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 18619371c9d4SSatish Balay Nb = 1; 18629371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 186323f34ed2SToby Isaac if (funcs[field]) { 18647318780aSToby Isaac for (q = 0; q < Nq; ++q) { 18652a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 18662a4e142eSMatthew G. Knepley 18672a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 18682a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 18692a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 18702a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 187163a3b9bcSJacob 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); 18729566063dSJacob Faibussowitsch PetscCall((*funcs[field])(coordDim, time, &coords[q * coordDim], Nc, funcVal, ctx)); 1873c3e24edfSBarry Smith #if defined(needs_fix_with_return_code_argument) 1874e735a8a9SMatthew G. Knepley if (ierr) { 18759566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 18769566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 18779566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 1878e735a8a9SMatthew G. Knepley } 1879c3e24edfSBarry Smith #endif 18809566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant)); 18819566063dSJacob Faibussowitsch else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant)); 188263a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1883e729f68cSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1884beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 18854bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 1886e729f68cSMatthew G. Knepley } 1887e729f68cSMatthew G. Knepley } 188823f34ed2SToby Isaac } 1889beaa55a6SMatthew G. Knepley fieldOffset += Nb; 18909c3cf19fSMatthew G. Knepley qc += Nc; 1891e729f68cSMatthew G. Knepley } 18929566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 18939566063dSJacob Faibussowitsch PetscCall(VecSetValue(D, c - cStart, elemDiff, INSERT_VALUES)); 1894e729f68cSMatthew G. Knepley } 18959566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 18969566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 18979566063dSJacob Faibussowitsch PetscCall(VecSqrtAbs(D)); 18983ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1899e729f68cSMatthew G. Knepley } 1900e729f68cSMatthew G. Knepley 19015f0b18bfSMatthew G. Knepley /*@ 19022353bfffSMatthew G. Knepley DMPlexComputeL2FluxDiffVecLocal - This function computes the integral of the difference between the gradient of field `f`in `u` and field `mf` in `mu` 19032353bfffSMatthew G. Knepley 19042353bfffSMatthew G. Knepley Collective 19052353bfffSMatthew G. Knepley 19062353bfffSMatthew G. Knepley Input Parameters: 19072353bfffSMatthew G. Knepley + lu - The local `Vec` containing the primal solution 19082353bfffSMatthew G. Knepley . f - The field number for the potential 19092353bfffSMatthew G. Knepley . lmu - The local `Vec` containing the mixed solution 19102353bfffSMatthew G. Knepley - mf - The field number for the flux 19112353bfffSMatthew G. Knepley 19122353bfffSMatthew G. Knepley Output Parameter: 19132353bfffSMatthew G. Knepley . eFlux - A global `Vec` which holds $||\nabla u_f - \mu_{mf}||$ 19142353bfffSMatthew G. Knepley 19152353bfffSMatthew G. Knepley Level: advanced 19162353bfffSMatthew G. Knepley 19172353bfffSMatthew G. Knepley Notes: 19182353bfffSMatthew G. Knepley We assume that the `DM` for each solution has the same topology, geometry, and quadrature. 19192353bfffSMatthew G. Knepley 19202353bfffSMatthew G. Knepley This is usually used to get an error estimate for the primal solution, using the flux from a mixed solution. 19212353bfffSMatthew G. Knepley 19222353bfffSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeL2FluxDiffVec()`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 19232353bfffSMatthew G. Knepley @*/ 19242353bfffSMatthew G. Knepley PetscErrorCode DMPlexComputeL2FluxDiffVecLocal(Vec lu, PetscInt f, Vec lmu, PetscInt mf, Vec eFlux) 19252353bfffSMatthew G. Knepley { 19262353bfffSMatthew G. Knepley DM dm, mdm, edm; 19272353bfffSMatthew G. Knepley PetscFE fe, mfe; 19282353bfffSMatthew G. Knepley PetscFEGeom fegeom; 19292353bfffSMatthew G. Knepley PetscQuadrature quad; 19302353bfffSMatthew G. Knepley const PetscReal *quadWeights; 19312353bfffSMatthew G. Knepley PetscReal *coords; 19322353bfffSMatthew G. Knepley PetscScalar *interpolant, *minterpolant, *earray; 19332353bfffSMatthew G. Knepley PetscInt cdim, mcdim, cStart, cEnd, Nc, mNc, qNc, Nq; 19342353bfffSMatthew G. Knepley MPI_Comm comm; 19352353bfffSMatthew G. Knepley 19362353bfffSMatthew G. Knepley PetscFunctionBegin; 19372353bfffSMatthew G. Knepley PetscCall(VecGetDM(lu, &dm)); 19382353bfffSMatthew G. Knepley PetscCall(VecGetDM(lmu, &mdm)); 19392353bfffSMatthew G. Knepley PetscCall(VecGetDM(eFlux, &edm)); 19402353bfffSMatthew G. Knepley PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 19412353bfffSMatthew G. Knepley PetscCall(VecSet(eFlux, 0.0)); 19422353bfffSMatthew G. Knepley 19432353bfffSMatthew G. Knepley // Check if the both problems are on the same mesh 19442353bfffSMatthew G. Knepley PetscCall(DMGetCoordinateDim(dm, &cdim)); 19452353bfffSMatthew G. Knepley PetscCall(DMGetCoordinateDim(mdm, &mcdim)); 19462353bfffSMatthew G. Knepley PetscCheck(cdim == mcdim, comm, PETSC_ERR_ARG_SIZ, "primal coordinate Dim %" PetscInt_FMT " != %" PetscInt_FMT " mixed coordinate Dim", cdim, mcdim); 19472353bfffSMatthew G. Knepley fegeom.dimEmbed = cdim; 19482353bfffSMatthew G. Knepley 19492353bfffSMatthew G. Knepley PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe)); 19502353bfffSMatthew G. Knepley PetscCall(DMGetField(mdm, mf, NULL, (PetscObject *)&mfe)); 19512353bfffSMatthew G. Knepley PetscCall(PetscFEGetNumComponents(fe, &Nc)); 19522353bfffSMatthew G. Knepley PetscCall(PetscFEGetNumComponents(mfe, &mNc)); 19532353bfffSMatthew G. Knepley PetscCall(PetscFEGetQuadrature(fe, &quad)); 19542353bfffSMatthew G. Knepley PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights)); 19552353bfffSMatthew G. Knepley PetscCheck(qNc == 1 || qNc == mNc, comm, PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, mNc); 19562353bfffSMatthew G. Knepley 19572353bfffSMatthew G. Knepley PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 19582353bfffSMatthew G. Knepley PetscCall(VecGetArrayWrite(eFlux, &earray)); 19592353bfffSMatthew 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)); 19602353bfffSMatthew G. Knepley for (PetscInt c = cStart; c < cEnd; ++c) { 19612353bfffSMatthew G. Knepley PetscScalar *x = NULL; 19622353bfffSMatthew G. Knepley PetscScalar *mx = NULL; 19632353bfffSMatthew G. Knepley PetscScalar *eval = NULL; 19642353bfffSMatthew G. Knepley PetscReal fluxElemDiff = 0.0; 19652353bfffSMatthew G. Knepley 19662353bfffSMatthew G. Knepley PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 19672353bfffSMatthew G. Knepley PetscCall(DMPlexVecGetClosure(dm, NULL, lu, c, NULL, &x)); 19682353bfffSMatthew G. Knepley PetscCall(DMPlexVecGetClosure(mdm, NULL, lmu, c, NULL, &mx)); 19692353bfffSMatthew G. Knepley 19702353bfffSMatthew G. Knepley for (PetscInt q = 0; q < Nq; ++q) { 19712353bfffSMatthew G. Knepley PetscFEGeom qgeom; 19722353bfffSMatthew G. Knepley 19732353bfffSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 19742353bfffSMatthew G. Knepley qgeom.J = &fegeom.J[q * cdim * cdim]; 19752353bfffSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * cdim * cdim]; 19762353bfffSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 19772353bfffSMatthew G. Knepley 19782353bfffSMatthew 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); 19792353bfffSMatthew G. Knepley 19802353bfffSMatthew G. Knepley PetscCall(PetscFEInterpolate_Static(mfe, &mx[0], &qgeom, q, minterpolant)); 19812353bfffSMatthew G. Knepley PetscCall(PetscFEInterpolateGradient_Static(fe, 1, &x[0], &qgeom, q, interpolant)); 19822353bfffSMatthew G. Knepley 19832353bfffSMatthew G. Knepley /* Now take the elementwise difference and store that in a vector. */ 19842353bfffSMatthew G. Knepley for (PetscInt fc = 0; fc < mNc; ++fc) { 19852353bfffSMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : fc)]; 19862353bfffSMatthew G. Knepley fluxElemDiff += PetscSqr(PetscRealPart(interpolant[fc] - minterpolant[fc])) * wt * fegeom.detJ[q]; 19872353bfffSMatthew G. Knepley } 19882353bfffSMatthew G. Knepley } 19892353bfffSMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(dm, NULL, lu, c, NULL, &x)); 19902353bfffSMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(mdm, NULL, lmu, c, NULL, &mx)); 19912353bfffSMatthew G. Knepley PetscCall(DMPlexPointGlobalRef(edm, c, earray, (void *)&eval)); 19922353bfffSMatthew G. Knepley if (eval) eval[0] = fluxElemDiff; 19932353bfffSMatthew G. Knepley } 19942353bfffSMatthew G. Knepley PetscCall(PetscFree6(interpolant, minterpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 19952353bfffSMatthew G. Knepley PetscCall(VecRestoreArrayWrite(eFlux, &earray)); 19962353bfffSMatthew G. Knepley 19972353bfffSMatthew G. Knepley PetscCall(VecAssemblyBegin(eFlux)); 19982353bfffSMatthew G. Knepley PetscCall(VecAssemblyEnd(eFlux)); 19992353bfffSMatthew G. Knepley PetscCall(VecSqrtAbs(eFlux)); 20002353bfffSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 20012353bfffSMatthew G. Knepley } 20022353bfffSMatthew G. Knepley 20032353bfffSMatthew G. Knepley /*@ 20042353bfffSMatthew G. Knepley DMPlexComputeL2FluxDiffVec - This function computes the integral of the difference between the gradient of field `f`in `u` and field `mf` in `mu` 20052353bfffSMatthew G. Knepley 20062353bfffSMatthew G. Knepley Collective 20072353bfffSMatthew G. Knepley 20082353bfffSMatthew G. Knepley Input Parameters: 20092353bfffSMatthew G. Knepley + u - The global `Vec` containing the primal solution 20102353bfffSMatthew G. Knepley . f - The field number for the potential 20112353bfffSMatthew G. Knepley . mu - The global `Vec` containing the mixed solution 20122353bfffSMatthew G. Knepley - mf - The field number for the flux 20132353bfffSMatthew G. Knepley 20142353bfffSMatthew G. Knepley Output Parameter: 20152353bfffSMatthew G. Knepley . eFlux - A global `Vec` which holds $||\nabla u_f - \mu_{mf}||$ 20162353bfffSMatthew G. Knepley 20172353bfffSMatthew G. Knepley Level: advanced 20182353bfffSMatthew G. Knepley 20192353bfffSMatthew G. Knepley Notes: 20202353bfffSMatthew G. Knepley We assume that the `DM` for each solution has the same topology, geometry, and quadrature. 20212353bfffSMatthew G. Knepley 20222353bfffSMatthew G. Knepley This is usually used to get an error estimate for the primal solution, using the flux from a mixed solution. 20232353bfffSMatthew G. Knepley 20242353bfffSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeL2FluxDiffVecLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 20252353bfffSMatthew G. Knepley @*/ 20262353bfffSMatthew G. Knepley PetscErrorCode DMPlexComputeL2FluxDiffVec(Vec u, PetscInt f, Vec mu, PetscInt mf, Vec eFlux) 20272353bfffSMatthew G. Knepley { 20282353bfffSMatthew G. Knepley DM dm, mdm; 20292353bfffSMatthew G. Knepley Vec lu, lmu; 20302353bfffSMatthew G. Knepley 20312353bfffSMatthew G. Knepley PetscFunctionBegin; 20322353bfffSMatthew G. Knepley PetscCall(VecGetDM(u, &dm)); 20332353bfffSMatthew G. Knepley PetscCall(DMGetLocalVector(dm, &lu)); 20342353bfffSMatthew G. Knepley PetscCall(DMGlobalToLocal(dm, u, INSERT_VALUES, lu)); 20352353bfffSMatthew G. Knepley PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, lu, 0.0, NULL, NULL, NULL)); 20362353bfffSMatthew G. Knepley 20372353bfffSMatthew G. Knepley PetscCall(VecGetDM(mu, &mdm)); 20382353bfffSMatthew G. Knepley PetscCall(DMGetLocalVector(mdm, &lmu)); 20392353bfffSMatthew G. Knepley PetscCall(DMGlobalToLocal(mdm, mu, INSERT_VALUES, lmu)); 20402353bfffSMatthew G. Knepley PetscCall(DMPlexInsertBoundaryValues(mdm, PETSC_TRUE, lmu, 0.0, NULL, NULL, NULL)); 20412353bfffSMatthew G. Knepley 20422353bfffSMatthew G. Knepley PetscCall(DMPlexComputeL2FluxDiffVecLocal(lu, f, lmu, mf, eFlux)); 20432353bfffSMatthew G. Knepley 20442353bfffSMatthew G. Knepley PetscCall(DMRestoreLocalVector(dm, &lu)); 20452353bfffSMatthew G. Knepley PetscCall(DMRestoreLocalVector(mdm, &lmu)); 20462353bfffSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 20472353bfffSMatthew G. Knepley } 20482353bfffSMatthew G. Knepley 20492353bfffSMatthew G. Knepley /*@ 205020f4b53cSBarry Smith DMPlexComputeClementInterpolant - This function computes the L2 projection of the cellwise values of a function u onto P1 20515f0b18bfSMatthew G. Knepley 205220f4b53cSBarry Smith Collective 20535f0b18bfSMatthew G. Knepley 20545f0b18bfSMatthew G. Knepley Input Parameters: 2055a1cb98faSBarry Smith + dm - The `DM` 20565f0b18bfSMatthew G. Knepley - locX - The coefficient vector u_h 20575f0b18bfSMatthew G. Knepley 20585f0b18bfSMatthew G. Knepley Output Parameter: 2059a1cb98faSBarry Smith . locC - A `Vec` which holds the Clement interpolant of the function 20605f0b18bfSMatthew G. Knepley 20615f0b18bfSMatthew G. Knepley Level: developer 20625f0b18bfSMatthew G. Knepley 2063a1cb98faSBarry Smith Note: 2064a1cb98faSBarry 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 2065a1cb98faSBarry Smith 20661cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 20675f0b18bfSMatthew G. Knepley @*/ 2068d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeClementInterpolant(DM dm, Vec locX, Vec locC) 2069d71ae5a4SJacob Faibussowitsch { 20705f0b18bfSMatthew G. Knepley PetscInt debug = ((DM_Plex *)dm->data)->printFEM; 20715f0b18bfSMatthew G. Knepley DM dmc; 20725f0b18bfSMatthew G. Knepley PetscQuadrature quad; 20735f0b18bfSMatthew G. Knepley PetscScalar *interpolant, *valsum; 20745f0b18bfSMatthew G. Knepley PetscFEGeom fegeom; 20755f0b18bfSMatthew G. Knepley PetscReal *coords; 20765f0b18bfSMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 20775f0b18bfSMatthew G. Knepley PetscInt dim, cdim, Nf, f, Nc = 0, Nq, qNc, cStart, cEnd, vStart, vEnd, v; 20785f0b18bfSMatthew G. Knepley 20795f0b18bfSMatthew G. Knepley PetscFunctionBegin; 20809566063dSJacob Faibussowitsch PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite)); 20819566063dSJacob Faibussowitsch PetscCall(VecGetDM(locC, &dmc)); 20829566063dSJacob Faibussowitsch PetscCall(VecSet(locC, 0.0)); 20839566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 20849566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &cdim)); 20855f0b18bfSMatthew G. Knepley fegeom.dimEmbed = cdim; 20869566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 20875f0b18bfSMatthew G. Knepley PetscCheck(Nf > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!"); 20885f0b18bfSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 20895f0b18bfSMatthew G. Knepley PetscObject obj; 20905f0b18bfSMatthew G. Knepley PetscClassId id; 20915f0b18bfSMatthew G. Knepley PetscInt fNc; 20925f0b18bfSMatthew G. Knepley 20939566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, f, NULL, &obj)); 20949566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 20955f0b18bfSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 20965f0b18bfSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 20975f0b18bfSMatthew G. Knepley 20989566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 20999566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &fNc)); 21005f0b18bfSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 21015f0b18bfSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 21025f0b18bfSMatthew G. Knepley 21039566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 21049566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &fNc)); 210563a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 21065f0b18bfSMatthew G. Knepley Nc += fNc; 21075f0b18bfSMatthew G. Knepley } 21089566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 210963a3b9bcSJacob Faibussowitsch PetscCheck(qNc == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " > 1", qNc); 21109566063dSJacob Faibussowitsch PetscCall(PetscMalloc6(Nc * 2, &valsum, Nc, &interpolant, cdim * Nq, &coords, Nq, &fegeom.detJ, cdim * cdim * Nq, &fegeom.J, cdim * cdim * Nq, &fegeom.invJ)); 21119566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 21129566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 21135f0b18bfSMatthew G. Knepley for (v = vStart; v < vEnd; ++v) { 21145f0b18bfSMatthew G. Knepley PetscScalar volsum = 0.0; 21155f0b18bfSMatthew G. Knepley PetscInt *star = NULL; 21165f0b18bfSMatthew G. Knepley PetscInt starSize, st, fc; 21175f0b18bfSMatthew G. Knepley 21189566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(valsum, Nc)); 21199566063dSJacob Faibussowitsch PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 21205f0b18bfSMatthew G. Knepley for (st = 0; st < starSize * 2; st += 2) { 21215f0b18bfSMatthew G. Knepley const PetscInt cell = star[st]; 21225f0b18bfSMatthew G. Knepley PetscScalar *val = &valsum[Nc]; 21235f0b18bfSMatthew G. Knepley PetscScalar *x = NULL; 21245f0b18bfSMatthew G. Knepley PetscReal vol = 0.0; 21255f0b18bfSMatthew G. Knepley PetscInt foff = 0; 21265f0b18bfSMatthew G. Knepley 21275f0b18bfSMatthew G. Knepley if ((cell < cStart) || (cell >= cEnd)) continue; 21289566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 21299566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x)); 21305f0b18bfSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 21315f0b18bfSMatthew G. Knepley PetscObject obj; 21325f0b18bfSMatthew G. Knepley PetscClassId id; 21335f0b18bfSMatthew G. Knepley PetscInt Nb, fNc, q; 21345f0b18bfSMatthew G. Knepley 21359566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(val, Nc)); 21369566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, f, NULL, &obj)); 21379566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 21389371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 21399371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &fNc)); 21409371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 21419371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 21429371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &fNc)); 21439371c9d4SSatish Balay Nb = 1; 21449371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 21455f0b18bfSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 21465f0b18bfSMatthew G. Knepley const PetscReal wt = quadWeights[q] * fegeom.detJ[q]; 21475f0b18bfSMatthew G. Knepley PetscFEGeom qgeom; 21485f0b18bfSMatthew G. Knepley 21495f0b18bfSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 21505f0b18bfSMatthew G. Knepley qgeom.J = &fegeom.J[q * cdim * cdim]; 21515f0b18bfSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * cdim * cdim]; 21525f0b18bfSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 215363a3b9bcSJacob 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); 21549566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[foff], &qgeom, q, interpolant)); 215563a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 21565f0b18bfSMatthew G. Knepley for (fc = 0; fc < fNc; ++fc) val[foff + fc] += interpolant[fc] * wt; 21575f0b18bfSMatthew G. Knepley vol += wt; 21585f0b18bfSMatthew G. Knepley } 21595f0b18bfSMatthew G. Knepley foff += Nb; 21605f0b18bfSMatthew G. Knepley } 21619566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x)); 21625f0b18bfSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) valsum[fc] += val[fc]; 21635f0b18bfSMatthew G. Knepley volsum += vol; 21645f0b18bfSMatthew G. Knepley if (debug) { 21659566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " value: [", v, cell)); 21665f0b18bfSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 21679566063dSJacob Faibussowitsch if (fc) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 21689566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(val[fc]))); 21695f0b18bfSMatthew G. Knepley } 21709566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n")); 21715f0b18bfSMatthew G. Knepley } 21725f0b18bfSMatthew G. Knepley } 21735f0b18bfSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) valsum[fc] /= volsum; 21749566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 21759566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dmc, NULL, locC, v, valsum, INSERT_VALUES)); 21765f0b18bfSMatthew G. Knepley } 21779566063dSJacob Faibussowitsch PetscCall(PetscFree6(valsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 21783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 21795f0b18bfSMatthew G. Knepley } 21805f0b18bfSMatthew G. Knepley 21815f0b18bfSMatthew G. Knepley /*@ 218220f4b53cSBarry Smith DMPlexComputeGradientClementInterpolant - This function computes the L2 projection of the cellwise gradient of a function u onto P1 21831555c271SMatthew G. Knepley 218420f4b53cSBarry Smith Collective 2185c0f8e1fdSMatthew G. Knepley 21861555c271SMatthew G. Knepley Input Parameters: 2187a1cb98faSBarry Smith + dm - The `DM` 21885f0b18bfSMatthew G. Knepley - locX - The coefficient vector u_h 21891555c271SMatthew G. Knepley 21901555c271SMatthew G. Knepley Output Parameter: 2191a1cb98faSBarry Smith . locC - A `Vec` which holds the Clement interpolant of the gradient 21921555c271SMatthew G. Knepley 21931555c271SMatthew G. Knepley Level: developer 21941555c271SMatthew G. Knepley 2195a1cb98faSBarry Smith Note: 2196a1cb98faSBarry 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 2197a1cb98faSBarry Smith 21981cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 21991555c271SMatthew G. Knepley @*/ 2200d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeGradientClementInterpolant(DM dm, Vec locX, Vec locC) 2201d71ae5a4SJacob Faibussowitsch { 2202db1066baSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 2203db1066baSMatthew G. Knepley PetscInt debug = mesh->printFEM; 22041555c271SMatthew G. Knepley DM dmC; 22051555c271SMatthew G. Knepley PetscQuadrature quad; 22061555c271SMatthew G. Knepley PetscScalar *interpolant, *gradsum; 22074bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 22084bee2e38SMatthew G. Knepley PetscReal *coords; 22091555c271SMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 2210485ad865SMatthew G. Knepley PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, vStart, vEnd, v, field, fieldOffset; 22111555c271SMatthew G. Knepley 22121555c271SMatthew G. Knepley PetscFunctionBegin; 22139566063dSJacob Faibussowitsch PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite)); 22149566063dSJacob Faibussowitsch PetscCall(VecGetDM(locC, &dmC)); 22159566063dSJacob Faibussowitsch PetscCall(VecSet(locC, 0.0)); 22169566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 22179566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 22184bee2e38SMatthew G. Knepley fegeom.dimEmbed = coordDim; 22199566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &numFields)); 22205f80ce2aSJacob Faibussowitsch PetscCheck(numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!"); 22211555c271SMatthew G. Knepley for (field = 0; field < numFields; ++field) { 22221555c271SMatthew G. Knepley PetscObject obj; 22231555c271SMatthew G. Knepley PetscClassId id; 22241555c271SMatthew G. Knepley PetscInt Nc; 22251555c271SMatthew G. Knepley 22269566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 22279566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 22281555c271SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 22291555c271SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 22301555c271SMatthew G. Knepley 22319566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 22329566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 22331555c271SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 22341555c271SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 22351555c271SMatthew G. Knepley 22369566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 22379566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 223863a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 22391555c271SMatthew G. Knepley numComponents += Nc; 22401555c271SMatthew G. Knepley } 22419566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 224263a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 22439566063dSJacob 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)); 22449566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 22459566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 22461555c271SMatthew G. Knepley for (v = vStart; v < vEnd; ++v) { 22471555c271SMatthew G. Knepley PetscScalar volsum = 0.0; 22481555c271SMatthew G. Knepley PetscInt *star = NULL; 22491555c271SMatthew G. Knepley PetscInt starSize, st, d, fc; 22501555c271SMatthew G. Knepley 22519566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(gradsum, coordDim * numComponents)); 22529566063dSJacob Faibussowitsch PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 22531555c271SMatthew G. Knepley for (st = 0; st < starSize * 2; st += 2) { 22541555c271SMatthew G. Knepley const PetscInt cell = star[st]; 22551555c271SMatthew G. Knepley PetscScalar *grad = &gradsum[coordDim * numComponents]; 22561555c271SMatthew G. Knepley PetscScalar *x = NULL; 22571555c271SMatthew G. Knepley PetscReal vol = 0.0; 22581555c271SMatthew G. Knepley 22591555c271SMatthew G. Knepley if ((cell < cStart) || (cell >= cEnd)) continue; 22609566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 22619566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x)); 22621555c271SMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 22631555c271SMatthew G. Knepley PetscObject obj; 22641555c271SMatthew G. Knepley PetscClassId id; 22651555c271SMatthew G. Knepley PetscInt Nb, Nc, q, qc = 0; 22661555c271SMatthew G. Knepley 22679566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(grad, coordDim * numComponents)); 22689566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 22699566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 22709371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 22719371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 22729371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 22739371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 22749371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 22759371c9d4SSatish Balay Nb = 1; 22769371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 22771555c271SMatthew G. Knepley for (q = 0; q < Nq; ++q) { 22782a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 22792a4e142eSMatthew G. Knepley 22802a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 22812a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 22822a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 22832a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 228463a3b9bcSJacob 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); 22859566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolateGradient_Static((PetscFE)obj, 1, &x[fieldOffset], &qgeom, q, interpolant)); 228663a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 22871555c271SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 228853d2db2dSJoe Wallwork const PetscReal wt = quadWeights[q * qNc + qc]; 22891555c271SMatthew G. Knepley 22904bee2e38SMatthew G. Knepley for (d = 0; d < coordDim; ++d) grad[fc * coordDim + d] += interpolant[fc * dim + d] * wt * fegeom.detJ[q]; 22911555c271SMatthew G. Knepley } 22924bee2e38SMatthew G. Knepley vol += quadWeights[q * qNc] * fegeom.detJ[q]; 22931555c271SMatthew G. Knepley } 22941555c271SMatthew G. Knepley fieldOffset += Nb; 22951555c271SMatthew G. Knepley qc += Nc; 22961555c271SMatthew G. Knepley } 22979566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x)); 2298f8527842SMatthew G. Knepley for (fc = 0; fc < numComponents; ++fc) { 2299ad540459SPierre Jolivet for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] += grad[fc * coordDim + d]; 2300f8527842SMatthew G. Knepley } 2301f8527842SMatthew G. Knepley volsum += vol; 2302db1066baSMatthew G. Knepley if (debug) { 23039566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " gradient: [", v, cell)); 23041555c271SMatthew G. Knepley for (fc = 0; fc < numComponents; ++fc) { 23051555c271SMatthew G. Knepley for (d = 0; d < coordDim; ++d) { 23069566063dSJacob Faibussowitsch if (fc || d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 23079566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(grad[fc * coordDim + d]))); 23081555c271SMatthew G. Knepley } 23091555c271SMatthew G. Knepley } 23109566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n")); 2311db1066baSMatthew G. Knepley } 23121555c271SMatthew G. Knepley } 23131555c271SMatthew G. Knepley for (fc = 0; fc < numComponents; ++fc) { 23141555c271SMatthew G. Knepley for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] /= volsum; 23151555c271SMatthew G. Knepley } 23169566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 23179566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dmC, NULL, locC, v, gradsum, INSERT_VALUES)); 23181555c271SMatthew G. Knepley } 23199566063dSJacob Faibussowitsch PetscCall(PetscFree6(gradsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 23203ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 23211555c271SMatthew G. Knepley } 23221555c271SMatthew G. Knepley 23236493148fSStefano Zampini PetscErrorCode DMPlexComputeIntegral_Internal(DM dm, Vec locX, PetscInt cStart, PetscInt cEnd, PetscScalar *cintegral, void *user) 2324d71ae5a4SJacob Faibussowitsch { 2325cbf8eb3cSStefano Zampini DM dmAux = NULL, plexA = NULL; 232661aaff12SToby Isaac PetscDS prob, probAux = NULL; 232773d901b8SMatthew G. Knepley PetscSection section, sectionAux; 23286493148fSStefano Zampini Vec locA; 2329c330f8ffSToby Isaac PetscInt dim, numCells = cEnd - cStart, c, f; 2330c330f8ffSToby Isaac PetscBool useFVM = PETSC_FALSE; 2331338f77d5SMatthew G. Knepley /* DS */ 2332338f77d5SMatthew G. Knepley PetscInt Nf, totDim, *uOff, *uOff_x, numConstants; 2333338f77d5SMatthew G. Knepley PetscInt NfAux, totDimAux, *aOff; 23348e3a54c0SPierre Jolivet PetscScalar *u, *a = NULL; 2335338f77d5SMatthew G. Knepley const PetscScalar *constants; 2336338f77d5SMatthew G. Knepley /* Geometry */ 2337c330f8ffSToby Isaac PetscFEGeom *cgeomFEM; 2338338f77d5SMatthew G. Knepley DM dmGrad; 2339c330f8ffSToby Isaac PetscQuadrature affineQuad = NULL; 2340338f77d5SMatthew G. Knepley Vec cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL; 2341b5a3613cSMatthew G. Knepley PetscFVCellGeom *cgeomFVM; 2342338f77d5SMatthew G. Knepley const PetscScalar *lgrad; 2343b7260050SToby Isaac PetscInt maxDegree; 2344c330f8ffSToby Isaac DMField coordField; 2345c330f8ffSToby Isaac IS cellIS; 234673d901b8SMatthew G. Knepley 234773d901b8SMatthew G. Knepley PetscFunctionBegin; 23489566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 23499566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 23509566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 23519566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 2352338f77d5SMatthew G. Knepley /* Determine which discretizations we have */ 2353b5a3613cSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 2354b5a3613cSMatthew G. Knepley PetscObject obj; 2355b5a3613cSMatthew G. Knepley PetscClassId id; 2356b5a3613cSMatthew G. Knepley 23579566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 23589566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 2359338f77d5SMatthew G. Knepley if (id == PETSCFV_CLASSID) useFVM = PETSC_TRUE; 2360338f77d5SMatthew G. Knepley } 2361338f77d5SMatthew G. Knepley /* Read DS information */ 23629566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 23639566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(prob, &uOff)); 23649566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x)); 23659566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PETSC_COMM_SELF, numCells, cStart, 1, &cellIS)); 23669566063dSJacob Faibussowitsch PetscCall(PetscDSGetConstants(prob, &numConstants, &constants)); 2367338f77d5SMatthew G. Knepley /* Read Auxiliary DS information */ 23689566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 23699a2a23afSMatthew G. Knepley if (locA) { 23709566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 2371cbf8eb3cSStefano Zampini PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 23729566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 23739566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(probAux, &NfAux)); 23749566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 23759566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 23769566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(probAux, &aOff)); 2377338f77d5SMatthew G. Knepley } 2378338f77d5SMatthew G. Knepley /* Allocate data arrays */ 23799566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(numCells * totDim, &u)); 23809566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 2381338f77d5SMatthew G. Knepley /* Read out geometry */ 23829566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 23839566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 2384b7260050SToby Isaac if (maxDegree <= 1) { 23859566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 238648a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &cgeomFEM)); 2387b5a3613cSMatthew G. Knepley } 2388b5a3613cSMatthew G. Knepley if (useFVM) { 2389338f77d5SMatthew G. Knepley PetscFV fv = NULL; 2390b5a3613cSMatthew G. Knepley Vec grad; 2391b5a3613cSMatthew G. Knepley PetscInt fStart, fEnd; 2392b5a3613cSMatthew G. Knepley PetscBool compGrad; 2393b5a3613cSMatthew G. Knepley 2394338f77d5SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 2395338f77d5SMatthew G. Knepley PetscObject obj; 2396338f77d5SMatthew G. Knepley PetscClassId id; 2397338f77d5SMatthew G. Knepley 23989566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 23999566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 24009371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 24019371c9d4SSatish Balay fv = (PetscFV)obj; 24029371c9d4SSatish Balay break; 24039371c9d4SSatish Balay } 2404338f77d5SMatthew G. Knepley } 24059566063dSJacob Faibussowitsch PetscCall(PetscFVGetComputeGradients(fv, &compGrad)); 24069566063dSJacob Faibussowitsch PetscCall(PetscFVSetComputeGradients(fv, PETSC_TRUE)); 24079566063dSJacob Faibussowitsch PetscCall(DMPlexComputeGeometryFVM(dm, &cellGeometryFVM, &faceGeometryFVM)); 24089566063dSJacob Faibussowitsch PetscCall(DMPlexComputeGradientFVM(dm, fv, faceGeometryFVM, cellGeometryFVM, &dmGrad)); 24099566063dSJacob Faibussowitsch PetscCall(PetscFVSetComputeGradients(fv, compGrad)); 24109566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM)); 2411b5a3613cSMatthew G. Knepley /* Reconstruct and limit cell gradients */ 24129566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 24139566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmGrad, &grad)); 24149566063dSJacob Faibussowitsch PetscCall(DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad)); 2415b5a3613cSMatthew G. Knepley /* Communicate gradient values */ 24169566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dmGrad, &locGrad)); 24179566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad)); 24189566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad)); 24199566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmGrad, &grad)); 2420b5a3613cSMatthew G. Knepley /* Handle non-essential (e.g. outflow) boundary values */ 24219566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, 0.0, faceGeometryFVM, cellGeometryFVM, locGrad)); 24229566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locGrad, &lgrad)); 2423b5a3613cSMatthew G. Knepley } 2424338f77d5SMatthew G. Knepley /* Read out data from inputs */ 242573d901b8SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 242673d901b8SMatthew G. Knepley PetscScalar *x = NULL; 242773d901b8SMatthew G. Knepley PetscInt i; 242873d901b8SMatthew G. Knepley 24299566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, locX, c, NULL, &x)); 24300f2d7e86SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i]; 24319566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, locX, c, NULL, &x)); 243273d901b8SMatthew G. Knepley if (dmAux) { 2433cbf8eb3cSStefano Zampini PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, c, NULL, &x)); 24340f2d7e86SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i]; 2435cbf8eb3cSStefano Zampini PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, c, NULL, &x)); 243673d901b8SMatthew G. Knepley } 243773d901b8SMatthew G. Knepley } 2438338f77d5SMatthew G. Knepley /* Do integration for each field */ 243973d901b8SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 2440c1f031eeSMatthew G. Knepley PetscObject obj; 2441c1f031eeSMatthew G. Knepley PetscClassId id; 2442c1f031eeSMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 244373d901b8SMatthew G. Knepley 24449566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 24459566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 2446c1f031eeSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 2447c1f031eeSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 2448c1f031eeSMatthew G. Knepley PetscQuadrature q; 2449c330f8ffSToby Isaac PetscFEGeom *chunkGeom = NULL; 2450c1f031eeSMatthew G. Knepley PetscInt Nq, Nb; 2451c1f031eeSMatthew G. Knepley 24529566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 24539566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 24549566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL)); 24559566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 2456c1f031eeSMatthew G. Knepley blockSize = Nb * Nq; 245773d901b8SMatthew G. Knepley batchSize = numBlocks * blockSize; 24589566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 245973d901b8SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 246073d901b8SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 246173d901b8SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 246273d901b8SMatthew G. Knepley offset = numCells - Nr; 246348a46eb9SPierre Jolivet if (!affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, q, PETSC_FALSE, &cgeomFEM)); 24649566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 24659566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrate(prob, f, Ne, chunkGeom, u, probAux, a, cintegral)); 24669566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &chunkGeom)); 24678e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrate(prob, f, Nr, chunkGeom, &u[offset * totDim], probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), &cintegral[offset * Nf])); 24689566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &chunkGeom)); 246948a46eb9SPierre Jolivet if (!affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM)); 2470c1f031eeSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 2471c1f031eeSMatthew G. Knepley PetscInt foff; 2472420e96edSMatthew G. Knepley PetscPointFunc obj_func; 2473c1f031eeSMatthew G. Knepley 24749566063dSJacob Faibussowitsch PetscCall(PetscDSGetObjective(prob, f, &obj_func)); 24759566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, f, &foff)); 2476c1f031eeSMatthew G. Knepley if (obj_func) { 2477c1f031eeSMatthew G. Knepley for (c = 0; c < numCells; ++c) { 2478b5a3613cSMatthew G. Knepley PetscScalar *u_x; 2479d627b919SMatthew G. Knepley PetscScalar lint = 0.; 2480b5a3613cSMatthew G. Knepley 24819566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, c, lgrad, &u_x)); 248255bffe1bSPierre 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); 2483338f77d5SMatthew G. Knepley cintegral[c * Nf + f] += PetscRealPart(lint) * cgeomFVM[c].volume; 248473d901b8SMatthew G. Knepley } 2485c1f031eeSMatthew G. Knepley } 248663a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 2487c1f031eeSMatthew G. Knepley } 2488338f77d5SMatthew G. Knepley /* Cleanup data arrays */ 2489b5a3613cSMatthew G. Knepley if (useFVM) { 24909566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(locGrad, &lgrad)); 24919566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM)); 24929566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 24939566063dSJacob Faibussowitsch PetscCall(VecDestroy(&faceGeometryFVM)); 24949566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cellGeometryFVM)); 24959566063dSJacob Faibussowitsch PetscCall(DMDestroy(&dmGrad)); 2496b5a3613cSMatthew G. Knepley } 24979566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscFree(a)); 2498cbf8eb3cSStefano Zampini PetscCall(DMDestroy(&plexA)); 24999566063dSJacob Faibussowitsch PetscCall(PetscFree(u)); 2500338f77d5SMatthew G. Knepley /* Cleanup */ 250148a46eb9SPierre Jolivet if (affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM)); 25029566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 25039566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cellIS)); 25043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2505338f77d5SMatthew G. Knepley } 2506338f77d5SMatthew G. Knepley 2507338f77d5SMatthew G. Knepley /*@ 2508338f77d5SMatthew G. Knepley DMPlexComputeIntegralFEM - Form the integral over the domain from the global input X using pointwise functions specified by the user 2509338f77d5SMatthew G. Knepley 2510338f77d5SMatthew G. Knepley Input Parameters: 2511338f77d5SMatthew G. Knepley + dm - The mesh 2512338f77d5SMatthew G. Knepley . X - Global input vector 2513338f77d5SMatthew G. Knepley - user - The user context 2514338f77d5SMatthew G. Knepley 2515338f77d5SMatthew G. Knepley Output Parameter: 2516338f77d5SMatthew G. Knepley . integral - Integral for each field 2517338f77d5SMatthew G. Knepley 2518338f77d5SMatthew G. Knepley Level: developer 2519338f77d5SMatthew G. Knepley 25201cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()` 2521338f77d5SMatthew G. Knepley @*/ 2522d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscScalar *integral, void *user) 2523d71ae5a4SJacob Faibussowitsch { 2524cbf8eb3cSStefano Zampini PetscInt printFEM; 2525b8feb594SMatthew G. Knepley PetscScalar *cintegral, *lintegral; 2526412e9a14SMatthew G. Knepley PetscInt Nf, f, cellHeight, cStart, cEnd, cell; 25276493148fSStefano Zampini Vec locX; 2528338f77d5SMatthew G. Knepley 2529338f77d5SMatthew G. Knepley PetscFunctionBegin; 2530338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2531338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 25324f572ea9SToby Isaac PetscAssertPointer(integral, 3); 25339566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 2534cbf8eb3cSStefano Zampini PetscCall(DMPlexConvertPlex(dm, &dm, PETSC_TRUE)); 25359566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 25369566063dSJacob Faibussowitsch PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 25379566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 2538338f77d5SMatthew G. Knepley /* TODO Introduce a loop over large chunks (right now this is a single chunk) */ 25399566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &lintegral, (cEnd - cStart) * Nf, &cintegral)); 25406493148fSStefano Zampini /* Get local solution with boundary values */ 25416493148fSStefano Zampini PetscCall(DMGetLocalVector(dm, &locX)); 25426493148fSStefano Zampini PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 25436493148fSStefano Zampini PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 25446493148fSStefano Zampini PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 25456493148fSStefano Zampini PetscCall(DMPlexComputeIntegral_Internal(dm, locX, cStart, cEnd, cintegral, user)); 25466493148fSStefano Zampini PetscCall(DMRestoreLocalVector(dm, &locX)); 2547cbf8eb3cSStefano Zampini printFEM = ((DM_Plex *)dm->data)->printFEM; 2548338f77d5SMatthew G. Knepley /* Sum up values */ 2549338f77d5SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 2550338f77d5SMatthew G. Knepley const PetscInt c = cell - cStart; 2551338f77d5SMatthew G. Knepley 2552cbf8eb3cSStefano Zampini if (printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf])); 2553b8feb594SMatthew G. Knepley for (f = 0; f < Nf; ++f) lintegral[f] += cintegral[c * Nf + f]; 2554338f77d5SMatthew G. Knepley } 2555*e91c04dfSPierre Jolivet PetscCallMPI(MPIU_Allreduce(lintegral, integral, Nf, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 2556cbf8eb3cSStefano Zampini if (printFEM) { 25579566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Integral:")); 25589566063dSJacob Faibussowitsch for (f = 0; f < Nf; ++f) PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), " %g", (double)PetscRealPart(integral[f]))); 25599566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "\n")); 256073d901b8SMatthew G. Knepley } 25619566063dSJacob Faibussowitsch PetscCall(PetscFree2(lintegral, cintegral)); 25629566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 2563cbf8eb3cSStefano Zampini PetscCall(DMDestroy(&dm)); 25643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2565338f77d5SMatthew G. Knepley } 2566338f77d5SMatthew G. Knepley 2567338f77d5SMatthew G. Knepley /*@ 2568338f77d5SMatthew G. Knepley DMPlexComputeCellwiseIntegralFEM - Form the vector of cellwise integrals F from the global input X using pointwise functions specified by the user 2569338f77d5SMatthew G. Knepley 2570338f77d5SMatthew G. Knepley Input Parameters: 2571338f77d5SMatthew G. Knepley + dm - The mesh 2572338f77d5SMatthew G. Knepley . X - Global input vector 2573338f77d5SMatthew G. Knepley - user - The user context 2574338f77d5SMatthew G. Knepley 2575338f77d5SMatthew G. Knepley Output Parameter: 257660225df5SJacob Faibussowitsch . F - Cellwise integrals for each field 2577338f77d5SMatthew G. Knepley 2578338f77d5SMatthew G. Knepley Level: developer 2579338f77d5SMatthew G. Knepley 25801cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()` 2581338f77d5SMatthew G. Knepley @*/ 2582d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellwiseIntegralFEM(DM dm, Vec X, Vec F, void *user) 2583d71ae5a4SJacob Faibussowitsch { 2584cbf8eb3cSStefano Zampini PetscInt printFEM; 2585338f77d5SMatthew G. Knepley DM dmF; 25869c8ab049SStefano Zampini PetscSection sectionF = NULL; 2587338f77d5SMatthew G. Knepley PetscScalar *cintegral, *af; 25889c8ab049SStefano Zampini PetscInt Nf, f, cellHeight, cStart, cEnd, cell, n; 25896493148fSStefano Zampini Vec locX; 2590338f77d5SMatthew G. Knepley 2591338f77d5SMatthew G. Knepley PetscFunctionBegin; 2592338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2593338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2594338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(F, VEC_CLASSID, 3); 25959566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 2596cbf8eb3cSStefano Zampini PetscCall(DMPlexConvertPlex(dm, &dm, PETSC_TRUE)); 25979566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 25989566063dSJacob Faibussowitsch PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 25999566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 2600338f77d5SMatthew G. Knepley /* TODO Introduce a loop over large chunks (right now this is a single chunk) */ 26019566063dSJacob Faibussowitsch PetscCall(PetscCalloc1((cEnd - cStart) * Nf, &cintegral)); 26026493148fSStefano Zampini /* Get local solution with boundary values */ 26036493148fSStefano Zampini PetscCall(DMGetLocalVector(dm, &locX)); 26046493148fSStefano Zampini PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 26056493148fSStefano Zampini PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 26066493148fSStefano Zampini PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 26076493148fSStefano Zampini PetscCall(DMPlexComputeIntegral_Internal(dm, locX, cStart, cEnd, cintegral, user)); 26086493148fSStefano Zampini PetscCall(DMRestoreLocalVector(dm, &locX)); 2609338f77d5SMatthew G. Knepley /* Put values in F */ 26109566063dSJacob Faibussowitsch PetscCall(VecGetArray(F, &af)); 26119c8ab049SStefano Zampini PetscCall(VecGetDM(F, &dmF)); 26129c8ab049SStefano Zampini if (dmF) PetscCall(DMGetLocalSection(dmF, §ionF)); 26139c8ab049SStefano Zampini PetscCall(VecGetLocalSize(F, &n)); 26149c8ab049SStefano Zampini PetscCheck(n >= (cEnd - cStart) * Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Vector size %" PetscInt_FMT " < %" PetscInt_FMT, n, (cEnd - cStart) * Nf); 2615cbf8eb3cSStefano Zampini printFEM = ((DM_Plex *)dm->data)->printFEM; 2616338f77d5SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 2617338f77d5SMatthew G. Knepley const PetscInt c = cell - cStart; 26189c8ab049SStefano Zampini PetscInt dof = Nf, off = c * Nf; 2619338f77d5SMatthew G. Knepley 2620cbf8eb3cSStefano Zampini if (printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf])); 26219c8ab049SStefano Zampini if (sectionF) { 26229566063dSJacob Faibussowitsch PetscCall(PetscSectionGetDof(sectionF, cell, &dof)); 26239566063dSJacob Faibussowitsch PetscCall(PetscSectionGetOffset(sectionF, cell, &off)); 26249c8ab049SStefano Zampini } 262563a3b9bcSJacob Faibussowitsch PetscCheck(dof == Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cell dofs %" PetscInt_FMT " != %" PetscInt_FMT, dof, Nf); 2626338f77d5SMatthew G. Knepley for (f = 0; f < Nf; ++f) af[off + f] = cintegral[c * Nf + f]; 2627338f77d5SMatthew G. Knepley } 26289566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(F, &af)); 26299566063dSJacob Faibussowitsch PetscCall(PetscFree(cintegral)); 26309566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 2631cbf8eb3cSStefano Zampini PetscCall(DMDestroy(&dm)); 26323ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 263373d901b8SMatthew G. Knepley } 263473d901b8SMatthew G. Knepley 263579ab67a3SMatthew 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) 2636d71ae5a4SJacob Faibussowitsch { 26379b6f715bSMatthew G. Knepley DM plex = NULL, plexA = NULL; 2638a6e0b375SMatthew G. Knepley DMEnclosureType encAux; 26399b6f715bSMatthew G. Knepley PetscDS prob, probAux = NULL; 26409b6f715bSMatthew G. Knepley PetscSection section, sectionAux = NULL; 26419b6f715bSMatthew G. Knepley Vec locA = NULL; 26429b6f715bSMatthew G. Knepley DMField coordField; 26439b6f715bSMatthew G. Knepley PetscInt Nf, totDim, *uOff, *uOff_x; 26449b6f715bSMatthew G. Knepley PetscInt NfAux = 0, totDimAux = 0, *aOff = NULL; 26459b6f715bSMatthew G. Knepley PetscScalar *u, *a = NULL; 264664c72086SMatthew G. Knepley const PetscScalar *constants; 26479b6f715bSMatthew G. Knepley PetscInt numConstants, f; 264864c72086SMatthew G. Knepley 264964c72086SMatthew G. Knepley PetscFunctionBegin; 26509566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 26519566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 26529566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 26539566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 26549566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &Nf)); 265564c72086SMatthew G. Knepley /* Determine which discretizations we have */ 26569b6f715bSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 265764c72086SMatthew G. Knepley PetscObject obj; 265864c72086SMatthew G. Knepley PetscClassId id; 265964c72086SMatthew G. Knepley 26609566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 26619566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 266263a3b9bcSJacob Faibussowitsch PetscCheck(id != PETSCFV_CLASSID, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Not supported for FVM (field %" PetscInt_FMT ")", f); 266364c72086SMatthew G. Knepley } 266464c72086SMatthew G. Knepley /* Read DS information */ 26659566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 26669566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(prob, &uOff)); 26679566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x)); 26689566063dSJacob Faibussowitsch PetscCall(PetscDSGetConstants(prob, &numConstants, &constants)); 266964c72086SMatthew G. Knepley /* Read Auxiliary DS information */ 26709566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 26719b6f715bSMatthew G. Knepley if (locA) { 26729b6f715bSMatthew G. Knepley DM dmAux; 26739b6f715bSMatthew G. Knepley 26749566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 26759566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 26769566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 26779566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 26789566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(probAux, &NfAux)); 26799566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 26809566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 26819566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(probAux, &aOff)); 268264c72086SMatthew G. Knepley } 26839b6f715bSMatthew G. Knepley /* Integrate over points */ 26849b6f715bSMatthew G. Knepley { 26859b6f715bSMatthew G. Knepley PetscFEGeom *fgeom, *chunkGeom = NULL; 2686b7260050SToby Isaac PetscInt maxDegree; 26879b6f715bSMatthew G. Knepley PetscQuadrature qGeom = NULL; 26889b6f715bSMatthew G. Knepley const PetscInt *points; 26899b6f715bSMatthew G. Knepley PetscInt numFaces, face, Nq, field; 26909b6f715bSMatthew G. Knepley PetscInt numChunks, chunkSize, chunk, Nr, offset; 269164c72086SMatthew G. Knepley 26929566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 26939566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 269432603206SJames Wright PetscCall(PetscCalloc2(numFaces * totDim, &u, (locA ? (size_t)numFaces * totDimAux : 0), &a)); 26959566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 269679ab67a3SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 269779ab67a3SMatthew G. Knepley const PetscInt point = points[face], *support; 269879ab67a3SMatthew G. Knepley PetscScalar *x = NULL; 269979ab67a3SMatthew G. Knepley 270079ab67a3SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, point, &support)); 270179ab67a3SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 270279ab67a3SMatthew G. Knepley for (PetscInt i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 270379ab67a3SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 270479ab67a3SMatthew G. Knepley if (locA) { 270579ab67a3SMatthew G. Knepley PetscInt subp; 270679ab67a3SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 270779ab67a3SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 270879ab67a3SMatthew G. Knepley for (PetscInt i = 0; i < totDimAux; ++i) a[f * totDimAux + i] = x[i]; 270979ab67a3SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 271079ab67a3SMatthew G. Knepley } 271179ab67a3SMatthew G. Knepley } 271264c72086SMatthew G. Knepley for (field = 0; field < Nf; ++field) { 271364c72086SMatthew G. Knepley PetscFE fe; 271464c72086SMatthew G. Knepley 27159566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fe)); 27169566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 27179b6f715bSMatthew G. Knepley if (!qGeom) { 27189566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 27199566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 27209b6f715bSMatthew G. Knepley } 27219566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 27229566063dSJacob Faibussowitsch PetscCall(DMPlexGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 27239b6f715bSMatthew G. Knepley /* Get blocking */ 27249b6f715bSMatthew G. Knepley { 27259b6f715bSMatthew G. Knepley PetscQuadrature q; 27269b6f715bSMatthew G. Knepley PetscInt numBatches, batchSize, numBlocks, blockSize; 27279b6f715bSMatthew G. Knepley PetscInt Nq, Nb; 27289b6f715bSMatthew G. Knepley 27299566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 27309566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 27319566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL)); 27329566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 273364c72086SMatthew G. Knepley blockSize = Nb * Nq; 273464c72086SMatthew G. Knepley batchSize = numBlocks * blockSize; 27359b6f715bSMatthew G. Knepley chunkSize = numBatches * batchSize; 27369566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 27379b6f715bSMatthew G. Knepley numChunks = numFaces / chunkSize; 27389b6f715bSMatthew G. Knepley Nr = numFaces % chunkSize; 273964c72086SMatthew G. Knepley offset = numFaces - Nr; 274064c72086SMatthew G. Knepley } 27419b6f715bSMatthew G. Knepley /* Do integration for each field */ 27429b6f715bSMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 27439566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, chunk * chunkSize, (chunk + 1) * chunkSize, &chunkGeom)); 274479ab67a3SMatthew G. Knepley PetscCall(PetscFEIntegrateBd(prob, field, funcs[field], chunkSize, chunkGeom, &u[chunk * chunkSize * totDim], probAux, PetscSafePointerPlusOffset(a, chunk * chunkSize * totDimAux), &fintegral[chunk * chunkSize * Nf])); 27459566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom)); 274664c72086SMatthew G. Knepley } 27479566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 274879ab67a3SMatthew G. Knepley PetscCall(PetscFEIntegrateBd(prob, field, funcs[field], Nr, chunkGeom, &u[offset * totDim], probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), &fintegral[offset * Nf])); 27499566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 275064c72086SMatthew G. Knepley /* Cleanup data arrays */ 27519566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 27529566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 275379ab67a3SMatthew G. Knepley } 27549566063dSJacob Faibussowitsch PetscCall(PetscFree2(u, a)); 27559566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 275664c72086SMatthew G. Knepley } 27579566063dSJacob Faibussowitsch if (plex) PetscCall(DMDestroy(&plex)); 27589566063dSJacob Faibussowitsch if (plexA) PetscCall(DMDestroy(&plexA)); 27593ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 27609b6f715bSMatthew G. Knepley } 27619b6f715bSMatthew G. Knepley 276260225df5SJacob Faibussowitsch /*@C 27639b6f715bSMatthew G. Knepley DMPlexComputeBdIntegral - Form the integral over the specified boundary from the global input X using pointwise functions specified by the user 27649b6f715bSMatthew G. Knepley 27659b6f715bSMatthew G. Knepley Input Parameters: 27669b6f715bSMatthew G. Knepley + dm - The mesh 27679b6f715bSMatthew G. Knepley . X - Global input vector 2768a1cb98faSBarry Smith . label - The boundary `DMLabel` 2769a1cb98faSBarry Smith . numVals - The number of label values to use, or `PETSC_DETERMINE` for all values 2770a1cb98faSBarry Smith . vals - The label values to use, or NULL for all values 277179ab67a3SMatthew G. Knepley . funcs - The functions to integrate along the boundary for each field 27729b6f715bSMatthew G. Knepley - user - The user context 27739b6f715bSMatthew G. Knepley 27749b6f715bSMatthew G. Knepley Output Parameter: 27759b6f715bSMatthew G. Knepley . integral - Integral for each field 27769b6f715bSMatthew G. Knepley 27779b6f715bSMatthew G. Knepley Level: developer 27789b6f715bSMatthew G. Knepley 27791cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeIntegralFEM()`, `DMPlexComputeBdResidualFEM()` 27809b6f715bSMatthew G. Knepley @*/ 278179ab67a3SMatthew 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) 2782d71ae5a4SJacob Faibussowitsch { 27839b6f715bSMatthew G. Knepley Vec locX; 27849b6f715bSMatthew G. Knepley PetscSection section; 27859b6f715bSMatthew G. Knepley DMLabel depthLabel; 27869b6f715bSMatthew G. Knepley IS facetIS; 27879b6f715bSMatthew G. Knepley PetscInt dim, Nf, f, v; 27889b6f715bSMatthew G. Knepley 27899b6f715bSMatthew G. Knepley PetscFunctionBegin; 27909b6f715bSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 27919b6f715bSMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2792292bffcbSToby Isaac PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3); 27934f572ea9SToby Isaac if (vals) PetscAssertPointer(vals, 5); 27944f572ea9SToby Isaac PetscAssertPointer(integral, 7); 27959566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 27969566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 27979566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 27989566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 27999566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 28009566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &Nf)); 28019b6f715bSMatthew G. Knepley /* Get local solution with boundary values */ 28029566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &locX)); 28039566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 28049566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 28059566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 28069b6f715bSMatthew G. Knepley /* Loop over label values */ 28079566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(integral, Nf)); 28089b6f715bSMatthew G. Knepley for (v = 0; v < numVals; ++v) { 28099b6f715bSMatthew G. Knepley IS pointIS; 28109b6f715bSMatthew G. Knepley PetscInt numFaces, face; 28119b6f715bSMatthew G. Knepley PetscScalar *fintegral; 28129b6f715bSMatthew G. Knepley 28139566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, vals[v], &pointIS)); 28149b6f715bSMatthew G. Knepley if (!pointIS) continue; /* No points with that id on this process */ 28159b6f715bSMatthew G. Knepley { 28169b6f715bSMatthew G. Knepley IS isectIS; 28179b6f715bSMatthew G. Knepley 28189b6f715bSMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 28199566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 28209566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 28219b6f715bSMatthew G. Knepley pointIS = isectIS; 28229b6f715bSMatthew G. Knepley } 28239566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 28249566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(numFaces * Nf, &fintegral)); 282579ab67a3SMatthew G. Knepley PetscCall(DMPlexComputeBdIntegral_Internal(dm, locX, pointIS, funcs, fintegral, user)); 28269b6f715bSMatthew G. Knepley /* Sum point contributions into integral */ 28279371c9d4SSatish Balay for (f = 0; f < Nf; ++f) 28289371c9d4SSatish Balay for (face = 0; face < numFaces; ++face) integral[f] += fintegral[face * Nf + f]; 28299566063dSJacob Faibussowitsch PetscCall(PetscFree(fintegral)); 28309566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 28319b6f715bSMatthew G. Knepley } 28329566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &locX)); 28339566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 28349566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 28353ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 283664c72086SMatthew G. Knepley } 283764c72086SMatthew G. Knepley 2838d69c5d34SMatthew G. Knepley /*@ 28390318f8a0SStefano Zampini DMPlexComputeInterpolatorNested - Form the local portion of the interpolation matrix from the coarse `DM` to a uniformly refined `DM`. 2840d69c5d34SMatthew G. Knepley 2841d69c5d34SMatthew G. Knepley Input Parameters: 2842cf51de39SMatthew G. Knepley + dmc - The coarse mesh 2843cf51de39SMatthew G. Knepley . dmf - The fine mesh 2844cf51de39SMatthew G. Knepley . isRefined - Flag indicating regular refinement, rather than the same topology 2845d69c5d34SMatthew G. Knepley - user - The user context 2846d69c5d34SMatthew G. Knepley 2847d69c5d34SMatthew G. Knepley Output Parameter: 2848934789fcSMatthew G. Knepley . In - The interpolation matrix 2849d69c5d34SMatthew G. Knepley 2850d69c5d34SMatthew G. Knepley Level: developer 2851d69c5d34SMatthew G. Knepley 2852ae3cf2c1SStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorGeneral()` 2853d69c5d34SMatthew G. Knepley @*/ 2854d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, PetscBool isRefined, Mat In, void *user) 2855d71ae5a4SJacob Faibussowitsch { 2856d69c5d34SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmc->data; 2857d69c5d34SMatthew G. Knepley const char *name = "Interpolator"; 2858d69c5d34SMatthew G. Knepley PetscFE *feRef; 285997c42addSMatthew G. Knepley PetscFV *fvRef; 2860d69c5d34SMatthew G. Knepley PetscSection fsection, fglobalSection; 2861d69c5d34SMatthew G. Knepley PetscSection csection, cglobalSection; 2862d69c5d34SMatthew G. Knepley PetscScalar *elemMat; 2863485ad865SMatthew G. Knepley PetscInt dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, c; 28642ea9c922SToby Isaac PetscInt cTotDim = 0, rTotDim = 0; 2865d69c5d34SMatthew G. Knepley 2866d69c5d34SMatthew G. Knepley PetscFunctionBegin; 28679566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 28689566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dmf, &dim)); 28699566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 28709566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &fglobalSection)); 28719566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 28729566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &cglobalSection)); 28739566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(fsection, &Nf)); 28749566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd)); 28759566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &feRef, Nf, &fvRef)); 2876d69c5d34SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 28772ea9c922SToby Isaac PetscObject obj, objc; 28782ea9c922SToby Isaac PetscClassId id, idc; 28792ea9c922SToby Isaac PetscInt rNb = 0, Nc = 0, cNb = 0; 2880d69c5d34SMatthew G. Knepley 28819566063dSJacob Faibussowitsch PetscCall(DMGetField(dmf, f, NULL, &obj)); 28829566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 288397c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 288497c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 288597c42addSMatthew G. Knepley 2886cf51de39SMatthew G. Knepley if (isRefined) { 28879566063dSJacob Faibussowitsch PetscCall(PetscFERefine(fe, &feRef[f])); 2888cf51de39SMatthew G. Knepley } else { 28899566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)fe)); 2890cf51de39SMatthew G. Knepley feRef[f] = fe; 2891cf51de39SMatthew G. Knepley } 28929566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feRef[f], &rNb)); 28939566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 289497c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 289597c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 289697c42addSMatthew G. Knepley PetscDualSpace Q; 289797c42addSMatthew G. Knepley 2898cf51de39SMatthew G. Knepley if (isRefined) { 28999566063dSJacob Faibussowitsch PetscCall(PetscFVRefine(fv, &fvRef[f])); 2900cf51de39SMatthew G. Knepley } else { 29019566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)fv)); 2902cf51de39SMatthew G. Knepley fvRef[f] = fv; 2903cf51de39SMatthew G. Knepley } 29049566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[f], &Q)); 29059566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &rNb)); 29069566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 29079566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 290897c42addSMatthew G. Knepley } 29099566063dSJacob Faibussowitsch PetscCall(DMGetField(dmc, f, NULL, &objc)); 29109566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(objc, &idc)); 29112ea9c922SToby Isaac if (idc == PETSCFE_CLASSID) { 29122ea9c922SToby Isaac PetscFE fe = (PetscFE)objc; 29132ea9c922SToby Isaac 29149566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cNb)); 29152ea9c922SToby Isaac } else if (id == PETSCFV_CLASSID) { 29162ea9c922SToby Isaac PetscFV fv = (PetscFV)obj; 29172ea9c922SToby Isaac PetscDualSpace Q; 29182ea9c922SToby Isaac 29199566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 29209566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &cNb)); 2921d69c5d34SMatthew G. Knepley } 29222ea9c922SToby Isaac rTotDim += rNb; 29232ea9c922SToby Isaac cTotDim += cNb; 29242ea9c922SToby Isaac } 29259566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(rTotDim * cTotDim, &elemMat)); 29269566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, rTotDim * cTotDim)); 2927d69c5d34SMatthew G. Knepley for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) { 2928d69c5d34SMatthew G. Knepley PetscDualSpace Qref; 2929d69c5d34SMatthew G. Knepley PetscQuadrature f; 2930d69c5d34SMatthew G. Knepley const PetscReal *qpoints, *qweights; 2931d69c5d34SMatthew G. Knepley PetscReal *points; 2932d69c5d34SMatthew G. Knepley PetscInt npoints = 0, Nc, Np, fpdim, i, k, p, d; 2933d69c5d34SMatthew G. Knepley 2934d69c5d34SMatthew G. Knepley /* Compose points from all dual basis functionals */ 293597c42addSMatthew G. Knepley if (feRef[fieldI]) { 29369566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feRef[fieldI], &Qref)); 29379566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feRef[fieldI], &Nc)); 293897c42addSMatthew G. Knepley } else { 29399566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[fieldI], &Qref)); 29409566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvRef[fieldI], &Nc)); 294197c42addSMatthew G. Knepley } 29429566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Qref, &fpdim)); 2943d69c5d34SMatthew G. Knepley for (i = 0; i < fpdim; ++i) { 29449566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 29459566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL)); 2946d69c5d34SMatthew G. Knepley npoints += Np; 2947d69c5d34SMatthew G. Knepley } 29489566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(npoints * dim, &points)); 2949d69c5d34SMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 29509566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 29519566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL)); 29529371c9d4SSatish Balay for (p = 0; p < Np; ++p, ++k) 29539371c9d4SSatish Balay for (d = 0; d < dim; ++d) points[k * dim + d] = qpoints[p * dim + d]; 2954d69c5d34SMatthew G. Knepley } 2955d69c5d34SMatthew G. Knepley 2956d69c5d34SMatthew G. Knepley for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) { 295797c42addSMatthew G. Knepley PetscObject obj; 295897c42addSMatthew G. Knepley PetscClassId id; 29599c3cf19fSMatthew G. Knepley PetscInt NcJ = 0, cpdim = 0, j, qNc; 2960d69c5d34SMatthew G. Knepley 29619566063dSJacob Faibussowitsch PetscCall(DMGetField(dmc, fieldJ, NULL, &obj)); 29629566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 296397c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 296497c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 2965ef0bb6c7SMatthew G. Knepley PetscTabulation T = NULL; 2966d69c5d34SMatthew G. Knepley 2967d69c5d34SMatthew G. Knepley /* Evaluate basis at points */ 29689566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &NcJ)); 29699566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cpdim)); 2970ffe73a53SMatthew G. Knepley /* For now, fields only interpolate themselves */ 2971ffe73a53SMatthew G. Knepley if (fieldI == fieldJ) { 297263a3b9bcSJacob 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); 29739566063dSJacob Faibussowitsch PetscCall(PetscFECreateTabulation(fe, 1, npoints, points, 0, &T)); 2974d69c5d34SMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 29759566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 29769566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights)); 297763a3b9bcSJacob 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); 2978d69c5d34SMatthew G. Knepley for (p = 0; p < Np; ++p, ++k) { 297936a6d9c0SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 2980d172c84bSMatthew G. Knepley /* 2981d172c84bSMatthew G. Knepley cTotDim: Total columns in element interpolation matrix, sum of number of dual basis functionals in each field 2982d172c84bSMatthew G. Knepley offsetI, offsetJ: Offsets into the larger element interpolation matrix for different fields 2983d172c84bSMatthew G. Knepley fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals 2984d172c84bSMatthew G. Knepley qNC, Nc, Ncj, c: Number of components in this field 2985d172c84bSMatthew G. Knepley Np, p: Number of quad points in the fine grid functional i 2986d172c84bSMatthew G. Knepley k: i*Np + p, overall point number for the interpolation 2987d172c84bSMatthew G. Knepley */ 2988ef0bb6c7SMatthew 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]; 298936a6d9c0SMatthew G. Knepley } 2990d69c5d34SMatthew G. Knepley } 2991d69c5d34SMatthew G. Knepley } 29929566063dSJacob Faibussowitsch PetscCall(PetscTabulationDestroy(&T)); 2993ffe73a53SMatthew G. Knepley } 299497c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 299597c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 299697c42addSMatthew G. Knepley 299797c42addSMatthew G. Knepley /* Evaluate constant function at points */ 29989566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &NcJ)); 299997c42addSMatthew G. Knepley cpdim = 1; 300097c42addSMatthew G. Knepley /* For now, fields only interpolate themselves */ 300197c42addSMatthew G. Knepley if (fieldI == fieldJ) { 300263a3b9bcSJacob 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); 300397c42addSMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 30049566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 30059566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights)); 300663a3b9bcSJacob 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); 300797c42addSMatthew G. Knepley for (p = 0; p < Np; ++p, ++k) { 300897c42addSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3009458eb97cSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[(offsetI + i) * cTotDim + offsetJ + j] += 1.0 * qweights[p * qNc + c]; 301097c42addSMatthew G. Knepley } 301197c42addSMatthew G. Knepley } 301297c42addSMatthew G. Knepley } 301397c42addSMatthew G. Knepley } 301497c42addSMatthew G. Knepley } 3015d172c84bSMatthew G. Knepley offsetJ += cpdim; 3016d69c5d34SMatthew G. Knepley } 3017d172c84bSMatthew G. Knepley offsetI += fpdim; 30189566063dSJacob Faibussowitsch PetscCall(PetscFree(points)); 3019d69c5d34SMatthew G. Knepley } 30209566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat)); 30217f5b169aSMatthew G. Knepley /* Preallocate matrix */ 30227f5b169aSMatthew G. Knepley { 3023c094ef40SMatthew G. Knepley Mat preallocator; 3024c094ef40SMatthew G. Knepley PetscScalar *vals; 3025c094ef40SMatthew G. Knepley PetscInt *cellCIndices, *cellFIndices; 3026c094ef40SMatthew G. Knepley PetscInt locRows, locCols, cell; 30277f5b169aSMatthew G. Knepley 30289566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(In, &locRows, &locCols)); 30299566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &preallocator)); 30309566063dSJacob Faibussowitsch PetscCall(MatSetType(preallocator, MATPREALLOCATOR)); 30319566063dSJacob Faibussowitsch PetscCall(MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE)); 30329566063dSJacob Faibussowitsch PetscCall(MatSetUp(preallocator)); 30339566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(rTotDim * cTotDim, &vals, cTotDim, &cellCIndices, rTotDim, &cellFIndices)); 30347f5b169aSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 3035cf51de39SMatthew G. Knepley if (isRefined) { 30369566063dSJacob Faibussowitsch PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices)); 30379566063dSJacob Faibussowitsch PetscCall(MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES)); 3038cf51de39SMatthew G. Knepley } else { 3039e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, PETSC_FALSE, dmc, csection, cglobalSection, PETSC_FALSE, preallocator, cell, vals, INSERT_VALUES)); 3040cf51de39SMatthew G. Knepley } 30417f5b169aSMatthew G. Knepley } 30429566063dSJacob Faibussowitsch PetscCall(PetscFree3(vals, cellCIndices, cellFIndices)); 30439566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY)); 30449566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY)); 30459566063dSJacob Faibussowitsch PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In)); 30469566063dSJacob Faibussowitsch PetscCall(MatDestroy(&preallocator)); 30477f5b169aSMatthew G. Knepley } 30487f5b169aSMatthew G. Knepley /* Fill matrix */ 30499566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(In)); 3050d69c5d34SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 3051cf51de39SMatthew G. Knepley if (isRefined) { 30529566063dSJacob Faibussowitsch PetscCall(DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES)); 3053cf51de39SMatthew G. Knepley } else { 3054e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, PETSC_FALSE, dmc, csection, cglobalSection, PETSC_FALSE, In, c, elemMat, INSERT_VALUES)); 3055cf51de39SMatthew G. Knepley } 3056d69c5d34SMatthew G. Knepley } 30579566063dSJacob Faibussowitsch for (f = 0; f < Nf; ++f) PetscCall(PetscFEDestroy(&feRef[f])); 30589566063dSJacob Faibussowitsch PetscCall(PetscFree2(feRef, fvRef)); 30599566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 30609566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY)); 30619566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY)); 30629318fe57SMatthew G. Knepley if (mesh->printFEM > 1) { 30639566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name)); 30642ce66baaSPierre Jolivet PetscCall(MatFilter(In, 1.0e-10, PETSC_FALSE, PETSC_FALSE)); 30659566063dSJacob Faibussowitsch PetscCall(MatView(In, NULL)); 3066d69c5d34SMatthew G. Knepley } 30679566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 30683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3069d69c5d34SMatthew G. Knepley } 30706c73c22cSMatthew G. Knepley 3071d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user) 3072d71ae5a4SJacob Faibussowitsch { 3073bd041c0cSMatthew G. Knepley SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_SUP, "Laziness"); 3074bd041c0cSMatthew G. Knepley } 3075bd041c0cSMatthew G. Knepley 307668132eb9SMatthew G. Knepley /*@ 30770318f8a0SStefano Zampini DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix from the coarse `DM` to a non-nested fine `DM`. 307868132eb9SMatthew G. Knepley 307968132eb9SMatthew G. Knepley Input Parameters: 308068132eb9SMatthew G. Knepley + dmf - The fine mesh 308168132eb9SMatthew G. Knepley . dmc - The coarse mesh 308268132eb9SMatthew G. Knepley - user - The user context 308368132eb9SMatthew G. Knepley 308468132eb9SMatthew G. Knepley Output Parameter: 308568132eb9SMatthew G. Knepley . In - The interpolation matrix 308668132eb9SMatthew G. Knepley 308768132eb9SMatthew G. Knepley Level: developer 308868132eb9SMatthew G. Knepley 3089ae3cf2c1SStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()` 309068132eb9SMatthew G. Knepley @*/ 3091d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user) 3092d71ae5a4SJacob Faibussowitsch { 309364e98e1dSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmf->data; 309464e98e1dSMatthew G. Knepley const char *name = "Interpolator"; 30954ef9d792SMatthew G. Knepley PetscDS prob; 3096a0806964SMatthew G. Knepley Mat interp; 3097a0806964SMatthew G. Knepley PetscSection fsection, globalFSection; 3098a0806964SMatthew G. Knepley PetscSection csection, globalCSection; 3099a0806964SMatthew G. Knepley PetscInt locRows, locCols; 31004ef9d792SMatthew G. Knepley PetscReal *x, *v0, *J, *invJ, detJ; 31014ef9d792SMatthew G. Knepley PetscReal *v0c, *Jc, *invJc, detJc; 31024ef9d792SMatthew G. Knepley PetscScalar *elemMat; 3103a0806964SMatthew G. Knepley PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell, s; 31044ef9d792SMatthew G. Knepley 31054ef9d792SMatthew G. Knepley PetscFunctionBegin; 31069566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 31079566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dmc, &dim)); 31089566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 31099566063dSJacob Faibussowitsch PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL)); 31109566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 31119566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ)); 31129566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc)); 31139566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 31149566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 31159566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 31169566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 3117a0806964SMatthew G. Knepley PetscCall(DMPlexGetSimplexOrBoxCells(dmf, 0, &cStart, &cEnd)); 31189566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 31199566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totDim, &elemMat)); 31204ef9d792SMatthew G. Knepley 3121a0806964SMatthew G. Knepley PetscCall(MatGetLocalSize(In, &locRows, &locCols)); 3122a0806964SMatthew G. Knepley PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &interp)); 3123a0806964SMatthew G. Knepley PetscCall(MatSetType(interp, MATPREALLOCATOR)); 3124a0806964SMatthew G. Knepley PetscCall(MatSetSizes(interp, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE)); 3125a0806964SMatthew G. Knepley PetscCall(MatSetUp(interp)); 3126a0806964SMatthew G. Knepley for (s = 0; s < 2; ++s) { 31274ef9d792SMatthew G. Knepley for (field = 0; field < Nf; ++field) { 31284ef9d792SMatthew G. Knepley PetscObject obj; 31294ef9d792SMatthew G. Knepley PetscClassId id; 3130c0d7054bSMatthew G. Knepley PetscDualSpace Q = NULL; 3131ef0bb6c7SMatthew G. Knepley PetscTabulation T = NULL; 31324ef9d792SMatthew G. Knepley PetscQuadrature f; 31334ef9d792SMatthew G. Knepley const PetscReal *qpoints, *qweights; 3134d0f6233fSMatthew G. Knepley PetscInt Nc, qNc, Np, fpdim, off, i, d; 31354ef9d792SMatthew G. Knepley 3136d0f6233fSMatthew G. Knepley PetscCall(PetscDSGetFieldOffset(prob, field, &off)); 31379566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 31389566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 31394ef9d792SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 31404ef9d792SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 31414ef9d792SMatthew G. Knepley 31429566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(fe, &Q)); 31439566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 3144a0806964SMatthew G. Knepley if (s) PetscCall(PetscFECreateTabulation(fe, 1, 1, x, 0, &T)); 31454ef9d792SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 31464ef9d792SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 31474ef9d792SMatthew G. Knepley 31489566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 31494ef9d792SMatthew G. Knepley Nc = 1; 315063a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 31519566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &fpdim)); 31524ef9d792SMatthew G. Knepley /* For each fine grid cell */ 31534ef9d792SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 31544ef9d792SMatthew G. Knepley PetscInt *findices, *cindices; 31554ef9d792SMatthew G. Knepley PetscInt numFIndices, numCIndices; 31564ef9d792SMatthew G. Knepley 31579566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 31589566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 3159d0f6233fSMatthew 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); 31604ef9d792SMatthew G. Knepley for (i = 0; i < fpdim; ++i) { 31614ef9d792SMatthew G. Knepley Vec pointVec; 31624ef9d792SMatthew G. Knepley PetscScalar *pV; 316312111d7cSToby Isaac PetscSF coarseCellSF = NULL; 31643a93e3b7SToby Isaac const PetscSFNode *coarseCells; 3165d0f6233fSMatthew G. Knepley PetscInt numCoarseCells, cpdim, row = findices[i + off], q, c, j; 31664ef9d792SMatthew G. Knepley 31674ef9d792SMatthew G. Knepley /* Get points from the dual basis functional quadrature */ 31689566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Q, i, &f)); 31699566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights)); 317063a3b9bcSJacob 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); 31719566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Np * dim, &pointVec)); 31729566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 31739566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 31744ef9d792SMatthew G. Knepley for (q = 0; q < Np; ++q) { 3175c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3176c330f8ffSToby Isaac 31774ef9d792SMatthew G. Knepley /* Transform point to real space */ 3178c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 31794ef9d792SMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 31804ef9d792SMatthew G. Knepley } 31819566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 31824ef9d792SMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 31831555c271SMatthew G. Knepley /* OPT: Read this out from preallocation information */ 31849566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 31854ef9d792SMatthew G. Knepley /* Update preallocation info */ 31869566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 31875f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Np, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 31889566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 31894ef9d792SMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 3190826eb36dSMatthew G. Knepley PetscReal pVReal[3]; 3191c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3192826eb36dSMatthew G. Knepley 31939566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3194a0806964SMatthew G. Knepley if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetDimension((PetscFE)obj, &cpdim)); 3195a0806964SMatthew G. Knepley else cpdim = 1; 3196a0806964SMatthew G. Knepley 3197a0806964SMatthew G. Knepley if (s) { 31984ef9d792SMatthew G. Knepley /* Transform points from real space to coarse reference space */ 31999566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc)); 3200e2d86523SMatthew G. Knepley for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]); 3201c330f8ffSToby Isaac CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 32024ef9d792SMatthew G. Knepley 32034ef9d792SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 32044ef9d792SMatthew G. Knepley /* Evaluate coarse basis on contained point */ 3205a0806964SMatthew G. Knepley PetscCall(PetscFEComputeTabulation((PetscFE)obj, 1, x, 0, T)); 32069566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 32074ef9d792SMatthew G. Knepley /* Get elemMat entries by multiplying by weight */ 32084ef9d792SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3209ef0bb6c7SMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j * Nc + c] * qweights[ccell * qNc + c]; 32104ef9d792SMatthew G. Knepley } 32114ef9d792SMatthew G. Knepley } else { 32124ef9d792SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 32139c3cf19fSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * qweights[ccell * qNc + c]; 32144ef9d792SMatthew G. Knepley } 32154ef9d792SMatthew G. Knepley } 32169566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 3217a0806964SMatthew G. Knepley } 3218a0806964SMatthew G. Knepley /* Update interpolator */ 3219d0f6233fSMatthew G. Knepley PetscCheck(numCIndices == totDim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, totDim); 3220a0806964SMatthew G. Knepley PetscCall(MatSetValues(interp, 1, &row, cpdim, &cindices[off], elemMat, INSERT_VALUES)); 32219566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 32224ef9d792SMatthew G. Knepley } 32239566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 32249566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 32259566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 32264ef9d792SMatthew G. Knepley } 32279566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 32284ef9d792SMatthew G. Knepley } 3229a0806964SMatthew G. Knepley if (s && id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T)); 3230a0806964SMatthew G. Knepley } 3231a0806964SMatthew G. Knepley if (!s) { 3232a0806964SMatthew G. Knepley PetscCall(MatAssemblyBegin(interp, MAT_FINAL_ASSEMBLY)); 3233a0806964SMatthew G. Knepley PetscCall(MatAssemblyEnd(interp, MAT_FINAL_ASSEMBLY)); 3234a0806964SMatthew G. Knepley PetscCall(MatPreallocatorPreallocate(interp, PETSC_TRUE, In)); 3235a0806964SMatthew G. Knepley PetscCall(MatDestroy(&interp)); 3236a0806964SMatthew G. Knepley interp = In; 3237a0806964SMatthew G. Knepley } 32384ef9d792SMatthew G. Knepley } 32399566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0, J, invJ)); 32409566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0c, Jc, invJc)); 32419566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 32429566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY)); 32439566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY)); 32449566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 32453ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 32464ef9d792SMatthew G. Knepley } 32474ef9d792SMatthew G. Knepley 324846fa42a0SMatthew G. Knepley /*@ 32490318f8a0SStefano Zampini DMPlexComputeMassMatrixGeneral - Form the local portion of the mass matrix from the coarse `DM` to a non-nested fine `DM`. 3250bd041c0cSMatthew G. Knepley 3251bd041c0cSMatthew G. Knepley Input Parameters: 3252bd041c0cSMatthew G. Knepley + dmf - The fine mesh 3253bd041c0cSMatthew G. Knepley . dmc - The coarse mesh 3254bd041c0cSMatthew G. Knepley - user - The user context 3255bd041c0cSMatthew G. Knepley 3256bd041c0cSMatthew G. Knepley Output Parameter: 3257bd041c0cSMatthew G. Knepley . mass - The mass matrix 3258bd041c0cSMatthew G. Knepley 3259bd041c0cSMatthew G. Knepley Level: developer 3260bd041c0cSMatthew G. Knepley 3261ae3cf2c1SStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeMassMatrixNested()`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeInterpolatorGeneral()` 3262bd041c0cSMatthew G. Knepley @*/ 3263d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, void *user) 3264d71ae5a4SJacob Faibussowitsch { 3265bd041c0cSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmf->data; 3266bd041c0cSMatthew G. Knepley const char *name = "Mass Matrix"; 3267bd041c0cSMatthew G. Knepley PetscDS prob; 3268bd041c0cSMatthew G. Knepley PetscSection fsection, csection, globalFSection, globalCSection; 3269e8f14785SLisandro Dalcin PetscHSetIJ ht; 3270bd041c0cSMatthew G. Knepley PetscLayout rLayout; 3271bd041c0cSMatthew G. Knepley PetscInt *dnz, *onz; 3272bd041c0cSMatthew G. Knepley PetscInt locRows, rStart, rEnd; 3273bd041c0cSMatthew G. Knepley PetscReal *x, *v0, *J, *invJ, detJ; 3274bd041c0cSMatthew G. Knepley PetscReal *v0c, *Jc, *invJc, detJc; 3275bd041c0cSMatthew G. Knepley PetscScalar *elemMat; 3276bd041c0cSMatthew G. Knepley PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell; 3277bd041c0cSMatthew G. Knepley 3278bd041c0cSMatthew G. Knepley PetscFunctionBegin; 32799566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dmc, &dim)); 32809566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 32819566063dSJacob Faibussowitsch PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL)); 32829566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 32839566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ)); 32849566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc)); 32859566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 32869566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 32879566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 32889566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 32899566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd)); 32909566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 32919566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totDim, &elemMat)); 3292bd041c0cSMatthew G. Knepley 32939566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mass, &locRows, NULL)); 32949566063dSJacob Faibussowitsch PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)mass), &rLayout)); 32959566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(rLayout, locRows)); 32969566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetBlockSize(rLayout, 1)); 32979566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(rLayout)); 32989566063dSJacob Faibussowitsch PetscCall(PetscLayoutGetRange(rLayout, &rStart, &rEnd)); 32999566063dSJacob Faibussowitsch PetscCall(PetscLayoutDestroy(&rLayout)); 33009566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz)); 33019566063dSJacob Faibussowitsch PetscCall(PetscHSetIJCreate(&ht)); 3302bd041c0cSMatthew G. Knepley for (field = 0; field < Nf; ++field) { 3303bd041c0cSMatthew G. Knepley PetscObject obj; 3304bd041c0cSMatthew G. Knepley PetscClassId id; 3305bd041c0cSMatthew G. Knepley PetscQuadrature quad; 3306bd041c0cSMatthew G. Knepley const PetscReal *qpoints; 3307bd041c0cSMatthew G. Knepley PetscInt Nq, Nc, i, d; 3308bd041c0cSMatthew G. Knepley 33099566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 33109566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 33119566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad)); 33129566063dSJacob Faibussowitsch else PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad)); 33139566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL)); 3314bd041c0cSMatthew G. Knepley /* For each fine grid cell */ 3315bd041c0cSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 3316bd041c0cSMatthew G. Knepley Vec pointVec; 3317bd041c0cSMatthew G. Knepley PetscScalar *pV; 3318bd041c0cSMatthew G. Knepley PetscSF coarseCellSF = NULL; 3319bd041c0cSMatthew G. Knepley const PetscSFNode *coarseCells; 3320bd041c0cSMatthew G. Knepley PetscInt numCoarseCells, q, c; 3321bd041c0cSMatthew G. Knepley PetscInt *findices, *cindices; 3322bd041c0cSMatthew G. Knepley PetscInt numFIndices, numCIndices; 3323bd041c0cSMatthew G. Knepley 33249566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 33259566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 3326bd041c0cSMatthew G. Knepley /* Get points from the quadrature */ 33279566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec)); 33289566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 33299566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 3330bd041c0cSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 3331c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3332c330f8ffSToby Isaac 3333bd041c0cSMatthew G. Knepley /* Transform point to real space */ 3334c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 3335bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 3336bd041c0cSMatthew G. Knepley } 33379566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 3338bd041c0cSMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 33399566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 33409566063dSJacob Faibussowitsch PetscCall(PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view")); 3341bd041c0cSMatthew G. Knepley /* Update preallocation info */ 33429566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 33435f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 3344bd041c0cSMatthew G. Knepley { 3345e8f14785SLisandro Dalcin PetscHashIJKey key; 3346e8f14785SLisandro Dalcin PetscBool missing; 3347bd041c0cSMatthew G. Knepley 3348bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 3349e8f14785SLisandro Dalcin key.i = findices[i]; 3350e8f14785SLisandro Dalcin if (key.i >= 0) { 3351bd041c0cSMatthew G. Knepley /* Get indices for coarse elements */ 3352bd041c0cSMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 33539566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3354bd041c0cSMatthew G. Knepley for (c = 0; c < numCIndices; ++c) { 3355e8f14785SLisandro Dalcin key.j = cindices[c]; 3356e8f14785SLisandro Dalcin if (key.j < 0) continue; 33579566063dSJacob Faibussowitsch PetscCall(PetscHSetIJQueryAdd(ht, key, &missing)); 3358bd041c0cSMatthew G. Knepley if (missing) { 3359e8f14785SLisandro Dalcin if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i - rStart]; 3360e8f14785SLisandro Dalcin else ++onz[key.i - rStart]; 3361bd041c0cSMatthew G. Knepley } 3362bd041c0cSMatthew G. Knepley } 33639566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3364bd041c0cSMatthew G. Knepley } 3365bd041c0cSMatthew G. Knepley } 3366bd041c0cSMatthew G. Knepley } 3367bd041c0cSMatthew G. Knepley } 33689566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 33699566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 33709566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3371bd041c0cSMatthew G. Knepley } 3372bd041c0cSMatthew G. Knepley } 33739566063dSJacob Faibussowitsch PetscCall(PetscHSetIJDestroy(&ht)); 33749566063dSJacob Faibussowitsch PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL)); 33759566063dSJacob Faibussowitsch PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE)); 33769566063dSJacob Faibussowitsch PetscCall(PetscFree2(dnz, onz)); 3377bd041c0cSMatthew G. Knepley for (field = 0; field < Nf; ++field) { 3378bd041c0cSMatthew G. Knepley PetscObject obj; 3379bd041c0cSMatthew G. Knepley PetscClassId id; 3380ef0bb6c7SMatthew G. Knepley PetscTabulation T, Tfine; 3381bd041c0cSMatthew G. Knepley PetscQuadrature quad; 3382bd041c0cSMatthew G. Knepley const PetscReal *qpoints, *qweights; 3383bd041c0cSMatthew G. Knepley PetscInt Nq, Nc, i, d; 3384bd041c0cSMatthew G. Knepley 33859566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 33869566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 3387ef0bb6c7SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 33889566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad)); 33899566063dSJacob Faibussowitsch PetscCall(PetscFEGetCellTabulation((PetscFE)obj, 1, &Tfine)); 33909566063dSJacob Faibussowitsch PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, 1, x, 0, &T)); 3391ef0bb6c7SMatthew G. Knepley } else { 33929566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad)); 3393ef0bb6c7SMatthew G. Knepley } 33949566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights)); 3395bd041c0cSMatthew G. Knepley /* For each fine grid cell */ 3396bd041c0cSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 3397bd041c0cSMatthew G. Knepley Vec pointVec; 3398bd041c0cSMatthew G. Knepley PetscScalar *pV; 3399bd041c0cSMatthew G. Knepley PetscSF coarseCellSF = NULL; 3400bd041c0cSMatthew G. Knepley const PetscSFNode *coarseCells; 3401bd041c0cSMatthew G. Knepley PetscInt numCoarseCells, cpdim, q, c, j; 3402bd041c0cSMatthew G. Knepley PetscInt *findices, *cindices; 3403bd041c0cSMatthew G. Knepley PetscInt numFIndices, numCIndices; 3404bd041c0cSMatthew G. Knepley 34059566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 34069566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 3407bd041c0cSMatthew G. Knepley /* Get points from the quadrature */ 34089566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec)); 34099566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 34109566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 3411bd041c0cSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 3412c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3413c330f8ffSToby Isaac 3414bd041c0cSMatthew G. Knepley /* Transform point to real space */ 3415c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 3416bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 3417bd041c0cSMatthew G. Knepley } 34189566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 3419bd041c0cSMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 34209566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 3421bd041c0cSMatthew G. Knepley /* Update matrix */ 34229566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 34235f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 34249566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 3425bd041c0cSMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 3426bd041c0cSMatthew G. Knepley PetscReal pVReal[3]; 3427c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3428c330f8ffSToby Isaac 34299566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3430bd041c0cSMatthew G. Knepley /* Transform points from real space to coarse reference space */ 34319566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc)); 3432bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]); 3433c330f8ffSToby Isaac CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 3434bd041c0cSMatthew G. Knepley 3435bd041c0cSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 3436bd041c0cSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 3437bd041c0cSMatthew G. Knepley 3438bd041c0cSMatthew G. Knepley /* Evaluate coarse basis on contained point */ 34399566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cpdim)); 34409566063dSJacob Faibussowitsch PetscCall(PetscFEComputeTabulation(fe, 1, x, 0, T)); 3441bd041c0cSMatthew G. Knepley /* Get elemMat entries by multiplying by weight */ 3442bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 34439566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 3444bd041c0cSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3445ef0bb6c7SMatthew 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; 3446bd041c0cSMatthew G. Knepley } 3447bd041c0cSMatthew G. Knepley /* Update interpolator */ 34489566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 344963a3b9bcSJacob Faibussowitsch PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim); 34509566063dSJacob Faibussowitsch PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES)); 3451bd041c0cSMatthew G. Knepley } 3452bd041c0cSMatthew G. Knepley } else { 3453bd041c0cSMatthew G. Knepley cpdim = 1; 3454bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 34559566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 3456bd041c0cSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3457bd041c0cSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * 1.0 * qweights[ccell * Nc + c] * detJ; 3458bd041c0cSMatthew G. Knepley } 3459bd041c0cSMatthew G. Knepley /* Update interpolator */ 34609566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 346163a3b9bcSJacob 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)); 346263a3b9bcSJacob Faibussowitsch PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim); 34639566063dSJacob Faibussowitsch PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES)); 3464bd041c0cSMatthew G. Knepley } 3465bd041c0cSMatthew G. Knepley } 34669566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3467bd041c0cSMatthew G. Knepley } 34689566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 34699566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 34709566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 34719566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3472bd041c0cSMatthew G. Knepley } 34739566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T)); 3474bd041c0cSMatthew G. Knepley } 34759566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0, J, invJ)); 34769566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0c, Jc, invJc)); 34779566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 34789566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY)); 34799566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY)); 34803ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3481bd041c0cSMatthew G. Knepley } 3482bd041c0cSMatthew G. Knepley 3483bd041c0cSMatthew G. Knepley /*@ 348446fa42a0SMatthew G. Knepley DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns 348546fa42a0SMatthew G. Knepley 348646fa42a0SMatthew G. Knepley Input Parameters: 348746fa42a0SMatthew G. Knepley + dmc - The coarse mesh 348860225df5SJacob Faibussowitsch . dmf - The fine mesh 348946fa42a0SMatthew G. Knepley - user - The user context 349046fa42a0SMatthew G. Knepley 349146fa42a0SMatthew G. Knepley Output Parameter: 349246fa42a0SMatthew G. Knepley . sc - The mapping 349346fa42a0SMatthew G. Knepley 349446fa42a0SMatthew G. Knepley Level: developer 349546fa42a0SMatthew G. Knepley 3496ae3cf2c1SStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()` 349746fa42a0SMatthew G. Knepley @*/ 3498d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user) 3499d71ae5a4SJacob Faibussowitsch { 3500e9d4ef1bSMatthew G. Knepley PetscDS prob; 35017c927364SMatthew G. Knepley PetscFE *feRef; 350297c42addSMatthew G. Knepley PetscFV *fvRef; 35037c927364SMatthew G. Knepley Vec fv, cv; 35047c927364SMatthew G. Knepley IS fis, cis; 35057c927364SMatthew G. Knepley PetscSection fsection, fglobalSection, csection, cglobalSection; 35067c927364SMatthew G. Knepley PetscInt *cmap, *cellCIndices, *cellFIndices, *cindices, *findices; 3507485ad865SMatthew G. Knepley PetscInt cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, c, dim, d, startC, endC, offsetC, offsetF, m; 35086f3d3cbcSMatthew G. Knepley PetscBool *needAvg; 35097c927364SMatthew G. Knepley 35107c927364SMatthew G. Knepley PetscFunctionBegin; 35119566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InjectorFEM, dmc, dmf, 0, 0)); 35129566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dmf, &dim)); 35139566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 35149566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &fglobalSection)); 35159566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 35169566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &cglobalSection)); 35179566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(fsection, &Nf)); 35189566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd)); 35199566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 35209566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(Nf, &feRef, Nf, &fvRef, Nf, &needAvg)); 35217c927364SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 352297c42addSMatthew G. Knepley PetscObject obj; 352397c42addSMatthew G. Knepley PetscClassId id; 3524aa7890ccSMatthew G. Knepley PetscInt fNb = 0, Nc = 0; 35257c927364SMatthew G. Knepley 35269566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 35279566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 352897c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 352997c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 35306f3d3cbcSMatthew G. Knepley PetscSpace sp; 35319b2fc754SMatthew G. Knepley PetscInt maxDegree; 353297c42addSMatthew G. Knepley 35339566063dSJacob Faibussowitsch PetscCall(PetscFERefine(fe, &feRef[f])); 35349566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feRef[f], &fNb)); 35359566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 35369566063dSJacob Faibussowitsch PetscCall(PetscFEGetBasisSpace(fe, &sp)); 35379566063dSJacob Faibussowitsch PetscCall(PetscSpaceGetDegree(sp, NULL, &maxDegree)); 35389b2fc754SMatthew G. Knepley if (!maxDegree) needAvg[f] = PETSC_TRUE; 353997c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 354097c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 354197c42addSMatthew G. Knepley PetscDualSpace Q; 354297c42addSMatthew G. Knepley 35439566063dSJacob Faibussowitsch PetscCall(PetscFVRefine(fv, &fvRef[f])); 35449566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[f], &Q)); 35459566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &fNb)); 35469566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 35476f3d3cbcSMatthew G. Knepley needAvg[f] = PETSC_TRUE; 354897c42addSMatthew G. Knepley } 3549d172c84bSMatthew G. Knepley fTotDim += fNb; 35507c927364SMatthew G. Knepley } 35519566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &cTotDim)); 35529566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(cTotDim, &cmap)); 35537c927364SMatthew G. Knepley for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) { 35547c927364SMatthew G. Knepley PetscFE feC; 355597c42addSMatthew G. Knepley PetscFV fvC; 35567c927364SMatthew G. Knepley PetscDualSpace QF, QC; 3557d172c84bSMatthew G. Knepley PetscInt order = -1, NcF, NcC, fpdim, cpdim; 35587c927364SMatthew G. Knepley 355997c42addSMatthew G. Knepley if (feRef[field]) { 35609566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&feC)); 35619566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feC, &NcC)); 35629566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feRef[field], &NcF)); 35639566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feRef[field], &QF)); 35649566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetOrder(QF, &order)); 35659566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QF, &fpdim)); 35669566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feC, &QC)); 35679566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QC, &cpdim)); 356897c42addSMatthew G. Knepley } else { 35699566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fvC)); 35709566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvC, &NcC)); 35719566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvRef[field], &NcF)); 35729566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[field], &QF)); 35739566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QF, &fpdim)); 35749566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvC, &QC)); 35759566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QC, &cpdim)); 357697c42addSMatthew G. Knepley } 357763a3b9bcSJacob 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); 35787c927364SMatthew G. Knepley for (c = 0; c < cpdim; ++c) { 35797c927364SMatthew G. Knepley PetscQuadrature cfunc; 3580d172c84bSMatthew G. Knepley const PetscReal *cqpoints, *cqweights; 3581d172c84bSMatthew G. Knepley PetscInt NqcC, NpC; 358297c42addSMatthew G. Knepley PetscBool found = PETSC_FALSE; 35837c927364SMatthew G. Knepley 35849566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(QC, c, &cfunc)); 35859566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights)); 358663a3b9bcSJacob 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); 35871dca8a05SBarry Smith PetscCheck(NpC == 1 || !feRef[field], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments"); 35887c927364SMatthew G. Knepley for (f = 0; f < fpdim; ++f) { 35897c927364SMatthew G. Knepley PetscQuadrature ffunc; 3590d172c84bSMatthew G. Knepley const PetscReal *fqpoints, *fqweights; 35917c927364SMatthew G. Knepley PetscReal sum = 0.0; 3592d172c84bSMatthew G. Knepley PetscInt NqcF, NpF; 35937c927364SMatthew G. Knepley 35949566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(QF, f, &ffunc)); 35959566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights)); 359663a3b9bcSJacob 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); 35977c927364SMatthew G. Knepley if (NpC != NpF) continue; 35987c927364SMatthew G. Knepley for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]); 35997c927364SMatthew G. Knepley if (sum > 1.0e-9) continue; 3600d172c84bSMatthew G. Knepley for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d] * fqweights[d]); 3601d172c84bSMatthew G. Knepley if (sum < 1.0e-9) continue; 3602d172c84bSMatthew G. Knepley cmap[offsetC + c] = offsetF + f; 360397c42addSMatthew G. Knepley found = PETSC_TRUE; 36047c927364SMatthew G. Knepley break; 36057c927364SMatthew G. Knepley } 360697c42addSMatthew G. Knepley if (!found) { 360797c42addSMatthew G. Knepley /* TODO We really want the average here, but some asshole put VecScatter in the interface */ 3608d172c84bSMatthew G. Knepley if (fvRef[field] || (feRef[field] && order == 0)) { 3609d172c84bSMatthew G. Knepley cmap[offsetC + c] = offsetF + 0; 361097c42addSMatthew G. Knepley } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection"); 361197c42addSMatthew G. Knepley } 36127c927364SMatthew G. Knepley } 3613d172c84bSMatthew G. Knepley offsetC += cpdim; 3614d172c84bSMatthew G. Knepley offsetF += fpdim; 36157c927364SMatthew G. Knepley } 36169371c9d4SSatish Balay for (f = 0; f < Nf; ++f) { 36179371c9d4SSatish Balay PetscCall(PetscFEDestroy(&feRef[f])); 36189371c9d4SSatish Balay PetscCall(PetscFVDestroy(&fvRef[f])); 36199371c9d4SSatish Balay } 36209566063dSJacob Faibussowitsch PetscCall(PetscFree3(feRef, fvRef, needAvg)); 36217c927364SMatthew G. Knepley 36229566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmf, &fv)); 36239566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmc, &cv)); 36249566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(cv, &startC, &endC)); 36259566063dSJacob Faibussowitsch PetscCall(PetscSectionGetConstrainedStorageSize(cglobalSection, &m)); 36269566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(cTotDim, &cellCIndices, fTotDim, &cellFIndices)); 36279566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &cindices)); 36289566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &findices)); 36297c927364SMatthew G. Knepley for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1; 36307c927364SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 36319566063dSJacob Faibussowitsch PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices)); 36327c927364SMatthew G. Knepley for (d = 0; d < cTotDim; ++d) { 36330bd915a7SMatthew G. Knepley if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue; 3634d2457c26SMatthew 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]]); 36357c927364SMatthew G. Knepley cindices[cellCIndices[d] - startC] = cellCIndices[d]; 36367c927364SMatthew G. Knepley findices[cellCIndices[d] - startC] = cellFIndices[cmap[d]]; 36377c927364SMatthew G. Knepley } 36387c927364SMatthew G. Knepley } 36399566063dSJacob Faibussowitsch PetscCall(PetscFree(cmap)); 36409566063dSJacob Faibussowitsch PetscCall(PetscFree2(cellCIndices, cellFIndices)); 36417c927364SMatthew G. Knepley 36429566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis)); 36439566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis)); 36449566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(cv, cis, fv, fis, sc)); 36459566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cis)); 36469566063dSJacob Faibussowitsch PetscCall(ISDestroy(&fis)); 36479566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmf, &fv)); 36489566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmc, &cv)); 36499566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InjectorFEM, dmc, dmf, 0, 0)); 36503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3651cb1e1211SMatthew G Knepley } 3652a1cf66bbSMatthew G. Knepley 36532f856554SMatthew G. Knepley /*@C 36542f856554SMatthew G. Knepley DMPlexGetCellFields - Retrieve the field values values for a chunk of cells 36552f856554SMatthew G. Knepley 36562f856554SMatthew G. Knepley Input Parameters: 3657a1cb98faSBarry Smith + dm - The `DM` 36582f856554SMatthew G. Knepley . cellIS - The cells to include 36592f856554SMatthew G. Knepley . locX - A local vector with the solution fields 36602f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 36612f856554SMatthew G. Knepley - locA - A local vector with auxiliary fields, or NULL 36622f856554SMatthew G. Knepley 36632f856554SMatthew G. Knepley Output Parameters: 36642f856554SMatthew G. Knepley + u - The field coefficients 36652f856554SMatthew G. Knepley . u_t - The fields derivative coefficients 36662f856554SMatthew G. Knepley - a - The auxiliary field coefficients 36672f856554SMatthew G. Knepley 36682f856554SMatthew G. Knepley Level: developer 36692f856554SMatthew G. Knepley 36701cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 36712f856554SMatthew G. Knepley @*/ 3672d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3673d71ae5a4SJacob Faibussowitsch { 36742f856554SMatthew G. Knepley DM plex, plexA = NULL; 3675a6e0b375SMatthew G. Knepley DMEnclosureType encAux; 36762f856554SMatthew G. Knepley PetscSection section, sectionAux; 36772f856554SMatthew G. Knepley PetscDS prob; 36782f856554SMatthew G. Knepley const PetscInt *cells; 36792f856554SMatthew G. Knepley PetscInt cStart, cEnd, numCells, totDim, totDimAux, c; 36802f856554SMatthew G. Knepley 36812f856554SMatthew G. Knepley PetscFunctionBegin; 36822f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3683064a246eSJacob Faibussowitsch PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 3684ad540459SPierre Jolivet if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 4); 3685ad540459SPierre Jolivet if (locA) PetscValidHeaderSpecific(locA, VEC_CLASSID, 5); 36864f572ea9SToby Isaac PetscAssertPointer(u, 6); 36874f572ea9SToby Isaac PetscAssertPointer(u_t, 7); 36884f572ea9SToby Isaac PetscAssertPointer(a, 8); 36899566063dSJacob Faibussowitsch PetscCall(DMPlexConvertPlex(dm, &plex, PETSC_FALSE)); 36909566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 36919566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 369207218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL)); 36939566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 36942f856554SMatthew G. Knepley if (locA) { 36952f856554SMatthew G. Knepley DM dmAux; 36962f856554SMatthew G. Knepley PetscDS probAux; 36972f856554SMatthew G. Knepley 36989566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 36999566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 37009566063dSJacob Faibussowitsch PetscCall(DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE)); 37019566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 37029566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 37039566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 37042f856554SMatthew G. Knepley } 37052f856554SMatthew G. Knepley numCells = cEnd - cStart; 37069566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u)); 37079371c9d4SSatish Balay if (locX_t) PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u_t)); 3708ad540459SPierre Jolivet else *u_t = NULL; 37099371c9d4SSatish Balay if (locA) PetscCall(DMGetWorkArray(dm, numCells * totDimAux, MPIU_SCALAR, a)); 3710ad540459SPierre Jolivet else *a = NULL; 37112f856554SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 37122f856554SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 37132f856554SMatthew G. Knepley const PetscInt cind = c - cStart; 37142f856554SMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a; 37152f856554SMatthew G. Knepley PetscInt i; 37162f856554SMatthew G. Knepley 37179566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x)); 37182f856554SMatthew G. Knepley for (i = 0; i < totDim; ++i) ul[cind * totDim + i] = x[i]; 37199566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x)); 37202f856554SMatthew G. Knepley if (locX_t) { 37219566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t)); 37222f856554SMatthew G. Knepley for (i = 0; i < totDim; ++i) ul_t[cind * totDim + i] = x_t[i]; 37239566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t)); 37242f856554SMatthew G. Knepley } 37252f856554SMatthew G. Knepley if (locA) { 37262f856554SMatthew G. Knepley PetscInt subcell; 37279566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell)); 37289566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x)); 37292f856554SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) al[cind * totDimAux + i] = x[i]; 37309566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x)); 37312f856554SMatthew G. Knepley } 37322f856554SMatthew G. Knepley } 37339566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 37349566063dSJacob Faibussowitsch if (locA) PetscCall(DMDestroy(&plexA)); 37359566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 37363ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 37372f856554SMatthew G. Knepley } 37382f856554SMatthew G. Knepley 37392f856554SMatthew G. Knepley /*@C 37402f856554SMatthew G. Knepley DMPlexRestoreCellFields - Restore the field values values for a chunk of cells 37412f856554SMatthew G. Knepley 37422f856554SMatthew G. Knepley Input Parameters: 3743a1cb98faSBarry Smith + dm - The `DM` 37442f856554SMatthew G. Knepley . cellIS - The cells to include 37452f856554SMatthew G. Knepley . locX - A local vector with the solution fields 37462f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 37472f856554SMatthew G. Knepley - locA - A local vector with auxiliary fields, or NULL 37482f856554SMatthew G. Knepley 37492f856554SMatthew G. Knepley Output Parameters: 37502f856554SMatthew G. Knepley + u - The field coefficients 37512f856554SMatthew G. Knepley . u_t - The fields derivative coefficients 37522f856554SMatthew G. Knepley - a - The auxiliary field coefficients 37532f856554SMatthew G. Knepley 37542f856554SMatthew G. Knepley Level: developer 37552f856554SMatthew G. Knepley 37561cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 37572f856554SMatthew G. Knepley @*/ 3758d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3759d71ae5a4SJacob Faibussowitsch { 37602f856554SMatthew G. Knepley PetscFunctionBegin; 37619566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u)); 37629566063dSJacob Faibussowitsch if (locX_t) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t)); 37639566063dSJacob Faibussowitsch if (locA) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a)); 37643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 37652f856554SMatthew G. Knepley } 37662f856554SMatthew G. Knepley 3767a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexGetHybridCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3768d71ae5a4SJacob Faibussowitsch { 376907218a29SMatthew G. Knepley DM plex, plexA = NULL; 377007218a29SMatthew G. Knepley DMEnclosureType encAux; 377107218a29SMatthew G. Knepley PetscSection section, sectionAux; 377207218a29SMatthew G. Knepley PetscDS ds, dsIn; 37736528b96dSMatthew G. Knepley const PetscInt *cells; 377407218a29SMatthew G. Knepley PetscInt cStart, cEnd, numCells, c, totDim, totDimAux, Nf, f; 37756528b96dSMatthew G. Knepley 37766528b96dSMatthew G. Knepley PetscFunctionBegin; 377707218a29SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 377807218a29SMatthew G. Knepley PetscValidHeaderSpecific(cellIS, IS_CLASSID, 2); 377907218a29SMatthew G. Knepley PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 378007218a29SMatthew G. Knepley if (locX_t) { PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 4); } 378107218a29SMatthew G. Knepley if (locA) { PetscValidHeaderSpecific(locA, VEC_CLASSID, 5); } 37824f572ea9SToby Isaac PetscAssertPointer(u, 6); 37834f572ea9SToby Isaac PetscAssertPointer(u_t, 7); 37844f572ea9SToby Isaac PetscAssertPointer(a, 8); 378507218a29SMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 378607218a29SMatthew G. Knepley numCells = cEnd - cStart; 378707218a29SMatthew G. Knepley PetscCall(DMPlexConvertPlex(dm, &plex, PETSC_FALSE)); 378807218a29SMatthew G. Knepley PetscCall(DMGetLocalSection(dm, §ion)); 378907218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn)); 379007218a29SMatthew G. Knepley PetscCall(PetscDSGetNumFields(dsIn, &Nf)); 379107218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsIn, &totDim)); 379207218a29SMatthew G. Knepley if (locA) { 379307218a29SMatthew G. Knepley DM dmAux; 379407218a29SMatthew G. Knepley PetscDS probAux; 379507218a29SMatthew G. Knepley 379607218a29SMatthew G. Knepley PetscCall(VecGetDM(locA, &dmAux)); 379707218a29SMatthew G. Knepley PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 379807218a29SMatthew G. Knepley PetscCall(DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE)); 379907218a29SMatthew G. Knepley PetscCall(DMGetLocalSection(dmAux, §ionAux)); 380007218a29SMatthew G. Knepley PetscCall(DMGetDS(dmAux, &probAux)); 380107218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 380207218a29SMatthew G. Knepley } 380307218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u)); 380407218a29SMatthew G. Knepley if (locX_t) PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u_t)); 380507218a29SMatthew G. Knepley else { 380607218a29SMatthew G. Knepley *u_t = NULL; 380707218a29SMatthew G. Knepley } 380807218a29SMatthew G. Knepley if (locA) PetscCall(DMGetWorkArray(dm, numCells * totDimAux, MPIU_SCALAR, a)); 380907218a29SMatthew G. Knepley else { 381007218a29SMatthew G. Knepley *a = NULL; 381107218a29SMatthew G. Knepley } 381207218a29SMatthew G. Knepley // Loop over cohesive cells 381307218a29SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 381407218a29SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 381507218a29SMatthew G. Knepley const PetscInt cind = c - cStart; 381674a0c561SMatthew G. Knepley PetscScalar *xf = NULL, *xc = NULL, *x = NULL, *xf_t = NULL, *xc_t = NULL; 38178e3a54c0SPierre Jolivet PetscScalar *ul = &(*u)[cind * totDim], *ul_t = PetscSafePointerPlusOffset(*u_t, cind * totDim); 381807218a29SMatthew G. Knepley const PetscInt *cone, *ornt; 381907218a29SMatthew G. Knepley PetscInt Nx = 0, Nxf, s; 382007218a29SMatthew G. Knepley 382107218a29SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cell, &cone)); 382207218a29SMatthew G. Knepley PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt)); 382307218a29SMatthew G. Knepley // Put in cohesive unknowns 382407218a29SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, &Nxf, &xf)); 382574a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &xf_t)); 382607218a29SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 382707218a29SMatthew G. Knepley PetscInt fdofIn, foff, foffIn; 382807218a29SMatthew G. Knepley PetscBool cohesive; 382907218a29SMatthew G. Knepley 383007218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(dsIn, f, &cohesive)); 383107218a29SMatthew G. Knepley if (!cohesive) continue; 383207218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsIn, f, &fdofIn)); 383307218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldOffsetCohesive(ds, f, &foff)); 383407218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldOffsetCohesive(dsIn, f, &foffIn)); 383507218a29SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul[foffIn + i] = xf[foff + i]; 383674a0c561SMatthew G. Knepley if (locX_t) 383774a0c561SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul_t[foffIn + i] = xf_t[foff + i]; 383807218a29SMatthew G. Knepley Nx += fdofIn; 383907218a29SMatthew G. Knepley } 384007218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, &Nxf, &xf)); 384174a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &xf_t)); 384207218a29SMatthew G. Knepley // Loop over sides of surface 384307218a29SMatthew G. Knepley for (s = 0; s < 2; ++s) { 384407218a29SMatthew G. Knepley const PetscInt *support; 384507218a29SMatthew G. Knepley const PetscInt face = cone[s]; 384607218a29SMatthew G. Knepley PetscInt ssize, ncell, Nxc; 384707218a29SMatthew G. Knepley 384807218a29SMatthew G. Knepley // I don't think I need the face to have 0 orientation in the hybrid cell 384907218a29SMatthew 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]); 385007218a29SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, face, &support)); 385107218a29SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, face, &ssize)); 385207218a29SMatthew G. Knepley if (support[0] == cell) ncell = support[1]; 385307218a29SMatthew G. Knepley else if (support[1] == cell) ncell = support[0]; 385407218a29SMatthew 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); 385507218a29SMatthew G. Knepley // Get closure of both face and cell, stick in cell for normal fields and face for cohesive fields 385607218a29SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plex, section, locX, ncell, &Nxc, &xc)); 385774a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecGetClosure(plex, section, locX_t, ncell, NULL, &xc_t)); 385807218a29SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 385907218a29SMatthew G. Knepley PetscInt fdofIn, foffIn; 386007218a29SMatthew G. Knepley PetscBool cohesive; 386107218a29SMatthew G. Knepley 386207218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(dsIn, f, &cohesive)); 386307218a29SMatthew G. Knepley if (cohesive) continue; 386407218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsIn, f, &fdofIn)); 386507218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldOffsetCohesive(dsIn, f, &foffIn)); 386607218a29SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul[foffIn + s * fdofIn + i] = xc[foffIn + i]; 386774a0c561SMatthew G. Knepley if (locX_t) 386874a0c561SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul_t[foffIn + s * fdofIn + i] = xc_t[foffIn + i]; 386907218a29SMatthew G. Knepley Nx += fdofIn; 387007218a29SMatthew G. Knepley } 387107218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plex, section, locX, ncell, &Nxc, &xc)); 387274a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, ncell, NULL, &xc_t)); 387307218a29SMatthew G. Knepley } 387407218a29SMatthew 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); 387507218a29SMatthew G. Knepley 387607218a29SMatthew G. Knepley if (locA) { 387707218a29SMatthew G. Knepley PetscScalar *al = &(*a)[cind * totDimAux]; 387807218a29SMatthew G. Knepley PetscInt subcell; 387907218a29SMatthew G. Knepley 388007218a29SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell)); 388107218a29SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, &Nx, &x)); 388207218a29SMatthew 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); 388307218a29SMatthew G. Knepley for (PetscInt i = 0; i < totDimAux; ++i) al[i] = x[i]; 388407218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, &Nx, &x)); 388507218a29SMatthew G. Knepley } 388607218a29SMatthew G. Knepley } 388707218a29SMatthew G. Knepley PetscCall(DMDestroy(&plex)); 388807218a29SMatthew G. Knepley PetscCall(DMDestroy(&plexA)); 388907218a29SMatthew G. Knepley PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 389007218a29SMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 389107218a29SMatthew G. Knepley } 389207218a29SMatthew G. Knepley 389307218a29SMatthew G. Knepley /* 38943e2b0218SMatthew G. Knepley DMPlexGetHybridFields - Get the field values for the negative side (s = 0) and positive side (s = 1) of the interface 389507218a29SMatthew G. Knepley 389607218a29SMatthew G. Knepley Input Parameters: 389707218a29SMatthew G. Knepley + dm - The full domain DM 389807218a29SMatthew G. Knepley . dmX - An array of DM for the field, say an auxiliary DM, indexed by s 389907218a29SMatthew G. Knepley . dsX - An array of PetscDS for the field, indexed by s 390007218a29SMatthew G. Knepley . cellIS - The interface cells for which we want values 390107218a29SMatthew G. Knepley . locX - An array of local vectors with the field values, indexed by s 390207218a29SMatthew G. Knepley - useCell - Flag to have values come from neighboring cell rather than endcap face 390307218a29SMatthew G. Knepley 390407218a29SMatthew G. Knepley Output Parameter: 390507218a29SMatthew G. Knepley . x - An array of field values, indexed by s 390607218a29SMatthew G. Knepley 390707218a29SMatthew G. Knepley Note: 390876fbde31SPierre Jolivet The arrays in `x` will be allocated using `DMGetWorkArray()`, and must be returned using `DMPlexRestoreHybridFields()`. 390907218a29SMatthew G. Knepley 391007218a29SMatthew G. Knepley Level: advanced 391107218a29SMatthew G. Knepley 391276fbde31SPierre Jolivet .seealso: `DMPlexRestoreHybridFields()`, `DMGetWorkArray()` 391307218a29SMatthew G. Knepley */ 391407218a29SMatthew G. Knepley static PetscErrorCode DMPlexGetHybridFields(DM dm, DM dmX[], PetscDS dsX[], IS cellIS, Vec locX[], PetscBool useCell, PetscScalar *x[]) 391507218a29SMatthew G. Knepley { 391607218a29SMatthew G. Knepley DM plexX[2]; 391707218a29SMatthew G. Knepley DMEnclosureType encX[2]; 391807218a29SMatthew G. Knepley PetscSection sectionX[2]; 391907218a29SMatthew G. Knepley const PetscInt *cells; 392007218a29SMatthew G. Knepley PetscInt cStart, cEnd, numCells, c, s, totDimX[2]; 392107218a29SMatthew G. Knepley 392207218a29SMatthew G. Knepley PetscFunctionBegin; 39234f572ea9SToby Isaac PetscAssertPointer(locX, 5); 392407218a29SMatthew G. Knepley if (!locX[0] || !locX[1]) PetscFunctionReturn(PETSC_SUCCESS); 39254f572ea9SToby Isaac PetscAssertPointer(dmX, 2); 39264f572ea9SToby Isaac PetscAssertPointer(dsX, 3); 392707218a29SMatthew G. Knepley PetscValidHeaderSpecific(cellIS, IS_CLASSID, 4); 39284f572ea9SToby Isaac PetscAssertPointer(x, 7); 39299566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 39306528b96dSMatthew G. Knepley numCells = cEnd - cStart; 3931148442b3SMatthew G. Knepley for (s = 0; s < 2; ++s) { 393207218a29SMatthew G. Knepley PetscValidHeaderSpecific(dmX[s], DM_CLASSID, 2); 393307218a29SMatthew G. Knepley PetscValidHeaderSpecific(dsX[s], PETSCDS_CLASSID, 3); 393407218a29SMatthew G. Knepley PetscValidHeaderSpecific(locX[s], VEC_CLASSID, 5); 393507218a29SMatthew G. Knepley PetscCall(DMPlexConvertPlex(dmX[s], &plexX[s], PETSC_FALSE)); 393607218a29SMatthew G. Knepley PetscCall(DMGetEnclosureRelation(dmX[s], dm, &encX[s])); 393707218a29SMatthew G. Knepley PetscCall(DMGetLocalSection(dmX[s], §ionX[s])); 393807218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsX[s], &totDimX[s])); 393907218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dmX[s], numCells * totDimX[s], MPIU_SCALAR, &x[s])); 394004c51a94SMatthew G. Knepley } 3941148442b3SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 39426528b96dSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 39436528b96dSMatthew G. Knepley const PetscInt cind = c - cStart; 39446528b96dSMatthew G. Knepley const PetscInt *cone, *ornt; 39456528b96dSMatthew G. Knepley 39469566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cell, &cone)); 39479566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt)); 394807218a29SMatthew 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]); 3949148442b3SMatthew G. Knepley for (s = 0; s < 2; ++s) { 395007218a29SMatthew G. Knepley const PetscInt tdX = totDimX[s]; 395107218a29SMatthew G. Knepley PetscScalar *closure = NULL, *xl = &x[s][cind * tdX]; 395207218a29SMatthew G. Knepley PetscInt face = cone[s], point = face, subpoint, Nx, i; 395307218a29SMatthew G. Knepley 395407218a29SMatthew G. Knepley if (useCell) { 39555fedec97SMatthew G. Knepley const PetscInt *support; 395607218a29SMatthew G. Knepley PetscInt ssize; 39576528b96dSMatthew G. Knepley 395807218a29SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, face, &support)); 395907218a29SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, face, &ssize)); 396007218a29SMatthew 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); 396107218a29SMatthew G. Knepley if (support[0] == cell) point = support[1]; 396207218a29SMatthew G. Knepley else if (support[1] == cell) point = support[0]; 396307218a29SMatthew 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); 396407218a29SMatthew G. Knepley } 396507218a29SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(plexX[s], dm, encX[s], point, &subpoint)); 3966e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(plexX[s], sectionX[s], PETSC_FALSE, locX[s], subpoint, ornt[s], &Nx, &closure)); 396707218a29SMatthew 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); 396807218a29SMatthew G. Knepley for (i = 0; i < Nx; ++i) xl[i] = closure[i]; 396907218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plexX[s], sectionX[s], locX[s], subpoint, &Nx, &closure)); 39706528b96dSMatthew G. Knepley } 39716528b96dSMatthew G. Knepley } 397207218a29SMatthew G. Knepley for (s = 0; s < 2; ++s) PetscCall(DMDestroy(&plexX[s])); 39739566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 39743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 39756528b96dSMatthew G. Knepley } 39766528b96dSMatthew G. Knepley 397707218a29SMatthew G. Knepley static PetscErrorCode DMPlexRestoreHybridFields(DM dm, DM dmX[], PetscDS dsX[], IS cellIS, Vec locX[], PetscBool useCell, PetscScalar *x[]) 3978d71ae5a4SJacob Faibussowitsch { 39796528b96dSMatthew G. Knepley PetscFunctionBegin; 398007218a29SMatthew G. Knepley if (!locX[0] || !locX[1]) PetscFunctionReturn(PETSC_SUCCESS); 398107218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dmX[0], 0, MPIU_SCALAR, &x[0])); 398207218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dmX[1], 0, MPIU_SCALAR, &x[1])); 39833ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 39846528b96dSMatthew G. Knepley } 39856528b96dSMatthew G. Knepley 39862f856554SMatthew G. Knepley /*@C 39872f856554SMatthew G. Knepley DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces 39882f856554SMatthew G. Knepley 39892f856554SMatthew G. Knepley Input Parameters: 3990a1cb98faSBarry Smith + dm - The `DM` 39912f856554SMatthew G. Knepley . fStart - The first face to include 39922f856554SMatthew G. Knepley . fEnd - The first face to exclude 39932f856554SMatthew G. Knepley . locX - A local vector with the solution fields 39942f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 39952f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 39962f856554SMatthew G. Knepley . cellGeometry - A local vector with cell geometry 399760225df5SJacob Faibussowitsch - locGrad - A local vector with field gradients, or NULL 39982f856554SMatthew G. Knepley 39992f856554SMatthew G. Knepley Output Parameters: 40002f856554SMatthew G. Knepley + Nface - The number of faces with field values 40012f856554SMatthew G. Knepley . uL - The field values at the left side of the face 40022f856554SMatthew G. Knepley - uR - The field values at the right side of the face 40032f856554SMatthew G. Knepley 40042f856554SMatthew G. Knepley Level: developer 40052f856554SMatthew G. Knepley 40061cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()` 40072f856554SMatthew G. Knepley @*/ 4008d71ae5a4SJacob 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) 4009d71ae5a4SJacob Faibussowitsch { 40102f856554SMatthew G. Knepley DM dmFace, dmCell, dmGrad = NULL; 40112f856554SMatthew G. Knepley PetscSection section; 40122f856554SMatthew G. Knepley PetscDS prob; 40132f856554SMatthew G. Knepley DMLabel ghostLabel; 40142f856554SMatthew G. Knepley const PetscScalar *facegeom, *cellgeom, *x, *lgrad; 40152f856554SMatthew G. Knepley PetscBool *isFE; 40162f856554SMatthew G. Knepley PetscInt dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face; 40172f856554SMatthew G. Knepley 40182f856554SMatthew G. Knepley PetscFunctionBegin; 40192f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 40202f856554SMatthew G. Knepley PetscValidHeaderSpecific(locX, VEC_CLASSID, 4); 4021ad540459SPierre Jolivet if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 5); 40222f856554SMatthew G. Knepley PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 6); 40232f856554SMatthew G. Knepley PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 7); 4024ad540459SPierre Jolivet if (locGrad) PetscValidHeaderSpecific(locGrad, VEC_CLASSID, 8); 40254f572ea9SToby Isaac PetscAssertPointer(uL, 10); 40264f572ea9SToby Isaac PetscAssertPointer(uR, 11); 40279566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 40289566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 40299566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 40309566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 40319566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalComponents(prob, &Nc)); 40329566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nf, &isFE)); 40332f856554SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 40342f856554SMatthew G. Knepley PetscObject obj; 40352f856554SMatthew G. Knepley PetscClassId id; 40362f856554SMatthew G. Knepley 40379566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 40389566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 40399371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 40409371c9d4SSatish Balay isFE[f] = PETSC_TRUE; 40419371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 40429371c9d4SSatish Balay isFE[f] = PETSC_FALSE; 40439371c9d4SSatish Balay } else { 40449371c9d4SSatish Balay isFE[f] = PETSC_FALSE; 40459371c9d4SSatish Balay } 40462f856554SMatthew G. Knepley } 40479566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 40489566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locX, &x)); 40499566063dSJacob Faibussowitsch PetscCall(VecGetDM(faceGeometry, &dmFace)); 40509566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 40519566063dSJacob Faibussowitsch PetscCall(VecGetDM(cellGeometry, &dmCell)); 40529566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 40532f856554SMatthew G. Knepley if (locGrad) { 40549566063dSJacob Faibussowitsch PetscCall(VecGetDM(locGrad, &dmGrad)); 40559566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locGrad, &lgrad)); 40562f856554SMatthew G. Knepley } 40579566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uL)); 40589566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uR)); 40592f856554SMatthew G. Knepley /* Right now just eat the extra work for FE (could make a cell loop) */ 40602f856554SMatthew G. Knepley for (face = fStart, iface = 0; face < fEnd; ++face) { 40612f856554SMatthew G. Knepley const PetscInt *cells; 40622f856554SMatthew G. Knepley PetscFVFaceGeom *fg; 40632f856554SMatthew G. Knepley PetscFVCellGeom *cgL, *cgR; 40642f856554SMatthew G. Knepley PetscScalar *xL, *xR, *gL, *gR; 40652f856554SMatthew G. Knepley PetscScalar *uLl = *uL, *uRl = *uR; 40662f856554SMatthew G. Knepley PetscInt ghost, nsupp, nchild; 40672f856554SMatthew G. Knepley 40689566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 40699566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 40709566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 40712f856554SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 40729566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 40739566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &cells)); 40749566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL)); 40759566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR)); 40762f856554SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 40772f856554SMatthew G. Knepley PetscInt off; 40782f856554SMatthew G. Knepley 40799566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffset(prob, f, &off)); 40802f856554SMatthew G. Knepley if (isFE[f]) { 40812f856554SMatthew G. Knepley const PetscInt *cone; 40822f856554SMatthew G. Knepley PetscInt comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d; 40832f856554SMatthew G. Knepley 40842f856554SMatthew G. Knepley xL = xR = NULL; 40859566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldComponents(section, f, &comp)); 4086835f2295SStefano Zampini PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, &xL)); 4087835f2295SStefano Zampini PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, &xR)); 40889566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cells[0], &cone)); 40899566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, cells[0], &coneSizeL)); 40909371c9d4SSatish Balay for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL) 40919371c9d4SSatish Balay if (cone[faceLocL] == face) break; 40929566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cells[1], &cone)); 40939566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, cells[1], &coneSizeR)); 40949371c9d4SSatish Balay for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR) 40959371c9d4SSatish Balay if (cone[faceLocR] == face) break; 40961dca8a05SBarry 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]); 40972f856554SMatthew G. Knepley /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */ 40982f856554SMatthew G. Knepley /* TODO: this is a hack that might not be right for nonconforming */ 40992f856554SMatthew G. Knepley if (faceLocL < coneSizeL) { 41009566063dSJacob Faibussowitsch PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface * Nc + off])); 41019566063dSJacob Faibussowitsch if (rdof == ldof && faceLocR < coneSizeR) PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off])); 41022f856554SMatthew G. Knepley else { 41039371c9d4SSatish Balay for (d = 0; d < comp; ++d) uRl[iface * Nc + off + d] = uLl[iface * Nc + off + d]; 41049371c9d4SSatish Balay } 41059371c9d4SSatish Balay } else { 41069566063dSJacob Faibussowitsch PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off])); 41079566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldComponents(section, f, &comp)); 41082f856554SMatthew G. Knepley for (d = 0; d < comp; ++d) uLl[iface * Nc + off + d] = uRl[iface * Nc + off + d]; 41092f856554SMatthew G. Knepley } 4110835f2295SStefano Zampini PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, &xL)); 4111835f2295SStefano Zampini PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, &xR)); 41122f856554SMatthew G. Knepley } else { 41132f856554SMatthew G. Knepley PetscFV fv; 41142f856554SMatthew G. Knepley PetscInt numComp, c; 41152f856554SMatthew G. Knepley 41169566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, (PetscObject *)&fv)); 41179566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &numComp)); 41189566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL)); 41199566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR)); 41202f856554SMatthew G. Knepley if (dmGrad) { 41212f856554SMatthew G. Knepley PetscReal dxL[3], dxR[3]; 41222f856554SMatthew G. Knepley 41239566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL)); 41249566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR)); 41252f856554SMatthew G. Knepley DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL); 41262f856554SMatthew G. Knepley DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR); 41272f856554SMatthew G. Knepley for (c = 0; c < numComp; ++c) { 41282f856554SMatthew G. Knepley uLl[iface * Nc + off + c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c * dim], dxL); 41292f856554SMatthew G. Knepley uRl[iface * Nc + off + c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c * dim], dxR); 41302f856554SMatthew G. Knepley } 41312f856554SMatthew G. Knepley } else { 41322f856554SMatthew G. Knepley for (c = 0; c < numComp; ++c) { 41332f856554SMatthew G. Knepley uLl[iface * Nc + off + c] = xL[c]; 41342f856554SMatthew G. Knepley uRl[iface * Nc + off + c] = xR[c]; 41352f856554SMatthew G. Knepley } 41362f856554SMatthew G. Knepley } 41372f856554SMatthew G. Knepley } 41382f856554SMatthew G. Knepley } 41392f856554SMatthew G. Knepley ++iface; 41402f856554SMatthew G. Knepley } 41412f856554SMatthew G. Knepley *Nface = iface; 41429566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(locX, &x)); 41439566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 41449566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 414548a46eb9SPierre Jolivet if (locGrad) PetscCall(VecRestoreArrayRead(locGrad, &lgrad)); 41469566063dSJacob Faibussowitsch PetscCall(PetscFree(isFE)); 41473ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 41482f856554SMatthew G. Knepley } 41492f856554SMatthew G. Knepley 41502f856554SMatthew G. Knepley /*@C 41512f856554SMatthew G. Knepley DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces 41522f856554SMatthew G. Knepley 41532f856554SMatthew G. Knepley Input Parameters: 4154a1cb98faSBarry Smith + dm - The `DM` 41552f856554SMatthew G. Knepley . fStart - The first face to include 41562f856554SMatthew G. Knepley . fEnd - The first face to exclude 41572f856554SMatthew G. Knepley . locX - A local vector with the solution fields 41582f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 41592f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 41602f856554SMatthew G. Knepley . cellGeometry - A local vector with cell geometry 416160225df5SJacob Faibussowitsch - locGrad - A local vector with field gradients, or NULL 41622f856554SMatthew G. Knepley 41632f856554SMatthew G. Knepley Output Parameters: 41642f856554SMatthew G. Knepley + Nface - The number of faces with field values 41652f856554SMatthew G. Knepley . uL - The field values at the left side of the face 41662f856554SMatthew G. Knepley - uR - The field values at the right side of the face 41672f856554SMatthew G. Knepley 41682f856554SMatthew G. Knepley Level: developer 41692f856554SMatthew G. Knepley 41701cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 41712f856554SMatthew G. Knepley @*/ 4172d71ae5a4SJacob 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) 4173d71ae5a4SJacob Faibussowitsch { 41742f856554SMatthew G. Knepley PetscFunctionBegin; 41759566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL)); 41769566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR)); 41773ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 41782f856554SMatthew G. Knepley } 41792f856554SMatthew G. Knepley 41802f856554SMatthew G. Knepley /*@C 41812f856554SMatthew G. Knepley DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces 41822f856554SMatthew G. Knepley 41832f856554SMatthew G. Knepley Input Parameters: 4184a1cb98faSBarry Smith + dm - The `DM` 41852f856554SMatthew G. Knepley . fStart - The first face to include 41862f856554SMatthew G. Knepley . fEnd - The first face to exclude 41872f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 41882f856554SMatthew G. Knepley - cellGeometry - A local vector with cell geometry 41892f856554SMatthew G. Knepley 41902f856554SMatthew G. Knepley Output Parameters: 41912f856554SMatthew G. Knepley + Nface - The number of faces with field values 41922f856554SMatthew G. Knepley . fgeom - The extract the face centroid and normal 41932f856554SMatthew G. Knepley - vol - The cell volume 41942f856554SMatthew G. Knepley 41952f856554SMatthew G. Knepley Level: developer 41962f856554SMatthew G. Knepley 41971cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()` 41982f856554SMatthew G. Knepley @*/ 4199d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 4200d71ae5a4SJacob Faibussowitsch { 42012f856554SMatthew G. Knepley DM dmFace, dmCell; 42022f856554SMatthew G. Knepley DMLabel ghostLabel; 42032f856554SMatthew G. Knepley const PetscScalar *facegeom, *cellgeom; 42042f856554SMatthew G. Knepley PetscInt dim, numFaces = fEnd - fStart, iface, face; 42052f856554SMatthew G. Knepley 42062f856554SMatthew G. Knepley PetscFunctionBegin; 42072f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 42082f856554SMatthew G. Knepley PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 4); 42092f856554SMatthew G. Knepley PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 5); 42104f572ea9SToby Isaac PetscAssertPointer(fgeom, 7); 42114f572ea9SToby Isaac PetscAssertPointer(vol, 8); 42129566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 42139566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 42149566063dSJacob Faibussowitsch PetscCall(VecGetDM(faceGeometry, &dmFace)); 42159566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 42169566063dSJacob Faibussowitsch PetscCall(VecGetDM(cellGeometry, &dmCell)); 42179566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 42189566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(numFaces, fgeom)); 42199566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * 2, MPIU_SCALAR, vol)); 42202f856554SMatthew G. Knepley for (face = fStart, iface = 0; face < fEnd; ++face) { 42212f856554SMatthew G. Knepley const PetscInt *cells; 42222f856554SMatthew G. Knepley PetscFVFaceGeom *fg; 42232f856554SMatthew G. Knepley PetscFVCellGeom *cgL, *cgR; 42242f856554SMatthew G. Knepley PetscFVFaceGeom *fgeoml = *fgeom; 42252f856554SMatthew G. Knepley PetscReal *voll = *vol; 42262f856554SMatthew G. Knepley PetscInt ghost, d, nchild, nsupp; 42272f856554SMatthew G. Knepley 42289566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 42299566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 42309566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 42312f856554SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 42329566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 42339566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &cells)); 42349566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL)); 42359566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR)); 42362f856554SMatthew G. Knepley for (d = 0; d < dim; ++d) { 42372f856554SMatthew G. Knepley fgeoml[iface].centroid[d] = fg->centroid[d]; 42382f856554SMatthew G. Knepley fgeoml[iface].normal[d] = fg->normal[d]; 42392f856554SMatthew G. Knepley } 42402f856554SMatthew G. Knepley voll[iface * 2 + 0] = cgL->volume; 42412f856554SMatthew G. Knepley voll[iface * 2 + 1] = cgR->volume; 42422f856554SMatthew G. Knepley ++iface; 42432f856554SMatthew G. Knepley } 42442f856554SMatthew G. Knepley *Nface = iface; 42459566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 42469566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 42473ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 42482f856554SMatthew G. Knepley } 42492f856554SMatthew G. Knepley 42502f856554SMatthew G. Knepley /*@C 42512f856554SMatthew G. Knepley DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces 42522f856554SMatthew G. Knepley 42532f856554SMatthew G. Knepley Input Parameters: 4254a1cb98faSBarry Smith + dm - The `DM` 42552f856554SMatthew G. Knepley . fStart - The first face to include 42562f856554SMatthew G. Knepley . fEnd - The first face to exclude 42572f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 42582f856554SMatthew G. Knepley - cellGeometry - A local vector with cell geometry 42592f856554SMatthew G. Knepley 42602f856554SMatthew G. Knepley Output Parameters: 42612f856554SMatthew G. Knepley + Nface - The number of faces with field values 42622f856554SMatthew G. Knepley . fgeom - The extract the face centroid and normal 42632f856554SMatthew G. Knepley - vol - The cell volume 42642f856554SMatthew G. Knepley 42652f856554SMatthew G. Knepley Level: developer 42662f856554SMatthew G. Knepley 42671cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 42682f856554SMatthew G. Knepley @*/ 4269d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 4270d71ae5a4SJacob Faibussowitsch { 42712f856554SMatthew G. Knepley PetscFunctionBegin; 42729566063dSJacob Faibussowitsch PetscCall(PetscFree(*fgeom)); 42739566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_REAL, vol)); 42743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 42752f856554SMatthew G. Knepley } 42762f856554SMatthew G. Knepley 4277d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 4278d71ae5a4SJacob Faibussowitsch { 4279a1cf66bbSMatthew G. Knepley char composeStr[33] = {0}; 4280a1cf66bbSMatthew G. Knepley PetscObjectId id; 4281a1cf66bbSMatthew G. Knepley PetscContainer container; 4282a1cf66bbSMatthew G. Knepley 4283a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 42849566063dSJacob Faibussowitsch PetscCall(PetscObjectGetId((PetscObject)quad, &id)); 428563a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%" PetscInt64_FMT "\n", id)); 42869566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)pointIS, composeStr, (PetscObject *)&container)); 4287a1cf66bbSMatthew G. Knepley if (container) { 42889566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(container, (void **)geom)); 4289a1cf66bbSMatthew G. Knepley } else { 42909566063dSJacob Faibussowitsch PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom)); 42919566063dSJacob Faibussowitsch PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container)); 42929566063dSJacob Faibussowitsch PetscCall(PetscContainerSetPointer(container, (void *)*geom)); 429349abdd8aSBarry Smith PetscCall(PetscContainerSetCtxDestroy(container, PetscContainerCtxDestroy_PetscFEGeom)); 42949566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)pointIS, composeStr, (PetscObject)container)); 42959566063dSJacob Faibussowitsch PetscCall(PetscContainerDestroy(&container)); 4296a1cf66bbSMatthew G. Knepley } 42973ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4298a1cf66bbSMatthew G. Knepley } 4299a1cf66bbSMatthew G. Knepley 4300d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 4301d71ae5a4SJacob Faibussowitsch { 4302a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 4303a1cf66bbSMatthew G. Knepley *geom = NULL; 43043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4305a1cf66bbSMatthew G. Knepley } 4306a1cf66bbSMatthew G. Knepley 4307d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user) 4308d71ae5a4SJacob Faibussowitsch { 430992d50984SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 431092d50984SMatthew G. Knepley const char *name = "Residual"; 431192d50984SMatthew G. Knepley DM dmAux = NULL; 431292d50984SMatthew G. Knepley DMLabel ghostLabel = NULL; 431392d50984SMatthew G. Knepley PetscDS prob = NULL; 431492d50984SMatthew G. Knepley PetscDS probAux = NULL; 431592d50984SMatthew G. Knepley PetscBool useFEM = PETSC_FALSE; 431692d50984SMatthew G. Knepley PetscBool isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 431792d50984SMatthew G. Knepley DMField coordField = NULL; 4318c0006e53SPatrick Farrell Vec locA; 4319c0006e53SPatrick Farrell PetscScalar *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL; 432092d50984SMatthew G. Knepley IS chunkIS; 432192d50984SMatthew G. Knepley const PetscInt *cells; 432292d50984SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 4323364207b6SKarl Rupp PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd; 43241690c2aeSBarry Smith PetscInt maxDegree = PETSC_INT_MAX; 432506ad1575SMatthew G. Knepley PetscFormKey key; 432692d50984SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 432792d50984SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 432892d50984SMatthew G. Knepley 432992d50984SMatthew G. Knepley PetscFunctionBegin; 43309566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 433192d50984SMatthew G. Knepley /* FEM+FVM */ 433292d50984SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 43339566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 43349566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 43359566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 43369566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 43379566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 433892d50984SMatthew G. Knepley if (locA) { 43399566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 43409566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 43419566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 434292d50984SMatthew G. Knepley } 434392d50984SMatthew G. Knepley /* 2: Get geometric data */ 434492d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 434592d50984SMatthew G. Knepley PetscObject obj; 434692d50984SMatthew G. Knepley PetscClassId id; 434792d50984SMatthew G. Knepley PetscBool fimp; 434892d50984SMatthew G. Knepley 43499566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 435092d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 43519566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 43529566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 4353ad540459SPierre Jolivet if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE; 43545f80ce2aSJacob Faibussowitsch PetscCheck(id != PETSCFV_CLASSID, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Use of FVM with PCPATCH not yet implemented"); 435592d50984SMatthew G. Knepley } 435692d50984SMatthew G. Knepley if (useFEM) { 43579566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 43589566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 435992d50984SMatthew G. Knepley if (maxDegree <= 1) { 43609566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 436148a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 436292d50984SMatthew G. Knepley } else { 43639566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 436492d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 436592d50984SMatthew G. Knepley PetscObject obj; 436692d50984SMatthew G. Knepley PetscClassId id; 436792d50984SMatthew G. Knepley PetscBool fimp; 436892d50984SMatthew G. Knepley 43699566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 437092d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 43719566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 43729566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 437392d50984SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 437492d50984SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 437592d50984SMatthew G. Knepley 43769566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 43779566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 43789566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 437992d50984SMatthew G. Knepley } 438092d50984SMatthew G. Knepley } 438192d50984SMatthew G. Knepley } 438292d50984SMatthew G. Knepley } 438392d50984SMatthew G. Knepley /* Loop over chunks */ 43849566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 43859566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 43869566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS)); 438792d50984SMatthew G. Knepley numCells = cEnd - cStart; 438892d50984SMatthew G. Knepley numChunks = 1; 438992d50984SMatthew G. Knepley cellChunkSize = numCells / numChunks; 439092d50984SMatthew G. Knepley numChunks = PetscMin(1, numCells); 43916528b96dSMatthew G. Knepley key.label = NULL; 43926528b96dSMatthew G. Knepley key.value = 0; 439306ad1575SMatthew G. Knepley key.part = 0; 439492d50984SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 4395c0006e53SPatrick Farrell PetscScalar *elemVec, *fluxL = NULL, *fluxR = NULL; 4396c0006e53SPatrick Farrell PetscReal *vol = NULL; 4397c0006e53SPatrick Farrell PetscFVFaceGeom *fgeom = NULL; 439892d50984SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 4399c0006e53SPatrick Farrell PetscInt numFaces = 0; 440092d50984SMatthew G. Knepley 440192d50984SMatthew G. Knepley /* Extract field coefficients */ 440292d50984SMatthew G. Knepley if (useFEM) { 44039566063dSJacob Faibussowitsch PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells)); 44049566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 44059566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 44069566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numCells * totDim)); 440792d50984SMatthew G. Knepley } 440892d50984SMatthew 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 */ 440992d50984SMatthew G. Knepley /* Loop over fields */ 441092d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 441192d50984SMatthew G. Knepley PetscObject obj; 441292d50984SMatthew G. Knepley PetscClassId id; 441392d50984SMatthew G. Knepley PetscBool fimp; 441492d50984SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 441592d50984SMatthew G. Knepley 44166528b96dSMatthew G. Knepley key.field = f; 44179566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 441892d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 44199566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 44209566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 442192d50984SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 442292d50984SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 442392d50984SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 442492d50984SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 442592d50984SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 442692d50984SMatthew G. Knepley PetscInt Nq, Nb; 442792d50984SMatthew G. Knepley 44289566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 44299566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 44309566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 443192d50984SMatthew G. Knepley blockSize = Nb; 443292d50984SMatthew G. Knepley batchSize = numBlocks * blockSize; 44339566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 443492d50984SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 443592d50984SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 443692d50984SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 443792d50984SMatthew G. Knepley offset = numCells - Nr; 443892d50984SMatthew G. Knepley /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 443992d50984SMatthew 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) */ 44409566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom)); 44419566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateResidual(prob, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec)); 44429566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom)); 44438e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateResidual(prob, key, Nr, chunkGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, &a[offset * totDimAux], t, &elemVec[offset * totDim])); 44449566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom)); 444592d50984SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 444692d50984SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 444792d50984SMatthew G. Knepley 444892d50984SMatthew G. Knepley Ne = numFaces; 444992d50984SMatthew G. Knepley /* Riemann solve over faces (need fields at face centroids) */ 445092d50984SMatthew G. Knepley /* We need to evaluate FE fields at those coordinates */ 44519566063dSJacob Faibussowitsch PetscCall(PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR)); 445263a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 445392d50984SMatthew G. Knepley } 445492d50984SMatthew G. Knepley /* Loop over domain */ 445592d50984SMatthew G. Knepley if (useFEM) { 445692d50984SMatthew G. Knepley /* Add elemVec to locX */ 445792d50984SMatthew G. Knepley for (c = cS; c < cE; ++c) { 445892d50984SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 445992d50984SMatthew G. Knepley const PetscInt cind = c - cStart; 446092d50984SMatthew G. Knepley 44619566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim])); 446292d50984SMatthew G. Knepley if (ghostLabel) { 446392d50984SMatthew G. Knepley PetscInt ghostVal; 446492d50984SMatthew G. Knepley 44659566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 446692d50984SMatthew G. Knepley if (ghostVal > 0) continue; 446792d50984SMatthew G. Knepley } 44689566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES)); 446992d50984SMatthew G. Knepley } 447092d50984SMatthew G. Knepley } 447192d50984SMatthew G. Knepley /* Handle time derivative */ 447292d50984SMatthew G. Knepley if (locX_t) { 447392d50984SMatthew G. Knepley PetscScalar *x_t, *fa; 447492d50984SMatthew G. Knepley 44759566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 44769566063dSJacob Faibussowitsch PetscCall(VecGetArray(locX_t, &x_t)); 447792d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 447892d50984SMatthew G. Knepley PetscFV fv; 447992d50984SMatthew G. Knepley PetscObject obj; 448092d50984SMatthew G. Knepley PetscClassId id; 448192d50984SMatthew G. Knepley PetscInt pdim, d; 448292d50984SMatthew G. Knepley 44839566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 44849566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 448592d50984SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 448692d50984SMatthew G. Knepley fv = (PetscFV)obj; 44879566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 448892d50984SMatthew G. Knepley for (c = cS; c < cE; ++c) { 448992d50984SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 449092d50984SMatthew G. Knepley PetscScalar *u_t, *r; 449192d50984SMatthew G. Knepley 449292d50984SMatthew G. Knepley if (ghostLabel) { 449392d50984SMatthew G. Knepley PetscInt ghostVal; 449492d50984SMatthew G. Knepley 44959566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 449692d50984SMatthew G. Knepley if (ghostVal > 0) continue; 449792d50984SMatthew G. Knepley } 44989566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t)); 44999566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r)); 450092d50984SMatthew G. Knepley for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 450192d50984SMatthew G. Knepley } 450292d50984SMatthew G. Knepley } 45039566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locX_t, &x_t)); 45049566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 450592d50984SMatthew G. Knepley } 450692d50984SMatthew G. Knepley if (useFEM) { 45079566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 45089566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 450992d50984SMatthew G. Knepley } 451092d50984SMatthew G. Knepley } 45119566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISDestroy(&chunkIS)); 45129566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 451392d50984SMatthew G. Knepley /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */ 451492d50984SMatthew G. Knepley if (useFEM) { 451592d50984SMatthew G. Knepley if (maxDegree <= 1) { 45169566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 45179566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 451892d50984SMatthew G. Knepley } else { 451992d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 45209566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 45219566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&quads[f])); 452292d50984SMatthew G. Knepley } 45239566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 452492d50984SMatthew G. Knepley } 452592d50984SMatthew G. Knepley } 45269566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 45273ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 452892d50984SMatthew G. Knepley } 452992d50984SMatthew G. Knepley 4530a1cf66bbSMatthew G. Knepley /* 4531a1cf66bbSMatthew 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 4532a1cf66bbSMatthew G. Knepley 4533a1cf66bbSMatthew G. Knepley X - The local solution vector 4534a5b23f4aSJose E. Roman X_t - The local solution time derivative vector, or NULL 4535a1cf66bbSMatthew G. Knepley */ 4536d71ae5a4SJacob 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) 4537d71ae5a4SJacob Faibussowitsch { 4538a1cf66bbSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 4539a1cf66bbSMatthew G. Knepley const char *name = "Jacobian", *nameP = "JacobianPre"; 4540a1cf66bbSMatthew G. Knepley DM dmAux = NULL; 4541a1cf66bbSMatthew G. Knepley PetscDS prob, probAux = NULL; 4542a1cf66bbSMatthew G. Knepley PetscSection sectionAux = NULL; 4543a1cf66bbSMatthew G. Knepley Vec A; 4544a1cf66bbSMatthew G. Knepley DMField coordField; 4545a1cf66bbSMatthew G. Knepley PetscFEGeom *cgeomFEM; 4546a1cf66bbSMatthew G. Knepley PetscQuadrature qGeom = NULL; 4547a1cf66bbSMatthew G. Knepley Mat J = Jac, JP = JacP; 4548a1cf66bbSMatthew G. Knepley PetscScalar *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL; 4549e432b41dSStefano Zampini PetscBool hasJac, hasPrec, hasDyn, assembleJac, *isFE, hasFV = PETSC_FALSE; 4550a1cf66bbSMatthew G. Knepley const PetscInt *cells; 455106ad1575SMatthew G. Knepley PetscFormKey key; 45529b2fc754SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0; 4553a1cf66bbSMatthew G. Knepley 4554a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 45559566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(cellIS, &numCells)); 45569566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 45579566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 45589566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 45599566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &A)); 45609a2a23afSMatthew G. Knepley if (A) { 45619566063dSJacob Faibussowitsch PetscCall(VecGetDM(A, &dmAux)); 45629566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 45639566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 4564a1cf66bbSMatthew G. Knepley } 4565a1cf66bbSMatthew G. Knepley /* Get flags */ 45669566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 45679566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE)); 4568a1cf66bbSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 4569a1cf66bbSMatthew G. Knepley PetscObject disc; 4570a1cf66bbSMatthew G. Knepley PetscClassId id; 45719566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, &disc)); 45729566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(disc, &id)); 45739371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 45749371c9d4SSatish Balay isFE[fieldI] = PETSC_TRUE; 45759371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 45769371c9d4SSatish Balay hasFV = PETSC_TRUE; 45779371c9d4SSatish Balay isFE[fieldI] = PETSC_FALSE; 45789371c9d4SSatish Balay } 4579a1cf66bbSMatthew G. Knepley } 45809566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobian(prob, &hasJac)); 45819566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec)); 45829566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 4583a1cf66bbSMatthew G. Knepley assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE; 4584a1cf66bbSMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 45859566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); /* No allocated space for FV stuff, so ignore the zero entries */ 45869566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 45879566063dSJacob Faibussowitsch if (probAux) PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 4588a1cf66bbSMatthew G. Knepley /* Compute batch sizes */ 4589a1cf66bbSMatthew G. Knepley if (isFE[0]) { 4590a1cf66bbSMatthew G. Knepley PetscFE fe; 4591a1cf66bbSMatthew G. Knepley PetscQuadrature q; 4592a1cf66bbSMatthew G. Knepley PetscInt numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb; 4593a1cf66bbSMatthew G. Knepley 45949566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe)); 45959566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 45969566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL)); 45979566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 45989566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 4599a1cf66bbSMatthew G. Knepley blockSize = Nb * numQuadPoints; 4600a1cf66bbSMatthew G. Knepley batchSize = numBlocks * blockSize; 4601a1cf66bbSMatthew G. Knepley chunkSize = numBatches * batchSize; 4602a1cf66bbSMatthew G. Knepley numChunks = numCells / chunkSize + numCells % chunkSize; 46039566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 4604a1cf66bbSMatthew G. Knepley } else { 4605a1cf66bbSMatthew G. Knepley chunkSize = numCells; 4606a1cf66bbSMatthew G. Knepley numChunks = 1; 4607a1cf66bbSMatthew G. Knepley } 4608a1cf66bbSMatthew G. Knepley /* Get work space */ 4609a1cf66bbSMatthew 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; 46109566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work)); 46119566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(work, wsz)); 4612a1cf66bbSMatthew G. Knepley off = 0; 4613a1cf66bbSMatthew G. Knepley u = X ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL; 4614a1cf66bbSMatthew G. Knepley u_t = X_t ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL; 4615a1cf66bbSMatthew G. Knepley a = dmAux ? (sz = chunkSize * totDimAux, off += sz, work + off - sz) : NULL; 4616a1cf66bbSMatthew G. Knepley elemMat = hasJac ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 4617a1cf66bbSMatthew G. Knepley elemMatP = hasPrec ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 4618a1cf66bbSMatthew G. Knepley elemMatD = hasDyn ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 461963a3b9bcSJacob Faibussowitsch PetscCheck(off == wsz, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %" PetscInt_FMT " should be %" PetscInt_FMT, off, wsz); 4620a1cf66bbSMatthew G. Knepley /* Setup geometry */ 46219566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 46229566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 46239566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 4624a1cf66bbSMatthew G. Knepley if (!qGeom) { 4625a1cf66bbSMatthew G. Knepley PetscFE fe; 4626a1cf66bbSMatthew G. Knepley 46279566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe)); 46289566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 46299566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 4630a1cf66bbSMatthew G. Knepley } 46319566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 4632a1cf66bbSMatthew G. Knepley /* Compute volume integrals */ 46339566063dSJacob Faibussowitsch if (assembleJac) PetscCall(MatZeroEntries(J)); 46349566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(JP)); 46356528b96dSMatthew G. Knepley key.label = NULL; 46366528b96dSMatthew G. Knepley key.value = 0; 463706ad1575SMatthew G. Knepley key.part = 0; 4638a1cf66bbSMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) { 4639a1cf66bbSMatthew G. Knepley const PetscInt Ncell = PetscMin(chunkSize, numCells - offCell); 4640a1cf66bbSMatthew G. Knepley PetscInt c; 4641a1cf66bbSMatthew G. Knepley 4642a1cf66bbSMatthew G. Knepley /* Extract values */ 4643a1cf66bbSMatthew G. Knepley for (c = 0; c < Ncell; ++c) { 4644a1cf66bbSMatthew G. Knepley const PetscInt cell = cells ? cells[c + offCell] : c + offCell; 4645a1cf66bbSMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 4646a1cf66bbSMatthew G. Knepley PetscInt i; 4647a1cf66bbSMatthew G. Knepley 4648a1cf66bbSMatthew G. Knepley if (X) { 46499566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x)); 4650a1cf66bbSMatthew G. Knepley for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i]; 46519566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x)); 4652a1cf66bbSMatthew G. Knepley } 4653a1cf66bbSMatthew G. Knepley if (X_t) { 46549566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t)); 4655a1cf66bbSMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[c * totDim + i] = x_t[i]; 46569566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t)); 4657a1cf66bbSMatthew G. Knepley } 4658a1cf66bbSMatthew G. Knepley if (dmAux) { 46599566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x)); 4660a1cf66bbSMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i]; 46619566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x)); 4662a1cf66bbSMatthew G. Knepley } 4663a1cf66bbSMatthew G. Knepley } 4664a1cf66bbSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 4665a1cf66bbSMatthew G. Knepley PetscFE fe; 46669566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 4667a1cf66bbSMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 46686528b96dSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 46699566063dSJacob Faibussowitsch if (hasJac) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat)); 46709566063dSJacob Faibussowitsch if (hasPrec) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP)); 46719566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD)); 4672a1cf66bbSMatthew G. Knepley } 4673a1cf66bbSMatthew G. Knepley /* For finite volume, add the identity */ 4674a1cf66bbSMatthew G. Knepley if (!isFE[fieldI]) { 4675a1cf66bbSMatthew G. Knepley PetscFV fv; 4676a1cf66bbSMatthew G. Knepley PetscInt eOffset = 0, Nc, fc, foff; 4677a1cf66bbSMatthew G. Knepley 46789566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, fieldI, &foff)); 46799566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv)); 46809566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 4681a1cf66bbSMatthew G. Knepley for (c = 0; c < chunkSize; ++c, eOffset += totDim * totDim) { 4682a1cf66bbSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 4683a1cf66bbSMatthew G. Knepley const PetscInt i = foff + fc; 4684ad540459SPierre Jolivet if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0; 4685ad540459SPierre Jolivet if (hasPrec) elemMatP[eOffset + i * totDim + i] = 1.0; 4686a1cf66bbSMatthew G. Knepley } 4687a1cf66bbSMatthew G. Knepley } 4688a1cf66bbSMatthew G. Knepley } 4689a1cf66bbSMatthew G. Knepley } 4690a1cf66bbSMatthew G. Knepley /* Add contribution from X_t */ 46919371c9d4SSatish Balay if (hasDyn) { 46929371c9d4SSatish Balay for (c = 0; c < chunkSize * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 46939371c9d4SSatish Balay } 4694a1cf66bbSMatthew G. Knepley /* Insert values into matrix */ 4695a1cf66bbSMatthew G. Knepley for (c = 0; c < Ncell; ++c) { 4696a1cf66bbSMatthew G. Knepley const PetscInt cell = cells ? cells[c + offCell] : c + offCell; 4697a1cf66bbSMatthew G. Knepley if (mesh->printFEM > 1) { 46989566063dSJacob Faibussowitsch if (hasJac) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[(c - cStart) * totDim * totDim])); 46999566063dSJacob Faibussowitsch if (hasPrec) PetscCall(DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c - cStart) * totDim * totDim])); 4700a1cf66bbSMatthew G. Knepley } 4701e8e188d2SZach Atkins if (assembleJac) PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES)); 4702e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, JP, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES)); 4703a1cf66bbSMatthew G. Knepley } 4704a1cf66bbSMatthew G. Knepley } 4705a1cf66bbSMatthew G. Knepley /* Cleanup */ 47069566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 47079566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 47089566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE)); 47099566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE)); 47109566063dSJacob 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)); 4711a1cf66bbSMatthew G. Knepley /* Compute boundary integrals */ 47129566063dSJacob Faibussowitsch /* PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx)); */ 4713a1cf66bbSMatthew G. Knepley /* Assemble matrix */ 47149371c9d4SSatish Balay if (assembleJac) { 47159371c9d4SSatish Balay PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY)); 47169371c9d4SSatish Balay PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY)); 47179371c9d4SSatish Balay } 47189371c9d4SSatish Balay PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY)); 47199371c9d4SSatish Balay PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 47209566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 47213ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4722a1cf66bbSMatthew G. Knepley } 47233e9753d6SMatthew G. Knepley 47244ee01570SBarry Smith /* FEM Assembly Function */ 47253e9753d6SMatthew G. Knepley 4726d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMConvertPlex_Internal(DM dm, DM *plex, PetscBool copy) 4727d71ae5a4SJacob Faibussowitsch { 47283e9753d6SMatthew G. Knepley PetscBool isPlex; 47293e9753d6SMatthew G. Knepley 47303e9753d6SMatthew G. Knepley PetscFunctionBegin; 47319566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex)); 47323e9753d6SMatthew G. Knepley if (isPlex) { 47333e9753d6SMatthew G. Knepley *plex = dm; 47349566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)dm)); 47353e9753d6SMatthew G. Knepley } else { 47369566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex)); 47373e9753d6SMatthew G. Knepley if (!*plex) { 47389566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, plex)); 47399566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex)); 47403e9753d6SMatthew G. Knepley } else { 47419566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)*plex)); 47423e9753d6SMatthew G. Knepley } 4743cbf8eb3cSStefano Zampini if (copy) PetscCall(DMCopyAuxiliaryVec(dm, *plex)); 47443e9753d6SMatthew G. Knepley } 47453ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 47463e9753d6SMatthew G. Knepley } 47473e9753d6SMatthew G. Knepley 47483e9753d6SMatthew G. Knepley /*@ 47493e9753d6SMatthew G. Knepley DMPlexGetGeometryFVM - Return precomputed geometric data 47503e9753d6SMatthew G. Knepley 475120f4b53cSBarry Smith Collective 47523e9753d6SMatthew G. Knepley 47533e9753d6SMatthew G. Knepley Input Parameter: 4754a1cb98faSBarry Smith . dm - The `DM` 47553e9753d6SMatthew G. Knepley 47563e9753d6SMatthew G. Knepley Output Parameters: 47573e9753d6SMatthew G. Knepley + facegeom - The values precomputed from face geometry 47583e9753d6SMatthew G. Knepley . cellgeom - The values precomputed from cell geometry 47593e9753d6SMatthew G. Knepley - minRadius - The minimum radius over the mesh of an inscribed sphere in a cell 47603e9753d6SMatthew G. Knepley 47613e9753d6SMatthew G. Knepley Level: developer 47623e9753d6SMatthew G. Knepley 47631cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMTSSetRHSFunctionLocal()` 47643e9753d6SMatthew G. Knepley @*/ 4765d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGeometryFVM(DM dm, Vec *facegeom, Vec *cellgeom, PetscReal *minRadius) 4766d71ae5a4SJacob Faibussowitsch { 47673e9753d6SMatthew G. Knepley DM plex; 47683e9753d6SMatthew G. Knepley 47693e9753d6SMatthew G. Knepley PetscFunctionBegin; 47703e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 47719566063dSJacob Faibussowitsch PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE)); 47729566063dSJacob Faibussowitsch PetscCall(DMPlexGetDataFVM(plex, NULL, cellgeom, facegeom, NULL)); 47739566063dSJacob Faibussowitsch if (minRadius) PetscCall(DMPlexGetMinRadius(plex, minRadius)); 47749566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 47753ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 47763e9753d6SMatthew G. Knepley } 47773e9753d6SMatthew G. Knepley 47783e9753d6SMatthew G. Knepley /*@ 47793e9753d6SMatthew G. Knepley DMPlexGetGradientDM - Return gradient data layout 47803e9753d6SMatthew G. Knepley 478120f4b53cSBarry Smith Collective 47823e9753d6SMatthew G. Knepley 47833e9753d6SMatthew G. Knepley Input Parameters: 4784a1cb98faSBarry Smith + dm - The `DM` 478520f4b53cSBarry Smith - fv - The `PetscFV` 47863e9753d6SMatthew G. Knepley 47873e9753d6SMatthew G. Knepley Output Parameter: 47883e9753d6SMatthew G. Knepley . dmGrad - The layout for gradient values 47893e9753d6SMatthew G. Knepley 47903e9753d6SMatthew G. Knepley Level: developer 47913e9753d6SMatthew G. Knepley 47921cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetGeometryFVM()` 47933e9753d6SMatthew G. Knepley @*/ 4794d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGradientDM(DM dm, PetscFV fv, DM *dmGrad) 4795d71ae5a4SJacob Faibussowitsch { 47963e9753d6SMatthew G. Knepley DM plex; 47973e9753d6SMatthew G. Knepley PetscBool computeGradients; 47983e9753d6SMatthew G. Knepley 47993e9753d6SMatthew G. Knepley PetscFunctionBegin; 48003e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 48013e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 48024f572ea9SToby Isaac PetscAssertPointer(dmGrad, 3); 48039566063dSJacob Faibussowitsch PetscCall(PetscFVGetComputeGradients(fv, &computeGradients)); 48049371c9d4SSatish Balay if (!computeGradients) { 48059371c9d4SSatish Balay *dmGrad = NULL; 48063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 48079371c9d4SSatish Balay } 48089566063dSJacob Faibussowitsch PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE)); 48099566063dSJacob Faibussowitsch PetscCall(DMPlexGetDataFVM(plex, fv, NULL, NULL, dmGrad)); 48109566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 48113ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 48123e9753d6SMatthew G. Knepley } 48133e9753d6SMatthew G. Knepley 4814d71ae5a4SJacob 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) 4815d71ae5a4SJacob Faibussowitsch { 48163e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 48173e9753d6SMatthew G. Knepley DM plex = NULL, plexA = NULL; 4818673019faSMatthew G. Knepley const char *name = "BdResidual"; 48193e9753d6SMatthew G. Knepley DMEnclosureType encAux; 48203e9753d6SMatthew G. Knepley PetscDS prob, probAux = NULL; 48213e9753d6SMatthew G. Knepley PetscSection section, sectionAux = NULL; 48223e9753d6SMatthew G. Knepley Vec locA = NULL; 48233e9753d6SMatthew G. Knepley PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemVec = NULL; 48243e9753d6SMatthew G. Knepley PetscInt totDim, totDimAux = 0; 48253e9753d6SMatthew G. Knepley 48263e9753d6SMatthew G. Knepley PetscFunctionBegin; 48279566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 48289566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 48299566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 48309566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 48319566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA)); 48323e9753d6SMatthew G. Knepley if (locA) { 48333e9753d6SMatthew G. Knepley DM dmAux; 48343e9753d6SMatthew G. Knepley 48359566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 48369566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 48379566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 48389566063dSJacob Faibussowitsch PetscCall(DMGetDS(plexA, &probAux)); 48399566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 48409566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexA, §ionAux)); 48413e9753d6SMatthew G. Knepley } 48420c290148SMatthew G. Knepley { 48433e9753d6SMatthew G. Knepley PetscFEGeom *fgeom; 48443e9753d6SMatthew G. Knepley PetscInt maxDegree; 48453e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 48463e9753d6SMatthew G. Knepley IS pointIS; 48473e9753d6SMatthew G. Knepley const PetscInt *points; 48483e9753d6SMatthew G. Knepley PetscInt numFaces, face, Nq; 48493e9753d6SMatthew G. Knepley 48509566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS)); 48510c290148SMatthew G. Knepley if (!pointIS) goto end; /* No points with that id on this process */ 48523e9753d6SMatthew G. Knepley { 48533e9753d6SMatthew G. Knepley IS isectIS; 48543e9753d6SMatthew G. Knepley 48553e9753d6SMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 48569566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 48579566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 48583e9753d6SMatthew G. Knepley pointIS = isectIS; 48593e9753d6SMatthew G. Knepley } 48609566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 48619566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 486232603206SJames 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)); 48639566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 486448a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 48653e9753d6SMatthew G. Knepley if (!qGeom) { 48663e9753d6SMatthew G. Knepley PetscFE fe; 48673e9753d6SMatthew G. Knepley 48689566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe)); 48699566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 48709566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 48713e9753d6SMatthew G. Knepley } 48729566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 48739566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 48743e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 4875f15274beSMatthew Knepley const PetscInt point = points[face], *support; 48763e9753d6SMatthew G. Knepley PetscScalar *x = NULL; 4877f15274beSMatthew Knepley PetscInt i; 48783e9753d6SMatthew G. Knepley 48799566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, point, &support)); 48809566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 48813e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 48829566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 48833e9753d6SMatthew G. Knepley if (locX_t) { 48849566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x)); 48853e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i]; 48869566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x)); 48873e9753d6SMatthew G. Knepley } 48883e9753d6SMatthew G. Knepley if (locA) { 48893e9753d6SMatthew G. Knepley PetscInt subp; 48903e9753d6SMatthew G. Knepley 48919566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 48929566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 48933e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i]; 48949566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 48953e9753d6SMatthew G. Knepley } 48963e9753d6SMatthew G. Knepley } 48979566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numFaces * totDim)); 48983e9753d6SMatthew G. Knepley { 48993e9753d6SMatthew G. Knepley PetscFE fe; 49003e9753d6SMatthew G. Knepley PetscInt Nb; 49013e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 49023e9753d6SMatthew G. Knepley /* Conforming batches */ 49033e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 49043e9753d6SMatthew G. Knepley /* Remainder */ 49053e9753d6SMatthew G. Knepley PetscInt Nr, offset; 49063e9753d6SMatthew G. Knepley 49079566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe)); 49089566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 49099566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 49103e9753d6SMatthew G. Knepley /* TODO: documentation is unclear about what is going on with these numbers: how should Nb / Nq factor in ? */ 49113e9753d6SMatthew G. Knepley blockSize = Nb; 49123e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 49139566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 49143e9753d6SMatthew G. Knepley numChunks = numFaces / (numBatches * batchSize); 49153e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 49163e9753d6SMatthew G. Knepley Nr = numFaces % (numBatches * batchSize); 49173e9753d6SMatthew G. Knepley offset = numFaces - Nr; 49189566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom)); 49199566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBdResidual(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec)); 49209566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom)); 49219566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 49228e3a54c0SPierre 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])); 49239566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 49243e9753d6SMatthew G. Knepley } 49253e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 49263e9753d6SMatthew G. Knepley const PetscInt point = points[face], *support; 49273e9753d6SMatthew G. Knepley 4928673019faSMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(point, name, totDim, &elemVec[face * totDim])); 49299566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(plex, point, &support)); 49309566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(plex, NULL, locF, support[0], &elemVec[face * totDim], ADD_ALL_VALUES)); 49313e9753d6SMatthew G. Knepley } 49329566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 49339566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 49349566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 49359566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 49369566063dSJacob Faibussowitsch PetscCall(PetscFree4(u, u_t, elemVec, a)); 49373e9753d6SMatthew G. Knepley } 49380c290148SMatthew G. Knepley end: 4939673019faSMatthew G. Knepley if (mesh->printFEM) { 4940673019faSMatthew G. Knepley PetscSection s; 4941673019faSMatthew G. Knepley Vec locFbc; 4942673019faSMatthew G. Knepley PetscInt pStart, pEnd, maxDof; 4943673019faSMatthew G. Knepley PetscScalar *zeroes; 4944673019faSMatthew G. Knepley 4945673019faSMatthew G. Knepley PetscCall(DMGetLocalSection(dm, &s)); 4946673019faSMatthew G. Knepley PetscCall(VecDuplicate(locF, &locFbc)); 4947673019faSMatthew G. Knepley PetscCall(VecCopy(locF, locFbc)); 4948673019faSMatthew G. Knepley PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 4949673019faSMatthew G. Knepley PetscCall(PetscSectionGetMaxDof(s, &maxDof)); 4950673019faSMatthew G. Knepley PetscCall(PetscCalloc1(maxDof, &zeroes)); 4951673019faSMatthew G. Knepley for (PetscInt p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, s, p, zeroes, INSERT_BC_VALUES)); 4952673019faSMatthew G. Knepley PetscCall(PetscFree(zeroes)); 4953673019faSMatthew G. Knepley PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc)); 4954673019faSMatthew G. Knepley PetscCall(VecDestroy(&locFbc)); 4955673019faSMatthew G. Knepley } 49569566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 49579566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plexA)); 49583ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 49593e9753d6SMatthew G. Knepley } 49603e9753d6SMatthew G. Knepley 4961d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeBdResidualSingle(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF) 4962d71ae5a4SJacob Faibussowitsch { 49633e9753d6SMatthew G. Knepley DMField coordField; 49643e9753d6SMatthew G. Knepley DMLabel depthLabel; 49653e9753d6SMatthew G. Knepley IS facetIS; 49663e9753d6SMatthew G. Knepley PetscInt dim; 49673e9753d6SMatthew G. Knepley 49683e9753d6SMatthew G. Knepley PetscFunctionBegin; 49699566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 49709566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 49719566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 49729566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 49739566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS)); 49749566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 49753ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 49763e9753d6SMatthew G. Knepley } 49773e9753d6SMatthew G. Knepley 4978a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexComputeBdResidual_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4979d71ae5a4SJacob Faibussowitsch { 49803e9753d6SMatthew G. Knepley PetscDS prob; 49813e9753d6SMatthew G. Knepley PetscInt numBd, bd; 49823e9753d6SMatthew G. Knepley DMField coordField = NULL; 49833e9753d6SMatthew G. Knepley IS facetIS = NULL; 49843e9753d6SMatthew G. Knepley DMLabel depthLabel; 49853e9753d6SMatthew G. Knepley PetscInt dim; 49863e9753d6SMatthew G. Knepley 49873e9753d6SMatthew G. Knepley PetscFunctionBegin; 49889566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 49899566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 49909566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 49919566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 49929566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 49933e9753d6SMatthew G. Knepley for (bd = 0; bd < numBd; ++bd) { 499445480ffeSMatthew G. Knepley PetscWeakForm wf; 49953e9753d6SMatthew G. Knepley DMBoundaryConditionType type; 49963e9753d6SMatthew G. Knepley DMLabel label; 49973e9753d6SMatthew G. Knepley const PetscInt *values; 49980c290148SMatthew G. Knepley PetscInt field, numValues, v; 49993e9753d6SMatthew G. Knepley PetscObject obj; 50003e9753d6SMatthew G. Knepley PetscClassId id; 50010c290148SMatthew G. Knepley PetscFormKey key; 50023e9753d6SMatthew G. Knepley 50039566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &field, NULL, NULL, NULL, NULL, NULL)); 50043d3e5d66SMatthew G. Knepley if (type & DM_BC_ESSENTIAL) continue; 50059566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 50069566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 50073d3e5d66SMatthew G. Knepley if (id != PETSCFE_CLASSID) continue; 50083e9753d6SMatthew G. Knepley if (!facetIS) { 50093e9753d6SMatthew G. Knepley DMLabel depthLabel; 50103e9753d6SMatthew G. Knepley PetscInt dim; 50113e9753d6SMatthew G. Knepley 50129566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 50139566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 50149566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 50153e9753d6SMatthew G. Knepley } 50169566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 50170c290148SMatthew G. Knepley for (v = 0; v < numValues; ++v) { 50180c290148SMatthew G. Knepley key.label = label; 50190c290148SMatthew G. Knepley key.value = values[v]; 50200c290148SMatthew G. Knepley key.field = field; 50210c290148SMatthew G. Knepley key.part = 0; 50229566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS)); 50230c290148SMatthew G. Knepley } 50243e9753d6SMatthew G. Knepley } 50259566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 50263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 50273e9753d6SMatthew G. Knepley } 50283e9753d6SMatthew G. Knepley 5029d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 5030d71ae5a4SJacob Faibussowitsch { 50313e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 50323e9753d6SMatthew G. Knepley const char *name = "Residual"; 50333e9753d6SMatthew G. Knepley DM dmAux = NULL; 50343e9753d6SMatthew G. Knepley DM dmGrad = NULL; 50353e9753d6SMatthew G. Knepley DMLabel ghostLabel = NULL; 50366528b96dSMatthew G. Knepley PetscDS ds = NULL; 50376528b96dSMatthew G. Knepley PetscDS dsAux = NULL; 50383e9753d6SMatthew G. Knepley PetscSection section = NULL; 50393e9753d6SMatthew G. Knepley PetscBool useFEM = PETSC_FALSE; 50403e9753d6SMatthew G. Knepley PetscBool useFVM = PETSC_FALSE; 50413e9753d6SMatthew G. Knepley PetscBool isImplicit = (locX_t || time == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 50423e9753d6SMatthew G. Knepley PetscFV fvm = NULL; 50433e9753d6SMatthew G. Knepley DMField coordField = NULL; 50445962854dSMatthew G. Knepley Vec locA, cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL; 50453e9753d6SMatthew G. Knepley PetscScalar *u = NULL, *u_t, *a, *uL, *uR; 50463e9753d6SMatthew G. Knepley IS chunkIS; 50473e9753d6SMatthew G. Knepley const PetscInt *cells; 50483e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 50493e9753d6SMatthew G. Knepley PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, faceChunkSize, chunk, fStart, fEnd; 50501690c2aeSBarry Smith PetscInt maxDegree = PETSC_INT_MAX; 50513e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 50523e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 50533e9753d6SMatthew G. Knepley 50543e9753d6SMatthew G. Knepley PetscFunctionBegin; 50559566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 50563cc88e6aSStefano Zampini if (!cellIS) goto end; 50573cc88e6aSStefano Zampini PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 50583cc88e6aSStefano Zampini if (cStart >= cEnd) goto end; 50593e9753d6SMatthew G. Knepley /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 50603e9753d6SMatthew G. Knepley /* TODO The FVM geometry is over-manipulated. Make the precalc functions return exactly what we need */ 50613e9753d6SMatthew G. Knepley /* FEM+FVM */ 50629566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 50633e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 50649566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 50659566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 506607218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, NULL)); 50679566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 50689566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 50699566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA)); 50703e9753d6SMatthew G. Knepley if (locA) { 50713e9753d6SMatthew G. Knepley PetscInt subcell; 50729566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 50731059d808SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(dmAux, dm, DM_ENC_UNKNOWN, cells ? cells[cStart] : cStart, &subcell)); 507407218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux, subcell, &dsAux, NULL)); 50759566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux)); 50763e9753d6SMatthew G. Knepley } 50773e9753d6SMatthew G. Knepley /* 2: Get geometric data */ 50783e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 50793e9753d6SMatthew G. Knepley PetscObject obj; 50803e9753d6SMatthew G. Knepley PetscClassId id; 50813e9753d6SMatthew G. Knepley PetscBool fimp; 50823e9753d6SMatthew G. Knepley 50839566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 50843e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 50859566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 50869566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 5087ad540459SPierre Jolivet if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE; 50889371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 50899371c9d4SSatish Balay useFVM = PETSC_TRUE; 50909371c9d4SSatish Balay fvm = (PetscFV)obj; 50919371c9d4SSatish Balay } 50923e9753d6SMatthew G. Knepley } 50933e9753d6SMatthew G. Knepley if (useFEM) { 50949566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 50959566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 50963e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 50979566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 509848a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 50993e9753d6SMatthew G. Knepley } else { 51009566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 51013e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 51023e9753d6SMatthew G. Knepley PetscObject obj; 51033e9753d6SMatthew G. Knepley PetscClassId id; 51043e9753d6SMatthew G. Knepley PetscBool fimp; 51053e9753d6SMatthew G. Knepley 51069566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 51073e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 51089566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 51099566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 51103e9753d6SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 51113e9753d6SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 51123e9753d6SMatthew G. Knepley 51139566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 51149566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 51159566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 51163e9753d6SMatthew G. Knepley } 51173e9753d6SMatthew G. Knepley } 51183e9753d6SMatthew G. Knepley } 51193e9753d6SMatthew G. Knepley } 51205962854dSMatthew G. Knepley // Handle non-essential (e.g. outflow) boundary values 51213e9753d6SMatthew G. Knepley if (useFVM) { 51225962854dSMatthew G. Knepley PetscCall(DMPlexInsertBoundaryValuesFVM(dm, fvm, locX, time, &locGrad)); 51239566063dSJacob Faibussowitsch PetscCall(DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL)); 51249566063dSJacob Faibussowitsch PetscCall(DMPlexGetGradientDM(dm, fvm, &dmGrad)); 51253e9753d6SMatthew G. Knepley } 51263e9753d6SMatthew G. Knepley /* Loop over chunks */ 51279566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS)); 51283e9753d6SMatthew G. Knepley numCells = cEnd - cStart; 51293e9753d6SMatthew G. Knepley numChunks = 1; 51303e9753d6SMatthew G. Knepley cellChunkSize = numCells / numChunks; 51313e9753d6SMatthew G. Knepley faceChunkSize = (fEnd - fStart) / numChunks; 51323e9753d6SMatthew G. Knepley numChunks = PetscMin(1, numCells); 51333e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 51343e9753d6SMatthew G. Knepley PetscScalar *elemVec, *fluxL, *fluxR; 51353e9753d6SMatthew G. Knepley PetscReal *vol; 51363e9753d6SMatthew G. Knepley PetscFVFaceGeom *fgeom; 51373e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 51383e9753d6SMatthew G. Knepley PetscInt fS = fStart + chunk * faceChunkSize, fE = PetscMin(fS + faceChunkSize, fEnd), numFaces = 0, face; 51393e9753d6SMatthew G. Knepley 51403e9753d6SMatthew G. Knepley /* Extract field coefficients */ 51413e9753d6SMatthew G. Knepley if (useFEM) { 51429566063dSJacob Faibussowitsch PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells)); 51439566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 51449566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 51459566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numCells * totDim)); 51463e9753d6SMatthew G. Knepley } 51473e9753d6SMatthew G. Knepley if (useFVM) { 51489566063dSJacob Faibussowitsch PetscCall(DMPlexGetFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR)); 51499566063dSJacob Faibussowitsch PetscCall(DMPlexGetFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol)); 51509566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL)); 51519566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR)); 51529566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(fluxL, numFaces * totDim)); 51539566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(fluxR, numFaces * totDim)); 51543e9753d6SMatthew G. Knepley } 51553e9753d6SMatthew 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 */ 51563e9753d6SMatthew G. Knepley /* Loop over fields */ 51573e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 51583e9753d6SMatthew G. Knepley PetscObject obj; 51593e9753d6SMatthew G. Knepley PetscClassId id; 51603e9753d6SMatthew G. Knepley PetscBool fimp; 51613e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 51623e9753d6SMatthew G. Knepley 51636528b96dSMatthew G. Knepley key.field = f; 51649566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 51653e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 51669566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 51679566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 51683e9753d6SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 51693e9753d6SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 51703e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 51713e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 51723e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 51733e9753d6SMatthew G. Knepley PetscInt Nq, Nb; 51743e9753d6SMatthew G. Knepley 51759566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 51769566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 51779566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 51783e9753d6SMatthew G. Knepley blockSize = Nb; 51793e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 51809566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 51813e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 51823e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 51833e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 51843e9753d6SMatthew G. Knepley offset = numCells - Nr; 51853e9753d6SMatthew G. Knepley /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 51863e9753d6SMatthew 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) */ 51879566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom)); 51889566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateResidual(ds, key, Ne, chunkGeom, u, u_t, dsAux, a, t, elemVec)); 51899566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom)); 51908e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateResidual(ds, key, Nr, chunkGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), dsAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, &elemVec[offset * totDim])); 51919566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom)); 51923e9753d6SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 51933e9753d6SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 51943e9753d6SMatthew G. Knepley 51953e9753d6SMatthew G. Knepley Ne = numFaces; 51963e9753d6SMatthew G. Knepley /* Riemann solve over faces (need fields at face centroids) */ 51973e9753d6SMatthew G. Knepley /* We need to evaluate FE fields at those coordinates */ 51989566063dSJacob Faibussowitsch PetscCall(PetscFVIntegrateRHSFunction(fv, ds, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR)); 519963a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 52003e9753d6SMatthew G. Knepley } 52013e9753d6SMatthew G. Knepley /* Loop over domain */ 52023e9753d6SMatthew G. Knepley if (useFEM) { 52033e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 52043e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 52053e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 52063e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 52073e9753d6SMatthew G. Knepley 52089566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim])); 52093e9753d6SMatthew G. Knepley if (ghostLabel) { 52103e9753d6SMatthew G. Knepley PetscInt ghostVal; 52113e9753d6SMatthew G. Knepley 52129566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 52133e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 52143e9753d6SMatthew G. Knepley } 52159566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES)); 52163e9753d6SMatthew G. Knepley } 52173e9753d6SMatthew G. Knepley } 52183e9753d6SMatthew G. Knepley if (useFVM) { 52193e9753d6SMatthew G. Knepley PetscScalar *fa; 52203e9753d6SMatthew G. Knepley PetscInt iface; 52213e9753d6SMatthew G. Knepley 52229566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 52233e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 52243e9753d6SMatthew G. Knepley PetscFV fv; 52253e9753d6SMatthew G. Knepley PetscObject obj; 52263e9753d6SMatthew G. Knepley PetscClassId id; 52275962854dSMatthew G. Knepley PetscInt cdim, foff, pdim; 52283e9753d6SMatthew G. Knepley 52295962854dSMatthew G. Knepley PetscCall(DMGetCoordinateDim(dm, &cdim)); 52309566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 52319566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(ds, f, &foff)); 52329566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 52333e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 52343e9753d6SMatthew G. Knepley fv = (PetscFV)obj; 52359566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 52363e9753d6SMatthew G. Knepley /* Accumulate fluxes to cells */ 52373e9753d6SMatthew G. Knepley for (face = fS, iface = 0; face < fE; ++face) { 52383e9753d6SMatthew G. Knepley const PetscInt *scells; 52393e9753d6SMatthew G. Knepley PetscScalar *fL = NULL, *fR = NULL; 52403e9753d6SMatthew G. Knepley PetscInt ghost, d, nsupp, nchild; 52413e9753d6SMatthew G. Knepley 52429566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 52439566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 52449566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 52453e9753d6SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 52469566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &scells)); 52479566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, scells[0], &ghost)); 52489566063dSJacob Faibussowitsch if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[0], f, fa, &fL)); 52499566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, scells[1], &ghost)); 52509566063dSJacob Faibussowitsch if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[1], f, fa, &fR)); 52515962854dSMatthew G. Knepley if (mesh->printFVM > 1) { 52525962854dSMatthew G. Knepley PetscCall(DMPrintCellVectorReal(face, "Residual: normal", cdim, fgeom[iface].normal)); 52535962854dSMatthew G. Knepley PetscCall(DMPrintCellVector(face, "Residual: left state", pdim, &uL[iface * totDim + foff])); 52545962854dSMatthew G. Knepley PetscCall(DMPrintCellVector(face, "Residual: right state", pdim, &uR[iface * totDim + foff])); 52555962854dSMatthew G. Knepley PetscCall(DMPrintCellVector(face, "Residual: left flux", pdim, &fluxL[iface * totDim + foff])); 52565962854dSMatthew G. Knepley PetscCall(DMPrintCellVector(face, "Residual: right flux", pdim, &fluxR[iface * totDim + foff])); 52575962854dSMatthew G. Knepley } 52583e9753d6SMatthew G. Knepley for (d = 0; d < pdim; ++d) { 52593e9753d6SMatthew G. Knepley if (fL) fL[d] -= fluxL[iface * totDim + foff + d]; 52603e9753d6SMatthew G. Knepley if (fR) fR[d] += fluxR[iface * totDim + foff + d]; 52613e9753d6SMatthew G. Knepley } 52623e9753d6SMatthew G. Knepley ++iface; 52633e9753d6SMatthew G. Knepley } 52643e9753d6SMatthew G. Knepley } 52659566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 52663e9753d6SMatthew G. Knepley } 52673e9753d6SMatthew G. Knepley /* Handle time derivative */ 52683e9753d6SMatthew G. Knepley if (locX_t) { 52693e9753d6SMatthew G. Knepley PetscScalar *x_t, *fa; 52703e9753d6SMatthew G. Knepley 52719566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 52729566063dSJacob Faibussowitsch PetscCall(VecGetArray(locX_t, &x_t)); 52733e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 52743e9753d6SMatthew G. Knepley PetscFV fv; 52753e9753d6SMatthew G. Knepley PetscObject obj; 52763e9753d6SMatthew G. Knepley PetscClassId id; 52773e9753d6SMatthew G. Knepley PetscInt pdim, d; 52783e9753d6SMatthew G. Knepley 52799566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 52809566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 52813e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 52823e9753d6SMatthew G. Knepley fv = (PetscFV)obj; 52839566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 52843e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 52853e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 52863e9753d6SMatthew G. Knepley PetscScalar *u_t, *r; 52873e9753d6SMatthew G. Knepley 52883e9753d6SMatthew G. Knepley if (ghostLabel) { 52893e9753d6SMatthew G. Knepley PetscInt ghostVal; 52903e9753d6SMatthew G. Knepley 52919566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 52923e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 52933e9753d6SMatthew G. Knepley } 52949566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t)); 52959566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r)); 52963e9753d6SMatthew G. Knepley for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 52973e9753d6SMatthew G. Knepley } 52983e9753d6SMatthew G. Knepley } 52999566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locX_t, &x_t)); 53009566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 53013e9753d6SMatthew G. Knepley } 53023e9753d6SMatthew G. Knepley if (useFEM) { 53039566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 53049566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 53053e9753d6SMatthew G. Knepley } 53063e9753d6SMatthew G. Knepley if (useFVM) { 53079566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR)); 53089566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol)); 53099566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL)); 53109566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR)); 53119566063dSJacob Faibussowitsch if (dmGrad) PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 53123e9753d6SMatthew G. Knepley } 53133e9753d6SMatthew G. Knepley } 53149566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISDestroy(&chunkIS)); 53159566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 53163e9753d6SMatthew G. Knepley 53173e9753d6SMatthew G. Knepley if (useFEM) { 53189566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Internal(dm, locX, locX_t, t, locF, user)); 53193e9753d6SMatthew G. Knepley 53203e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 53219566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 53229566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 53233e9753d6SMatthew G. Knepley } else { 53243e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 53259566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 53269566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&quads[f])); 53273e9753d6SMatthew G. Knepley } 53289566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 53293e9753d6SMatthew G. Knepley } 53303e9753d6SMatthew G. Knepley } 53313e9753d6SMatthew G. Knepley 53323e9753d6SMatthew G. Knepley /* FEM */ 53333e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 53343e9753d6SMatthew G. Knepley /* 2: Get geometric data */ 53353e9753d6SMatthew G. Knepley /* 3: Handle boundary values */ 53363e9753d6SMatthew G. Knepley /* 4: Loop over domain */ 53373e9753d6SMatthew G. Knepley /* Extract coefficients */ 53383e9753d6SMatthew G. Knepley /* Loop over fields */ 53393e9753d6SMatthew G. Knepley /* Set tiling for FE*/ 53403e9753d6SMatthew G. Knepley /* Integrate FE residual to get elemVec */ 53413e9753d6SMatthew G. Knepley /* Loop over subdomain */ 53423e9753d6SMatthew G. Knepley /* Loop over quad points */ 53433e9753d6SMatthew G. Knepley /* Transform coords to real space */ 53443e9753d6SMatthew G. Knepley /* Evaluate field and aux fields at point */ 53453e9753d6SMatthew G. Knepley /* Evaluate residual at point */ 53463e9753d6SMatthew G. Knepley /* Transform residual to real space */ 53473e9753d6SMatthew G. Knepley /* Add residual to elemVec */ 53483e9753d6SMatthew G. Knepley /* Loop over domain */ 53493e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 53503e9753d6SMatthew G. Knepley 53513e9753d6SMatthew G. Knepley /* FVM */ 53523e9753d6SMatthew G. Knepley /* Get geometric data */ 53533e9753d6SMatthew G. Knepley /* If using gradients */ 53543e9753d6SMatthew G. Knepley /* Compute gradient data */ 53553e9753d6SMatthew G. Knepley /* Loop over domain faces */ 53563e9753d6SMatthew G. Knepley /* Count computational faces */ 53573e9753d6SMatthew G. Knepley /* Reconstruct cell gradient */ 53583e9753d6SMatthew G. Knepley /* Loop over domain cells */ 53593e9753d6SMatthew G. Knepley /* Limit cell gradients */ 53603e9753d6SMatthew G. Knepley /* Handle boundary values */ 53613e9753d6SMatthew G. Knepley /* Loop over domain faces */ 53623e9753d6SMatthew G. Knepley /* Read out field, centroid, normal, volume for each side of face */ 53633e9753d6SMatthew G. Knepley /* Riemann solve over faces */ 53643e9753d6SMatthew G. Knepley /* Loop over domain faces */ 53653e9753d6SMatthew G. Knepley /* Accumulate fluxes to cells */ 53663e9753d6SMatthew G. Knepley /* TODO Change printFEM to printDisc here */ 53673e9753d6SMatthew G. Knepley if (mesh->printFEM) { 53683e9753d6SMatthew G. Knepley Vec locFbc; 53693e9753d6SMatthew G. Knepley PetscInt pStart, pEnd, p, maxDof; 53703e9753d6SMatthew G. Knepley PetscScalar *zeroes; 53713e9753d6SMatthew G. Knepley 53729566063dSJacob Faibussowitsch PetscCall(VecDuplicate(locF, &locFbc)); 53739566063dSJacob Faibussowitsch PetscCall(VecCopy(locF, locFbc)); 53749566063dSJacob Faibussowitsch PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 53759566063dSJacob Faibussowitsch PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 53769566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(maxDof, &zeroes)); 537748a46eb9SPierre Jolivet for (p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES)); 53789566063dSJacob Faibussowitsch PetscCall(PetscFree(zeroes)); 53799566063dSJacob Faibussowitsch PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc)); 53809566063dSJacob Faibussowitsch PetscCall(VecDestroy(&locFbc)); 53813e9753d6SMatthew G. Knepley } 53823cc88e6aSStefano Zampini end: 53839566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 53843ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 53853e9753d6SMatthew G. Knepley } 53863e9753d6SMatthew G. Knepley 53876528b96dSMatthew G. Knepley /* 53886528b96dSMatthew G. Knepley 1) Allow multiple kernels for BdResidual for hybrid DS 53896528b96dSMatthew G. Knepley 53906528b96dSMatthew G. Knepley DONE 2) Get out dsAux for either side at the same time as cohesive cell dsAux 53916528b96dSMatthew G. Knepley 53926528b96dSMatthew G. Knepley DONE 3) Change DMGetCellFields() to get different aux data a[] for each side 53936528b96dSMatthew G. Knepley - I think I just need to replace a[] with the closure from each face 53946528b96dSMatthew G. Knepley 53956528b96dSMatthew G. Knepley 4) Run both kernels for each non-hybrid field with correct dsAux, and then hybrid field as before 53966528b96dSMatthew G. Knepley */ 5397d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Hybrid_Internal(DM dm, PetscFormKey key[], IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 5398d71ae5a4SJacob Faibussowitsch { 53993e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 54003e9753d6SMatthew G. Knepley const char *name = "Hybrid Residual"; 540104c51a94SMatthew G. Knepley DM dmAux[3] = {NULL, NULL, NULL}; 54023e9753d6SMatthew G. Knepley DMLabel ghostLabel = NULL; 54036528b96dSMatthew G. Knepley PetscDS ds = NULL; 540407218a29SMatthew G. Knepley PetscDS dsIn = NULL; 54056528b96dSMatthew G. Knepley PetscDS dsAux[3] = {NULL, NULL, NULL}; 540604c51a94SMatthew G. Knepley Vec locA[3] = {NULL, NULL, NULL}; 540707218a29SMatthew G. Knepley DM dmScale[3] = {NULL, NULL, NULL}; 540807218a29SMatthew G. Knepley PetscDS dsScale[3] = {NULL, NULL, NULL}; 540907218a29SMatthew G. Knepley Vec locS[3] = {NULL, NULL, NULL}; 54103e9753d6SMatthew G. Knepley PetscSection section = NULL; 54113e9753d6SMatthew G. Knepley DMField coordField = NULL; 541207218a29SMatthew G. Knepley PetscScalar *a[3] = {NULL, NULL, NULL}; 541307218a29SMatthew G. Knepley PetscScalar *s[3] = {NULL, NULL, NULL}; 5414b2ab40e6SMatthew G. Knepley PetscScalar *u = NULL, *u_t; 541507218a29SMatthew G. Knepley PetscScalar *elemVecNeg, *elemVecPos, *elemVecCoh; 54163e9753d6SMatthew G. Knepley IS chunkIS; 54173e9753d6SMatthew G. Knepley const PetscInt *cells; 54183e9753d6SMatthew G. Knepley PetscInt *faces; 54193e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 54203e2b0218SMatthew G. Knepley PetscInt Nf, f, totDim, totDimIn, totDimAux[3], totDimScale[3], numChunks, cellChunkSize, chunk; 54211690c2aeSBarry Smith PetscInt maxDegree = PETSC_INT_MAX; 54223e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 54233e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 54243e9753d6SMatthew G. Knepley 54253e9753d6SMatthew G. Knepley PetscFunctionBegin; 54263cc88e6aSStefano Zampini PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 54273cc88e6aSStefano Zampini if (!cellIS) goto end; 5428437e83fbSMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5429437e83fbSMatthew G. Knepley PetscCall(ISGetLocalSize(cellIS, &numCells)); 54303cc88e6aSStefano Zampini if (cStart >= cEnd) goto end; 54315fedec97SMatthew G. Knepley if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) { 54325fedec97SMatthew G. Knepley const char *name; 54339566063dSJacob Faibussowitsch PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name)); 543463a3b9bcSJacob 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); 54355fedec97SMatthew G. Knepley } 54363e9753d6SMatthew G. Knepley /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 54373e9753d6SMatthew G. Knepley /* FEM */ 54383e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 5439b98a7184SJames Wright PetscCall(DMGetLocalSection(dm, §ion)); 54409566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 544107218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn)); 54429566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 54439566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 544407218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsIn, &totDimIn)); 54459566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2])); 544604c51a94SMatthew G. Knepley if (locA[2]) { 54471059d808SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 54481059d808SMatthew G. Knepley 54499566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA[2], &dmAux[2])); 545007218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2], NULL)); 54519566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2])); 54526528b96dSMatthew G. Knepley { 54536528b96dSMatthew G. Knepley const PetscInt *cone; 54546528b96dSMatthew G. Knepley PetscInt c; 54556528b96dSMatthew G. Knepley 54561059d808SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 54576528b96dSMatthew G. Knepley for (c = 0; c < 2; ++c) { 54586528b96dSMatthew G. Knepley const PetscInt *support; 54596528b96dSMatthew G. Knepley PetscInt ssize, s; 54606528b96dSMatthew G. Knepley 54619566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 54629566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 54631059d808SMatthew 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); 54641059d808SMatthew G. Knepley if (support[0] == cellStart) s = 1; 54651059d808SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 54661059d808SMatthew 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); 54679566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c])); 5468c75bfeddSPierre 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); 54699566063dSJacob Faibussowitsch if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c])); 5470ad540459SPierre Jolivet else dmAux[c] = dmAux[2]; 547107218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c], NULL)); 54729566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c])); 54736528b96dSMatthew G. Knepley } 54746528b96dSMatthew G. Knepley } 54753e9753d6SMatthew G. Knepley } 547607218a29SMatthew G. Knepley /* Handle mass matrix scaling 547707218a29SMatthew G. Knepley The field in key[2] is the field to be scaled, and the scaling field is the first in the dsScale */ 547807218a29SMatthew G. Knepley PetscCall(DMGetAuxiliaryVec(dm, key[2].label, -key[2].value, key[2].part, &locS[2])); 547907218a29SMatthew G. Knepley if (locS[2]) { 54803e2b0218SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 548107218a29SMatthew G. Knepley PetscInt Nb, Nbs; 548207218a29SMatthew G. Knepley 548307218a29SMatthew G. Knepley PetscCall(VecGetDM(locS[2], &dmScale[2])); 54843e2b0218SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[2], cellStart, &dsScale[2], NULL)); 54853e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[2], &totDimScale[2])); 548607218a29SMatthew G. Knepley // BRAD: This is not set correctly 548707218a29SMatthew G. Knepley key[2].field = 2; 548807218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, key[2].field, &Nb)); 548907218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsScale[2], 0, &Nbs)); 549007218a29SMatthew 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); 54913e2b0218SMatthew G. Knepley { 54923e2b0218SMatthew G. Knepley const PetscInt *cone; 54933e2b0218SMatthew G. Knepley PetscInt c; 54943e2b0218SMatthew G. Knepley 54953e2b0218SMatthew G. Knepley locS[1] = locS[0] = locS[2]; 54963e2b0218SMatthew G. Knepley dmScale[1] = dmScale[0] = dmScale[2]; 54973e2b0218SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 54983e2b0218SMatthew G. Knepley for (c = 0; c < 2; ++c) { 54993e2b0218SMatthew G. Knepley const PetscInt *support; 55003e2b0218SMatthew G. Knepley PetscInt ssize, s; 55013e2b0218SMatthew G. Knepley 55023e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 55033e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 55043e2b0218SMatthew 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); 55053e2b0218SMatthew G. Knepley if (support[0] == cellStart) s = 1; 55063e2b0218SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 55073e2b0218SMatthew 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); 55083e2b0218SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[c], support[s], &dsScale[c], NULL)); 55093e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[c], &totDimScale[c])); 55103e2b0218SMatthew G. Knepley } 55113e2b0218SMatthew G. Knepley } 551207218a29SMatthew G. Knepley } 55133e9753d6SMatthew G. Knepley /* 2: Setup geometric data */ 55149566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 55159566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 55163e9753d6SMatthew G. Knepley if (maxDegree > 1) { 55179566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 55183e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 55193e9753d6SMatthew G. Knepley PetscFE fe; 55203e9753d6SMatthew G. Knepley 55219566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 55223e9753d6SMatthew G. Knepley if (fe) { 55239566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 55249566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 55253e9753d6SMatthew G. Knepley } 55263e9753d6SMatthew G. Knepley } 55273e9753d6SMatthew G. Knepley } 55283e9753d6SMatthew G. Knepley /* Loop over chunks */ 55293e9753d6SMatthew G. Knepley cellChunkSize = numCells; 55303e9753d6SMatthew G. Knepley numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize); 553107218a29SMatthew G. Knepley PetscCall(PetscCalloc1(2 * cellChunkSize, &faces)); 553207218a29SMatthew G. Knepley PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS)); 55333e9753d6SMatthew G. Knepley /* Extract field coefficients */ 55343e9753d6SMatthew G. Knepley /* NOTE This needs the end cap faces to have identical orientations */ 553507218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 553607218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 55373e2b0218SMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s)); 553807218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecNeg)); 553907218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecPos)); 554007218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecCoh)); 55413e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 55423e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 55433e9753d6SMatthew G. Knepley 554407218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemVecNeg, cellChunkSize * totDim)); 554507218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemVecPos, cellChunkSize * totDim)); 554607218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemVecCoh, cellChunkSize * totDim)); 55473e9753d6SMatthew G. Knepley /* Get faces */ 55483e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 55493e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 55503e9753d6SMatthew G. Knepley const PetscInt *cone; 55519566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cell, &cone)); 555207218a29SMatthew G. Knepley faces[(c - cS) * 2 + 0] = cone[0]; 555307218a29SMatthew G. Knepley faces[(c - cS) * 2 + 1] = cone[1]; 55543e9753d6SMatthew G. Knepley } 555507218a29SMatthew G. Knepley PetscCall(ISGeneralSetIndices(chunkIS, 2 * cellChunkSize, faces, PETSC_USE_POINTER)); 55563e9753d6SMatthew G. Knepley /* Get geometric data */ 55573e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 55589566063dSJacob Faibussowitsch if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad)); 55599566063dSJacob Faibussowitsch if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom)); 55603e9753d6SMatthew G. Knepley } else { 55613e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 55629566063dSJacob Faibussowitsch if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f])); 55633e9753d6SMatthew G. Knepley } 55643e9753d6SMatthew G. Knepley } 55653e9753d6SMatthew G. Knepley /* Loop over fields */ 55663e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 55673e9753d6SMatthew G. Knepley PetscFE fe; 55683e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 5569148442b3SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 55703e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 55713e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 55725fedec97SMatthew G. Knepley PetscBool isCohesiveField; 55733e9753d6SMatthew G. Knepley 55749566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 55753e9753d6SMatthew G. Knepley if (!fe) continue; 55769566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 55779566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 55789566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 55793e9753d6SMatthew G. Knepley blockSize = Nb; 55803e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 55819566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 55823e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 55833e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 55843e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 55853e9753d6SMatthew G. Knepley offset = numCells - Nr; 558607218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, 0, offset * 2, &chunkGeom)); 558707218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, offset * 2, numCells * 2, &remGeom)); 55889566063dSJacob Faibussowitsch PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField)); 55895fedec97SMatthew G. Knepley chunkGeom->isCohesive = remGeom->isCohesive = PETSC_TRUE; 55906528b96dSMatthew G. Knepley key[0].field = f; 55916528b96dSMatthew G. Knepley key[1].field = f; 55925fedec97SMatthew G. Knepley key[2].field = f; 559307218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, elemVecNeg)); 55948e3a54c0SPierre 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])); 559507218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, elemVecPos)); 55968e3a54c0SPierre 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])); 559707218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, elemVecCoh)); 55988e3a54c0SPierre 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])); 55999566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom)); 56009566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom)); 56013e9753d6SMatthew G. Knepley } 56023e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 56033e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 56043e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 56053e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 560607218a29SMatthew G. Knepley PetscInt i; 56073e9753d6SMatthew G. Knepley 560807218a29SMatthew G. Knepley /* Scale element values */ 560907218a29SMatthew G. Knepley if (locS[0]) { 56103e2b0218SMatthew G. Knepley PetscInt Nb, off = cind * totDim, soff = cind * totDimScale[0]; 561107218a29SMatthew G. Knepley PetscBool cohesive; 561207218a29SMatthew G. Knepley 561307218a29SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 561407218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, f, &Nb)); 561507218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(ds, f, &cohesive)); 561607218a29SMatthew G. Knepley if (f == key[2].field) { 561707218a29SMatthew G. Knepley PetscCheck(cohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Scaling should not happen for face fields"); 561807218a29SMatthew G. Knepley // No cohesive scaling field is currently input 561907218a29SMatthew 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]; 562007218a29SMatthew G. Knepley off += Nb; 562107218a29SMatthew G. Knepley } else { 562207218a29SMatthew G. Knepley const PetscInt N = cohesive ? Nb : Nb * 2; 562307218a29SMatthew G. Knepley 562407218a29SMatthew G. Knepley for (i = 0; i < N; ++i) elemVecCoh[off + i] += elemVecNeg[off + i] + elemVecPos[off + i]; 562507218a29SMatthew G. Knepley off += N; 562607218a29SMatthew G. Knepley } 562707218a29SMatthew G. Knepley } 562807218a29SMatthew G. Knepley } else { 562907218a29SMatthew G. Knepley for (i = cind * totDim; i < (cind + 1) * totDim; ++i) elemVecCoh[i] += elemVecNeg[i] + elemVecPos[i]; 563007218a29SMatthew G. Knepley } 563107218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVecCoh[cind * totDim])); 56323e9753d6SMatthew G. Knepley if (ghostLabel) { 56333e9753d6SMatthew G. Knepley PetscInt ghostVal; 56343e9753d6SMatthew G. Knepley 56359566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 56363e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 56373e9753d6SMatthew G. Knepley } 563807218a29SMatthew G. Knepley PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVecCoh[cind * totDim], ADD_ALL_VALUES)); 56393e9753d6SMatthew G. Knepley } 56403e9753d6SMatthew G. Knepley } 56419566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 564207218a29SMatthew G. Knepley PetscCall(DMPlexRestoreHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 56433e2b0218SMatthew G. Knepley PetscCall(DMPlexRestoreHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s)); 564407218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecNeg)); 564507218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecPos)); 564607218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecCoh)); 56479566063dSJacob Faibussowitsch PetscCall(PetscFree(faces)); 56489566063dSJacob Faibussowitsch PetscCall(ISDestroy(&chunkIS)); 56499566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 56503e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 56519566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 56529566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 56533e9753d6SMatthew G. Knepley } else { 56543e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 56559566063dSJacob Faibussowitsch if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 56569566063dSJacob Faibussowitsch if (quads) PetscCall(PetscQuadratureDestroy(&quads[f])); 56573e9753d6SMatthew G. Knepley } 56589566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 56593e9753d6SMatthew G. Knepley } 566085cc2951SMatthew G. Knepley if (mesh->printFEM) { 566185cc2951SMatthew G. Knepley Vec locFbc; 566285cc2951SMatthew G. Knepley PetscInt pStart, pEnd, p, maxDof; 566385cc2951SMatthew G. Knepley PetscScalar *zeroes; 566485cc2951SMatthew G. Knepley 566585cc2951SMatthew G. Knepley PetscCall(VecDuplicate(locF, &locFbc)); 566685cc2951SMatthew G. Knepley PetscCall(VecCopy(locF, locFbc)); 566785cc2951SMatthew G. Knepley PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 566885cc2951SMatthew G. Knepley PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 566985cc2951SMatthew G. Knepley PetscCall(PetscCalloc1(maxDof, &zeroes)); 567085cc2951SMatthew G. Knepley for (p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES)); 567185cc2951SMatthew G. Knepley PetscCall(PetscFree(zeroes)); 567285cc2951SMatthew G. Knepley PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc)); 567385cc2951SMatthew G. Knepley PetscCall(VecDestroy(&locFbc)); 567485cc2951SMatthew G. Knepley } 56753cc88e6aSStefano Zampini end: 56769566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 56773ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 56783e9753d6SMatthew G. Knepley } 56793e9753d6SMatthew G. Knepley 5680a4e35b19SJacob 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) 5681d71ae5a4SJacob Faibussowitsch { 56823e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 56833e9753d6SMatthew G. Knepley DM plex = NULL, plexA = NULL, tdm; 56843e9753d6SMatthew G. Knepley DMEnclosureType encAux; 5685be62b2b4SMatthew G. Knepley PetscDS ds, dsAux = NULL; 56863e9753d6SMatthew G. Knepley PetscSection section, sectionAux = NULL; 5687e432b41dSStefano Zampini PetscSection globalSection; 56883e9753d6SMatthew G. Knepley Vec locA = NULL, tv; 5689be62b2b4SMatthew G. Knepley PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL; 56903e9753d6SMatthew G. Knepley PetscInt v; 56913e9753d6SMatthew G. Knepley PetscInt Nf, totDim, totDimAux = 0; 5692be62b2b4SMatthew G. Knepley PetscBool hasJac = PETSC_FALSE, hasPrec = PETSC_FALSE, transform; 56933e9753d6SMatthew G. Knepley 56943e9753d6SMatthew G. Knepley PetscFunctionBegin; 56959566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 56969566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 56979566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 56989566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 5699be62b2b4SMatthew G. Knepley PetscCall(DMGetDS(dm, &ds)); 5700be62b2b4SMatthew G. Knepley PetscCall(PetscDSGetNumFields(ds, &Nf)); 5701be62b2b4SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 570221a4fad8SMatthew G. Knepley PetscCall(PetscWeakFormHasBdJacobian(wf, &hasJac)); 570321a4fad8SMatthew G. Knepley PetscCall(PetscWeakFormHasBdJacobianPreconditioner(wf, &hasPrec)); 570421a4fad8SMatthew G. Knepley if (!hasJac && !hasPrec) PetscFunctionReturn(PETSC_SUCCESS); 570521a4fad8SMatthew G. Knepley PetscCall(DMConvert(dm, DMPLEX, &plex)); 57069566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, label, values[0], 0, &locA)); 57073e9753d6SMatthew G. Knepley if (locA) { 57083e9753d6SMatthew G. Knepley DM dmAux; 57093e9753d6SMatthew G. Knepley 57109566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 57119566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 57129566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 5713be62b2b4SMatthew G. Knepley PetscCall(DMGetDS(plexA, &dsAux)); 5714be62b2b4SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux)); 57159566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexA, §ionAux)); 57163e9753d6SMatthew G. Knepley } 57173e9753d6SMatthew G. Knepley 57189566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 57193e9753d6SMatthew G. Knepley for (v = 0; v < numValues; ++v) { 57203e9753d6SMatthew G. Knepley PetscFEGeom *fgeom; 57213e9753d6SMatthew G. Knepley PetscInt maxDegree; 57223e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 57233e9753d6SMatthew G. Knepley IS pointIS; 57243e9753d6SMatthew G. Knepley const PetscInt *points; 572506ad1575SMatthew G. Knepley PetscFormKey key; 57263e9753d6SMatthew G. Knepley PetscInt numFaces, face, Nq; 57273e9753d6SMatthew G. Knepley 572845480ffeSMatthew G. Knepley key.label = label; 572945480ffeSMatthew G. Knepley key.value = values[v]; 573006ad1575SMatthew G. Knepley key.part = 0; 57319566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS)); 57323e9753d6SMatthew G. Knepley if (!pointIS) continue; /* No points with that id on this process */ 57333e9753d6SMatthew G. Knepley { 57343e9753d6SMatthew G. Knepley IS isectIS; 57353e9753d6SMatthew G. Knepley 57363e9753d6SMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a prior if one is a superset of the other */ 57379566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 57389566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 57393e9753d6SMatthew G. Knepley pointIS = isectIS; 57403e9753d6SMatthew G. Knepley } 57419566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 57429566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 574332603206SJames 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)); 57449566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 574548a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 57463e9753d6SMatthew G. Knepley if (!qGeom) { 57473e9753d6SMatthew G. Knepley PetscFE fe; 57483e9753d6SMatthew G. Knepley 5749be62b2b4SMatthew G. Knepley PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&fe)); 57509566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 57519566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 57523e9753d6SMatthew G. Knepley } 57539566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 57549566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 57553e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 5756f15274beSMatthew Knepley const PetscInt point = points[face], *support; 57573e9753d6SMatthew G. Knepley PetscScalar *x = NULL; 5758f15274beSMatthew Knepley PetscInt i; 57593e9753d6SMatthew G. Knepley 57609566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, point, &support)); 57619566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 57623e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 57639566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 57643e9753d6SMatthew G. Knepley if (locX_t) { 57659566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x)); 57663e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i]; 57679566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x)); 57683e9753d6SMatthew G. Knepley } 57693e9753d6SMatthew G. Knepley if (locA) { 57703e9753d6SMatthew G. Knepley PetscInt subp; 57719566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 57729566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 57733e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i]; 57749566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 57753e9753d6SMatthew G. Knepley } 57763e9753d6SMatthew G. Knepley } 577721a4fad8SMatthew G. Knepley if (elemMat) PetscCall(PetscArrayzero(elemMat, numFaces * totDim * totDim)); 577821a4fad8SMatthew G. Knepley if (elemMatP) PetscCall(PetscArrayzero(elemMatP, numFaces * totDim * totDim)); 57793e9753d6SMatthew G. Knepley { 57803e9753d6SMatthew G. Knepley PetscFE fe; 57813e9753d6SMatthew G. Knepley PetscInt Nb; 57823e9753d6SMatthew G. Knepley /* Conforming batches */ 57833e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 57843e9753d6SMatthew G. Knepley /* Remainder */ 57853e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 57863e9753d6SMatthew G. Knepley PetscInt fieldJ, Nr, offset; 57873e9753d6SMatthew G. Knepley 5788be62b2b4SMatthew G. Knepley PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&fe)); 57899566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 57909566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 57913e9753d6SMatthew G. Knepley blockSize = Nb; 57923e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 57939566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 57943e9753d6SMatthew G. Knepley numChunks = numFaces / (numBatches * batchSize); 57953e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 57963e9753d6SMatthew G. Knepley Nr = numFaces % (numBatches * batchSize); 57973e9753d6SMatthew G. Knepley offset = numFaces - Nr; 57989566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom)); 57993e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 580045480ffeSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 5801be62b2b4SMatthew G. Knepley if (hasJac) PetscCall(PetscFEIntegrateBdJacobian(ds, wf, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, dsAux, a, t, X_tShift, elemMat)); 5802be62b2b4SMatthew G. Knepley if (hasPrec) PetscCall(PetscFEIntegrateBdJacobian(ds, wf, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, dsAux, a, t, X_tShift, elemMatP)); 58033e9753d6SMatthew G. Knepley } 58049566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 58053e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 580645480ffeSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 5807be62b2b4SMatthew G. Knepley if (hasJac) 58088e3a54c0SPierre 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])); 5809be62b2b4SMatthew G. Knepley if (hasPrec) 58108e3a54c0SPierre 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])); 58113e9753d6SMatthew G. Knepley } 58129566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 58133e9753d6SMatthew G. Knepley } 58143e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 58153e9753d6SMatthew G. Knepley const PetscInt point = points[face], *support; 58163e9753d6SMatthew G. Knepley 58173e9753d6SMatthew G. Knepley /* Transform to global basis before insertion in Jacobian */ 58189566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(plex, point, &support)); 581921a4fad8SMatthew G. Knepley if (hasJac && transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMat[face * totDim * totDim])); 582021a4fad8SMatthew G. Knepley if (hasPrec && transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMatP[face * totDim * totDim])); 5821be62b2b4SMatthew G. Knepley if (hasPrec) { 5822be62b2b4SMatthew G. Knepley if (hasJac) { 58239566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face * totDim * totDim])); 582421a4fad8SMatthew G. Knepley PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, Jac, support[0], &elemMat[face * totDim * totDim], ADD_VALUES)); 58253e9753d6SMatthew G. Knepley } 5826be62b2b4SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMatP[face * totDim * totDim])); 5827be62b2b4SMatthew G. Knepley PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, JacP, support[0], &elemMatP[face * totDim * totDim], ADD_VALUES)); 5828be62b2b4SMatthew G. Knepley } else { 5829be62b2b4SMatthew G. Knepley if (hasJac) { 5830be62b2b4SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face * totDim * totDim])); 583121a4fad8SMatthew G. Knepley PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, Jac, support[0], &elemMat[face * totDim * totDim], ADD_VALUES)); 5832be62b2b4SMatthew G. Knepley } 5833be62b2b4SMatthew G. Knepley } 5834be62b2b4SMatthew G. Knepley } 58359566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 58369566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 58379566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 58389566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 5839be62b2b4SMatthew G. Knepley PetscCall(PetscFree5(u, u_t, elemMat, elemMatP, a)); 58403e9753d6SMatthew G. Knepley } 58419566063dSJacob Faibussowitsch if (plex) PetscCall(DMDestroy(&plex)); 58429566063dSJacob Faibussowitsch if (plexA) PetscCall(DMDestroy(&plexA)); 58433ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 58443e9753d6SMatthew G. Knepley } 58453e9753d6SMatthew G. Knepley 5846d71ae5a4SJacob 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) 5847d71ae5a4SJacob Faibussowitsch { 58483e9753d6SMatthew G. Knepley DMField coordField; 58493e9753d6SMatthew G. Knepley DMLabel depthLabel; 58503e9753d6SMatthew G. Knepley IS facetIS; 58513e9753d6SMatthew G. Knepley PetscInt dim; 58523e9753d6SMatthew G. Knepley 58533e9753d6SMatthew G. Knepley PetscFunctionBegin; 58549566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 58559566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 58569566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 58579566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 58589566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, field, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS)); 58599566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 58603ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 58613e9753d6SMatthew G. Knepley } 58623e9753d6SMatthew G. Knepley 5863a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexComputeBdJacobian_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP, void *user) 5864d71ae5a4SJacob Faibussowitsch { 58653e9753d6SMatthew G. Knepley PetscDS prob; 58663e9753d6SMatthew G. Knepley PetscInt dim, numBd, bd; 58673e9753d6SMatthew G. Knepley DMLabel depthLabel; 58683e9753d6SMatthew G. Knepley DMField coordField = NULL; 58693e9753d6SMatthew G. Knepley IS facetIS; 58703e9753d6SMatthew G. Knepley 58713e9753d6SMatthew G. Knepley PetscFunctionBegin; 58729566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 58739566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 58749566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 58759566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 58769566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 58779566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 58783e9753d6SMatthew G. Knepley for (bd = 0; bd < numBd; ++bd) { 587945480ffeSMatthew G. Knepley PetscWeakForm wf; 58803e9753d6SMatthew G. Knepley DMBoundaryConditionType type; 58813e9753d6SMatthew G. Knepley DMLabel label; 58823e9753d6SMatthew G. Knepley const PetscInt *values; 58833e9753d6SMatthew G. Knepley PetscInt fieldI, numValues; 58843e9753d6SMatthew G. Knepley PetscObject obj; 58853e9753d6SMatthew G. Knepley PetscClassId id; 58863e9753d6SMatthew G. Knepley 58879566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &fieldI, NULL, NULL, NULL, NULL, NULL)); 58883d3e5d66SMatthew G. Knepley if (type & DM_BC_ESSENTIAL) continue; 58899566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, &obj)); 58909566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 58913d3e5d66SMatthew G. Knepley if (id != PETSCFE_CLASSID) continue; 58929566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, fieldI, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS)); 58933e9753d6SMatthew G. Knepley } 58949566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 58953ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 58963e9753d6SMatthew G. Knepley } 58973e9753d6SMatthew G. Knepley 5898d71ae5a4SJacob 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) 5899d71ae5a4SJacob Faibussowitsch { 59003e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 59013e9753d6SMatthew G. Knepley const char *name = "Jacobian"; 59029a2a23afSMatthew G. Knepley DM dmAux = NULL, plex, tdm; 59033e9753d6SMatthew G. Knepley DMEnclosureType encAux; 59043e9753d6SMatthew G. Knepley Vec A, tv; 59053e9753d6SMatthew G. Knepley DMField coordField; 59063e9753d6SMatthew G. Knepley PetscDS prob, probAux = NULL; 5907e432b41dSStefano Zampini PetscSection section, globalSection, sectionAux; 59083e9753d6SMatthew G. Knepley PetscScalar *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL; 59093e9753d6SMatthew G. Knepley const PetscInt *cells; 59103e9753d6SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ; 591128351e22SJed Brown PetscInt totDim, totDimAux = 0, cStart, cEnd, numCells, c; 5912e04ae0b4SMatthew G. Knepley PetscBool hasJac = PETSC_FALSE, hasPrec = PETSC_FALSE, hasDyn, hasFV = PETSC_FALSE, transform; 59133e9753d6SMatthew G. Knepley 59143e9753d6SMatthew G. Knepley PetscFunctionBegin; 5915af18b51aSmarkadams4 PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 5916ae3cf2c1SStefano Zampini PetscCall(DMGetLocalSection(dm, §ion)); 5917ae3cf2c1SStefano Zampini PetscCall(DMGetGlobalSection(dm, &globalSection)); 5918ae3cf2c1SStefano Zampini PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A)); 5919ae3cf2c1SStefano Zampini if (A) { 5920ae3cf2c1SStefano Zampini PetscCall(VecGetDM(A, &dmAux)); 5921ae3cf2c1SStefano Zampini PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 5922ae3cf2c1SStefano Zampini PetscCall(DMConvert(dmAux, DMPLEX, &plex)); 5923ae3cf2c1SStefano Zampini PetscCall(DMGetLocalSection(plex, §ionAux)); 5924ae3cf2c1SStefano Zampini PetscCall(DMGetDS(dmAux, &probAux)); 5925ae3cf2c1SStefano Zampini PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 5926ae3cf2c1SStefano Zampini } 5927ae3cf2c1SStefano Zampini PetscCall(DMGetCoordinateField(dm, &coordField)); 5928e04ae0b4SMatthew G. Knepley if (!cellIS) goto end; 59299566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5930437e83fbSMatthew G. Knepley PetscCall(ISGetLocalSize(cellIS, &numCells)); 5931437e83fbSMatthew G. Knepley if (cStart >= cEnd) goto end; 59329566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 59339566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 59349566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 593507218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL)); 59369566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 59379566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 59389566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobian(prob, &hasJac)); 59399566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec)); 59403e9753d6SMatthew G. Knepley /* user passed in the same matrix, avoid double contributions and 59413e9753d6SMatthew G. Knepley only assemble the Jacobian */ 59423e9753d6SMatthew G. Knepley if (hasJac && Jac == JacP) hasPrec = PETSC_FALSE; 59439566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 59443e9753d6SMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 594532603206SJames 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)); 59469566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 59473e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 59483e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 59493e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 59503e9753d6SMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 59513e9753d6SMatthew G. Knepley PetscInt i; 59523e9753d6SMatthew G. Knepley 59539566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x)); 59543e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i]; 59559566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x)); 59563e9753d6SMatthew G. Knepley if (X_t) { 59579566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t)); 59583e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i]; 59599566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t)); 59603e9753d6SMatthew G. Knepley } 59613e9753d6SMatthew G. Knepley if (dmAux) { 59623e9753d6SMatthew G. Knepley PetscInt subcell; 59639566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell)); 59649566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x)); 59653e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i]; 59669566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x)); 59673e9753d6SMatthew G. Knepley } 59683e9753d6SMatthew G. Knepley } 59699566063dSJacob Faibussowitsch if (hasJac) PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim)); 59709566063dSJacob Faibussowitsch if (hasPrec) PetscCall(PetscArrayzero(elemMatP, numCells * totDim * totDim)); 59719566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim)); 59723e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 59733e9753d6SMatthew G. Knepley PetscClassId id; 59743e9753d6SMatthew G. Knepley PetscFE fe; 59753e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 59763e9753d6SMatthew G. Knepley PetscInt Nb; 59773e9753d6SMatthew G. Knepley /* Conforming batches */ 59783e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 59793e9753d6SMatthew G. Knepley /* Remainder */ 59803e9753d6SMatthew G. Knepley PetscInt Nr, offset, Nq; 59813e9753d6SMatthew G. Knepley PetscInt maxDegree; 59823e9753d6SMatthew G. Knepley PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 59833e9753d6SMatthew G. Knepley 59849566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 59859566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 59869371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 59879371c9d4SSatish Balay hasFV = PETSC_TRUE; 59889371c9d4SSatish Balay continue; 59899371c9d4SSatish Balay } 59909566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 59919566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 59929566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 599348a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 59943e9753d6SMatthew G. Knepley if (!qGeom) { 59959566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 59969566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 59973e9753d6SMatthew G. Knepley } 59989566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 59999566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 60003e9753d6SMatthew G. Knepley blockSize = Nb; 60013e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 60029566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 60033e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 60043e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 60053e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 60063e9753d6SMatthew G. Knepley offset = numCells - Nr; 60079566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 60089566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom)); 60093e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 60106528b96dSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 60113e9753d6SMatthew G. Knepley if (hasJac) { 60129566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 60138e3a54c0SPierre 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])); 60143e9753d6SMatthew G. Knepley } 60153e9753d6SMatthew G. Knepley if (hasPrec) { 60169566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP)); 60178e3a54c0SPierre 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])); 60183e9753d6SMatthew G. Knepley } 60193e9753d6SMatthew G. Knepley if (hasDyn) { 60209566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD)); 60218e3a54c0SPierre 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])); 60223e9753d6SMatthew G. Knepley } 60233e9753d6SMatthew G. Knepley } 60249566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom)); 60259566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom)); 60269566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 60279566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 60283e9753d6SMatthew G. Knepley } 60293e9753d6SMatthew G. Knepley /* Add contribution from X_t */ 60309371c9d4SSatish Balay if (hasDyn) { 60319371c9d4SSatish Balay for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 60329371c9d4SSatish Balay } 60333e9753d6SMatthew G. Knepley if (hasFV) { 60343e9753d6SMatthew G. Knepley PetscClassId id; 60353e9753d6SMatthew G. Knepley PetscFV fv; 60363e9753d6SMatthew G. Knepley PetscInt offsetI, NcI, NbI = 1, fc, f; 60373e9753d6SMatthew G. Knepley 60383e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 60399566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv)); 60409566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, fieldI, &offsetI)); 60419566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId((PetscObject)fv, &id)); 60423e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 60432f86f8c5SMatthew G. Knepley /* Put in the weighted identity */ 60449566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &NcI)); 60453e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 60463e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 60473e9753d6SMatthew G. Knepley const PetscInt eOffset = cind * totDim * totDim; 60482f86f8c5SMatthew G. Knepley PetscReal vol; 60492f86f8c5SMatthew G. Knepley 60502f86f8c5SMatthew G. Knepley PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 60513e9753d6SMatthew G. Knepley for (fc = 0; fc < NcI; ++fc) { 60523e9753d6SMatthew G. Knepley for (f = 0; f < NbI; ++f) { 60533e9753d6SMatthew G. Knepley const PetscInt i = offsetI + f * NcI + fc; 60543e9753d6SMatthew G. Knepley if (hasPrec) { 60552f86f8c5SMatthew G. Knepley if (hasJac) elemMat[eOffset + i * totDim + i] = vol; 60562f86f8c5SMatthew G. Knepley elemMatP[eOffset + i * totDim + i] = vol; 60579371c9d4SSatish Balay } else { 60582f86f8c5SMatthew G. Knepley elemMat[eOffset + i * totDim + i] = vol; 60599371c9d4SSatish Balay } 60603e9753d6SMatthew G. Knepley } 60613e9753d6SMatthew G. Knepley } 60623e9753d6SMatthew G. Knepley } 60633e9753d6SMatthew G. Knepley } 60643e9753d6SMatthew G. Knepley /* No allocated space for FV stuff, so ignore the zero entries */ 60659566063dSJacob Faibussowitsch PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); 60663e9753d6SMatthew G. Knepley } 60673e9753d6SMatthew G. Knepley /* Insert values into matrix */ 60683e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 60693e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 60703e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 60713e9753d6SMatthew G. Knepley 60723e9753d6SMatthew G. Knepley /* Transform to global basis before insertion in Jacobian */ 60739566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind * totDim * totDim])); 60743e9753d6SMatthew G. Knepley if (hasPrec) { 60753e9753d6SMatthew G. Knepley if (hasJac) { 60769566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 6077e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMat[cind * totDim * totDim], ADD_VALUES)); 60783e9753d6SMatthew G. Knepley } 60799566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind * totDim * totDim])); 6080be62b2b4SMatthew G. Knepley PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, JacP, cell, &elemMatP[cind * totDim * totDim], ADD_VALUES)); 60813e9753d6SMatthew G. Knepley } else { 60823e9753d6SMatthew G. Knepley if (hasJac) { 60839566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 6084e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, JacP, cell, &elemMat[cind * totDim * totDim], ADD_VALUES)); 60853e9753d6SMatthew G. Knepley } 60863e9753d6SMatthew G. Knepley } 60873e9753d6SMatthew G. Knepley } 60889566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 60899566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE)); 60909566063dSJacob Faibussowitsch PetscCall(PetscFree5(u, u_t, elemMat, elemMatP, elemMatD)); 60913e9753d6SMatthew G. Knepley if (dmAux) { 60929566063dSJacob Faibussowitsch PetscCall(PetscFree(a)); 60939566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 60943e9753d6SMatthew G. Knepley } 60953e9753d6SMatthew G. Knepley /* Compute boundary integrals */ 60969566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, user)); 60973e9753d6SMatthew G. Knepley /* Assemble matrix */ 60989371c9d4SSatish Balay end: { 6099e04ae0b4SMatthew G. Knepley PetscBool assOp = hasJac && hasPrec ? PETSC_TRUE : PETSC_FALSE, gassOp; 6100e04ae0b4SMatthew G. Knepley 6101462c564dSBarry Smith PetscCallMPI(MPIU_Allreduce(&assOp, &gassOp, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 61023e9753d6SMatthew G. Knepley if (hasJac && hasPrec) { 61039566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY)); 61049566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY)); 61053e9753d6SMatthew G. Knepley } 6106e04ae0b4SMatthew G. Knepley } 61079566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY)); 61089566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 61099566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 61103ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 61113e9753d6SMatthew G. Knepley } 61123e9753d6SMatthew G. Knepley 6113d71ae5a4SJacob 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) 6114d71ae5a4SJacob Faibussowitsch { 61153e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 61163e9753d6SMatthew G. Knepley const char *name = "Hybrid Jacobian"; 6117148442b3SMatthew G. Knepley DM dmAux[3] = {NULL, NULL, NULL}; 6118148442b3SMatthew G. Knepley DMLabel ghostLabel = NULL; 61193e9753d6SMatthew G. Knepley DM plex = NULL; 61203e9753d6SMatthew G. Knepley DM plexA = NULL; 6121148442b3SMatthew G. Knepley PetscDS ds = NULL; 612207218a29SMatthew G. Knepley PetscDS dsIn = NULL; 6123148442b3SMatthew G. Knepley PetscDS dsAux[3] = {NULL, NULL, NULL}; 6124148442b3SMatthew G. Knepley Vec locA[3] = {NULL, NULL, NULL}; 612507218a29SMatthew G. Knepley DM dmScale[3] = {NULL, NULL, NULL}; 612607218a29SMatthew G. Knepley PetscDS dsScale[3] = {NULL, NULL, NULL}; 612707218a29SMatthew G. Knepley Vec locS[3] = {NULL, NULL, NULL}; 61283e9753d6SMatthew G. Knepley PetscSection section = NULL; 6129148442b3SMatthew G. Knepley PetscSection sectionAux[3] = {NULL, NULL, NULL}; 61303e9753d6SMatthew G. Knepley DMField coordField = NULL; 613107218a29SMatthew G. Knepley PetscScalar *a[3] = {NULL, NULL, NULL}; 613207218a29SMatthew G. Knepley PetscScalar *s[3] = {NULL, NULL, NULL}; 613307218a29SMatthew G. Knepley PetscScalar *u = NULL, *u_t; 613407218a29SMatthew G. Knepley PetscScalar *elemMatNeg, *elemMatPos, *elemMatCoh; 613507218a29SMatthew G. Knepley PetscScalar *elemMatNegP, *elemMatPosP, *elemMatCohP; 6136e432b41dSStefano Zampini PetscSection globalSection; 61373e9753d6SMatthew G. Knepley IS chunkIS; 61383e9753d6SMatthew G. Knepley const PetscInt *cells; 61393e9753d6SMatthew G. Knepley PetscInt *faces; 61403e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 61413e2b0218SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ, totDim, totDimIn, totDimAux[3], totDimScale[3], numChunks, cellChunkSize, chunk; 61421690c2aeSBarry Smith PetscInt maxDegree = PETSC_INT_MAX; 61433e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 61443e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 6145e432b41dSStefano Zampini PetscBool hasBdJac, hasBdPrec; 61463e9753d6SMatthew G. Knepley 61473e9753d6SMatthew G. Knepley PetscFunctionBegin; 61483cc88e6aSStefano Zampini PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 61493cc88e6aSStefano Zampini if (!cellIS) goto end; 6150437e83fbSMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 6151437e83fbSMatthew G. Knepley PetscCall(ISGetLocalSize(cellIS, &numCells)); 61523cc88e6aSStefano Zampini if (cStart >= cEnd) goto end; 61535fedec97SMatthew G. Knepley if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) { 61545fedec97SMatthew G. Knepley const char *name; 61559566063dSJacob Faibussowitsch PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name)); 615663a3b9bcSJacob 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); 61575fedec97SMatthew G. Knepley } 61589566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 6159b98a7184SJames Wright PetscCall(DMGetLocalSection(dm, §ion)); 61609566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 61619566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 616207218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn)); 61639566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 61649566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 616507218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsIn, &totDimIn)); 61669566063dSJacob Faibussowitsch PetscCall(PetscDSHasBdJacobian(ds, &hasBdJac)); 61679566063dSJacob Faibussowitsch PetscCall(PetscDSHasBdJacobianPreconditioner(ds, &hasBdPrec)); 61689566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2])); 6169148442b3SMatthew G. Knepley if (locA[2]) { 61701059d808SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 61711059d808SMatthew G. Knepley 61729566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA[2], &dmAux[2])); 61739566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux[2], DMPLEX, &plexA)); 6174b98a7184SJames Wright PetscCall(DMGetLocalSection(dmAux[2], §ionAux[2])); 617507218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2], NULL)); 61769566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2])); 6177148442b3SMatthew G. Knepley { 6178148442b3SMatthew G. Knepley const PetscInt *cone; 6179148442b3SMatthew G. Knepley PetscInt c; 6180148442b3SMatthew G. Knepley 61811059d808SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 6182148442b3SMatthew G. Knepley for (c = 0; c < 2; ++c) { 6183148442b3SMatthew G. Knepley const PetscInt *support; 6184148442b3SMatthew G. Knepley PetscInt ssize, s; 6185148442b3SMatthew G. Knepley 61869566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 61879566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 61881059d808SMatthew 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); 61891059d808SMatthew G. Knepley if (support[0] == cellStart) s = 1; 61901059d808SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 61911059d808SMatthew 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); 61929566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c])); 61939566063dSJacob Faibussowitsch if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c])); 6194ad540459SPierre Jolivet else dmAux[c] = dmAux[2]; 619507218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c], NULL)); 61969566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c])); 6197148442b3SMatthew G. Knepley } 6198148442b3SMatthew G. Knepley } 61993e9753d6SMatthew G. Knepley } 620007218a29SMatthew G. Knepley /* Handle mass matrix scaling 620107218a29SMatthew G. Knepley The field in key[2] is the field to be scaled, and the scaling field is the first in the dsScale */ 620207218a29SMatthew G. Knepley PetscCall(DMGetAuxiliaryVec(dm, key[2].label, -key[2].value, key[2].part, &locS[2])); 620307218a29SMatthew G. Knepley if (locS[2]) { 62043e2b0218SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 620507218a29SMatthew G. Knepley PetscInt Nb, Nbs; 620607218a29SMatthew G. Knepley 620707218a29SMatthew G. Knepley PetscCall(VecGetDM(locS[2], &dmScale[2])); 620807218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[2], cells ? cells[cStart] : cStart, &dsScale[2], NULL)); 62093e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[2], &totDimScale[2])); 621007218a29SMatthew G. Knepley // BRAD: This is not set correctly 621107218a29SMatthew G. Knepley key[2].field = 2; 621207218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, key[2].field, &Nb)); 621307218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsScale[2], 0, &Nbs)); 621407218a29SMatthew 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); 62153e2b0218SMatthew G. Knepley { 62163e2b0218SMatthew G. Knepley const PetscInt *cone; 62173e2b0218SMatthew G. Knepley PetscInt c; 62183e2b0218SMatthew G. Knepley 62193e2b0218SMatthew G. Knepley locS[1] = locS[0] = locS[2]; 62203e2b0218SMatthew G. Knepley dmScale[1] = dmScale[0] = dmScale[2]; 62213e2b0218SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 62223e2b0218SMatthew G. Knepley for (c = 0; c < 2; ++c) { 62233e2b0218SMatthew G. Knepley const PetscInt *support; 62243e2b0218SMatthew G. Knepley PetscInt ssize, s; 62253e2b0218SMatthew G. Knepley 62263e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 62273e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 62283e2b0218SMatthew 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); 62293e2b0218SMatthew G. Knepley if (support[0] == cellStart) s = 1; 62303e2b0218SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 62313e2b0218SMatthew 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); 62323e2b0218SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[c], support[s], &dsScale[c], NULL)); 62333e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[c], &totDimScale[c])); 62343e2b0218SMatthew G. Knepley } 62353e2b0218SMatthew G. Knepley } 623607218a29SMatthew G. Knepley } 623707218a29SMatthew G. Knepley /* 2: Setup geometric data */ 62389566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 62399566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 62403e9753d6SMatthew G. Knepley if (maxDegree > 1) { 62413e9753d6SMatthew G. Knepley PetscInt f; 62429566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 62433e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 62443e9753d6SMatthew G. Knepley PetscFE fe; 62453e9753d6SMatthew G. Knepley 62469566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 62473e9753d6SMatthew G. Knepley if (fe) { 62489566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 62499566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 62503e9753d6SMatthew G. Knepley } 62513e9753d6SMatthew G. Knepley } 62523e9753d6SMatthew G. Knepley } 625307218a29SMatthew G. Knepley /* Loop over chunks */ 62543e9753d6SMatthew G. Knepley cellChunkSize = numCells; 62553e9753d6SMatthew G. Knepley numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize); 625607218a29SMatthew G. Knepley PetscCall(PetscCalloc1(2 * cellChunkSize, &faces)); 6257a4158a15SMatthew G. Knepley PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 1 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS)); 625807218a29SMatthew G. Knepley /* Extract field coefficients */ 625907218a29SMatthew G. Knepley /* NOTE This needs the end cap faces to have identical orientations */ 626007218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 626107218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 62628bf0a22dSMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s)); 626307218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNeg)); 626407218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPos)); 626507218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCoh)); 626607218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNegP)); 626707218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPosP)); 626807218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCohP)); 62693e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 62703e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 62713e9753d6SMatthew G. Knepley 627207218a29SMatthew G. Knepley if (hasBdJac) { 627307218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatNeg, cellChunkSize * totDim * totDim)); 627407218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatPos, cellChunkSize * totDim * totDim)); 627507218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatCoh, cellChunkSize * totDim * totDim)); 627607218a29SMatthew G. Knepley } 627707218a29SMatthew G. Knepley if (hasBdPrec) { 627807218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatNegP, cellChunkSize * totDim * totDim)); 627907218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatPosP, cellChunkSize * totDim * totDim)); 628007218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatCohP, cellChunkSize * totDim * totDim)); 628107218a29SMatthew G. Knepley } 62823e9753d6SMatthew G. Knepley /* Get faces */ 62833e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 62843e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 62853e9753d6SMatthew G. Knepley const PetscInt *cone; 62869566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(plex, cell, &cone)); 628707218a29SMatthew G. Knepley faces[(c - cS) * 2 + 0] = cone[0]; 628807218a29SMatthew G. Knepley faces[(c - cS) * 2 + 1] = cone[1]; 62893e9753d6SMatthew G. Knepley } 629007218a29SMatthew G. Knepley PetscCall(ISGeneralSetIndices(chunkIS, 2 * cellChunkSize, faces, PETSC_USE_POINTER)); 62913e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 62929566063dSJacob Faibussowitsch if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad)); 62939566063dSJacob Faibussowitsch if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom)); 62943e9753d6SMatthew G. Knepley } else { 62953e9753d6SMatthew G. Knepley PetscInt f; 62963e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 62979566063dSJacob Faibussowitsch if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f])); 62983e9753d6SMatthew G. Knepley } 62993e9753d6SMatthew G. Knepley } 63003e9753d6SMatthew G. Knepley 63013e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 63023e9753d6SMatthew G. Knepley PetscFE feI; 63033e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[fieldI]; 63043e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 63053e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[fieldI]; 63063e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 63075fedec97SMatthew G. Knepley PetscBool isCohesiveField; 63083e9753d6SMatthew G. Knepley 63099566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&feI)); 63103e9753d6SMatthew G. Knepley if (!feI) continue; 63119566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(feI, NULL, &numBlocks, NULL, &numBatches)); 63129566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 63139566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feI, &Nb)); 63143e9753d6SMatthew G. Knepley blockSize = Nb; 63153e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 63169566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(feI, blockSize, numBlocks, batchSize, numBatches)); 63173e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 63183e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 63193e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 63203e9753d6SMatthew G. Knepley offset = numCells - Nr; 632107218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, 0, offset * 2, &chunkGeom)); 632207218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, offset * 2, numCells * 2, &remGeom)); 63239566063dSJacob Faibussowitsch PetscCall(PetscDSGetCohesive(ds, fieldI, &isCohesiveField)); 63243e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 63253e9753d6SMatthew G. Knepley PetscFE feJ; 63263e9753d6SMatthew G. Knepley 63279566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *)&feJ)); 63283e9753d6SMatthew G. Knepley if (!feJ) continue; 6329148442b3SMatthew G. Knepley key[0].field = fieldI * Nf + fieldJ; 6330148442b3SMatthew G. Knepley key[1].field = fieldI * Nf + fieldJ; 63315fedec97SMatthew G. Knepley key[2].field = fieldI * Nf + fieldJ; 6332148442b3SMatthew G. Knepley if (hasBdJac) { 633307218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMatNeg)); 63348e3a54c0SPierre 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])); 633507218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMatPos)); 63368e3a54c0SPierre 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])); 6337148442b3SMatthew G. Knepley } 6338148442b3SMatthew G. Knepley if (hasBdPrec) { 633907218a29SMatthew 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)); 63408e3a54c0SPierre 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])); 634107218a29SMatthew 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)); 63428e3a54c0SPierre 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])); 6343148442b3SMatthew G. Knepley } 63445fedec97SMatthew G. Knepley if (hasBdJac) { 634507218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMatCoh)); 63468e3a54c0SPierre 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])); 6347148442b3SMatthew G. Knepley } 63485fedec97SMatthew G. Knepley if (hasBdPrec) { 634907218a29SMatthew 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)); 63508e3a54c0SPierre 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])); 63513e9753d6SMatthew G. Knepley } 63523e9753d6SMatthew G. Knepley } 63539566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom)); 63549566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom)); 63553e9753d6SMatthew G. Knepley } 63563e9753d6SMatthew G. Knepley /* Insert values into matrix */ 63573e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 63583e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 635907218a29SMatthew G. Knepley const PetscInt cind = c - cS, coff = cind * totDim * totDim; 636007218a29SMatthew G. Knepley PetscInt i, j; 63613e9753d6SMatthew G. Knepley 636207218a29SMatthew G. Knepley /* Scale element values */ 636307218a29SMatthew G. Knepley if (locS[0]) { 63643e2b0218SMatthew G. Knepley PetscInt Nb, soff = cind * totDimScale[0], off = 0; 636507218a29SMatthew G. Knepley PetscBool cohesive; 636607218a29SMatthew G. Knepley 636707218a29SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 636807218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, fieldI, &Nb)); 636907218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(ds, fieldI, &cohesive)); 637007218a29SMatthew G. Knepley 637107218a29SMatthew G. Knepley if (fieldI == key[2].field) { 637207218a29SMatthew G. Knepley PetscCheck(cohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Scaling should not happen for face fields"); 63738bf0a22dSMatthew G. Knepley for (i = 0; i < Nb; ++i) { 637407218a29SMatthew 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]; 63758bf0a22dSMatthew G. Knepley if (hasBdPrec) 63768bf0a22dSMatthew 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]; 63778bf0a22dSMatthew G. Knepley } 637807218a29SMatthew G. Knepley off += Nb; 637907218a29SMatthew G. Knepley } else { 638007218a29SMatthew G. Knepley const PetscInt N = cohesive ? Nb : Nb * 2; 638107218a29SMatthew G. Knepley 63828bf0a22dSMatthew G. Knepley for (i = 0; i < N; ++i) { 638307218a29SMatthew 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]; 63848bf0a22dSMatthew G. Knepley if (hasBdPrec) 63858bf0a22dSMatthew 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]; 63868bf0a22dSMatthew G. Knepley } 638707218a29SMatthew G. Knepley off += N; 638807218a29SMatthew G. Knepley } 638907218a29SMatthew G. Knepley } 639007218a29SMatthew G. Knepley } else { 639107218a29SMatthew G. Knepley for (i = 0; i < totDim * totDim; ++i) elemMatCoh[coff + i] += elemMatNeg[coff + i] + elemMatPos[coff + i]; 63928bf0a22dSMatthew G. Knepley if (hasBdPrec) 63938bf0a22dSMatthew G. Knepley for (i = 0; i < totDim * totDim; ++i) elemMatCohP[coff + i] += elemMatNegP[coff + i] + elemMatPosP[coff + i]; 639407218a29SMatthew G. Knepley } 63953e9753d6SMatthew G. Knepley if (hasBdPrec) { 63963e9753d6SMatthew G. Knepley if (hasBdJac) { 639707218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCoh[cind * totDim * totDim])); 6398e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMatCoh[cind * totDim * totDim], ADD_VALUES)); 63993e9753d6SMatthew G. Knepley } 640007218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCohP[cind * totDim * totDim])); 640107218a29SMatthew G. Knepley PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMatCohP[cind * totDim * totDim], ADD_VALUES)); 64023e9753d6SMatthew G. Knepley } else if (hasBdJac) { 640307218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCoh[cind * totDim * totDim])); 6404e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, JacP, cell, &elemMatCoh[cind * totDim * totDim], ADD_VALUES)); 64053e9753d6SMatthew G. Knepley } 64063e9753d6SMatthew G. Knepley } 64073e9753d6SMatthew G. Knepley } 64089566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 640907218a29SMatthew G. Knepley PetscCall(DMPlexRestoreHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 641007218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNeg)); 641107218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPos)); 641207218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCoh)); 641307218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNegP)); 641407218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPosP)); 641507218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCohP)); 64169566063dSJacob Faibussowitsch PetscCall(PetscFree(faces)); 64179566063dSJacob Faibussowitsch PetscCall(ISDestroy(&chunkIS)); 64189566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 64193e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 64209566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 64219566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 64223e9753d6SMatthew G. Knepley } else { 64233e9753d6SMatthew G. Knepley PetscInt f; 64243e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 64259566063dSJacob Faibussowitsch if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 64269566063dSJacob Faibussowitsch if (quads) PetscCall(PetscQuadratureDestroy(&quads[f])); 64273e9753d6SMatthew G. Knepley } 64289566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 64293e9753d6SMatthew G. Knepley } 64309566063dSJacob Faibussowitsch if (dmAux[2]) PetscCall(DMDestroy(&plexA)); 64319566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 64323cc88e6aSStefano Zampini end: 64339566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 64343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 64353e9753d6SMatthew G. Knepley } 64368e3a2eefSMatthew G. Knepley 64378e3a2eefSMatthew G. Knepley /* 64388e3a2eefSMatthew 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. 64398e3a2eefSMatthew G. Knepley 64408e3a2eefSMatthew G. Knepley Input Parameters: 64418e3a2eefSMatthew G. Knepley + dm - The mesh 6442baca6076SPierre Jolivet . key - The PetscWeakFormKey indicating where integration should happen 644306ad1575SMatthew G. Knepley . cellIS - The cells to integrate over 64448e3a2eefSMatthew G. Knepley . t - The time 6445145b44c9SPierre Jolivet . X_tShift - The multiplier for the Jacobian with respect to X_t 64468e3a2eefSMatthew G. Knepley . X - Local solution vector 64478e3a2eefSMatthew G. Knepley . X_t - Time-derivative of the local solution vector 64488e3a2eefSMatthew G. Knepley . Y - Local input vector 644906ad1575SMatthew G. Knepley - user - the user context 64508e3a2eefSMatthew G. Knepley 64518e3a2eefSMatthew G. Knepley Output Parameter: 64528e3a2eefSMatthew G. Knepley . Z - Local output vector 64538e3a2eefSMatthew G. Knepley 64548e3a2eefSMatthew G. Knepley Note: 64558e3a2eefSMatthew G. Knepley We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator, 64568e3a2eefSMatthew G. Knepley like a GPU, or vectorize on a multicore machine. 64578e3a2eefSMatthew G. Knepley */ 6458d71ae5a4SJacob 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) 6459d71ae5a4SJacob Faibussowitsch { 64608e3a2eefSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 64618e3a2eefSMatthew G. Knepley const char *name = "Jacobian"; 64628e3a2eefSMatthew G. Knepley DM dmAux = NULL, plex, plexAux = NULL; 64638e3a2eefSMatthew G. Knepley DMEnclosureType encAux; 64648e3a2eefSMatthew G. Knepley Vec A; 64658e3a2eefSMatthew G. Knepley DMField coordField; 64668e3a2eefSMatthew G. Knepley PetscDS prob, probAux = NULL; 64678e3a2eefSMatthew G. Knepley PetscQuadrature quad; 64688e3a2eefSMatthew G. Knepley PetscSection section, globalSection, sectionAux; 64698e3a2eefSMatthew G. Knepley PetscScalar *elemMat, *elemMatD, *u, *u_t, *a = NULL, *y, *z; 64708e3a2eefSMatthew G. Knepley const PetscInt *cells; 64718e3a2eefSMatthew G. Knepley PetscInt Nf, fieldI, fieldJ; 64728e3a2eefSMatthew G. Knepley PetscInt totDim, totDimAux = 0, cStart, cEnd, numCells, c; 64738e3a2eefSMatthew G. Knepley PetscBool hasDyn; 64748e3a2eefSMatthew G. Knepley 64758e3a2eefSMatthew G. Knepley PetscFunctionBegin; 64769566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 64779566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 64789566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(cellIS, &numCells)); 64799566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 64809566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 64819566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 648207218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL)); 64839566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 64849566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 64859566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 64868e3a2eefSMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 64879566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A)); 64888e3a2eefSMatthew G. Knepley if (A) { 64899566063dSJacob Faibussowitsch PetscCall(VecGetDM(A, &dmAux)); 64909566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 64919566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexAux)); 64929566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexAux, §ionAux)); 64939566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 64949566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 64958e3a2eefSMatthew G. Knepley } 64969566063dSJacob Faibussowitsch PetscCall(VecSet(Z, 0.0)); 649732603206SJames 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)); 64989566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 64999566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 65008e3a2eefSMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 65018e3a2eefSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 65028e3a2eefSMatthew G. Knepley const PetscInt cind = c - cStart; 65038e3a2eefSMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 65048e3a2eefSMatthew G. Knepley PetscInt i; 65058e3a2eefSMatthew G. Knepley 65069566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, X, cell, NULL, &x)); 65078e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i]; 65089566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, X, cell, NULL, &x)); 65098e3a2eefSMatthew G. Knepley if (X_t) { 65109566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, X_t, cell, NULL, &x_t)); 65118e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i]; 65129566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, X_t, cell, NULL, &x_t)); 65138e3a2eefSMatthew G. Knepley } 65148e3a2eefSMatthew G. Knepley if (dmAux) { 65158e3a2eefSMatthew G. Knepley PetscInt subcell; 65169566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell)); 65179566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexAux, sectionAux, A, subcell, NULL, &x)); 65188e3a2eefSMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i]; 65199566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexAux, sectionAux, A, subcell, NULL, &x)); 65208e3a2eefSMatthew G. Knepley } 65219566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, Y, cell, NULL, &x)); 65228e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) y[cind * totDim + i] = x[i]; 65239566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, Y, cell, NULL, &x)); 65248e3a2eefSMatthew G. Knepley } 65259566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim)); 65269566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim)); 65278e3a2eefSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 65288e3a2eefSMatthew G. Knepley PetscFE fe; 65298e3a2eefSMatthew G. Knepley PetscInt Nb; 65308e3a2eefSMatthew G. Knepley /* Conforming batches */ 65318e3a2eefSMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 65328e3a2eefSMatthew G. Knepley /* Remainder */ 65338e3a2eefSMatthew G. Knepley PetscInt Nr, offset, Nq; 65348e3a2eefSMatthew G. Knepley PetscQuadrature qGeom = NULL; 65358e3a2eefSMatthew G. Knepley PetscInt maxDegree; 65368e3a2eefSMatthew G. Knepley PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 65378e3a2eefSMatthew G. Knepley 65389566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 65399566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 65409566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 65419566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 65429566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 65439566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 65448e3a2eefSMatthew G. Knepley if (!qGeom) { 65459566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 65469566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 65478e3a2eefSMatthew G. Knepley } 65489566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 65499566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 65508e3a2eefSMatthew G. Knepley blockSize = Nb; 65518e3a2eefSMatthew G. Knepley batchSize = numBlocks * blockSize; 65529566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 65538e3a2eefSMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 65548e3a2eefSMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 65558e3a2eefSMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 65568e3a2eefSMatthew G. Knepley offset = numCells - Nr; 65579566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 65589566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom)); 65598e3a2eefSMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 65608e3a2eefSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 65619566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 65628e3a54c0SPierre 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])); 65638e3a2eefSMatthew G. Knepley if (hasDyn) { 65649566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD)); 65658e3a54c0SPierre 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])); 65668e3a2eefSMatthew G. Knepley } 65678e3a2eefSMatthew G. Knepley } 65689566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom)); 65699566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom)); 65709566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 65719566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 65728e3a2eefSMatthew G. Knepley } 65738e3a2eefSMatthew G. Knepley if (hasDyn) { 65748e3a2eefSMatthew G. Knepley for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 65758e3a2eefSMatthew G. Knepley } 65768e3a2eefSMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 65778e3a2eefSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 65788e3a2eefSMatthew G. Knepley const PetscInt cind = c - cStart; 65796497c311SBarry Smith const PetscBLASInt one = 1; 65806497c311SBarry Smith PetscBLASInt M; 65818e3a2eefSMatthew G. Knepley const PetscScalar a = 1.0, b = 0.0; 65828e3a2eefSMatthew G. Knepley 65836497c311SBarry Smith PetscCall(PetscBLASIntCast(totDim, &M)); 6584792fecdfSBarry Smith PetscCallBLAS("BLASgemv", BLASgemv_("N", &M, &M, &a, &elemMat[cind * totDim * totDim], &M, &y[cind * totDim], &one, &b, z, &one)); 65858e3a2eefSMatthew G. Knepley if (mesh->printFEM > 1) { 65869566063dSJacob Faibussowitsch PetscCall(DMPrintCellMatrix(c, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 65879566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, "Y", totDim, &y[cind * totDim])); 65889566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, "Z", totDim, z)); 65898e3a2eefSMatthew G. Knepley } 65909566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, Z, cell, z, ADD_VALUES)); 65918e3a2eefSMatthew G. Knepley } 65929566063dSJacob Faibussowitsch PetscCall(PetscFree6(u, u_t, elemMat, elemMatD, y, z)); 65938e3a2eefSMatthew G. Knepley if (mesh->printFEM) { 65949566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)Z), "Z:\n")); 65959566063dSJacob Faibussowitsch PetscCall(VecView(Z, NULL)); 65968e3a2eefSMatthew G. Knepley } 65971059d808SMatthew G. Knepley PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 65989566063dSJacob Faibussowitsch PetscCall(PetscFree(a)); 65999566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plexAux)); 66009566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 66019566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 66023ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 66038e3a2eefSMatthew G. Knepley } 6604d52c2f21SMatthew G. Knepley 6605d52c2f21SMatthew 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[]) 6606d52c2f21SMatthew G. Knepley { 6607d52c2f21SMatthew G. Knepley f0[0] = u[0]; 6608d52c2f21SMatthew G. Knepley } 6609d52c2f21SMatthew G. Knepley 6610d52c2f21SMatthew 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[]) 6611d52c2f21SMatthew G. Knepley { 6612d52c2f21SMatthew G. Knepley f0[0] = x[(int)PetscRealPart(constants[0])] * u[0]; 6613d52c2f21SMatthew G. Knepley } 6614d52c2f21SMatthew G. Knepley 6615d52c2f21SMatthew 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[]) 6616d52c2f21SMatthew G. Knepley { 6617d52c2f21SMatthew G. Knepley PetscInt d; 6618d52c2f21SMatthew G. Knepley 6619d52c2f21SMatthew G. Knepley f0[0] = 0.0; 6620d52c2f21SMatthew G. Knepley for (d = 0; d < dim; ++d) f0[0] += PetscSqr(x[d]) * u[0]; 6621d52c2f21SMatthew G. Knepley } 6622d52c2f21SMatthew G. Knepley 6623d52c2f21SMatthew G. Knepley /*@ 6624d52c2f21SMatthew G. Knepley DMPlexComputeMoments - Compute the first three moments for a field 6625d52c2f21SMatthew G. Knepley 6626d52c2f21SMatthew G. Knepley Noncollective 6627d52c2f21SMatthew G. Knepley 6628d52c2f21SMatthew G. Knepley Input Parameters: 6629d52c2f21SMatthew G. Knepley + dm - the `DMPLEX` 6630d52c2f21SMatthew G. Knepley - u - the field 6631d52c2f21SMatthew G. Knepley 6632d52c2f21SMatthew G. Knepley Output Parameter: 6633d52c2f21SMatthew G. Knepley . moments - the field moments 6634d52c2f21SMatthew G. Knepley 6635d52c2f21SMatthew G. Knepley Level: intermediate 6636d52c2f21SMatthew G. Knepley 6637d52c2f21SMatthew G. Knepley Note: 663817314648SMatthew G. Knepley The `moments` array should be of length cdim + 2, where cdim is the number of components for the coordinate field. 6639d52c2f21SMatthew G. Knepley 6640d52c2f21SMatthew G. Knepley .seealso: `DM`, `DMPLEX`, `DMSwarmComputeMoments()` 6641d52c2f21SMatthew G. Knepley @*/ 6642d52c2f21SMatthew G. Knepley PetscErrorCode DMPlexComputeMoments(DM dm, Vec u, PetscReal moments[]) 6643d52c2f21SMatthew G. Knepley { 6644d52c2f21SMatthew G. Knepley PetscDS ds; 6645d52c2f21SMatthew G. Knepley PetscScalar mom, constants[1]; 6646d52c2f21SMatthew G. Knepley const PetscScalar *oldConstants; 664717314648SMatthew G. Knepley PetscInt cdim, Nf, field = 0, Ncon; 6648d52c2f21SMatthew G. Knepley MPI_Comm comm; 6649d52c2f21SMatthew G. Knepley void *user; 6650d52c2f21SMatthew G. Knepley 6651d52c2f21SMatthew G. Knepley PetscFunctionBeginUser; 6652d52c2f21SMatthew G. Knepley PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 665317314648SMatthew G. Knepley PetscCall(DMGetCoordinateDim(dm, &cdim)); 6654d52c2f21SMatthew G. Knepley PetscCall(DMGetApplicationContext(dm, &user)); 6655d52c2f21SMatthew G. Knepley PetscCall(DMGetDS(dm, &ds)); 6656d52c2f21SMatthew G. Knepley PetscCall(PetscDSGetNumFields(ds, &Nf)); 6657d52c2f21SMatthew G. Knepley PetscCall(PetscDSGetConstants(ds, &Ncon, &oldConstants)); 6658d52c2f21SMatthew G. Knepley PetscCheck(Nf == 1, comm, PETSC_ERR_ARG_WRONG, "We currently only support 1 field, not %" PetscInt_FMT, Nf); 6659d52c2f21SMatthew G. Knepley PetscCall(PetscDSSetObjective(ds, field, &f0_1)); 6660d52c2f21SMatthew G. Knepley PetscCall(DMPlexComputeIntegralFEM(dm, u, &mom, user)); 6661d52c2f21SMatthew G. Knepley moments[0] = PetscRealPart(mom); 666217314648SMatthew G. Knepley for (PetscInt c = 0; c < cdim; ++c) { 6663d52c2f21SMatthew G. Knepley constants[0] = c; 666417314648SMatthew G. Knepley PetscCall(PetscDSSetConstants(ds, 1, constants)); 6665d52c2f21SMatthew G. Knepley PetscCall(PetscDSSetObjective(ds, field, &f0_x)); 6666d52c2f21SMatthew G. Knepley PetscCall(DMPlexComputeIntegralFEM(dm, u, &mom, user)); 6667d52c2f21SMatthew G. Knepley moments[c + 1] = PetscRealPart(mom); 6668d52c2f21SMatthew G. Knepley } 6669d52c2f21SMatthew G. Knepley PetscCall(PetscDSSetObjective(ds, field, &f0_x2)); 6670d52c2f21SMatthew G. Knepley PetscCall(DMPlexComputeIntegralFEM(dm, u, &mom, user)); 667117314648SMatthew G. Knepley moments[cdim + 1] = PetscRealPart(mom); 6672d52c2f21SMatthew G. Knepley PetscCall(PetscDSSetConstants(ds, Ncon, (PetscScalar *)oldConstants)); 6673d52c2f21SMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 6674d52c2f21SMatthew G. Knepley } 6675