1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2da97024aSMatthew G. Knepley #include <petscsf.h> 3cb1e1211SMatthew G Knepley 48e3a2eefSMatthew G. Knepley #include <petscblaslapack.h> 5e8f14785SLisandro Dalcin #include <petsc/private/hashsetij.h> 6af0996ceSBarry Smith #include <petsc/private/petscfeimpl.h> 7af0996ceSBarry Smith #include <petsc/private/petscfvimpl.h> 8a0845e3aSMatthew G. Knepley 95f0b18bfSMatthew G. Knepley PetscBool Clementcite = PETSC_FALSE; 105f0b18bfSMatthew G. Knepley const char ClementCitation[] = "@article{clement1975approximation,\n" 115f0b18bfSMatthew G. Knepley " title = {Approximation by finite element functions using local regularization},\n" 125f0b18bfSMatthew G. Knepley " author = {Philippe Cl{\\'e}ment},\n" 135f0b18bfSMatthew G. Knepley " journal = {Revue fran{\\c{c}}aise d'automatique, informatique, recherche op{\\'e}rationnelle. Analyse num{\\'e}rique},\n" 145f0b18bfSMatthew G. Knepley " volume = {9},\n" 155f0b18bfSMatthew G. Knepley " number = {R2},\n" 165f0b18bfSMatthew G. Knepley " pages = {77--84},\n" 175f0b18bfSMatthew G. Knepley " year = {1975}\n}\n"; 185f0b18bfSMatthew G. Knepley 19d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexConvertPlex(DM dm, DM *plex, PetscBool copy) 20d71ae5a4SJacob Faibussowitsch { 212f856554SMatthew G. Knepley PetscBool isPlex; 222f856554SMatthew G. Knepley 232f856554SMatthew G. Knepley PetscFunctionBegin; 249566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex)); 252f856554SMatthew G. Knepley if (isPlex) { 262f856554SMatthew G. Knepley *plex = dm; 279566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)dm)); 282f856554SMatthew G. Knepley } else { 299566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex)); 302f856554SMatthew G. Knepley if (!*plex) { 319566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, plex)); 329566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex)); 332f856554SMatthew G. Knepley if (copy) { 342f856554SMatthew G. Knepley DMSubDomainHookLink link; 359a2a23afSMatthew G. Knepley 369566063dSJacob Faibussowitsch PetscCall(DMCopyAuxiliaryVec(dm, *plex)); 379a2a23afSMatthew G. Knepley /* Run the subdomain hook (this will copy the DMSNES/DMTS) */ 382f856554SMatthew G. Knepley for (link = dm->subdomainhook; link; link = link->next) { 399566063dSJacob Faibussowitsch if (link->ddhook) PetscCall((*link->ddhook)(dm, *plex, link->ctx)); 402f856554SMatthew G. Knepley } 412f856554SMatthew G. Knepley } 422f856554SMatthew G. Knepley } else { 439566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)*plex)); 442f856554SMatthew G. Knepley } 452f856554SMatthew G. Knepley } 463ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 472f856554SMatthew G. Knepley } 482f856554SMatthew G. Knepley 49d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscContainerUserDestroy_PetscFEGeom(void *ctx) 50d71ae5a4SJacob Faibussowitsch { 519b6f715bSMatthew G. Knepley PetscFEGeom *geom = (PetscFEGeom *)ctx; 529b6f715bSMatthew G. Knepley 539b6f715bSMatthew G. Knepley PetscFunctionBegin; 549566063dSJacob Faibussowitsch PetscCall(PetscFEGeomDestroy(&geom)); 553ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 569b6f715bSMatthew G. Knepley } 579b6f715bSMatthew G. Knepley 58d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 59d71ae5a4SJacob Faibussowitsch { 609b6f715bSMatthew G. Knepley char composeStr[33] = {0}; 619b6f715bSMatthew G. Knepley PetscObjectId id; 629b6f715bSMatthew G. Knepley PetscContainer container; 639b6f715bSMatthew G. Knepley 649b6f715bSMatthew G. Knepley PetscFunctionBegin; 659566063dSJacob Faibussowitsch PetscCall(PetscObjectGetId((PetscObject)quad, &id)); 6663a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(composeStr, 32, "DMPlexGetFEGeom_%" PetscInt64_FMT "\n", id)); 679566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)pointIS, composeStr, (PetscObject *)&container)); 689b6f715bSMatthew G. Knepley if (container) { 699566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(container, (void **)geom)); 709b6f715bSMatthew G. Knepley } else { 719566063dSJacob Faibussowitsch PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom)); 729566063dSJacob Faibussowitsch PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container)); 739566063dSJacob Faibussowitsch PetscCall(PetscContainerSetPointer(container, (void *)*geom)); 749566063dSJacob Faibussowitsch PetscCall(PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom)); 759566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)pointIS, composeStr, (PetscObject)container)); 769566063dSJacob Faibussowitsch PetscCall(PetscContainerDestroy(&container)); 779b6f715bSMatthew G. Knepley } 783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 799b6f715bSMatthew G. Knepley } 809b6f715bSMatthew G. Knepley 81d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 82d71ae5a4SJacob Faibussowitsch { 839b6f715bSMatthew G. Knepley PetscFunctionBegin; 849b6f715bSMatthew G. Knepley *geom = NULL; 853ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 869b6f715bSMatthew G. Knepley } 879b6f715bSMatthew G. Knepley 8846fa42a0SMatthew G. Knepley /*@ 8946fa42a0SMatthew G. Knepley DMPlexGetScale - Get the scale for the specified fundamental unit 9046fa42a0SMatthew G. Knepley 9120f4b53cSBarry Smith Not Collective 9246fa42a0SMatthew G. Knepley 934165533cSJose E. Roman Input Parameters: 94a1cb98faSBarry Smith + dm - the `DM` 9546fa42a0SMatthew G. Knepley - unit - The SI unit 9646fa42a0SMatthew G. Knepley 974165533cSJose E. Roman Output Parameter: 9846fa42a0SMatthew G. Knepley . scale - The value used to scale all quantities with this unit 9946fa42a0SMatthew G. Knepley 10046fa42a0SMatthew G. Knepley Level: advanced 10146fa42a0SMatthew G. Knepley 1021cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetScale()`, `PetscUnit` 10346fa42a0SMatthew G. Knepley @*/ 104d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale) 105d71ae5a4SJacob Faibussowitsch { 106cb1e1211SMatthew G Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 107cb1e1211SMatthew G Knepley 108cb1e1211SMatthew G Knepley PetscFunctionBegin; 109cb1e1211SMatthew G Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1104f572ea9SToby Isaac PetscAssertPointer(scale, 3); 111cb1e1211SMatthew G Knepley *scale = mesh->scale[unit]; 1123ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 113cb1e1211SMatthew G Knepley } 114cb1e1211SMatthew G Knepley 11546fa42a0SMatthew G. Knepley /*@ 11646fa42a0SMatthew G. Knepley DMPlexSetScale - Set the scale for the specified fundamental unit 11746fa42a0SMatthew G. Knepley 11820f4b53cSBarry Smith Not Collective 11946fa42a0SMatthew G. Knepley 1204165533cSJose E. Roman Input Parameters: 121a1cb98faSBarry Smith + dm - the `DM` 12246fa42a0SMatthew G. Knepley . unit - The SI unit 12346fa42a0SMatthew G. Knepley - scale - The value used to scale all quantities with this unit 12446fa42a0SMatthew G. Knepley 12546fa42a0SMatthew G. Knepley Level: advanced 12646fa42a0SMatthew G. Knepley 1271cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetScale()`, `PetscUnit` 12846fa42a0SMatthew G. Knepley @*/ 129d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale) 130d71ae5a4SJacob Faibussowitsch { 131cb1e1211SMatthew G Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 132cb1e1211SMatthew G Knepley 133cb1e1211SMatthew G Knepley PetscFunctionBegin; 134cb1e1211SMatthew G Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 135cb1e1211SMatthew G Knepley mesh->scale[unit] = scale; 1363ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 137cb1e1211SMatthew G Knepley } 138cb1e1211SMatthew G Knepley 139*e8e188d2SZach Atkins /*@ 140*e8e188d2SZach Atkins DMPlexGetUseMatClosurePermutation - Get flag for using a closure permutation for matrix insertion 141*e8e188d2SZach Atkins 142*e8e188d2SZach Atkins Not collective 143*e8e188d2SZach Atkins 144*e8e188d2SZach Atkins Input Parameter: 145*e8e188d2SZach Atkins . dm - The `DM` 146*e8e188d2SZach Atkins 147*e8e188d2SZach Atkins Output Parameter: 148*e8e188d2SZach Atkins . useClPerm - The flag 149*e8e188d2SZach Atkins 150*e8e188d2SZach Atkins Level: intermediate 151*e8e188d2SZach Atkins 152*e8e188d2SZach Atkins .seealso: `DMPlexSetUseMatClosurePermutation()` 153*e8e188d2SZach Atkins @*/ 154*e8e188d2SZach Atkins PetscErrorCode DMPlexGetUseMatClosurePermutation(DM dm, PetscBool *useClPerm) 155*e8e188d2SZach Atkins { 156*e8e188d2SZach Atkins DM_Plex *mesh = (DM_Plex *)dm->data; 157*e8e188d2SZach Atkins 158*e8e188d2SZach Atkins PetscFunctionBegin; 159*e8e188d2SZach Atkins PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 160*e8e188d2SZach Atkins PetscAssertPointer(useClPerm, 2); 161*e8e188d2SZach Atkins *useClPerm = mesh->useMatClPerm; 162*e8e188d2SZach Atkins PetscFunctionReturn(PETSC_SUCCESS); 163*e8e188d2SZach Atkins } 164*e8e188d2SZach Atkins 165*e8e188d2SZach Atkins /*@ 166*e8e188d2SZach Atkins DMPlexSetUseMatClosurePermutation - Set flag for using a closure permutation for matrix insertion 167*e8e188d2SZach Atkins 168*e8e188d2SZach Atkins Not collective 169*e8e188d2SZach Atkins 170*e8e188d2SZach Atkins Input Parameters: 171*e8e188d2SZach Atkins + dm - The `DM` 172*e8e188d2SZach Atkins - useClPerm - The flag 173*e8e188d2SZach Atkins 174*e8e188d2SZach Atkins Level: intermediate 175*e8e188d2SZach Atkins 176*e8e188d2SZach Atkins .seealso: `DMPlexGetUseMatClosurePermutation()` 177*e8e188d2SZach Atkins @*/ 178*e8e188d2SZach Atkins PetscErrorCode DMPlexSetUseMatClosurePermutation(DM dm, PetscBool useClPerm) 179*e8e188d2SZach Atkins { 180*e8e188d2SZach Atkins DM_Plex *mesh = (DM_Plex *)dm->data; 181*e8e188d2SZach Atkins 182*e8e188d2SZach Atkins PetscFunctionBegin; 183*e8e188d2SZach Atkins PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 184*e8e188d2SZach Atkins PetscValidLogicalCollectiveBool(dm, useClPerm, 2); 185*e8e188d2SZach Atkins mesh->useMatClPerm = useClPerm; 186*e8e188d2SZach Atkins PetscFunctionReturn(PETSC_SUCCESS); 187*e8e188d2SZach Atkins } 188*e8e188d2SZach Atkins 189d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexProjectRigidBody_Private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nc, PetscScalar *mode, void *ctx) 190d71ae5a4SJacob Faibussowitsch { 1919371c9d4SSatish Balay const PetscInt eps[3][3][3] = { 1929371c9d4SSatish Balay {{0, 0, 0}, {0, 0, 1}, {0, -1, 0}}, 1939371c9d4SSatish Balay {{0, 0, -1}, {0, 0, 0}, {1, 0, 0} }, 1949371c9d4SSatish Balay {{0, 1, 0}, {-1, 0, 0}, {0, 0, 0} } 1959371c9d4SSatish Balay }; 196026175e5SToby Isaac PetscInt *ctxInt = (PetscInt *)ctx; 197ad917190SMatthew G. Knepley PetscInt dim2 = ctxInt[0]; 198026175e5SToby Isaac PetscInt d = ctxInt[1]; 199026175e5SToby Isaac PetscInt i, j, k = dim > 2 ? d - dim : d; 200026175e5SToby Isaac 201ad917190SMatthew G. Knepley PetscFunctionBegin; 20263a3b9bcSJacob Faibussowitsch PetscCheck(dim == dim2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Input dimension %" PetscInt_FMT " does not match context dimension %" PetscInt_FMT, dim, dim2); 203026175e5SToby Isaac for (i = 0; i < dim; i++) mode[i] = 0.; 204026175e5SToby Isaac if (d < dim) { 20512adca46SMatthew G. Knepley mode[d] = 1.; /* Translation along axis d */ 206ad917190SMatthew G. Knepley } else { 207026175e5SToby Isaac for (i = 0; i < dim; i++) { 2089371c9d4SSatish Balay for (j = 0; j < dim; j++) { mode[j] += eps[i][j][k] * X[i]; /* Rotation about axis d */ } 209026175e5SToby Isaac } 210026175e5SToby Isaac } 2113ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 212026175e5SToby Isaac } 213026175e5SToby Isaac 214cc4e42d9SMartin Diehl /*@ 21512adca46SMatthew G. Knepley DMPlexCreateRigidBody - For the default global section, create rigid body modes by function space interpolation 216cb1e1211SMatthew G Knepley 21720f4b53cSBarry Smith Collective 218cb1e1211SMatthew G Knepley 2194165533cSJose E. Roman Input Parameters: 220a1cb98faSBarry Smith + dm - the `DM` 22156cf3b9cSMatthew G. Knepley - field - The field number for the rigid body space, or 0 for the default 222cb1e1211SMatthew G Knepley 2234165533cSJose E. Roman Output Parameter: 224cb1e1211SMatthew G Knepley . sp - the null space 225cb1e1211SMatthew G Knepley 226cb1e1211SMatthew G Knepley Level: advanced 227cb1e1211SMatthew G Knepley 228a1cb98faSBarry Smith Note: 229a1cb98faSBarry Smith This is necessary to provide a suitable coarse space for algebraic multigrid 230a1cb98faSBarry Smith 2311cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `MatNullSpaceCreate()`, `PCGAMG` 232cb1e1211SMatthew G Knepley @*/ 233d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscInt field, MatNullSpace *sp) 234d71ae5a4SJacob Faibussowitsch { 23556cf3b9cSMatthew G. Knepley PetscErrorCode (**func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *); 236cb1e1211SMatthew G Knepley MPI_Comm comm; 237026175e5SToby Isaac Vec mode[6]; 238026175e5SToby Isaac PetscSection section, globalSection; 23956cf3b9cSMatthew G. Knepley PetscInt dim, dimEmbed, Nf, n, m, mmin, d, i, j; 240db14aad5SMatthew G. Knepley void **ctxs; 241cb1e1211SMatthew G Knepley 242cb1e1211SMatthew G Knepley PetscFunctionBegin; 2439566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 2449566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 2459566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &dimEmbed)); 2469566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 24763a3b9bcSJacob Faibussowitsch PetscCheck(!Nf || !(field < 0 || field >= Nf), comm, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", field, Nf); 24856cf3b9cSMatthew G. Knepley if (dim == 1 && Nf < 2) { 2499566063dSJacob Faibussowitsch PetscCall(MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp)); 2503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 251cb1e1211SMatthew G Knepley } 2529566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 2539566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 2549566063dSJacob Faibussowitsch PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &n)); 255db14aad5SMatthew G. Knepley PetscCall(PetscCalloc2(Nf, &func, Nf, &ctxs)); 256b247467aSMatthew G. Knepley m = (dim * (dim + 1)) / 2; 2579566063dSJacob Faibussowitsch PetscCall(VecCreate(comm, &mode[0])); 2589566063dSJacob Faibussowitsch PetscCall(VecSetType(mode[0], dm->vectype)); 2599566063dSJacob Faibussowitsch PetscCall(VecSetSizes(mode[0], n, PETSC_DETERMINE)); 2609566063dSJacob Faibussowitsch PetscCall(VecSetUp(mode[0])); 2619566063dSJacob Faibussowitsch PetscCall(VecGetSize(mode[0], &n)); 262b247467aSMatthew G. Knepley mmin = PetscMin(m, n); 26356cf3b9cSMatthew G. Knepley func[field] = DMPlexProjectRigidBody_Private; 2649566063dSJacob Faibussowitsch for (i = 1; i < m; ++i) PetscCall(VecDuplicate(mode[0], &mode[i])); 265026175e5SToby Isaac for (d = 0; d < m; d++) { 266330485fdSToby Isaac PetscInt ctx[2]; 267cb1e1211SMatthew G Knepley 268db14aad5SMatthew G. Knepley ctxs[field] = (void *)(&ctx[0]); 2699d8fbdeaSMatthew G. Knepley ctx[0] = dimEmbed; 270330485fdSToby Isaac ctx[1] = d; 271db14aad5SMatthew G. Knepley PetscCall(DMProjectFunction(dm, 0.0, func, ctxs, INSERT_VALUES, mode[d])); 272cb1e1211SMatthew G Knepley } 2733b2202bfSJacob Faibussowitsch /* Orthonormalize system */ 274b50a2c0aSJacob Faibussowitsch for (i = 0; i < mmin; ++i) { 275b77f2eeeSJacob Faibussowitsch PetscScalar dots[6]; 276b50a2c0aSJacob Faibussowitsch 2779566063dSJacob Faibussowitsch PetscCall(VecNormalize(mode[i], NULL)); 2789566063dSJacob Faibussowitsch PetscCall(VecMDot(mode[i], mmin - i - 1, mode + i + 1, dots + i + 1)); 279b50a2c0aSJacob Faibussowitsch for (j = i + 1; j < mmin; ++j) { 280b77f2eeeSJacob Faibussowitsch dots[j] *= -1.0; 2819566063dSJacob Faibussowitsch PetscCall(VecAXPY(mode[j], dots[j], mode[i])); 282b50a2c0aSJacob Faibussowitsch } 283cb1e1211SMatthew G Knepley } 2849566063dSJacob Faibussowitsch PetscCall(MatNullSpaceCreate(comm, PETSC_FALSE, mmin, mode, sp)); 2859566063dSJacob Faibussowitsch for (i = 0; i < m; ++i) PetscCall(VecDestroy(&mode[i])); 286db14aad5SMatthew G. Knepley PetscCall(PetscFree2(func, ctxs)); 2873ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 288cb1e1211SMatthew G Knepley } 289cb1e1211SMatthew G Knepley 290cc4e42d9SMartin Diehl /*@ 29112adca46SMatthew G. Knepley DMPlexCreateRigidBodies - For the default global section, create rigid body modes by function space interpolation 29212adca46SMatthew G. Knepley 29320f4b53cSBarry Smith Collective 29412adca46SMatthew G. Knepley 2954165533cSJose E. Roman Input Parameters: 296a1cb98faSBarry Smith + dm - the `DM` 29712adca46SMatthew G. Knepley . nb - The number of bodies 298a1cb98faSBarry Smith . label - The `DMLabel` marking each domain 29912adca46SMatthew G. Knepley . nids - The number of ids per body 30012adca46SMatthew G. Knepley - ids - An array of the label ids in sequence for each domain 30112adca46SMatthew G. Knepley 3024165533cSJose E. Roman Output Parameter: 30312adca46SMatthew G. Knepley . sp - the null space 30412adca46SMatthew G. Knepley 30512adca46SMatthew G. Knepley Level: advanced 30612adca46SMatthew G. Knepley 307a1cb98faSBarry Smith Note: 308a1cb98faSBarry Smith This is necessary to provide a suitable coarse space for algebraic multigrid 309a1cb98faSBarry Smith 3101cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `MatNullSpaceCreate()` 31112adca46SMatthew G. Knepley @*/ 312d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRigidBodies(DM dm, PetscInt nb, DMLabel label, const PetscInt nids[], const PetscInt ids[], MatNullSpace *sp) 313d71ae5a4SJacob Faibussowitsch { 31412adca46SMatthew G. Knepley MPI_Comm comm; 31512adca46SMatthew G. Knepley PetscSection section, globalSection; 31612adca46SMatthew G. Knepley Vec *mode; 31712adca46SMatthew G. Knepley PetscScalar *dots; 31812adca46SMatthew G. Knepley PetscInt dim, dimEmbed, n, m, b, d, i, j, off; 31912adca46SMatthew G. Knepley 32012adca46SMatthew G. Knepley PetscFunctionBegin; 3219566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 3229566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 3239566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &dimEmbed)); 3249566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 3259566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 3269566063dSJacob Faibussowitsch PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &n)); 32712adca46SMatthew G. Knepley m = nb * (dim * (dim + 1)) / 2; 3289566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(m, &mode, m, &dots)); 3299566063dSJacob Faibussowitsch PetscCall(VecCreate(comm, &mode[0])); 3309566063dSJacob Faibussowitsch PetscCall(VecSetSizes(mode[0], n, PETSC_DETERMINE)); 3319566063dSJacob Faibussowitsch PetscCall(VecSetUp(mode[0])); 3329566063dSJacob Faibussowitsch for (i = 1; i < m; ++i) PetscCall(VecDuplicate(mode[0], &mode[i])); 33312adca46SMatthew G. Knepley for (b = 0, off = 0; b < nb; ++b) { 33412adca46SMatthew G. Knepley for (d = 0; d < m / nb; ++d) { 33512adca46SMatthew G. Knepley PetscInt ctx[2]; 33612adca46SMatthew G. Knepley PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *) = DMPlexProjectRigidBody_Private; 33712adca46SMatthew G. Knepley void *voidctx = (void *)(&ctx[0]); 33812adca46SMatthew G. Knepley 33912adca46SMatthew G. Knepley ctx[0] = dimEmbed; 34012adca46SMatthew G. Knepley ctx[1] = d; 3419566063dSJacob Faibussowitsch PetscCall(DMProjectFunctionLabel(dm, 0.0, label, nids[b], &ids[off], 0, NULL, &func, &voidctx, INSERT_VALUES, mode[d])); 34212adca46SMatthew G. Knepley off += nids[b]; 34312adca46SMatthew G. Knepley } 34412adca46SMatthew G. Knepley } 3453b2202bfSJacob Faibussowitsch /* Orthonormalize system */ 346606c1a1cSJacob Faibussowitsch for (i = 0; i < m; ++i) { 347b77f2eeeSJacob Faibussowitsch PetscScalar dots[6]; 3485a0e29b9SJacob Faibussowitsch 3499566063dSJacob Faibussowitsch PetscCall(VecNormalize(mode[i], NULL)); 3509566063dSJacob Faibussowitsch PetscCall(VecMDot(mode[i], m - i - 1, mode + i + 1, dots + i + 1)); 3515a0e29b9SJacob Faibussowitsch for (j = i + 1; j < m; ++j) { 352b77f2eeeSJacob Faibussowitsch dots[j] *= -1.0; 3539566063dSJacob Faibussowitsch PetscCall(VecAXPY(mode[j], dots[j], mode[i])); 3545a0e29b9SJacob Faibussowitsch } 35512adca46SMatthew G. Knepley } 3569566063dSJacob Faibussowitsch PetscCall(MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp)); 3579566063dSJacob Faibussowitsch for (i = 0; i < m; ++i) PetscCall(VecDestroy(&mode[i])); 3589566063dSJacob Faibussowitsch PetscCall(PetscFree2(mode, dots)); 3593ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 36012adca46SMatthew G. Knepley } 36112adca46SMatthew G. Knepley 362b29cfa1cSToby Isaac /*@ 363b29cfa1cSToby Isaac DMPlexSetMaxProjectionHeight - In DMPlexProjectXXXLocal() functions, the projected values of a basis function's dofs 364b29cfa1cSToby Isaac are computed by associating the basis function with one of the mesh points in its transitively-closed support, and 365a4e35b19SJacob Faibussowitsch evaluating the dual space basis of that point. 366b29cfa1cSToby Isaac 367b29cfa1cSToby Isaac Input Parameters: 368a1cb98faSBarry Smith + dm - the `DMPLEX` object 369b29cfa1cSToby Isaac - height - the maximum projection height >= 0 370b29cfa1cSToby Isaac 371b29cfa1cSToby Isaac Level: advanced 372b29cfa1cSToby Isaac 373a4e35b19SJacob Faibussowitsch Notes: 374a4e35b19SJacob Faibussowitsch A basis function is associated with the point in its transitively-closed support whose mesh 375a4e35b19SJacob Faibussowitsch height is highest (w.r.t. DAG height), but not greater than the maximum projection height, 376a4e35b19SJacob Faibussowitsch which is set with this function. By default, the maximum projection height is zero, which 377a4e35b19SJacob Faibussowitsch means that only mesh cells are used to project basis functions. A height of one, for 378a4e35b19SJacob Faibussowitsch example, evaluates a cell-interior basis functions using its cells dual space basis, but all 379a4e35b19SJacob Faibussowitsch other basis functions with the dual space basis of a face. 380a4e35b19SJacob Faibussowitsch 3811cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMaxProjectionHeight()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()` 382b29cfa1cSToby Isaac @*/ 383d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetMaxProjectionHeight(DM dm, PetscInt height) 384d71ae5a4SJacob Faibussowitsch { 385b29cfa1cSToby Isaac DM_Plex *plex = (DM_Plex *)dm->data; 386b29cfa1cSToby Isaac 387b29cfa1cSToby Isaac PetscFunctionBegin; 388b29cfa1cSToby Isaac PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 389b29cfa1cSToby Isaac plex->maxProjectionHeight = height; 3903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 391b29cfa1cSToby Isaac } 392b29cfa1cSToby Isaac 393b29cfa1cSToby Isaac /*@ 394b29cfa1cSToby Isaac DMPlexGetMaxProjectionHeight - Get the maximum height (w.r.t. DAG) of mesh points used to evaluate dual bases in 395b29cfa1cSToby Isaac DMPlexProjectXXXLocal() functions. 396b29cfa1cSToby Isaac 3972fe279fdSBarry Smith Input Parameter: 398a1cb98faSBarry Smith . dm - the `DMPLEX` object 399b29cfa1cSToby Isaac 4002fe279fdSBarry Smith Output Parameter: 401b29cfa1cSToby Isaac . height - the maximum projection height 402b29cfa1cSToby Isaac 403b29cfa1cSToby Isaac Level: intermediate 404b29cfa1cSToby Isaac 4051cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetMaxProjectionHeight()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()` 406b29cfa1cSToby Isaac @*/ 407d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetMaxProjectionHeight(DM dm, PetscInt *height) 408d71ae5a4SJacob Faibussowitsch { 409b29cfa1cSToby Isaac DM_Plex *plex = (DM_Plex *)dm->data; 410b29cfa1cSToby Isaac 411b29cfa1cSToby Isaac PetscFunctionBegin; 412b29cfa1cSToby Isaac PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 413b29cfa1cSToby Isaac *height = plex->maxProjectionHeight; 4143ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 415b29cfa1cSToby Isaac } 416b29cfa1cSToby Isaac 417ca3d3a14SMatthew G. Knepley typedef struct { 418ca3d3a14SMatthew G. Knepley PetscReal alpha; /* The first Euler angle, and in 2D the only one */ 419ca3d3a14SMatthew G. Knepley PetscReal beta; /* The second Euler angle */ 420ca3d3a14SMatthew G. Knepley PetscReal gamma; /* The third Euler angle */ 421ca3d3a14SMatthew G. Knepley PetscInt dim; /* The dimension of R */ 422ca3d3a14SMatthew G. Knepley PetscScalar *R; /* The rotation matrix, transforming a vector in the local basis to the global basis */ 423ca3d3a14SMatthew G. Knepley PetscScalar *RT; /* The transposed rotation matrix, transforming a vector in the global basis to the local basis */ 424ca3d3a14SMatthew G. Knepley } RotCtx; 425ca3d3a14SMatthew G. Knepley 426ca3d3a14SMatthew G. Knepley /* 427ca3d3a14SMatthew G. Knepley Note: Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that 428ca3d3a14SMatthew 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: 429ca3d3a14SMatthew 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. 430ca3d3a14SMatthew 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. 431ca3d3a14SMatthew G. Knepley $ The XYZ system rotates a third time about the z axis by gamma. 432ca3d3a14SMatthew G. Knepley */ 433d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformSetUp_Rotation_Internal(DM dm, void *ctx) 434d71ae5a4SJacob Faibussowitsch { 435ca3d3a14SMatthew G. Knepley RotCtx *rc = (RotCtx *)ctx; 436ca3d3a14SMatthew G. Knepley PetscInt dim = rc->dim; 437ca3d3a14SMatthew G. Knepley PetscReal c1, s1, c2, s2, c3, s3; 438ca3d3a14SMatthew G. Knepley 439ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 4409566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(PetscSqr(dim), &rc->R, PetscSqr(dim), &rc->RT)); 441ca3d3a14SMatthew G. Knepley switch (dim) { 442ca3d3a14SMatthew G. Knepley case 2: 4439371c9d4SSatish Balay c1 = PetscCosReal(rc->alpha); 4449371c9d4SSatish Balay s1 = PetscSinReal(rc->alpha); 4459371c9d4SSatish Balay rc->R[0] = c1; 4469371c9d4SSatish Balay rc->R[1] = s1; 4479371c9d4SSatish Balay rc->R[2] = -s1; 4489371c9d4SSatish Balay rc->R[3] = c1; 4499566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(rc->RT, rc->R, PetscSqr(dim))); 450b458e8f1SJose E. Roman DMPlex_Transpose2D_Internal(rc->RT); 451ca3d3a14SMatthew G. Knepley break; 452ca3d3a14SMatthew G. Knepley case 3: 4539371c9d4SSatish Balay c1 = PetscCosReal(rc->alpha); 4549371c9d4SSatish Balay s1 = PetscSinReal(rc->alpha); 4559371c9d4SSatish Balay c2 = PetscCosReal(rc->beta); 4569371c9d4SSatish Balay s2 = PetscSinReal(rc->beta); 4579371c9d4SSatish Balay c3 = PetscCosReal(rc->gamma); 4589371c9d4SSatish Balay s3 = PetscSinReal(rc->gamma); 4599371c9d4SSatish Balay rc->R[0] = c1 * c3 - c2 * s1 * s3; 4609371c9d4SSatish Balay rc->R[1] = c3 * s1 + c1 * c2 * s3; 4619371c9d4SSatish Balay rc->R[2] = s2 * s3; 4629371c9d4SSatish Balay rc->R[3] = -c1 * s3 - c2 * c3 * s1; 4639371c9d4SSatish Balay rc->R[4] = c1 * c2 * c3 - s1 * s3; 4649371c9d4SSatish Balay rc->R[5] = c3 * s2; 4659371c9d4SSatish Balay rc->R[6] = s1 * s2; 4669371c9d4SSatish Balay rc->R[7] = -c1 * s2; 4679371c9d4SSatish Balay rc->R[8] = c2; 4689566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(rc->RT, rc->R, PetscSqr(dim))); 469b458e8f1SJose E. Roman DMPlex_Transpose3D_Internal(rc->RT); 470ca3d3a14SMatthew G. Knepley break; 471d71ae5a4SJacob Faibussowitsch default: 472d71ae5a4SJacob Faibussowitsch SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Dimension %" PetscInt_FMT " not supported", dim); 473ca3d3a14SMatthew G. Knepley } 4743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 475ca3d3a14SMatthew G. Knepley } 476ca3d3a14SMatthew G. Knepley 477d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformDestroy_Rotation_Internal(DM dm, void *ctx) 478d71ae5a4SJacob Faibussowitsch { 479ca3d3a14SMatthew G. Knepley RotCtx *rc = (RotCtx *)ctx; 480ca3d3a14SMatthew G. Knepley 481ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 4829566063dSJacob Faibussowitsch PetscCall(PetscFree2(rc->R, rc->RT)); 4839566063dSJacob Faibussowitsch PetscCall(PetscFree(rc)); 4843ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 485ca3d3a14SMatthew G. Knepley } 486ca3d3a14SMatthew G. Knepley 487d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformGetMatrix_Rotation_Internal(DM dm, const PetscReal x[], PetscBool l2g, const PetscScalar **A, void *ctx) 488d71ae5a4SJacob Faibussowitsch { 489ca3d3a14SMatthew G. Knepley RotCtx *rc = (RotCtx *)ctx; 490ca3d3a14SMatthew G. Knepley 491ca3d3a14SMatthew G. Knepley PetscFunctionBeginHot; 4924f572ea9SToby Isaac PetscAssertPointer(ctx, 5); 4939371c9d4SSatish Balay if (l2g) { 4949371c9d4SSatish Balay *A = rc->R; 4959371c9d4SSatish Balay } else { 4969371c9d4SSatish Balay *A = rc->RT; 4979371c9d4SSatish Balay } 4983ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 499ca3d3a14SMatthew G. Knepley } 500ca3d3a14SMatthew G. Knepley 501d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformApplyReal_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscReal *y, PetscReal *z, void *ctx) 502d71ae5a4SJacob Faibussowitsch { 503ec277c0fSMatthew G. Knepley PetscFunctionBegin; 504ab6a9622SMatthew G. Knepley #if defined(PETSC_USE_COMPLEX) 505ab6a9622SMatthew G. Knepley switch (dim) { 5069371c9d4SSatish Balay case 2: { 50727104ee2SJacob Faibussowitsch PetscScalar yt[2] = {y[0], y[1]}, zt[2] = {0.0, 0.0}; 508ab6a9622SMatthew G. Knepley 5099566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx)); 5109371c9d4SSatish Balay z[0] = PetscRealPart(zt[0]); 5119371c9d4SSatish Balay z[1] = PetscRealPart(zt[1]); 5129371c9d4SSatish Balay } break; 5139371c9d4SSatish Balay case 3: { 51427104ee2SJacob Faibussowitsch PetscScalar yt[3] = {y[0], y[1], y[2]}, zt[3] = {0.0, 0.0, 0.0}; 515ab6a9622SMatthew G. Knepley 5169566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx)); 5179371c9d4SSatish Balay z[0] = PetscRealPart(zt[0]); 5189371c9d4SSatish Balay z[1] = PetscRealPart(zt[1]); 5199371c9d4SSatish Balay z[2] = PetscRealPart(zt[2]); 5209371c9d4SSatish Balay } break; 521ab6a9622SMatthew G. Knepley } 522ab6a9622SMatthew G. Knepley #else 5239566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, y, z, ctx)); 524ab6a9622SMatthew G. Knepley #endif 5253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 526ab6a9622SMatthew G. Knepley } 527ab6a9622SMatthew G. Knepley 528d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformApply_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscScalar *y, PetscScalar *z, void *ctx) 529d71ae5a4SJacob Faibussowitsch { 530ca3d3a14SMatthew G. Knepley const PetscScalar *A; 531ca3d3a14SMatthew G. Knepley 532ca3d3a14SMatthew G. Knepley PetscFunctionBeginHot; 5339566063dSJacob Faibussowitsch PetscCall((*dm->transformGetMatrix)(dm, x, l2g, &A, ctx)); 534ca3d3a14SMatthew G. Knepley switch (dim) { 535d71ae5a4SJacob Faibussowitsch case 2: 536d71ae5a4SJacob Faibussowitsch DMPlex_Mult2D_Internal(A, 1, y, z); 537d71ae5a4SJacob Faibussowitsch break; 538d71ae5a4SJacob Faibussowitsch case 3: 539d71ae5a4SJacob Faibussowitsch DMPlex_Mult3D_Internal(A, 1, y, z); 540d71ae5a4SJacob Faibussowitsch break; 541ca3d3a14SMatthew G. Knepley } 5423ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 543ca3d3a14SMatthew G. Knepley } 544ca3d3a14SMatthew G. Knepley 545d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformField_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscInt f, PetscBool l2g, PetscScalar *a) 546d71ae5a4SJacob Faibussowitsch { 547ca3d3a14SMatthew G. Knepley PetscSection ts; 548ca3d3a14SMatthew G. Knepley const PetscScalar *ta, *tva; 549ca3d3a14SMatthew G. Knepley PetscInt dof; 550ca3d3a14SMatthew G. Knepley 551ca3d3a14SMatthew G. Knepley PetscFunctionBeginHot; 5529566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(tdm, &ts)); 5539566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(ts, p, f, &dof)); 5549566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(tv, &ta)); 5559566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(tdm, p, f, ta, &tva)); 556ca3d3a14SMatthew G. Knepley if (l2g) { 557ca3d3a14SMatthew G. Knepley switch (dof) { 558d71ae5a4SJacob Faibussowitsch case 4: 559d71ae5a4SJacob Faibussowitsch DMPlex_Mult2D_Internal(tva, 1, a, a); 560d71ae5a4SJacob Faibussowitsch break; 561d71ae5a4SJacob Faibussowitsch case 9: 562d71ae5a4SJacob Faibussowitsch DMPlex_Mult3D_Internal(tva, 1, a, a); 563d71ae5a4SJacob Faibussowitsch break; 564ca3d3a14SMatthew G. Knepley } 565ca3d3a14SMatthew G. Knepley } else { 566ca3d3a14SMatthew G. Knepley switch (dof) { 567d71ae5a4SJacob Faibussowitsch case 4: 568d71ae5a4SJacob Faibussowitsch DMPlex_MultTranspose2D_Internal(tva, 1, a, a); 569d71ae5a4SJacob Faibussowitsch break; 570d71ae5a4SJacob Faibussowitsch case 9: 571d71ae5a4SJacob Faibussowitsch DMPlex_MultTranspose3D_Internal(tva, 1, a, a); 572d71ae5a4SJacob Faibussowitsch break; 573ca3d3a14SMatthew G. Knepley } 574ca3d3a14SMatthew G. Knepley } 5759566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(tv, &ta)); 5763ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 577ca3d3a14SMatthew G. Knepley } 578ca3d3a14SMatthew G. Knepley 579d71ae5a4SJacob 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) 580d71ae5a4SJacob Faibussowitsch { 581ca3d3a14SMatthew G. Knepley PetscSection s, ts; 582ca3d3a14SMatthew G. Knepley const PetscScalar *ta, *tvaf, *tvag; 583ca3d3a14SMatthew G. Knepley PetscInt fdof, gdof, fpdof, gpdof; 584ca3d3a14SMatthew G. Knepley 585ca3d3a14SMatthew G. Knepley PetscFunctionBeginHot; 5869566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, &s)); 5879566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(tdm, &ts)); 5889566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, pf, f, &fpdof)); 5899566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, pg, g, &gpdof)); 5909566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(ts, pf, f, &fdof)); 5919566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(ts, pg, g, &gdof)); 5929566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(tv, &ta)); 5939566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(tdm, pf, f, ta, &tvaf)); 5949566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(tdm, pg, g, ta, &tvag)); 595ca3d3a14SMatthew G. Knepley if (l2g) { 596ca3d3a14SMatthew G. Knepley switch (fdof) { 597d71ae5a4SJacob Faibussowitsch case 4: 598d71ae5a4SJacob Faibussowitsch DMPlex_MatMult2D_Internal(tvaf, gpdof, lda, a, a); 599d71ae5a4SJacob Faibussowitsch break; 600d71ae5a4SJacob Faibussowitsch case 9: 601d71ae5a4SJacob Faibussowitsch DMPlex_MatMult3D_Internal(tvaf, gpdof, lda, a, a); 602d71ae5a4SJacob Faibussowitsch break; 603ca3d3a14SMatthew G. Knepley } 604ca3d3a14SMatthew G. Knepley switch (gdof) { 605d71ae5a4SJacob Faibussowitsch case 4: 606d71ae5a4SJacob Faibussowitsch DMPlex_MatMultTransposeLeft2D_Internal(tvag, fpdof, lda, a, a); 607d71ae5a4SJacob Faibussowitsch break; 608d71ae5a4SJacob Faibussowitsch case 9: 609d71ae5a4SJacob Faibussowitsch DMPlex_MatMultTransposeLeft3D_Internal(tvag, fpdof, lda, a, a); 610d71ae5a4SJacob Faibussowitsch break; 611ca3d3a14SMatthew G. Knepley } 612ca3d3a14SMatthew G. Knepley } else { 613ca3d3a14SMatthew G. Knepley switch (fdof) { 614d71ae5a4SJacob Faibussowitsch case 4: 615d71ae5a4SJacob Faibussowitsch DMPlex_MatMultTranspose2D_Internal(tvaf, gpdof, lda, a, a); 616d71ae5a4SJacob Faibussowitsch break; 617d71ae5a4SJacob Faibussowitsch case 9: 618d71ae5a4SJacob Faibussowitsch DMPlex_MatMultTranspose3D_Internal(tvaf, gpdof, lda, a, a); 619d71ae5a4SJacob Faibussowitsch break; 620ca3d3a14SMatthew G. Knepley } 621ca3d3a14SMatthew G. Knepley switch (gdof) { 622d71ae5a4SJacob Faibussowitsch case 4: 623d71ae5a4SJacob Faibussowitsch DMPlex_MatMultLeft2D_Internal(tvag, fpdof, lda, a, a); 624d71ae5a4SJacob Faibussowitsch break; 625d71ae5a4SJacob Faibussowitsch case 9: 626d71ae5a4SJacob Faibussowitsch DMPlex_MatMultLeft3D_Internal(tvag, fpdof, lda, a, a); 627d71ae5a4SJacob Faibussowitsch break; 628ca3d3a14SMatthew G. Knepley } 629ca3d3a14SMatthew G. Knepley } 6309566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(tv, &ta)); 6313ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 632ca3d3a14SMatthew G. Knepley } 633ca3d3a14SMatthew G. Knepley 634d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformPoint_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool fieldActive[], PetscBool l2g, PetscScalar *a) 635d71ae5a4SJacob Faibussowitsch { 636ca3d3a14SMatthew G. Knepley PetscSection s; 637ca3d3a14SMatthew G. Knepley PetscSection clSection; 638ca3d3a14SMatthew G. Knepley IS clPoints; 639ca3d3a14SMatthew G. Knepley const PetscInt *clp; 640ca3d3a14SMatthew G. Knepley PetscInt *points = NULL; 641ca3d3a14SMatthew G. Knepley PetscInt Nf, f, Np, cp, dof, d = 0; 642ca3d3a14SMatthew G. Knepley 643ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 6449566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, &s)); 6459566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(s, &Nf)); 64607218a29SMatthew G. Knepley PetscCall(DMPlexGetCompressedClosure(dm, s, p, 0, &Np, &points, &clSection, &clPoints, &clp)); 647ca3d3a14SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 648ca3d3a14SMatthew G. Knepley for (cp = 0; cp < Np * 2; cp += 2) { 6499566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, points[cp], f, &dof)); 650ca3d3a14SMatthew G. Knepley if (!dof) continue; 6519566063dSJacob Faibussowitsch if (fieldActive[f]) PetscCall(DMPlexBasisTransformField_Internal(dm, tdm, tv, points[cp], f, l2g, &a[d])); 652ca3d3a14SMatthew G. Knepley d += dof; 653ca3d3a14SMatthew G. Knepley } 654ca3d3a14SMatthew G. Knepley } 6559566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp)); 6563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 657ca3d3a14SMatthew G. Knepley } 658ca3d3a14SMatthew G. Knepley 659d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformPointTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool l2g, PetscInt lda, PetscScalar *a) 660d71ae5a4SJacob Faibussowitsch { 661ca3d3a14SMatthew G. Knepley PetscSection s; 662ca3d3a14SMatthew G. Knepley PetscSection clSection; 663ca3d3a14SMatthew G. Knepley IS clPoints; 664ca3d3a14SMatthew G. Knepley const PetscInt *clp; 665ca3d3a14SMatthew G. Knepley PetscInt *points = NULL; 6668bdb3c71SMatthew G. Knepley PetscInt Nf, f, g, Np, cpf, cpg, fdof, gdof, r, c = 0; 667ca3d3a14SMatthew G. Knepley 668ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 6699566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, &s)); 6709566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(s, &Nf)); 67107218a29SMatthew G. Knepley PetscCall(DMPlexGetCompressedClosure(dm, s, p, 0, &Np, &points, &clSection, &clPoints, &clp)); 672ca3d3a14SMatthew G. Knepley for (f = 0, r = 0; f < Nf; ++f) { 673ca3d3a14SMatthew G. Knepley for (cpf = 0; cpf < Np * 2; cpf += 2) { 6749566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, points[cpf], f, &fdof)); 675ca3d3a14SMatthew G. Knepley for (g = 0, c = 0; g < Nf; ++g) { 676ca3d3a14SMatthew G. Knepley for (cpg = 0; cpg < Np * 2; cpg += 2) { 6779566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, points[cpg], g, &gdof)); 6789566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformFieldTensor_Internal(dm, tdm, tv, points[cpf], f, points[cpg], g, l2g, lda, &a[r * lda + c])); 679ca3d3a14SMatthew G. Knepley c += gdof; 680ca3d3a14SMatthew G. Knepley } 681ca3d3a14SMatthew G. Knepley } 68263a3b9bcSJacob Faibussowitsch PetscCheck(c == lda, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of columns %" PetscInt_FMT " should be %" PetscInt_FMT, c, lda); 683ca3d3a14SMatthew G. Knepley r += fdof; 684ca3d3a14SMatthew G. Knepley } 685ca3d3a14SMatthew G. Knepley } 68663a3b9bcSJacob Faibussowitsch PetscCheck(r == lda, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of rows %" PetscInt_FMT " should be %" PetscInt_FMT, c, lda); 6879566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp)); 6883ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 689ca3d3a14SMatthew G. Knepley } 690ca3d3a14SMatthew G. Knepley 691d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransform_Internal(DM dm, Vec lv, PetscBool l2g) 692d71ae5a4SJacob Faibussowitsch { 693ca3d3a14SMatthew G. Knepley DM tdm; 694ca3d3a14SMatthew G. Knepley Vec tv; 695ca3d3a14SMatthew G. Knepley PetscSection ts, s; 696ca3d3a14SMatthew G. Knepley const PetscScalar *ta; 697ca3d3a14SMatthew G. Knepley PetscScalar *a, *va; 698ca3d3a14SMatthew G. Knepley PetscInt pStart, pEnd, p, Nf, f; 699ca3d3a14SMatthew G. Knepley 700ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 7019566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 7029566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 7039566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(tdm, &ts)); 7049566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, &s)); 7059566063dSJacob Faibussowitsch PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 7069566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(s, &Nf)); 7079566063dSJacob Faibussowitsch PetscCall(VecGetArray(lv, &a)); 7089566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(tv, &ta)); 709ca3d3a14SMatthew G. Knepley for (p = pStart; p < pEnd; ++p) { 710ca3d3a14SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 7119566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, p, f, a, &va)); 7129566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformField_Internal(dm, tdm, tv, p, f, l2g, va)); 713ca3d3a14SMatthew G. Knepley } 714ca3d3a14SMatthew G. Knepley } 7159566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(lv, &a)); 7169566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(tv, &ta)); 7173ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 718ca3d3a14SMatthew G. Knepley } 719ca3d3a14SMatthew G. Knepley 720ca3d3a14SMatthew G. Knepley /*@ 721ca3d3a14SMatthew G. Knepley DMPlexGlobalToLocalBasis - Transform the values in the given local vector from the global basis to the local basis 722ca3d3a14SMatthew G. Knepley 723ca3d3a14SMatthew G. Knepley Input Parameters: 724a1cb98faSBarry Smith + dm - The `DM` 725ca3d3a14SMatthew G. Knepley - lv - A local vector with values in the global basis 726ca3d3a14SMatthew G. Knepley 7272fe279fdSBarry Smith Output Parameter: 728ca3d3a14SMatthew G. Knepley . lv - A local vector with values in the local basis 729ca3d3a14SMatthew G. Knepley 730ca3d3a14SMatthew G. Knepley Level: developer 731ca3d3a14SMatthew G. Knepley 732a1cb98faSBarry Smith Note: 733a1cb98faSBarry 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. 734a1cb98faSBarry Smith 7351cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexLocalToGlobalBasis()`, `DMGetLocalSection()`, `DMPlexCreateBasisRotation()` 736ca3d3a14SMatthew G. Knepley @*/ 737d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGlobalToLocalBasis(DM dm, Vec lv) 738d71ae5a4SJacob Faibussowitsch { 739ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 740ca3d3a14SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 741ca3d3a14SMatthew G. Knepley PetscValidHeaderSpecific(lv, VEC_CLASSID, 2); 7429566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransform_Internal(dm, lv, PETSC_FALSE)); 7433ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 744ca3d3a14SMatthew G. Knepley } 745ca3d3a14SMatthew G. Knepley 746ca3d3a14SMatthew G. Knepley /*@ 747ca3d3a14SMatthew G. Knepley DMPlexLocalToGlobalBasis - Transform the values in the given local vector from the local basis to the global basis 748ca3d3a14SMatthew G. Knepley 749ca3d3a14SMatthew G. Knepley Input Parameters: 750a1cb98faSBarry Smith + dm - The `DM` 751ca3d3a14SMatthew G. Knepley - lv - A local vector with values in the local basis 752ca3d3a14SMatthew G. Knepley 7532fe279fdSBarry Smith Output Parameter: 754ca3d3a14SMatthew G. Knepley . lv - A local vector with values in the global basis 755ca3d3a14SMatthew G. Knepley 756ca3d3a14SMatthew G. Knepley Level: developer 757ca3d3a14SMatthew G. Knepley 758a1cb98faSBarry Smith Note: 759a1cb98faSBarry 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. 760a1cb98faSBarry Smith 7611cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGlobalToLocalBasis()`, `DMGetLocalSection()`, `DMPlexCreateBasisRotation()` 762ca3d3a14SMatthew G. Knepley @*/ 763d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalToGlobalBasis(DM dm, Vec lv) 764d71ae5a4SJacob Faibussowitsch { 765ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 766ca3d3a14SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 767ca3d3a14SMatthew G. Knepley PetscValidHeaderSpecific(lv, VEC_CLASSID, 2); 7689566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransform_Internal(dm, lv, PETSC_TRUE)); 7693ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 770ca3d3a14SMatthew G. Knepley } 771ca3d3a14SMatthew G. Knepley 772ca3d3a14SMatthew G. Knepley /*@ 773ca3d3a14SMatthew G. Knepley DMPlexCreateBasisRotation - Create an internal transformation from the global basis, used to specify boundary conditions 774ca3d3a14SMatthew G. Knepley and global solutions, to a local basis, appropriate for discretization integrals and assembly. 775ca3d3a14SMatthew G. Knepley 776ca3d3a14SMatthew G. Knepley Input Parameters: 777a1cb98faSBarry Smith + dm - The `DM` 778ca3d3a14SMatthew G. Knepley . alpha - The first Euler angle, and in 2D the only one 779ca3d3a14SMatthew G. Knepley . beta - The second Euler angle 780f0fc11ceSJed Brown - gamma - The third Euler angle 781ca3d3a14SMatthew G. Knepley 782ca3d3a14SMatthew G. Knepley Level: developer 783ca3d3a14SMatthew G. Knepley 784a1cb98faSBarry Smith Note: 785a1cb98faSBarry Smith Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that 786a1cb98faSBarry 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 787a1cb98faSBarry Smith .vb 788a1cb98faSBarry 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. 789a1cb98faSBarry 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. 790a1cb98faSBarry Smith The XYZ system rotates a third time about the z axis by gamma. 791a1cb98faSBarry Smith .ve 792a1cb98faSBarry Smith 7931cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGlobalToLocalBasis()`, `DMPlexLocalToGlobalBasis()` 794ca3d3a14SMatthew G. Knepley @*/ 795d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateBasisRotation(DM dm, PetscReal alpha, PetscReal beta, PetscReal gamma) 796d71ae5a4SJacob Faibussowitsch { 797ca3d3a14SMatthew G. Knepley RotCtx *rc; 798ca3d3a14SMatthew G. Knepley PetscInt cdim; 799ca3d3a14SMatthew G. Knepley 800362febeeSStefano Zampini PetscFunctionBegin; 8019566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &cdim)); 8029566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(1, &rc)); 803ca3d3a14SMatthew G. Knepley dm->transformCtx = rc; 804ca3d3a14SMatthew G. Knepley dm->transformSetUp = DMPlexBasisTransformSetUp_Rotation_Internal; 805ca3d3a14SMatthew G. Knepley dm->transformDestroy = DMPlexBasisTransformDestroy_Rotation_Internal; 806ca3d3a14SMatthew G. Knepley dm->transformGetMatrix = DMPlexBasisTransformGetMatrix_Rotation_Internal; 807ca3d3a14SMatthew G. Knepley rc->dim = cdim; 808ca3d3a14SMatthew G. Knepley rc->alpha = alpha; 809ca3d3a14SMatthew G. Knepley rc->beta = beta; 810ca3d3a14SMatthew G. Knepley rc->gamma = gamma; 8119566063dSJacob Faibussowitsch PetscCall((*dm->transformSetUp)(dm, dm->transformCtx)); 8129566063dSJacob Faibussowitsch PetscCall(DMConstructBasisTransform_Internal(dm)); 8133ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 814ca3d3a14SMatthew G. Knepley } 815ca3d3a14SMatthew G. Knepley 816b278463cSMatthew G. Knepley /*@C 817ece3a9fcSMatthew G. Knepley DMPlexInsertBoundaryValuesEssential - Insert boundary values into a local vector using a function of the coordinates 818b278463cSMatthew G. Knepley 819b278463cSMatthew G. Knepley Input Parameters: 820a1cb98faSBarry Smith + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 821b278463cSMatthew G. Knepley . time - The time 822b278463cSMatthew G. Knepley . field - The field to constrain 8231c531cf8SMatthew G. Knepley . Nc - The number of constrained field components, or 0 for all components 82420f4b53cSBarry Smith . comps - An array of constrained component numbers, or `NULL` for all components 825a1cb98faSBarry Smith . label - The `DMLabel` defining constrained points 826a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points 827b278463cSMatthew G. Knepley . ids - An array of ids for constrained points 828b278463cSMatthew G. Knepley . func - A pointwise function giving boundary values 829b278463cSMatthew G. Knepley - ctx - An optional user context for bcFunc 830b278463cSMatthew G. Knepley 831b278463cSMatthew G. Knepley Output Parameter: 832b278463cSMatthew G. Knepley . locX - A local vector to receives the boundary values 833b278463cSMatthew G. Knepley 834b278463cSMatthew G. Knepley Level: developer 835b278463cSMatthew G. Knepley 8361cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLabel`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMPlexInsertBoundaryValuesEssentialBdField()`, `DMAddBoundary()` 837b278463cSMatthew G. Knepley @*/ 838d71ae5a4SJacob 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) 839d71ae5a4SJacob Faibussowitsch { 8400163fd50SMatthew G. Knepley PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx); 84155f2e967SMatthew G. Knepley void **ctxs; 842d7ddef95SMatthew G. Knepley PetscInt numFields; 843d7ddef95SMatthew G. Knepley 844d7ddef95SMatthew G. Knepley PetscFunctionBegin; 8459566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &numFields)); 8469566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs)); 847d7ddef95SMatthew G. Knepley funcs[field] = func; 848d7ddef95SMatthew G. Knepley ctxs[field] = ctx; 8499566063dSJacob Faibussowitsch PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numids, ids, Nc, comps, funcs, ctxs, INSERT_BC_VALUES, locX)); 8509566063dSJacob Faibussowitsch PetscCall(PetscFree2(funcs, ctxs)); 8513ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 852d7ddef95SMatthew G. Knepley } 853d7ddef95SMatthew G. Knepley 854b278463cSMatthew G. Knepley /*@C 855ece3a9fcSMatthew G. Knepley DMPlexInsertBoundaryValuesEssentialField - Insert boundary values into a local vector using a function of the coordinates and field data 856b278463cSMatthew G. Knepley 857b278463cSMatthew G. Knepley Input Parameters: 858a1cb98faSBarry Smith + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 859b278463cSMatthew G. Knepley . time - The time 860b278463cSMatthew G. Knepley . locU - A local vector with the input solution values 861b278463cSMatthew G. Knepley . field - The field to constrain 8621c531cf8SMatthew G. Knepley . Nc - The number of constrained field components, or 0 for all components 86320f4b53cSBarry Smith . comps - An array of constrained component numbers, or `NULL` for all components 864a1cb98faSBarry Smith . label - The `DMLabel` defining constrained points 865a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points 866b278463cSMatthew G. Knepley . ids - An array of ids for constrained points 867b278463cSMatthew G. Knepley . func - A pointwise function giving boundary values 868b278463cSMatthew G. Knepley - ctx - An optional user context for bcFunc 869b278463cSMatthew G. Knepley 870b278463cSMatthew G. Knepley Output Parameter: 871b278463cSMatthew G. Knepley . locX - A local vector to receives the boundary values 872b278463cSMatthew G. Knepley 873b278463cSMatthew G. Knepley Level: developer 874b278463cSMatthew G. Knepley 8751cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialBdField()`, `DMAddBoundary()` 876b278463cSMatthew G. Knepley @*/ 877d71ae5a4SJacob 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) 878d71ae5a4SJacob Faibussowitsch { 8799371c9d4SSatish 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[]); 880c60e475cSMatthew G. Knepley void **ctxs; 881c60e475cSMatthew G. Knepley PetscInt numFields; 882c60e475cSMatthew G. Knepley 883c60e475cSMatthew G. Knepley PetscFunctionBegin; 8849566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &numFields)); 8859566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs)); 886c60e475cSMatthew G. Knepley funcs[field] = func; 887c60e475cSMatthew G. Knepley ctxs[field] = ctx; 8889566063dSJacob Faibussowitsch PetscCall(DMProjectFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX)); 8899566063dSJacob Faibussowitsch PetscCall(PetscFree2(funcs, ctxs)); 8903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 891c60e475cSMatthew G. Knepley } 892c60e475cSMatthew G. Knepley 893b278463cSMatthew G. Knepley /*@C 894d5b43468SJose E. Roman DMPlexInsertBoundaryValuesEssentialBdField - Insert boundary values into a local vector using a function of the coordinates and boundary field data 895ece3a9fcSMatthew G. Knepley 89620f4b53cSBarry Smith Collective 897ece3a9fcSMatthew G. Knepley 898ece3a9fcSMatthew G. Knepley Input Parameters: 899a1cb98faSBarry Smith + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 900ece3a9fcSMatthew G. Knepley . time - The time 901ece3a9fcSMatthew G. Knepley . locU - A local vector with the input solution values 902ece3a9fcSMatthew G. Knepley . field - The field to constrain 903ece3a9fcSMatthew G. Knepley . Nc - The number of constrained field components, or 0 for all components 90420f4b53cSBarry Smith . comps - An array of constrained component numbers, or `NULL` for all components 905a1cb98faSBarry Smith . label - The `DMLabel` defining constrained points 906a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points 907ece3a9fcSMatthew G. Knepley . ids - An array of ids for constrained points 90820f4b53cSBarry Smith . func - A pointwise function giving boundary values, the calling sequence is given in `DMProjectBdFieldLabelLocal()` 90920f4b53cSBarry Smith - ctx - An optional user context for `func` 910ece3a9fcSMatthew G. Knepley 911ece3a9fcSMatthew G. Knepley Output Parameter: 912ece3a9fcSMatthew G. Knepley . locX - A local vector to receive the boundary values 913ece3a9fcSMatthew G. Knepley 914ece3a9fcSMatthew G. Knepley Level: developer 915ece3a9fcSMatthew G. Knepley 9161cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectBdFieldLabelLocal()`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMAddBoundary()` 917ece3a9fcSMatthew G. Knepley @*/ 918d71ae5a4SJacob 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) 919d71ae5a4SJacob Faibussowitsch { 9209371c9d4SSatish 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[]); 921ece3a9fcSMatthew G. Knepley void **ctxs; 922ece3a9fcSMatthew G. Knepley PetscInt numFields; 923ece3a9fcSMatthew G. Knepley 924ece3a9fcSMatthew G. Knepley PetscFunctionBegin; 9259566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &numFields)); 9269566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs)); 927ece3a9fcSMatthew G. Knepley funcs[field] = func; 928ece3a9fcSMatthew G. Knepley ctxs[field] = ctx; 9299566063dSJacob Faibussowitsch PetscCall(DMProjectBdFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX)); 9309566063dSJacob Faibussowitsch PetscCall(PetscFree2(funcs, ctxs)); 9313ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 932ece3a9fcSMatthew G. Knepley } 933ece3a9fcSMatthew G. Knepley 934ece3a9fcSMatthew G. Knepley /*@C 935b278463cSMatthew G. Knepley DMPlexInsertBoundaryValuesRiemann - Insert boundary values into a local vector 936b278463cSMatthew G. Knepley 937b278463cSMatthew G. Knepley Input Parameters: 938a1cb98faSBarry Smith + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 939b278463cSMatthew G. Knepley . time - The time 940b278463cSMatthew G. Knepley . faceGeometry - A vector with the FVM face geometry information 941b278463cSMatthew G. Knepley . cellGeometry - A vector with the FVM cell geometry information 942b278463cSMatthew G. Knepley . Grad - A vector with the FVM cell gradient information 943b278463cSMatthew G. Knepley . field - The field to constrain 9441c531cf8SMatthew G. Knepley . Nc - The number of constrained field components, or 0 for all components 94520f4b53cSBarry Smith . comps - An array of constrained component numbers, or `NULL` for all components 946a1cb98faSBarry Smith . label - The `DMLabel` defining constrained points 947a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points 948b278463cSMatthew G. Knepley . ids - An array of ids for constrained points 949b278463cSMatthew G. Knepley . func - A pointwise function giving boundary values 950b278463cSMatthew G. Knepley - ctx - An optional user context for bcFunc 951b278463cSMatthew G. Knepley 952b278463cSMatthew G. Knepley Output Parameter: 953b278463cSMatthew G. Knepley . locX - A local vector to receives the boundary values 954b278463cSMatthew G. Knepley 955b278463cSMatthew G. Knepley Level: developer 956b278463cSMatthew G. Knepley 957a1cb98faSBarry Smith Note: 958a1cb98faSBarry Smith This implementation currently ignores the numcomps/comps argument from `DMAddBoundary()` 959a1cb98faSBarry Smith 9601cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMAddBoundary()` 961b278463cSMatthew G. Knepley @*/ 962d71ae5a4SJacob 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) 963d71ae5a4SJacob Faibussowitsch { 96461f58d28SMatthew G. Knepley PetscDS prob; 965da97024aSMatthew G. Knepley PetscSF sf; 966d7ddef95SMatthew G. Knepley DM dmFace, dmCell, dmGrad; 96720369375SToby Isaac const PetscScalar *facegeom, *cellgeom = NULL, *grad; 968da97024aSMatthew G. Knepley const PetscInt *leaves; 969d7ddef95SMatthew G. Knepley PetscScalar *x, *fx; 970520b3818SMatthew G. Knepley PetscInt dim, nleaves, loc, fStart, fEnd, pdim, i; 9713ba16761SJacob Faibussowitsch PetscErrorCode ierru = PETSC_SUCCESS; 972d7ddef95SMatthew G. Knepley 973d7ddef95SMatthew G. Knepley PetscFunctionBegin; 9749566063dSJacob Faibussowitsch PetscCall(DMGetPointSF(dm, &sf)); 9759566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL)); 976da97024aSMatthew G. Knepley nleaves = PetscMax(0, nleaves); 9779566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 9789566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 9799566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 9809566063dSJacob Faibussowitsch PetscCall(VecGetDM(faceGeometry, &dmFace)); 9819566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 98220369375SToby Isaac if (cellGeometry) { 9839566063dSJacob Faibussowitsch PetscCall(VecGetDM(cellGeometry, &dmCell)); 9849566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 98520369375SToby Isaac } 986d7ddef95SMatthew G. Knepley if (Grad) { 987c0a6632aSMatthew G. Knepley PetscFV fv; 988c0a6632aSMatthew G. Knepley 9899566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fv)); 9909566063dSJacob Faibussowitsch PetscCall(VecGetDM(Grad, &dmGrad)); 9919566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(Grad, &grad)); 9929566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 9939566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, pdim, MPIU_SCALAR, &fx)); 994d7ddef95SMatthew G. Knepley } 9959566063dSJacob Faibussowitsch PetscCall(VecGetArray(locX, &x)); 996d7ddef95SMatthew G. Knepley for (i = 0; i < numids; ++i) { 997d7ddef95SMatthew G. Knepley IS faceIS; 998d7ddef95SMatthew G. Knepley const PetscInt *faces; 999d7ddef95SMatthew G. Knepley PetscInt numFaces, f; 1000d7ddef95SMatthew G. Knepley 10019566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, ids[i], &faceIS)); 1002d7ddef95SMatthew G. Knepley if (!faceIS) continue; /* No points with that id on this process */ 10039566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(faceIS, &numFaces)); 10049566063dSJacob Faibussowitsch PetscCall(ISGetIndices(faceIS, &faces)); 1005d7ddef95SMatthew G. Knepley for (f = 0; f < numFaces; ++f) { 1006d7ddef95SMatthew G. Knepley const PetscInt face = faces[f], *cells; 1007640bce14SSatish Balay PetscFVFaceGeom *fg; 1008d7ddef95SMatthew G. Knepley 1009d7ddef95SMatthew G. Knepley if ((face < fStart) || (face >= fEnd)) continue; /* Refinement adds non-faces to labels */ 10109566063dSJacob Faibussowitsch PetscCall(PetscFindInt(face, nleaves, (PetscInt *)leaves, &loc)); 1011da97024aSMatthew G. Knepley if (loc >= 0) continue; 10129566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 10139566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &cells)); 1014d7ddef95SMatthew G. Knepley if (Grad) { 1015640bce14SSatish Balay PetscFVCellGeom *cg; 1016640bce14SSatish Balay PetscScalar *cx, *cgrad; 1017d7ddef95SMatthew G. Knepley PetscScalar *xG; 1018d7ddef95SMatthew G. Knepley PetscReal dx[3]; 1019d7ddef95SMatthew G. Knepley PetscInt d; 1020d7ddef95SMatthew G. Knepley 10219566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cg)); 10229566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dm, cells[0], x, &cx)); 10239566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], grad, &cgrad)); 10249566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG)); 1025d7ddef95SMatthew G. Knepley DMPlex_WaxpyD_Internal(dim, -1, cg->centroid, fg->centroid, dx); 1026d7ddef95SMatthew G. Knepley for (d = 0; d < pdim; ++d) fx[d] = cx[d] + DMPlex_DotD_Internal(dim, &cgrad[d * dim], dx); 10279566063dSJacob Faibussowitsch PetscCall((*func)(time, fg->centroid, fg->normal, fx, xG, ctx)); 1028d7ddef95SMatthew G. Knepley } else { 1029640bce14SSatish Balay PetscScalar *xI; 1030d7ddef95SMatthew G. Knepley PetscScalar *xG; 1031d7ddef95SMatthew G. Knepley 10329566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dm, cells[0], x, &xI)); 10339566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG)); 1034e735a8a9SMatthew G. Knepley ierru = (*func)(time, fg->centroid, fg->normal, xI, xG, ctx); 1035e735a8a9SMatthew G. Knepley if (ierru) { 10369566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(faceIS, &faces)); 10379566063dSJacob Faibussowitsch PetscCall(ISDestroy(&faceIS)); 1038e735a8a9SMatthew G. Knepley goto cleanup; 1039e735a8a9SMatthew G. Knepley } 1040d7ddef95SMatthew G. Knepley } 1041d7ddef95SMatthew G. Knepley } 10429566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(faceIS, &faces)); 10439566063dSJacob Faibussowitsch PetscCall(ISDestroy(&faceIS)); 1044d7ddef95SMatthew G. Knepley } 1045e735a8a9SMatthew G. Knepley cleanup: 10469566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locX, &x)); 1047d7ddef95SMatthew G. Knepley if (Grad) { 10489566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, pdim, MPIU_SCALAR, &fx)); 10499566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(Grad, &grad)); 1050d7ddef95SMatthew G. Knepley } 10519566063dSJacob Faibussowitsch if (cellGeometry) PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 10529566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 10539566063dSJacob Faibussowitsch PetscCall(ierru); 10543ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1055d7ddef95SMatthew G. Knepley } 1056d7ddef95SMatthew G. Knepley 1057d71ae5a4SJacob Faibussowitsch static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 1058d71ae5a4SJacob Faibussowitsch { 10590c364540SMatthew G. Knepley PetscInt c; 10600c364540SMatthew G. Knepley for (c = 0; c < Nc; ++c) u[c] = 0.0; 10613ba16761SJacob Faibussowitsch return PETSC_SUCCESS; 10620c364540SMatthew G. Knepley } 10630c364540SMatthew G. Knepley 1064d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1065d71ae5a4SJacob Faibussowitsch { 10660c364540SMatthew G. Knepley PetscObject isZero; 1067e5e52638SMatthew G. Knepley PetscDS prob; 1068d7ddef95SMatthew G. Knepley PetscInt numBd, b; 106955f2e967SMatthew G. Knepley 107055f2e967SMatthew G. Knepley PetscFunctionBegin; 10719566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 10729566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 10739566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)locX, "__Vec_bc_zero__", &isZero)); 107455f2e967SMatthew G. Knepley for (b = 0; b < numBd; ++b) { 107545480ffeSMatthew G. Knepley PetscWeakForm wf; 1076f971fd6bSMatthew G. Knepley DMBoundaryConditionType type; 107745480ffeSMatthew G. Knepley const char *name; 1078d7ddef95SMatthew G. Knepley DMLabel label; 10791c531cf8SMatthew G. Knepley PetscInt field, Nc; 10801c531cf8SMatthew G. Knepley const PetscInt *comps; 1081d7ddef95SMatthew G. Knepley PetscObject obj; 1082d7ddef95SMatthew G. Knepley PetscClassId id; 108345480ffeSMatthew G. Knepley void (*bvfunc)(void); 1084d7ddef95SMatthew G. Knepley PetscInt numids; 1085d7ddef95SMatthew G. Knepley const PetscInt *ids; 108655f2e967SMatthew G. Knepley void *ctx; 108755f2e967SMatthew G. Knepley 10889566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, &bvfunc, NULL, &ctx)); 1089f971fd6bSMatthew G. Knepley if (insertEssential != (type & DM_BC_ESSENTIAL)) continue; 10909566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 10919566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 1092d7ddef95SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 1093c60e475cSMatthew G. Knepley switch (type) { 1094c60e475cSMatthew G. Knepley /* for FEM, there is no insertion to be done for non-essential boundary conditions */ 10959371c9d4SSatish Balay case DM_BC_ESSENTIAL: { 109645480ffeSMatthew G. Knepley PetscSimplePointFunc func = (PetscSimplePointFunc)bvfunc; 109745480ffeSMatthew G. Knepley 109845480ffeSMatthew G. Knepley if (isZero) func = zero; 10999566063dSJacob Faibussowitsch PetscCall(DMPlexLabelAddCells(dm, label)); 11009566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, func, ctx, locX)); 11019566063dSJacob Faibussowitsch PetscCall(DMPlexLabelClearCells(dm, label)); 11029371c9d4SSatish Balay } break; 11039371c9d4SSatish Balay case DM_BC_ESSENTIAL_FIELD: { 110445480ffeSMatthew G. Knepley PetscPointFunc func = (PetscPointFunc)bvfunc; 110545480ffeSMatthew G. Knepley 11069566063dSJacob Faibussowitsch PetscCall(DMPlexLabelAddCells(dm, label)); 11079566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, func, ctx, locX)); 11089566063dSJacob Faibussowitsch PetscCall(DMPlexLabelClearCells(dm, label)); 11099371c9d4SSatish Balay } break; 1110d71ae5a4SJacob Faibussowitsch default: 1111d71ae5a4SJacob Faibussowitsch break; 1112c60e475cSMatthew G. Knepley } 1113d7ddef95SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 111445480ffeSMatthew G. Knepley { 111545480ffeSMatthew G. Knepley PetscErrorCode (*func)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *) = (PetscErrorCode(*)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *))bvfunc; 111645480ffeSMatthew G. Knepley 111743ea7facSMatthew G. Knepley if (!faceGeomFVM) continue; 11189566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValuesRiemann(dm, time, faceGeomFVM, cellGeomFVM, gradFVM, field, Nc, comps, label, numids, ids, func, ctx, locX)); 111945480ffeSMatthew G. Knepley } 112063a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 112155f2e967SMatthew G. Knepley } 11223ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 112355f2e967SMatthew G. Knepley } 112455f2e967SMatthew G. Knepley 1125d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1126d71ae5a4SJacob Faibussowitsch { 112756cf3b9cSMatthew G. Knepley PetscObject isZero; 112856cf3b9cSMatthew G. Knepley PetscDS prob; 112956cf3b9cSMatthew G. Knepley PetscInt numBd, b; 113056cf3b9cSMatthew G. Knepley 113156cf3b9cSMatthew G. Knepley PetscFunctionBegin; 11323ba16761SJacob Faibussowitsch if (!locX) PetscFunctionReturn(PETSC_SUCCESS); 11339566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 11349566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 11359566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)locX, "__Vec_bc_zero__", &isZero)); 113656cf3b9cSMatthew G. Knepley for (b = 0; b < numBd; ++b) { 113745480ffeSMatthew G. Knepley PetscWeakForm wf; 113856cf3b9cSMatthew G. Knepley DMBoundaryConditionType type; 113945480ffeSMatthew G. Knepley const char *name; 114056cf3b9cSMatthew G. Knepley DMLabel label; 114156cf3b9cSMatthew G. Knepley PetscInt field, Nc; 114256cf3b9cSMatthew G. Knepley const PetscInt *comps; 114356cf3b9cSMatthew G. Knepley PetscObject obj; 114456cf3b9cSMatthew G. Knepley PetscClassId id; 114556cf3b9cSMatthew G. Knepley PetscInt numids; 114656cf3b9cSMatthew G. Knepley const PetscInt *ids; 114745480ffeSMatthew G. Knepley void (*bvfunc)(void); 114856cf3b9cSMatthew G. Knepley void *ctx; 114956cf3b9cSMatthew G. Knepley 11509566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, NULL, &bvfunc, &ctx)); 115156cf3b9cSMatthew G. Knepley if (insertEssential != (type & DM_BC_ESSENTIAL)) continue; 11529566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 11539566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 115456cf3b9cSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 115556cf3b9cSMatthew G. Knepley switch (type) { 115656cf3b9cSMatthew G. Knepley /* for FEM, there is no insertion to be done for non-essential boundary conditions */ 11579371c9d4SSatish Balay case DM_BC_ESSENTIAL: { 115845480ffeSMatthew G. Knepley PetscSimplePointFunc func_t = (PetscSimplePointFunc)bvfunc; 115945480ffeSMatthew G. Knepley 116045480ffeSMatthew G. Knepley if (isZero) func_t = zero; 11619566063dSJacob Faibussowitsch PetscCall(DMPlexLabelAddCells(dm, label)); 11629566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, func_t, ctx, locX)); 11639566063dSJacob Faibussowitsch PetscCall(DMPlexLabelClearCells(dm, label)); 11649371c9d4SSatish Balay } break; 11659371c9d4SSatish Balay case DM_BC_ESSENTIAL_FIELD: { 116645480ffeSMatthew G. Knepley PetscPointFunc func_t = (PetscPointFunc)bvfunc; 116745480ffeSMatthew G. Knepley 11689566063dSJacob Faibussowitsch PetscCall(DMPlexLabelAddCells(dm, label)); 11699566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, func_t, ctx, locX)); 11709566063dSJacob Faibussowitsch PetscCall(DMPlexLabelClearCells(dm, label)); 11719371c9d4SSatish Balay } break; 1172d71ae5a4SJacob Faibussowitsch default: 1173d71ae5a4SJacob Faibussowitsch break; 117456cf3b9cSMatthew G. Knepley } 117563a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 117656cf3b9cSMatthew G. Knepley } 11773ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 117856cf3b9cSMatthew G. Knepley } 117956cf3b9cSMatthew G. Knepley 1180f1d73a7aSMatthew G. Knepley /*@ 1181f1d73a7aSMatthew G. Knepley DMPlexInsertBoundaryValues - Puts coefficients which represent boundary values into the local solution vector 1182f1d73a7aSMatthew G. Knepley 1183ed808b8fSJed Brown Not Collective 1184ed808b8fSJed Brown 1185f1d73a7aSMatthew G. Knepley Input Parameters: 1186a1cb98faSBarry Smith + dm - The `DM` 1187f1d73a7aSMatthew G. Knepley . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions 1188f1d73a7aSMatthew G. Knepley . time - The time 1189f1d73a7aSMatthew G. Knepley . faceGeomFVM - Face geometry data for FV discretizations 1190f1d73a7aSMatthew G. Knepley . cellGeomFVM - Cell geometry data for FV discretizations 1191f1d73a7aSMatthew G. Knepley - gradFVM - Gradient reconstruction data for FV discretizations 1192f1d73a7aSMatthew G. Knepley 11932fe279fdSBarry Smith Output Parameter: 1194f1d73a7aSMatthew G. Knepley . locX - Solution updated with boundary values 1195f1d73a7aSMatthew G. Knepley 1196ed808b8fSJed Brown Level: intermediate 1197f1d73a7aSMatthew G. Knepley 11981cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunctionLabelLocal()`, `DMAddBoundary()` 1199f1d73a7aSMatthew G. Knepley @*/ 1200d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertBoundaryValues(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1201d71ae5a4SJacob Faibussowitsch { 1202f1d73a7aSMatthew G. Knepley PetscFunctionBegin; 1203f1d73a7aSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1204064a246eSJacob Faibussowitsch PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 1205ad540459SPierre Jolivet if (faceGeomFVM) PetscValidHeaderSpecific(faceGeomFVM, VEC_CLASSID, 5); 1206ad540459SPierre Jolivet if (cellGeomFVM) PetscValidHeaderSpecific(cellGeomFVM, VEC_CLASSID, 6); 1207ad540459SPierre Jolivet if (gradFVM) PetscValidHeaderSpecific(gradFVM, VEC_CLASSID, 7); 1208cac4c232SBarry Smith PetscTryMethod(dm, "DMPlexInsertBoundaryValues_C", (DM, PetscBool, Vec, PetscReal, Vec, Vec, Vec), (dm, insertEssential, locX, time, faceGeomFVM, cellGeomFVM, gradFVM)); 12093ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1210f1d73a7aSMatthew G. Knepley } 1211f1d73a7aSMatthew G. Knepley 121256cf3b9cSMatthew G. Knepley /*@ 1213a5b23f4aSJose E. Roman DMPlexInsertTimeDerivativeBoundaryValues - Puts coefficients which represent boundary values of the time derivative into the local solution vector 121456cf3b9cSMatthew G. Knepley 121556cf3b9cSMatthew G. Knepley Input Parameters: 1216a1cb98faSBarry Smith + dm - The `DM` 121756cf3b9cSMatthew G. Knepley . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions 121856cf3b9cSMatthew G. Knepley . time - The time 121956cf3b9cSMatthew G. Knepley . faceGeomFVM - Face geometry data for FV discretizations 122056cf3b9cSMatthew G. Knepley . cellGeomFVM - Cell geometry data for FV discretizations 122156cf3b9cSMatthew G. Knepley - gradFVM - Gradient reconstruction data for FV discretizations 122256cf3b9cSMatthew G. Knepley 12232fe279fdSBarry Smith Output Parameter: 122456cf3b9cSMatthew G. Knepley . locX_t - Solution updated with boundary values 122556cf3b9cSMatthew G. Knepley 122656cf3b9cSMatthew G. Knepley Level: developer 122756cf3b9cSMatthew G. Knepley 12281cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunctionLabelLocal()` 122956cf3b9cSMatthew G. Knepley @*/ 1230d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues(DM dm, PetscBool insertEssential, Vec locX_t, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1231d71ae5a4SJacob Faibussowitsch { 123256cf3b9cSMatthew G. Knepley PetscFunctionBegin; 123356cf3b9cSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1234ad540459SPierre Jolivet if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 3); 1235ad540459SPierre Jolivet if (faceGeomFVM) PetscValidHeaderSpecific(faceGeomFVM, VEC_CLASSID, 5); 1236ad540459SPierre Jolivet if (cellGeomFVM) PetscValidHeaderSpecific(cellGeomFVM, VEC_CLASSID, 6); 1237ad540459SPierre Jolivet if (gradFVM) PetscValidHeaderSpecific(gradFVM, VEC_CLASSID, 7); 1238cac4c232SBarry Smith PetscTryMethod(dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", (DM, PetscBool, Vec, PetscReal, Vec, Vec, Vec), (dm, insertEssential, locX_t, time, faceGeomFVM, cellGeomFVM, gradFVM)); 12393ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 124056cf3b9cSMatthew G. Knepley } 124156cf3b9cSMatthew G. Knepley 1242d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2Diff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 1243d71ae5a4SJacob Faibussowitsch { 1244574a98acSMatthew G. Knepley Vec localX; 1245574a98acSMatthew G. Knepley 1246574a98acSMatthew G. Knepley PetscFunctionBegin; 12479566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 12489566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, localX, time, NULL, NULL, NULL)); 12499566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 12509566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 12519566063dSJacob Faibussowitsch PetscCall(DMPlexComputeL2DiffLocal(dm, time, funcs, ctxs, localX, diff)); 12529566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 12533ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1254574a98acSMatthew G. Knepley } 1255574a98acSMatthew G. Knepley 1256574a98acSMatthew G. Knepley /*@C 125760225df5SJacob Faibussowitsch DMPlexComputeL2DiffLocal - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h. 1258574a98acSMatthew G. Knepley 125920f4b53cSBarry Smith Collective 1260c0f8e1fdSMatthew G. Knepley 1261574a98acSMatthew G. Knepley Input Parameters: 1262a1cb98faSBarry Smith + dm - The `DM` 1263574a98acSMatthew G. Knepley . time - The time 1264574a98acSMatthew G. Knepley . funcs - The functions to evaluate for each field component 126520f4b53cSBarry Smith . ctxs - Optional array of contexts to pass to each function, or `NULL`. 1266574a98acSMatthew G. Knepley - localX - The coefficient vector u_h, a local vector 1267574a98acSMatthew G. Knepley 1268574a98acSMatthew G. Knepley Output Parameter: 1269574a98acSMatthew G. Knepley . diff - The diff ||u - u_h||_2 1270574a98acSMatthew G. Knepley 1271574a98acSMatthew G. Knepley Level: developer 1272574a98acSMatthew G. Knepley 12731cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 1274574a98acSMatthew G. Knepley @*/ 1275d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeL2DiffLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec localX, PetscReal *diff) 1276d71ae5a4SJacob Faibussowitsch { 12770f09c10fSMatthew G. Knepley const PetscInt debug = ((DM_Plex *)dm->data)->printL2; 1278ca3d3a14SMatthew G. Knepley DM tdm; 1279ca3d3a14SMatthew G. Knepley Vec tv; 1280cb1e1211SMatthew G Knepley PetscSection section; 1281c5bbbd5bSMatthew G. Knepley PetscQuadrature quad; 12824bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 128315496722SMatthew G. Knepley PetscScalar *funcVal, *interpolant; 12844bee2e38SMatthew G. Knepley PetscReal *coords, *gcoords; 1285cb1e1211SMatthew G Knepley PetscReal localDiff = 0.0; 12867318780aSToby Isaac const PetscReal *quadWeights; 1287412e9a14SMatthew G. Knepley PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cellHeight, cStart, cEnd, c, field, fieldOffset; 1288ca3d3a14SMatthew G. Knepley PetscBool transform; 1289cb1e1211SMatthew G Knepley 1290cb1e1211SMatthew G Knepley PetscFunctionBegin; 12919566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 12929566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 12932a4e142eSMatthew G. Knepley fegeom.dimEmbed = coordDim; 12949566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 12959566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &numFields)); 12969566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 12979566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 12989566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 1299eae3dc7dSJacob Faibussowitsch PetscCheck(numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!"); 1300cb1e1211SMatthew G Knepley for (field = 0; field < numFields; ++field) { 130115496722SMatthew G. Knepley PetscObject obj; 130215496722SMatthew G. Knepley PetscClassId id; 1303c5bbbd5bSMatthew G. Knepley PetscInt Nc; 1304c5bbbd5bSMatthew G. Knepley 13059566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 13069566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 130715496722SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 130815496722SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 130915496722SMatthew G. Knepley 13109566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 13119566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 131215496722SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 131315496722SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 131415496722SMatthew G. Knepley 13159566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 13169566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 131763a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1318c5bbbd5bSMatthew G. Knepley numComponents += Nc; 1319cb1e1211SMatthew G Knepley } 13209566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights)); 132163a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 1322c9cb6370SYANG Zongze PetscCall(PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * (Nq + 1), &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ)); 13239566063dSJacob Faibussowitsch PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 13249566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 1325cb1e1211SMatthew G Knepley for (c = cStart; c < cEnd; ++c) { 1326a1e44745SMatthew G. Knepley PetscScalar *x = NULL; 1327cb1e1211SMatthew G Knepley PetscReal elemDiff = 0.0; 13289c3cf19fSMatthew G. Knepley PetscInt qc = 0; 1329cb1e1211SMatthew G Knepley 13309566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1331*e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, c, 0, NULL, &x)); 1332cb1e1211SMatthew G Knepley 133315496722SMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 133415496722SMatthew G. Knepley PetscObject obj; 133515496722SMatthew G. Knepley PetscClassId id; 1336c110b1eeSGeoffrey Irving void *const ctx = ctxs ? ctxs[field] : NULL; 133715496722SMatthew G. Knepley PetscInt Nb, Nc, q, fc; 1338cb1e1211SMatthew G Knepley 13399566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 13409566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 13419371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 13429371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 13439371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 13449371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 13459371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 13469371c9d4SSatish Balay Nb = 1; 13479371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1348cb1e1211SMatthew G Knepley if (debug) { 1349cb1e1211SMatthew G Knepley char title[1024]; 135063a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field)); 13519566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, title, Nb, &x[fieldOffset])); 1352cb1e1211SMatthew G Knepley } 13537318780aSToby Isaac for (q = 0; q < Nq; ++q) { 13542a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 1355d0609cedSBarry Smith PetscErrorCode ierr; 13562a4e142eSMatthew G. Knepley 13572a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 13582a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 13592a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 13602a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 136163a3b9bcSJacob 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); 1362d3a7d86cSMatthew G. Knepley if (transform) { 1363d3a7d86cSMatthew G. Knepley gcoords = &coords[coordDim * Nq]; 13649566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim * q], PETSC_TRUE, coordDim, &coords[coordDim * q], gcoords, dm->transformCtx)); 1365d3a7d86cSMatthew G. Knepley } else { 1366d3a7d86cSMatthew G. Knepley gcoords = &coords[coordDim * q]; 1367d3a7d86cSMatthew G. Knepley } 13689566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(funcVal, Nc)); 1369ca3d3a14SMatthew G. Knepley ierr = (*funcs[field])(coordDim, time, gcoords, Nc, funcVal, ctx); 1370e735a8a9SMatthew G. Knepley if (ierr) { 13719566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 13729566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 13739566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1374e735a8a9SMatthew G. Knepley } 13759566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[coordDim * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 13769566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant)); 13779566063dSJacob Faibussowitsch else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant)); 13782df84da0SMatthew G. Knepley else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 137915496722SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1380beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 13819371c9d4SSatish Balay if (debug) 13829371c9d4SSatish Balay PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " field %" PetscInt_FMT ",%" PetscInt_FMT " point %g %g %g diff %g (%g, %g)\n", c, field, fc, (double)(coordDim > 0 ? coords[coordDim * q] : 0.), (double)(coordDim > 1 ? coords[coordDim * q + 1] : 0.), (double)(coordDim > 2 ? coords[coordDim * q + 2] : 0.), 13839371c9d4SSatish Balay (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]), (double)PetscRealPart(interpolant[fc]), (double)PetscRealPart(funcVal[fc]))); 13844bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 1385cb1e1211SMatthew G Knepley } 1386cb1e1211SMatthew G Knepley } 13879c3cf19fSMatthew G. Knepley fieldOffset += Nb; 1388beaa55a6SMatthew G. Knepley qc += Nc; 1389cb1e1211SMatthew G Knepley } 13909566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 13919566063dSJacob Faibussowitsch if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff)); 1392cb1e1211SMatthew G Knepley localDiff += elemDiff; 1393cb1e1211SMatthew G Knepley } 13949566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 13951c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 1396cb1e1211SMatthew G Knepley *diff = PetscSqrtReal(*diff); 13973ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1398cb1e1211SMatthew G Knepley } 1399cb1e1211SMatthew G Knepley 1400d71ae5a4SJacob 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) 1401d71ae5a4SJacob Faibussowitsch { 14020f09c10fSMatthew G. Knepley const PetscInt debug = ((DM_Plex *)dm->data)->printL2; 1403ca3d3a14SMatthew G. Knepley DM tdm; 1404cb1e1211SMatthew G Knepley PetscSection section; 140540e14135SMatthew G. Knepley PetscQuadrature quad; 1406ca3d3a14SMatthew G. Knepley Vec localX, tv; 14079c3cf19fSMatthew G. Knepley PetscScalar *funcVal, *interpolant; 14082a4e142eSMatthew G. Knepley const PetscReal *quadWeights; 14094bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 14104bee2e38SMatthew G. Knepley PetscReal *coords, *gcoords; 141140e14135SMatthew G. Knepley PetscReal localDiff = 0.0; 1412485ad865SMatthew G. Knepley PetscInt dim, coordDim, qNc = 0, Nq = 0, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset; 1413ca3d3a14SMatthew G. Knepley PetscBool transform; 1414cb1e1211SMatthew G Knepley 1415cb1e1211SMatthew G Knepley PetscFunctionBegin; 14169566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 14179566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 14184bee2e38SMatthew G. Knepley fegeom.dimEmbed = coordDim; 14199566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 14209566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &numFields)); 14219566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 14229566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 14239566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 14249566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 14259566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 14269566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 1427652b88e8SMatthew G. Knepley for (field = 0; field < numFields; ++field) { 14280f2d7e86SMatthew G. Knepley PetscFE fe; 142940e14135SMatthew G. Knepley PetscInt Nc; 1430652b88e8SMatthew G. Knepley 14319566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, (PetscObject *)&fe)); 14329566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 14339566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 143440e14135SMatthew G. Knepley numComponents += Nc; 1435652b88e8SMatthew G. Knepley } 14369566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights)); 143763a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 14389566063dSJacob Faibussowitsch /* PetscCall(DMProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX)); */ 1439c9cb6370SYANG 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)); 14409566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 144140e14135SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 144240e14135SMatthew G. Knepley PetscScalar *x = NULL; 144340e14135SMatthew G. Knepley PetscReal elemDiff = 0.0; 14449c3cf19fSMatthew G. Knepley PetscInt qc = 0; 1445652b88e8SMatthew G. Knepley 14469566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1447*e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, c, 0, NULL, &x)); 144840e14135SMatthew G. Knepley 14499c3cf19fSMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 14500f2d7e86SMatthew G. Knepley PetscFE fe; 145151259fa3SMatthew G. Knepley void *const ctx = ctxs ? ctxs[field] : NULL; 14529c3cf19fSMatthew G. Knepley PetscInt Nb, Nc, q, fc; 145340e14135SMatthew G. Knepley 14549566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, (PetscObject *)&fe)); 14559566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 14569566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 145740e14135SMatthew G. Knepley if (debug) { 145840e14135SMatthew G. Knepley char title[1024]; 14599566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field)); 14609566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, title, Nb, &x[fieldOffset])); 1461652b88e8SMatthew G. Knepley } 14629c3cf19fSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 14632a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 1464d0609cedSBarry Smith PetscErrorCode ierr; 14652a4e142eSMatthew G. Knepley 14662a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 14672a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 14682a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 14692a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 14702df84da0SMatthew 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); 1471d3a7d86cSMatthew G. Knepley if (transform) { 1472d3a7d86cSMatthew G. Knepley gcoords = &coords[coordDim * Nq]; 14739566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim * q], PETSC_TRUE, coordDim, &coords[coordDim * q], gcoords, dm->transformCtx)); 1474d3a7d86cSMatthew G. Knepley } else { 1475d3a7d86cSMatthew G. Knepley gcoords = &coords[coordDim * q]; 1476d3a7d86cSMatthew G. Knepley } 14779566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(funcVal, Nc)); 14784bee2e38SMatthew G. Knepley ierr = (*funcs[field])(coordDim, time, gcoords, n, Nc, funcVal, ctx); 1479e735a8a9SMatthew G. Knepley if (ierr) { 14809566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 14819566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 14829566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, coords, fegeom.J, fegeom.invJ, interpolant, fegeom.detJ)); 1483e735a8a9SMatthew G. Knepley } 14849566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[coordDim * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 14859566063dSJacob Faibussowitsch PetscCall(PetscFEInterpolateGradient_Static(fe, 1, &x[fieldOffset], &qgeom, q, interpolant)); 14864bee2e38SMatthew G. Knepley /* Overwrite with the dot product if the normal is given */ 14874bee2e38SMatthew G. Knepley if (n) { 14884bee2e38SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 14894bee2e38SMatthew G. Knepley PetscScalar sum = 0.0; 14904bee2e38SMatthew G. Knepley PetscInt d; 14914bee2e38SMatthew G. Knepley for (d = 0; d < dim; ++d) sum += interpolant[fc * dim + d] * n[d]; 14924bee2e38SMatthew G. Knepley interpolant[fc] = sum; 14934bee2e38SMatthew G. Knepley } 14944bee2e38SMatthew G. Knepley } 14959c3cf19fSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1496beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 149763a3b9bcSJacob 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]))); 14984bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 149940e14135SMatthew G. Knepley } 150040e14135SMatthew G. Knepley } 15019c3cf19fSMatthew G. Knepley fieldOffset += Nb; 15029c3cf19fSMatthew G. Knepley qc += Nc; 150340e14135SMatthew G. Knepley } 15049566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 150563a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff)); 150640e14135SMatthew G. Knepley localDiff += elemDiff; 150740e14135SMatthew G. Knepley } 15089566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, coords, fegeom.J, fegeom.invJ, interpolant, fegeom.detJ)); 15099566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 15101c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 151140e14135SMatthew G. Knepley *diff = PetscSqrtReal(*diff); 15123ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1513cb1e1211SMatthew G Knepley } 1514cb1e1211SMatthew G Knepley 1515d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2FieldDiff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 1516d71ae5a4SJacob Faibussowitsch { 15170f09c10fSMatthew G. Knepley const PetscInt debug = ((DM_Plex *)dm->data)->printL2; 1518ca3d3a14SMatthew G. Knepley DM tdm; 1519083401c6SMatthew G. Knepley DMLabel depthLabel; 152073d901b8SMatthew G. Knepley PetscSection section; 1521ca3d3a14SMatthew G. Knepley Vec localX, tv; 152273d901b8SMatthew G. Knepley PetscReal *localDiff; 1523083401c6SMatthew G. Knepley PetscInt dim, depth, dE, Nf, f, Nds, s; 1524ca3d3a14SMatthew G. Knepley PetscBool transform; 152573d901b8SMatthew G. Knepley 152673d901b8SMatthew G. Knepley PetscFunctionBegin; 15279566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 15289566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &dE)); 15299566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 15309566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 15319566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 15329566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 15339566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 15349566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 15359566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 15369566063dSJacob Faibussowitsch PetscCall(DMLabelGetNumValues(depthLabel, &depth)); 1537083401c6SMatthew G. Knepley 15389566063dSJacob Faibussowitsch PetscCall(VecSet(localX, 0.0)); 15399566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 15409566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 15419566063dSJacob Faibussowitsch PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX)); 15429566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 15439566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(Nf, &localDiff)); 1544083401c6SMatthew G. Knepley for (s = 0; s < Nds; ++s) { 1545083401c6SMatthew G. Knepley PetscDS ds; 1546083401c6SMatthew G. Knepley DMLabel label; 1547083401c6SMatthew G. Knepley IS fieldIS, pointIS; 1548083401c6SMatthew G. Knepley const PetscInt *fields, *points = NULL; 1549083401c6SMatthew G. Knepley PetscQuadrature quad; 1550083401c6SMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 1551083401c6SMatthew G. Knepley PetscFEGeom fegeom; 1552083401c6SMatthew G. Knepley PetscReal *coords, *gcoords; 1553083401c6SMatthew G. Knepley PetscScalar *funcVal, *interpolant; 15545fedec97SMatthew G. Knepley PetscBool isCohesive; 1555083401c6SMatthew G. Knepley PetscInt qNc, Nq, totNc, cStart = 0, cEnd, c, dsNf; 155673d901b8SMatthew G. Knepley 155707218a29SMatthew G. Knepley PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL)); 15589566063dSJacob Faibussowitsch PetscCall(ISGetIndices(fieldIS, &fields)); 15599566063dSJacob Faibussowitsch PetscCall(PetscDSIsCohesive(ds, &isCohesive)); 15609566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &dsNf)); 15619566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalComponents(ds, &totNc)); 15629566063dSJacob Faibussowitsch PetscCall(PetscDSGetQuadrature(ds, &quad)); 15639566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 156463a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != totNc), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, totNc); 15659566063dSJacob Faibussowitsch PetscCall(PetscCalloc6(totNc, &funcVal, totNc, &interpolant, dE * (Nq + 1), &coords, Nq, &fegeom.detJ, dE * dE * Nq, &fegeom.J, dE * dE * Nq, &fegeom.invJ)); 1566083401c6SMatthew G. Knepley if (!label) { 15679566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1568083401c6SMatthew G. Knepley } else { 15699566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, 1, &pointIS)); 15709566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &cEnd)); 15719566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 1572083401c6SMatthew G. Knepley } 157373d901b8SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 1574083401c6SMatthew G. Knepley const PetscInt cell = points ? points[c] : c; 157573d901b8SMatthew G. Knepley PetscScalar *x = NULL; 15765fedec97SMatthew G. Knepley const PetscInt *cone; 15775fedec97SMatthew G. Knepley PetscInt qc = 0, fOff = 0, dep; 157873d901b8SMatthew G. Knepley 15799566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(depthLabel, cell, &dep)); 1580083401c6SMatthew G. Knepley if (dep != depth - 1) continue; 15815fedec97SMatthew G. Knepley if (isCohesive) { 15829566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cell, &cone)); 15839566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cone[0], quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 158496959cd1SMatthew G. Knepley } else { 15859566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 158696959cd1SMatthew G. Knepley } 1587*e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, cell, 0, NULL, &x)); 15885fedec97SMatthew G. Knepley for (f = 0; f < dsNf; ++f) { 158915496722SMatthew G. Knepley PetscObject obj; 159015496722SMatthew G. Knepley PetscClassId id; 1591083401c6SMatthew G. Knepley void *const ctx = ctxs ? ctxs[fields[f]] : NULL; 159215496722SMatthew G. Knepley PetscInt Nb, Nc, q, fc; 159315496722SMatthew G. Knepley PetscReal elemDiff = 0.0; 15945fedec97SMatthew G. Knepley PetscBool cohesive; 159515496722SMatthew G. Knepley 15969566063dSJacob Faibussowitsch PetscCall(PetscDSGetCohesive(ds, f, &cohesive)); 15979566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 15989566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 15999371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 16009371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 16019371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 16029371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 16039371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 16049371c9d4SSatish Balay Nb = 1; 16059371c9d4SSatish Balay } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]); 1606c82db6dbSMatthew G. Knepley if (isCohesive && !cohesive) { 1607c82db6dbSMatthew G. Knepley fOff += Nb * 2; 1608c82db6dbSMatthew G. Knepley qc += Nc; 1609c82db6dbSMatthew G. Knepley continue; 1610c82db6dbSMatthew G. Knepley } 161173d901b8SMatthew G. Knepley if (debug) { 161273d901b8SMatthew G. Knepley char title[1024]; 161363a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, fields[f])); 16149566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(cell, title, Nb, &x[fOff])); 161573d901b8SMatthew G. Knepley } 16167318780aSToby Isaac for (q = 0; q < Nq; ++q) { 16172a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 1618d0609cedSBarry Smith PetscErrorCode ierr; 16192a4e142eSMatthew G. Knepley 16202a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 1621083401c6SMatthew G. Knepley qgeom.J = &fegeom.J[q * dE * dE]; 1622083401c6SMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * dE * dE]; 16232a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 162463a3b9bcSJacob 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); 1625d3a7d86cSMatthew G. Knepley if (transform) { 1626083401c6SMatthew G. Knepley gcoords = &coords[dE * Nq]; 16279566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[dE * q], PETSC_TRUE, dE, &coords[dE * q], gcoords, dm->transformCtx)); 1628d3a7d86cSMatthew G. Knepley } else { 1629083401c6SMatthew G. Knepley gcoords = &coords[dE * q]; 1630d3a7d86cSMatthew G. Knepley } 16312df84da0SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) funcVal[fc] = 0.; 1632083401c6SMatthew G. Knepley ierr = (*funcs[fields[f]])(dE, time, gcoords, Nc, funcVal, ctx); 1633e735a8a9SMatthew G. Knepley if (ierr) { 16349566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x)); 16359566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 16369566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1637e735a8a9SMatthew G. Knepley } 16389566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[dE * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 163996959cd1SMatthew G. Knepley /* Call once for each face, except for lagrange field */ 16409566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fOff], &qgeom, q, interpolant)); 16419566063dSJacob Faibussowitsch else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fOff], q, interpolant)); 164263a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]); 164315496722SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1644beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 16459371c9d4SSatish Balay if (debug) 16469371c9d4SSatish Balay PetscCall(PetscPrintf(PETSC_COMM_SELF, " cell %" PetscInt_FMT " field %" PetscInt_FMT ",%" PetscInt_FMT " point %g %g %g diff %g\n", cell, fields[f], fc, (double)(dE > 0 ? coords[dE * q] : 0.), (double)(dE > 1 ? coords[dE * q + 1] : 0.), (double)(dE > 2 ? coords[dE * q + 2] : 0.), 16479371c9d4SSatish Balay (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]))); 16484bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 164973d901b8SMatthew G. Knepley } 165073d901b8SMatthew G. Knepley } 1651083401c6SMatthew G. Knepley fOff += Nb; 16529c3cf19fSMatthew G. Knepley qc += Nc; 1653083401c6SMatthew G. Knepley localDiff[fields[f]] += elemDiff; 165463a3b9bcSJacob 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]])); 165573d901b8SMatthew G. Knepley } 16569566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x)); 1657083401c6SMatthew G. Knepley } 1658083401c6SMatthew G. Knepley if (label) { 16599566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 16609566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 1661083401c6SMatthew G. Knepley } 16629566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(fieldIS, &fields)); 16639566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 166473d901b8SMatthew G. Knepley } 16659566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 16661c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(localDiff, diff, Nf, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 16679566063dSJacob Faibussowitsch PetscCall(PetscFree(localDiff)); 1668083401c6SMatthew G. Knepley for (f = 0; f < Nf; ++f) diff[f] = PetscSqrtReal(diff[f]); 16693ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 167073d901b8SMatthew G. Knepley } 167173d901b8SMatthew G. Knepley 1672e729f68cSMatthew G. Knepley /*@C 1673e729f68cSMatthew 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. 1674e729f68cSMatthew G. Knepley 167520f4b53cSBarry Smith Collective 1676c0f8e1fdSMatthew G. Knepley 1677e729f68cSMatthew G. Knepley Input Parameters: 1678a1cb98faSBarry Smith + dm - The `DM` 16790163fd50SMatthew G. Knepley . time - The time 168020f4b53cSBarry Smith . funcs - The functions to evaluate for each field component: `NULL` means that component does not contribute to error calculation 168120f4b53cSBarry Smith . ctxs - Optional array of contexts to pass to each function, or `NULL`. 1682e729f68cSMatthew G. Knepley - X - The coefficient vector u_h 1683e729f68cSMatthew G. Knepley 1684e729f68cSMatthew G. Knepley Output Parameter: 168520f4b53cSBarry Smith . D - A `Vec` which holds the difference ||u - u_h||_2 for each cell 1686e729f68cSMatthew G. Knepley 1687e729f68cSMatthew G. Knepley Level: developer 1688e729f68cSMatthew G. Knepley 16891cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 1690e729f68cSMatthew G. Knepley @*/ 1691d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeL2DiffVec(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, Vec D) 1692d71ae5a4SJacob Faibussowitsch { 1693e729f68cSMatthew G. Knepley PetscSection section; 1694e729f68cSMatthew G. Knepley PetscQuadrature quad; 1695e729f68cSMatthew G. Knepley Vec localX; 16964bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 1697e729f68cSMatthew G. Knepley PetscScalar *funcVal, *interpolant; 16984bee2e38SMatthew G. Knepley PetscReal *coords; 1699e729f68cSMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 1700485ad865SMatthew G. Knepley PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, c, field, fieldOffset; 1701e729f68cSMatthew G. Knepley 1702e729f68cSMatthew G. Knepley PetscFunctionBegin; 17039566063dSJacob Faibussowitsch PetscCall(VecSet(D, 0.0)); 17049566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 17059566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 17069566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 17079566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &numFields)); 17089566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 17099566063dSJacob Faibussowitsch PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX)); 17109566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 17119566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 1712e729f68cSMatthew G. Knepley for (field = 0; field < numFields; ++field) { 1713e729f68cSMatthew G. Knepley PetscObject obj; 1714e729f68cSMatthew G. Knepley PetscClassId id; 1715e729f68cSMatthew G. Knepley PetscInt Nc; 1716e729f68cSMatthew G. Knepley 17179566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 17189566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 1719e729f68cSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 1720e729f68cSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 1721e729f68cSMatthew G. Knepley 17229566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 17239566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 1724e729f68cSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 1725e729f68cSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 1726e729f68cSMatthew G. Knepley 17279566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 17289566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 172963a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1730e729f68cSMatthew G. Knepley numComponents += Nc; 1731e729f68cSMatthew G. Knepley } 17329566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 173363a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 17349566063dSJacob Faibussowitsch PetscCall(PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * Nq, &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ)); 17359566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1736e729f68cSMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 1737e729f68cSMatthew G. Knepley PetscScalar *x = NULL; 17386f288a59SMatthew G. Knepley PetscScalar elemDiff = 0.0; 17399c3cf19fSMatthew G. Knepley PetscInt qc = 0; 1740e729f68cSMatthew G. Knepley 17419566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1742*e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, c, 0, NULL, &x)); 1743e729f68cSMatthew G. Knepley 1744e729f68cSMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 1745e729f68cSMatthew G. Knepley PetscObject obj; 1746e729f68cSMatthew G. Knepley PetscClassId id; 1747e729f68cSMatthew G. Knepley void *const ctx = ctxs ? ctxs[field] : NULL; 1748e729f68cSMatthew G. Knepley PetscInt Nb, Nc, q, fc; 1749e729f68cSMatthew G. Knepley 17509566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 17519566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 17529371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 17539371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 17549371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 17559371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 17569371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 17579371c9d4SSatish Balay Nb = 1; 17589371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 175923f34ed2SToby Isaac if (funcs[field]) { 17607318780aSToby Isaac for (q = 0; q < Nq; ++q) { 17612a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 17622a4e142eSMatthew G. Knepley 17632a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 17642a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 17652a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 17662a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 176763a3b9bcSJacob 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); 17689566063dSJacob Faibussowitsch PetscCall((*funcs[field])(coordDim, time, &coords[q * coordDim], Nc, funcVal, ctx)); 1769c3e24edfSBarry Smith #if defined(needs_fix_with_return_code_argument) 1770e735a8a9SMatthew G. Knepley if (ierr) { 17719566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 17729566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 17739566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 1774e735a8a9SMatthew G. Knepley } 1775c3e24edfSBarry Smith #endif 17769566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant)); 17779566063dSJacob Faibussowitsch else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant)); 177863a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1779e729f68cSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1780beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 17814bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 1782e729f68cSMatthew G. Knepley } 1783e729f68cSMatthew G. Knepley } 178423f34ed2SToby Isaac } 1785beaa55a6SMatthew G. Knepley fieldOffset += Nb; 17869c3cf19fSMatthew G. Knepley qc += Nc; 1787e729f68cSMatthew G. Knepley } 17889566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 17899566063dSJacob Faibussowitsch PetscCall(VecSetValue(D, c - cStart, elemDiff, INSERT_VALUES)); 1790e729f68cSMatthew G. Knepley } 17919566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 17929566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 17939566063dSJacob Faibussowitsch PetscCall(VecSqrtAbs(D)); 17943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1795e729f68cSMatthew G. Knepley } 1796e729f68cSMatthew G. Knepley 17975f0b18bfSMatthew G. Knepley /*@ 179820f4b53cSBarry Smith DMPlexComputeClementInterpolant - This function computes the L2 projection of the cellwise values of a function u onto P1 17995f0b18bfSMatthew G. Knepley 180020f4b53cSBarry Smith Collective 18015f0b18bfSMatthew G. Knepley 18025f0b18bfSMatthew G. Knepley Input Parameters: 1803a1cb98faSBarry Smith + dm - The `DM` 18045f0b18bfSMatthew G. Knepley - locX - The coefficient vector u_h 18055f0b18bfSMatthew G. Knepley 18065f0b18bfSMatthew G. Knepley Output Parameter: 1807a1cb98faSBarry Smith . locC - A `Vec` which holds the Clement interpolant of the function 18085f0b18bfSMatthew G. Knepley 18095f0b18bfSMatthew G. Knepley Level: developer 18105f0b18bfSMatthew G. Knepley 1811a1cb98faSBarry Smith Note: 1812a1cb98faSBarry 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 1813a1cb98faSBarry Smith 18141cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 18155f0b18bfSMatthew G. Knepley @*/ 1816d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeClementInterpolant(DM dm, Vec locX, Vec locC) 1817d71ae5a4SJacob Faibussowitsch { 18185f0b18bfSMatthew G. Knepley PetscInt debug = ((DM_Plex *)dm->data)->printFEM; 18195f0b18bfSMatthew G. Knepley DM dmc; 18205f0b18bfSMatthew G. Knepley PetscQuadrature quad; 18215f0b18bfSMatthew G. Knepley PetscScalar *interpolant, *valsum; 18225f0b18bfSMatthew G. Knepley PetscFEGeom fegeom; 18235f0b18bfSMatthew G. Knepley PetscReal *coords; 18245f0b18bfSMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 18255f0b18bfSMatthew G. Knepley PetscInt dim, cdim, Nf, f, Nc = 0, Nq, qNc, cStart, cEnd, vStart, vEnd, v; 18265f0b18bfSMatthew G. Knepley 18275f0b18bfSMatthew G. Knepley PetscFunctionBegin; 18289566063dSJacob Faibussowitsch PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite)); 18299566063dSJacob Faibussowitsch PetscCall(VecGetDM(locC, &dmc)); 18309566063dSJacob Faibussowitsch PetscCall(VecSet(locC, 0.0)); 18319566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 18329566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &cdim)); 18335f0b18bfSMatthew G. Knepley fegeom.dimEmbed = cdim; 18349566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 18355f0b18bfSMatthew G. Knepley PetscCheck(Nf > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!"); 18365f0b18bfSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 18375f0b18bfSMatthew G. Knepley PetscObject obj; 18385f0b18bfSMatthew G. Knepley PetscClassId id; 18395f0b18bfSMatthew G. Knepley PetscInt fNc; 18405f0b18bfSMatthew G. Knepley 18419566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, f, NULL, &obj)); 18429566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 18435f0b18bfSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 18445f0b18bfSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 18455f0b18bfSMatthew G. Knepley 18469566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 18479566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &fNc)); 18485f0b18bfSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 18495f0b18bfSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 18505f0b18bfSMatthew G. Knepley 18519566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 18529566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &fNc)); 185363a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 18545f0b18bfSMatthew G. Knepley Nc += fNc; 18555f0b18bfSMatthew G. Knepley } 18569566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 185763a3b9bcSJacob Faibussowitsch PetscCheck(qNc == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " > 1", qNc); 18589566063dSJacob Faibussowitsch PetscCall(PetscMalloc6(Nc * 2, &valsum, Nc, &interpolant, cdim * Nq, &coords, Nq, &fegeom.detJ, cdim * cdim * Nq, &fegeom.J, cdim * cdim * Nq, &fegeom.invJ)); 18599566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 18609566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 18615f0b18bfSMatthew G. Knepley for (v = vStart; v < vEnd; ++v) { 18625f0b18bfSMatthew G. Knepley PetscScalar volsum = 0.0; 18635f0b18bfSMatthew G. Knepley PetscInt *star = NULL; 18645f0b18bfSMatthew G. Knepley PetscInt starSize, st, fc; 18655f0b18bfSMatthew G. Knepley 18669566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(valsum, Nc)); 18679566063dSJacob Faibussowitsch PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 18685f0b18bfSMatthew G. Knepley for (st = 0; st < starSize * 2; st += 2) { 18695f0b18bfSMatthew G. Knepley const PetscInt cell = star[st]; 18705f0b18bfSMatthew G. Knepley PetscScalar *val = &valsum[Nc]; 18715f0b18bfSMatthew G. Knepley PetscScalar *x = NULL; 18725f0b18bfSMatthew G. Knepley PetscReal vol = 0.0; 18735f0b18bfSMatthew G. Knepley PetscInt foff = 0; 18745f0b18bfSMatthew G. Knepley 18755f0b18bfSMatthew G. Knepley if ((cell < cStart) || (cell >= cEnd)) continue; 18769566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 18779566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x)); 18785f0b18bfSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 18795f0b18bfSMatthew G. Knepley PetscObject obj; 18805f0b18bfSMatthew G. Knepley PetscClassId id; 18815f0b18bfSMatthew G. Knepley PetscInt Nb, fNc, q; 18825f0b18bfSMatthew G. Knepley 18839566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(val, Nc)); 18849566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, f, NULL, &obj)); 18859566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 18869371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 18879371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &fNc)); 18889371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 18899371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 18909371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &fNc)); 18919371c9d4SSatish Balay Nb = 1; 18929371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 18935f0b18bfSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 18945f0b18bfSMatthew G. Knepley const PetscReal wt = quadWeights[q] * fegeom.detJ[q]; 18955f0b18bfSMatthew G. Knepley PetscFEGeom qgeom; 18965f0b18bfSMatthew G. Knepley 18975f0b18bfSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 18985f0b18bfSMatthew G. Knepley qgeom.J = &fegeom.J[q * cdim * cdim]; 18995f0b18bfSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * cdim * cdim]; 19005f0b18bfSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 190163a3b9bcSJacob 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); 19029566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[foff], &qgeom, q, interpolant)); 190363a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 19045f0b18bfSMatthew G. Knepley for (fc = 0; fc < fNc; ++fc) val[foff + fc] += interpolant[fc] * wt; 19055f0b18bfSMatthew G. Knepley vol += wt; 19065f0b18bfSMatthew G. Knepley } 19075f0b18bfSMatthew G. Knepley foff += Nb; 19085f0b18bfSMatthew G. Knepley } 19099566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x)); 19105f0b18bfSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) valsum[fc] += val[fc]; 19115f0b18bfSMatthew G. Knepley volsum += vol; 19125f0b18bfSMatthew G. Knepley if (debug) { 19139566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " value: [", v, cell)); 19145f0b18bfSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 19159566063dSJacob Faibussowitsch if (fc) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 19169566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(val[fc]))); 19175f0b18bfSMatthew G. Knepley } 19189566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n")); 19195f0b18bfSMatthew G. Knepley } 19205f0b18bfSMatthew G. Knepley } 19215f0b18bfSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) valsum[fc] /= volsum; 19229566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 19239566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dmc, NULL, locC, v, valsum, INSERT_VALUES)); 19245f0b18bfSMatthew G. Knepley } 19259566063dSJacob Faibussowitsch PetscCall(PetscFree6(valsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 19263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 19275f0b18bfSMatthew G. Knepley } 19285f0b18bfSMatthew G. Knepley 19295f0b18bfSMatthew G. Knepley /*@ 193020f4b53cSBarry Smith DMPlexComputeGradientClementInterpolant - This function computes the L2 projection of the cellwise gradient of a function u onto P1 19311555c271SMatthew G. Knepley 193220f4b53cSBarry Smith Collective 1933c0f8e1fdSMatthew G. Knepley 19341555c271SMatthew G. Knepley Input Parameters: 1935a1cb98faSBarry Smith + dm - The `DM` 19365f0b18bfSMatthew G. Knepley - locX - The coefficient vector u_h 19371555c271SMatthew G. Knepley 19381555c271SMatthew G. Knepley Output Parameter: 1939a1cb98faSBarry Smith . locC - A `Vec` which holds the Clement interpolant of the gradient 19401555c271SMatthew G. Knepley 19411555c271SMatthew G. Knepley Level: developer 19421555c271SMatthew G. Knepley 1943a1cb98faSBarry Smith Note: 1944a1cb98faSBarry 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 1945a1cb98faSBarry Smith 19461cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 19471555c271SMatthew G. Knepley @*/ 1948d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeGradientClementInterpolant(DM dm, Vec locX, Vec locC) 1949d71ae5a4SJacob Faibussowitsch { 1950db1066baSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 1951db1066baSMatthew G. Knepley PetscInt debug = mesh->printFEM; 19521555c271SMatthew G. Knepley DM dmC; 19531555c271SMatthew G. Knepley PetscQuadrature quad; 19541555c271SMatthew G. Knepley PetscScalar *interpolant, *gradsum; 19554bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 19564bee2e38SMatthew G. Knepley PetscReal *coords; 19571555c271SMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 1958485ad865SMatthew G. Knepley PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, vStart, vEnd, v, field, fieldOffset; 19591555c271SMatthew G. Knepley 19601555c271SMatthew G. Knepley PetscFunctionBegin; 19619566063dSJacob Faibussowitsch PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite)); 19629566063dSJacob Faibussowitsch PetscCall(VecGetDM(locC, &dmC)); 19639566063dSJacob Faibussowitsch PetscCall(VecSet(locC, 0.0)); 19649566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 19659566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 19664bee2e38SMatthew G. Knepley fegeom.dimEmbed = coordDim; 19679566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &numFields)); 19685f80ce2aSJacob Faibussowitsch PetscCheck(numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!"); 19691555c271SMatthew G. Knepley for (field = 0; field < numFields; ++field) { 19701555c271SMatthew G. Knepley PetscObject obj; 19711555c271SMatthew G. Knepley PetscClassId id; 19721555c271SMatthew G. Knepley PetscInt Nc; 19731555c271SMatthew G. Knepley 19749566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 19759566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 19761555c271SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 19771555c271SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 19781555c271SMatthew G. Knepley 19799566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 19809566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 19811555c271SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 19821555c271SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 19831555c271SMatthew G. Knepley 19849566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 19859566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 198663a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 19871555c271SMatthew G. Knepley numComponents += Nc; 19881555c271SMatthew G. Knepley } 19899566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 199063a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 19919566063dSJacob 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)); 19929566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 19939566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 19941555c271SMatthew G. Knepley for (v = vStart; v < vEnd; ++v) { 19951555c271SMatthew G. Knepley PetscScalar volsum = 0.0; 19961555c271SMatthew G. Knepley PetscInt *star = NULL; 19971555c271SMatthew G. Knepley PetscInt starSize, st, d, fc; 19981555c271SMatthew G. Knepley 19999566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(gradsum, coordDim * numComponents)); 20009566063dSJacob Faibussowitsch PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 20011555c271SMatthew G. Knepley for (st = 0; st < starSize * 2; st += 2) { 20021555c271SMatthew G. Knepley const PetscInt cell = star[st]; 20031555c271SMatthew G. Knepley PetscScalar *grad = &gradsum[coordDim * numComponents]; 20041555c271SMatthew G. Knepley PetscScalar *x = NULL; 20051555c271SMatthew G. Knepley PetscReal vol = 0.0; 20061555c271SMatthew G. Knepley 20071555c271SMatthew G. Knepley if ((cell < cStart) || (cell >= cEnd)) continue; 20089566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 20099566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x)); 20101555c271SMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 20111555c271SMatthew G. Knepley PetscObject obj; 20121555c271SMatthew G. Knepley PetscClassId id; 20131555c271SMatthew G. Knepley PetscInt Nb, Nc, q, qc = 0; 20141555c271SMatthew G. Knepley 20159566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(grad, coordDim * numComponents)); 20169566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 20179566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 20189371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 20199371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 20209371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 20219371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 20229371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 20239371c9d4SSatish Balay Nb = 1; 20249371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 20251555c271SMatthew G. Knepley for (q = 0; q < Nq; ++q) { 20262a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 20272a4e142eSMatthew G. Knepley 20282a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 20292a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 20302a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 20312a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 203263a3b9bcSJacob 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); 20339566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolateGradient_Static((PetscFE)obj, 1, &x[fieldOffset], &qgeom, q, interpolant)); 203463a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 20351555c271SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 203653d2db2dSJoe Wallwork const PetscReal wt = quadWeights[q * qNc + qc]; 20371555c271SMatthew G. Knepley 20384bee2e38SMatthew G. Knepley for (d = 0; d < coordDim; ++d) grad[fc * coordDim + d] += interpolant[fc * dim + d] * wt * fegeom.detJ[q]; 20391555c271SMatthew G. Knepley } 20404bee2e38SMatthew G. Knepley vol += quadWeights[q * qNc] * fegeom.detJ[q]; 20411555c271SMatthew G. Knepley } 20421555c271SMatthew G. Knepley fieldOffset += Nb; 20431555c271SMatthew G. Knepley qc += Nc; 20441555c271SMatthew G. Knepley } 20459566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x)); 2046f8527842SMatthew G. Knepley for (fc = 0; fc < numComponents; ++fc) { 2047ad540459SPierre Jolivet for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] += grad[fc * coordDim + d]; 2048f8527842SMatthew G. Knepley } 2049f8527842SMatthew G. Knepley volsum += vol; 2050db1066baSMatthew G. Knepley if (debug) { 20519566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " gradient: [", v, cell)); 20521555c271SMatthew G. Knepley for (fc = 0; fc < numComponents; ++fc) { 20531555c271SMatthew G. Knepley for (d = 0; d < coordDim; ++d) { 20549566063dSJacob Faibussowitsch if (fc || d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 20559566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(grad[fc * coordDim + d]))); 20561555c271SMatthew G. Knepley } 20571555c271SMatthew G. Knepley } 20589566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n")); 2059db1066baSMatthew G. Knepley } 20601555c271SMatthew G. Knepley } 20611555c271SMatthew G. Knepley for (fc = 0; fc < numComponents; ++fc) { 20621555c271SMatthew G. Knepley for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] /= volsum; 20631555c271SMatthew G. Knepley } 20649566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 20659566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dmC, NULL, locC, v, gradsum, INSERT_VALUES)); 20661555c271SMatthew G. Knepley } 20679566063dSJacob Faibussowitsch PetscCall(PetscFree6(gradsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 20683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 20691555c271SMatthew G. Knepley } 20701555c271SMatthew G. Knepley 2071d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeIntegral_Internal(DM dm, Vec X, PetscInt cStart, PetscInt cEnd, PetscScalar *cintegral, void *user) 2072d71ae5a4SJacob Faibussowitsch { 2073338f77d5SMatthew G. Knepley DM dmAux = NULL; 207461aaff12SToby Isaac PetscDS prob, probAux = NULL; 207573d901b8SMatthew G. Knepley PetscSection section, sectionAux; 2076338f77d5SMatthew G. Knepley Vec locX, locA; 2077c330f8ffSToby Isaac PetscInt dim, numCells = cEnd - cStart, c, f; 2078c330f8ffSToby Isaac PetscBool useFVM = PETSC_FALSE; 2079338f77d5SMatthew G. Knepley /* DS */ 2080338f77d5SMatthew G. Knepley PetscInt Nf, totDim, *uOff, *uOff_x, numConstants; 2081338f77d5SMatthew G. Knepley PetscInt NfAux, totDimAux, *aOff; 2082338f77d5SMatthew G. Knepley PetscScalar *u, *a; 2083338f77d5SMatthew G. Knepley const PetscScalar *constants; 2084338f77d5SMatthew G. Knepley /* Geometry */ 2085c330f8ffSToby Isaac PetscFEGeom *cgeomFEM; 2086338f77d5SMatthew G. Knepley DM dmGrad; 2087c330f8ffSToby Isaac PetscQuadrature affineQuad = NULL; 2088338f77d5SMatthew G. Knepley Vec cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL; 2089b5a3613cSMatthew G. Knepley PetscFVCellGeom *cgeomFVM; 2090338f77d5SMatthew G. Knepley const PetscScalar *lgrad; 2091b7260050SToby Isaac PetscInt maxDegree; 2092c330f8ffSToby Isaac DMField coordField; 2093c330f8ffSToby Isaac IS cellIS; 209473d901b8SMatthew G. Knepley 209573d901b8SMatthew G. Knepley PetscFunctionBegin; 20969566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 20979566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 20989566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 20999566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 2100338f77d5SMatthew G. Knepley /* Determine which discretizations we have */ 2101b5a3613cSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 2102b5a3613cSMatthew G. Knepley PetscObject obj; 2103b5a3613cSMatthew G. Knepley PetscClassId id; 2104b5a3613cSMatthew G. Knepley 21059566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 21069566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 2107338f77d5SMatthew G. Knepley if (id == PETSCFV_CLASSID) useFVM = PETSC_TRUE; 2108338f77d5SMatthew G. Knepley } 2109338f77d5SMatthew G. Knepley /* Get local solution with boundary values */ 21109566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &locX)); 21119566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 21129566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 21139566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 2114338f77d5SMatthew G. Knepley /* Read DS information */ 21159566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 21169566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(prob, &uOff)); 21179566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x)); 21189566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PETSC_COMM_SELF, numCells, cStart, 1, &cellIS)); 21199566063dSJacob Faibussowitsch PetscCall(PetscDSGetConstants(prob, &numConstants, &constants)); 2120338f77d5SMatthew G. Knepley /* Read Auxiliary DS information */ 21219566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 21229a2a23afSMatthew G. Knepley if (locA) { 21239566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 21249566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 21259566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(probAux, &NfAux)); 21269566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 21279566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 21289566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(probAux, &aOff)); 2129338f77d5SMatthew G. Knepley } 2130338f77d5SMatthew G. Knepley /* Allocate data arrays */ 21319566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(numCells * totDim, &u)); 21329566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 2133338f77d5SMatthew G. Knepley /* Read out geometry */ 21349566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 21359566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 2136b7260050SToby Isaac if (maxDegree <= 1) { 21379566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 213848a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &cgeomFEM)); 2139b5a3613cSMatthew G. Knepley } 2140b5a3613cSMatthew G. Knepley if (useFVM) { 2141338f77d5SMatthew G. Knepley PetscFV fv = NULL; 2142b5a3613cSMatthew G. Knepley Vec grad; 2143b5a3613cSMatthew G. Knepley PetscInt fStart, fEnd; 2144b5a3613cSMatthew G. Knepley PetscBool compGrad; 2145b5a3613cSMatthew G. Knepley 2146338f77d5SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 2147338f77d5SMatthew G. Knepley PetscObject obj; 2148338f77d5SMatthew G. Knepley PetscClassId id; 2149338f77d5SMatthew G. Knepley 21509566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 21519566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 21529371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 21539371c9d4SSatish Balay fv = (PetscFV)obj; 21549371c9d4SSatish Balay break; 21559371c9d4SSatish Balay } 2156338f77d5SMatthew G. Knepley } 21579566063dSJacob Faibussowitsch PetscCall(PetscFVGetComputeGradients(fv, &compGrad)); 21589566063dSJacob Faibussowitsch PetscCall(PetscFVSetComputeGradients(fv, PETSC_TRUE)); 21599566063dSJacob Faibussowitsch PetscCall(DMPlexComputeGeometryFVM(dm, &cellGeometryFVM, &faceGeometryFVM)); 21609566063dSJacob Faibussowitsch PetscCall(DMPlexComputeGradientFVM(dm, fv, faceGeometryFVM, cellGeometryFVM, &dmGrad)); 21619566063dSJacob Faibussowitsch PetscCall(PetscFVSetComputeGradients(fv, compGrad)); 21629566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM)); 2163b5a3613cSMatthew G. Knepley /* Reconstruct and limit cell gradients */ 21649566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 21659566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmGrad, &grad)); 21669566063dSJacob Faibussowitsch PetscCall(DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad)); 2167b5a3613cSMatthew G. Knepley /* Communicate gradient values */ 21689566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dmGrad, &locGrad)); 21699566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad)); 21709566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad)); 21719566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmGrad, &grad)); 2172b5a3613cSMatthew G. Knepley /* Handle non-essential (e.g. outflow) boundary values */ 21739566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, 0.0, faceGeometryFVM, cellGeometryFVM, locGrad)); 21749566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locGrad, &lgrad)); 2175b5a3613cSMatthew G. Knepley } 2176338f77d5SMatthew G. Knepley /* Read out data from inputs */ 217773d901b8SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 217873d901b8SMatthew G. Knepley PetscScalar *x = NULL; 217973d901b8SMatthew G. Knepley PetscInt i; 218073d901b8SMatthew G. Knepley 21819566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, locX, c, NULL, &x)); 21820f2d7e86SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i]; 21839566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, locX, c, NULL, &x)); 218473d901b8SMatthew G. Knepley if (dmAux) { 21859566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, locA, c, NULL, &x)); 21860f2d7e86SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i]; 21879566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, locA, c, NULL, &x)); 218873d901b8SMatthew G. Knepley } 218973d901b8SMatthew G. Knepley } 2190338f77d5SMatthew G. Knepley /* Do integration for each field */ 219173d901b8SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 2192c1f031eeSMatthew G. Knepley PetscObject obj; 2193c1f031eeSMatthew G. Knepley PetscClassId id; 2194c1f031eeSMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 219573d901b8SMatthew G. Knepley 21969566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 21979566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 2198c1f031eeSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 2199c1f031eeSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 2200c1f031eeSMatthew G. Knepley PetscQuadrature q; 2201c330f8ffSToby Isaac PetscFEGeom *chunkGeom = NULL; 2202c1f031eeSMatthew G. Knepley PetscInt Nq, Nb; 2203c1f031eeSMatthew G. Knepley 22049566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 22059566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 22069566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL)); 22079566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 2208c1f031eeSMatthew G. Knepley blockSize = Nb * Nq; 220973d901b8SMatthew G. Knepley batchSize = numBlocks * blockSize; 22109566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 221173d901b8SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 221273d901b8SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 221373d901b8SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 221473d901b8SMatthew G. Knepley offset = numCells - Nr; 221548a46eb9SPierre Jolivet if (!affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, q, PETSC_FALSE, &cgeomFEM)); 22169566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 22179566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrate(prob, f, Ne, chunkGeom, u, probAux, a, cintegral)); 22189566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &chunkGeom)); 22199566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrate(prob, f, Nr, chunkGeom, &u[offset * totDim], probAux, &a[offset * totDimAux], &cintegral[offset * Nf])); 22209566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &chunkGeom)); 222148a46eb9SPierre Jolivet if (!affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM)); 2222c1f031eeSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 2223c1f031eeSMatthew G. Knepley PetscInt foff; 2224420e96edSMatthew G. Knepley PetscPointFunc obj_func; 2225b69edc29SMatthew G. Knepley PetscScalar lint; 2226c1f031eeSMatthew G. Knepley 22279566063dSJacob Faibussowitsch PetscCall(PetscDSGetObjective(prob, f, &obj_func)); 22289566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, f, &foff)); 2229c1f031eeSMatthew G. Knepley if (obj_func) { 2230c1f031eeSMatthew G. Knepley for (c = 0; c < numCells; ++c) { 2231b5a3613cSMatthew G. Knepley PetscScalar *u_x; 2232b5a3613cSMatthew G. Knepley 22339566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, c, lgrad, &u_x)); 2234338f77d5SMatthew G. Knepley obj_func(dim, Nf, NfAux, uOff, uOff_x, &u[totDim * c + foff], NULL, u_x, aOff, NULL, &a[totDimAux * c], NULL, NULL, 0.0, cgeomFVM[c].centroid, numConstants, constants, &lint); 2235338f77d5SMatthew G. Knepley cintegral[c * Nf + f] += PetscRealPart(lint) * cgeomFVM[c].volume; 223673d901b8SMatthew G. Knepley } 2237c1f031eeSMatthew G. Knepley } 223863a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 2239c1f031eeSMatthew G. Knepley } 2240338f77d5SMatthew G. Knepley /* Cleanup data arrays */ 2241b5a3613cSMatthew G. Knepley if (useFVM) { 22429566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(locGrad, &lgrad)); 22439566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM)); 22449566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 22459566063dSJacob Faibussowitsch PetscCall(VecDestroy(&faceGeometryFVM)); 22469566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cellGeometryFVM)); 22479566063dSJacob Faibussowitsch PetscCall(DMDestroy(&dmGrad)); 2248b5a3613cSMatthew G. Knepley } 22499566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscFree(a)); 22509566063dSJacob Faibussowitsch PetscCall(PetscFree(u)); 2251338f77d5SMatthew G. Knepley /* Cleanup */ 225248a46eb9SPierre Jolivet if (affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM)); 22539566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 22549566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cellIS)); 22559566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &locX)); 22563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2257338f77d5SMatthew G. Knepley } 2258338f77d5SMatthew G. Knepley 2259338f77d5SMatthew G. Knepley /*@ 2260338f77d5SMatthew G. Knepley DMPlexComputeIntegralFEM - Form the integral over the domain from the global input X using pointwise functions specified by the user 2261338f77d5SMatthew G. Knepley 2262338f77d5SMatthew G. Knepley Input Parameters: 2263338f77d5SMatthew G. Knepley + dm - The mesh 2264338f77d5SMatthew G. Knepley . X - Global input vector 2265338f77d5SMatthew G. Knepley - user - The user context 2266338f77d5SMatthew G. Knepley 2267338f77d5SMatthew G. Knepley Output Parameter: 2268338f77d5SMatthew G. Knepley . integral - Integral for each field 2269338f77d5SMatthew G. Knepley 2270338f77d5SMatthew G. Knepley Level: developer 2271338f77d5SMatthew G. Knepley 22721cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()` 2273338f77d5SMatthew G. Knepley @*/ 2274d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscScalar *integral, void *user) 2275d71ae5a4SJacob Faibussowitsch { 2276338f77d5SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 2277b8feb594SMatthew G. Knepley PetscScalar *cintegral, *lintegral; 2278412e9a14SMatthew G. Knepley PetscInt Nf, f, cellHeight, cStart, cEnd, cell; 2279338f77d5SMatthew G. Knepley 2280338f77d5SMatthew G. Knepley PetscFunctionBegin; 2281338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2282338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 22834f572ea9SToby Isaac PetscAssertPointer(integral, 3); 22849566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 22859566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 22869566063dSJacob Faibussowitsch PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 22879566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 2288338f77d5SMatthew G. Knepley /* TODO Introduce a loop over large chunks (right now this is a single chunk) */ 22899566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &lintegral, (cEnd - cStart) * Nf, &cintegral)); 22909566063dSJacob Faibussowitsch PetscCall(DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user)); 2291338f77d5SMatthew G. Knepley /* Sum up values */ 2292338f77d5SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 2293338f77d5SMatthew G. Knepley const PetscInt c = cell - cStart; 2294338f77d5SMatthew G. Knepley 22959566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf])); 2296b8feb594SMatthew G. Knepley for (f = 0; f < Nf; ++f) lintegral[f] += cintegral[c * Nf + f]; 2297338f77d5SMatthew G. Knepley } 22981c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(lintegral, integral, Nf, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 229973d901b8SMatthew G. Knepley if (mesh->printFEM) { 23009566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Integral:")); 23019566063dSJacob Faibussowitsch for (f = 0; f < Nf; ++f) PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), " %g", (double)PetscRealPart(integral[f]))); 23029566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "\n")); 230373d901b8SMatthew G. Knepley } 23049566063dSJacob Faibussowitsch PetscCall(PetscFree2(lintegral, cintegral)); 23059566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 23063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2307338f77d5SMatthew G. Knepley } 2308338f77d5SMatthew G. Knepley 2309338f77d5SMatthew G. Knepley /*@ 2310338f77d5SMatthew G. Knepley DMPlexComputeCellwiseIntegralFEM - Form the vector of cellwise integrals F from the global input X using pointwise functions specified by the user 2311338f77d5SMatthew G. Knepley 2312338f77d5SMatthew G. Knepley Input Parameters: 2313338f77d5SMatthew G. Knepley + dm - The mesh 2314338f77d5SMatthew G. Knepley . X - Global input vector 2315338f77d5SMatthew G. Knepley - user - The user context 2316338f77d5SMatthew G. Knepley 2317338f77d5SMatthew G. Knepley Output Parameter: 231860225df5SJacob Faibussowitsch . F - Cellwise integrals for each field 2319338f77d5SMatthew G. Knepley 2320338f77d5SMatthew G. Knepley Level: developer 2321338f77d5SMatthew G. Knepley 23221cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()` 2323338f77d5SMatthew G. Knepley @*/ 2324d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellwiseIntegralFEM(DM dm, Vec X, Vec F, void *user) 2325d71ae5a4SJacob Faibussowitsch { 2326338f77d5SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 2327338f77d5SMatthew G. Knepley DM dmF; 2328338f77d5SMatthew G. Knepley PetscSection sectionF; 2329338f77d5SMatthew G. Knepley PetscScalar *cintegral, *af; 2330412e9a14SMatthew G. Knepley PetscInt Nf, f, cellHeight, cStart, cEnd, cell; 2331338f77d5SMatthew G. Knepley 2332338f77d5SMatthew G. Knepley PetscFunctionBegin; 2333338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2334338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2335338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(F, VEC_CLASSID, 3); 23369566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 23379566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 23389566063dSJacob Faibussowitsch PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 23399566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 2340338f77d5SMatthew G. Knepley /* TODO Introduce a loop over large chunks (right now this is a single chunk) */ 23419566063dSJacob Faibussowitsch PetscCall(PetscCalloc1((cEnd - cStart) * Nf, &cintegral)); 23429566063dSJacob Faibussowitsch PetscCall(DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user)); 2343338f77d5SMatthew G. Knepley /* Put values in F*/ 23449566063dSJacob Faibussowitsch PetscCall(VecGetDM(F, &dmF)); 23459566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmF, §ionF)); 23469566063dSJacob Faibussowitsch PetscCall(VecGetArray(F, &af)); 2347338f77d5SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 2348338f77d5SMatthew G. Knepley const PetscInt c = cell - cStart; 2349338f77d5SMatthew G. Knepley PetscInt dof, off; 2350338f77d5SMatthew G. Knepley 23519566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf])); 23529566063dSJacob Faibussowitsch PetscCall(PetscSectionGetDof(sectionF, cell, &dof)); 23539566063dSJacob Faibussowitsch PetscCall(PetscSectionGetOffset(sectionF, cell, &off)); 235463a3b9bcSJacob Faibussowitsch PetscCheck(dof == Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cell dofs %" PetscInt_FMT " != %" PetscInt_FMT, dof, Nf); 2355338f77d5SMatthew G. Knepley for (f = 0; f < Nf; ++f) af[off + f] = cintegral[c * Nf + f]; 2356338f77d5SMatthew G. Knepley } 23579566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(F, &af)); 23589566063dSJacob Faibussowitsch PetscCall(PetscFree(cintegral)); 23599566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 23603ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 236173d901b8SMatthew G. Knepley } 236273d901b8SMatthew G. Knepley 2363d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeBdIntegral_Internal(DM dm, Vec locX, IS pointIS, void (*func)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), PetscScalar *fintegral, void *user) 2364d71ae5a4SJacob Faibussowitsch { 23659b6f715bSMatthew G. Knepley DM plex = NULL, plexA = NULL; 2366a6e0b375SMatthew G. Knepley DMEnclosureType encAux; 23679b6f715bSMatthew G. Knepley PetscDS prob, probAux = NULL; 23689b6f715bSMatthew G. Knepley PetscSection section, sectionAux = NULL; 23699b6f715bSMatthew G. Knepley Vec locA = NULL; 23709b6f715bSMatthew G. Knepley DMField coordField; 23719b6f715bSMatthew G. Knepley PetscInt Nf, totDim, *uOff, *uOff_x; 23729b6f715bSMatthew G. Knepley PetscInt NfAux = 0, totDimAux = 0, *aOff = NULL; 23739b6f715bSMatthew G. Knepley PetscScalar *u, *a = NULL; 237464c72086SMatthew G. Knepley const PetscScalar *constants; 23759b6f715bSMatthew G. Knepley PetscInt numConstants, f; 237664c72086SMatthew G. Knepley 237764c72086SMatthew G. Knepley PetscFunctionBegin; 23789566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 23799566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 23809566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 23819566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 23829566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &Nf)); 238364c72086SMatthew G. Knepley /* Determine which discretizations we have */ 23849b6f715bSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 238564c72086SMatthew G. Knepley PetscObject obj; 238664c72086SMatthew G. Knepley PetscClassId id; 238764c72086SMatthew G. Knepley 23889566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 23899566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 239063a3b9bcSJacob Faibussowitsch PetscCheck(id != PETSCFV_CLASSID, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Not supported for FVM (field %" PetscInt_FMT ")", f); 239164c72086SMatthew G. Knepley } 239264c72086SMatthew G. Knepley /* Read DS information */ 23939566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 23949566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(prob, &uOff)); 23959566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x)); 23969566063dSJacob Faibussowitsch PetscCall(PetscDSGetConstants(prob, &numConstants, &constants)); 239764c72086SMatthew G. Knepley /* Read Auxiliary DS information */ 23989566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 23999b6f715bSMatthew G. Knepley if (locA) { 24009b6f715bSMatthew G. Knepley DM dmAux; 24019b6f715bSMatthew G. Knepley 24029566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 24039566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 24049566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 24059566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 24069566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(probAux, &NfAux)); 24079566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 24089566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 24099566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(probAux, &aOff)); 241064c72086SMatthew G. Knepley } 24119b6f715bSMatthew G. Knepley /* Integrate over points */ 24129b6f715bSMatthew G. Knepley { 24139b6f715bSMatthew G. Knepley PetscFEGeom *fgeom, *chunkGeom = NULL; 2414b7260050SToby Isaac PetscInt maxDegree; 24159b6f715bSMatthew G. Knepley PetscQuadrature qGeom = NULL; 24169b6f715bSMatthew G. Knepley const PetscInt *points; 24179b6f715bSMatthew G. Knepley PetscInt numFaces, face, Nq, field; 24189b6f715bSMatthew G. Knepley PetscInt numChunks, chunkSize, chunk, Nr, offset; 241964c72086SMatthew G. Knepley 24209566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 24219566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 24229566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(numFaces * totDim, &u, locA ? numFaces * totDimAux : 0, &a)); 24239566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 242464c72086SMatthew G. Knepley for (field = 0; field < Nf; ++field) { 242564c72086SMatthew G. Knepley PetscFE fe; 242664c72086SMatthew G. Knepley 24279566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fe)); 24289566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 24299b6f715bSMatthew G. Knepley if (!qGeom) { 24309566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 24319566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 24329b6f715bSMatthew G. Knepley } 24339566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 24349566063dSJacob Faibussowitsch PetscCall(DMPlexGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 24359b6f715bSMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 2436f15274beSMatthew Knepley const PetscInt point = points[face], *support; 24379b6f715bSMatthew G. Knepley PetscScalar *x = NULL; 2438f15274beSMatthew Knepley PetscInt i; 24399b6f715bSMatthew G. Knepley 24409566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, point, &support)); 24419566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 24429b6f715bSMatthew G. Knepley for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 24439566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 24449b6f715bSMatthew G. Knepley if (locA) { 24459b6f715bSMatthew G. Knepley PetscInt subp; 24469566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 24479566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 24489b6f715bSMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[f * totDimAux + i] = x[i]; 24499566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 24509b6f715bSMatthew G. Knepley } 24519b6f715bSMatthew G. Knepley } 24529b6f715bSMatthew G. Knepley /* Get blocking */ 24539b6f715bSMatthew G. Knepley { 24549b6f715bSMatthew G. Knepley PetscQuadrature q; 24559b6f715bSMatthew G. Knepley PetscInt numBatches, batchSize, numBlocks, blockSize; 24569b6f715bSMatthew G. Knepley PetscInt Nq, Nb; 24579b6f715bSMatthew G. Knepley 24589566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 24599566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 24609566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL)); 24619566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 246264c72086SMatthew G. Knepley blockSize = Nb * Nq; 246364c72086SMatthew G. Knepley batchSize = numBlocks * blockSize; 24649b6f715bSMatthew G. Knepley chunkSize = numBatches * batchSize; 24659566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 24669b6f715bSMatthew G. Knepley numChunks = numFaces / chunkSize; 24679b6f715bSMatthew G. Knepley Nr = numFaces % chunkSize; 246864c72086SMatthew G. Knepley offset = numFaces - Nr; 246964c72086SMatthew G. Knepley } 24709b6f715bSMatthew G. Knepley /* Do integration for each field */ 24719b6f715bSMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 24729566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, chunk * chunkSize, (chunk + 1) * chunkSize, &chunkGeom)); 24739566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBd(prob, field, func, chunkSize, chunkGeom, u, probAux, a, fintegral)); 24749566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom)); 247564c72086SMatthew G. Knepley } 24769566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 24779566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBd(prob, field, func, Nr, chunkGeom, &u[offset * totDim], probAux, a ? &a[offset * totDimAux] : NULL, &fintegral[offset * Nf])); 24789566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 247964c72086SMatthew G. Knepley /* Cleanup data arrays */ 24809566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 24819566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 24829566063dSJacob Faibussowitsch PetscCall(PetscFree2(u, a)); 24839566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 248464c72086SMatthew G. Knepley } 248564c72086SMatthew G. Knepley } 24869566063dSJacob Faibussowitsch if (plex) PetscCall(DMDestroy(&plex)); 24879566063dSJacob Faibussowitsch if (plexA) PetscCall(DMDestroy(&plexA)); 24883ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 24899b6f715bSMatthew G. Knepley } 24909b6f715bSMatthew G. Knepley 249160225df5SJacob Faibussowitsch /*@C 24929b6f715bSMatthew G. Knepley DMPlexComputeBdIntegral - Form the integral over the specified boundary from the global input X using pointwise functions specified by the user 24939b6f715bSMatthew G. Knepley 24949b6f715bSMatthew G. Knepley Input Parameters: 24959b6f715bSMatthew G. Knepley + dm - The mesh 24969b6f715bSMatthew G. Knepley . X - Global input vector 2497a1cb98faSBarry Smith . label - The boundary `DMLabel` 2498a1cb98faSBarry Smith . numVals - The number of label values to use, or `PETSC_DETERMINE` for all values 2499a1cb98faSBarry Smith . vals - The label values to use, or NULL for all values 250067b8a455SSatish Balay . func - The function to integrate along the boundary 25019b6f715bSMatthew G. Knepley - user - The user context 25029b6f715bSMatthew G. Knepley 25039b6f715bSMatthew G. Knepley Output Parameter: 25049b6f715bSMatthew G. Knepley . integral - Integral for each field 25059b6f715bSMatthew G. Knepley 25069b6f715bSMatthew G. Knepley Level: developer 25079b6f715bSMatthew G. Knepley 25081cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeIntegralFEM()`, `DMPlexComputeBdResidualFEM()` 25099b6f715bSMatthew G. Knepley @*/ 2510d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeBdIntegral(DM dm, Vec X, DMLabel label, PetscInt numVals, const PetscInt vals[], void (*func)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), PetscScalar *integral, void *user) 2511d71ae5a4SJacob Faibussowitsch { 25129b6f715bSMatthew G. Knepley Vec locX; 25139b6f715bSMatthew G. Knepley PetscSection section; 25149b6f715bSMatthew G. Knepley DMLabel depthLabel; 25159b6f715bSMatthew G. Knepley IS facetIS; 25169b6f715bSMatthew G. Knepley PetscInt dim, Nf, f, v; 25179b6f715bSMatthew G. Knepley 25189b6f715bSMatthew G. Knepley PetscFunctionBegin; 25199b6f715bSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 25209b6f715bSMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2521292bffcbSToby Isaac PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3); 25224f572ea9SToby Isaac if (vals) PetscAssertPointer(vals, 5); 25234f572ea9SToby Isaac PetscAssertPointer(integral, 7); 25249566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 25259566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 25269566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 25279566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 25289566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 25299566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &Nf)); 25309b6f715bSMatthew G. Knepley /* Get local solution with boundary values */ 25319566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &locX)); 25329566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 25339566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 25349566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 25359b6f715bSMatthew G. Knepley /* Loop over label values */ 25369566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(integral, Nf)); 25379b6f715bSMatthew G. Knepley for (v = 0; v < numVals; ++v) { 25389b6f715bSMatthew G. Knepley IS pointIS; 25399b6f715bSMatthew G. Knepley PetscInt numFaces, face; 25409b6f715bSMatthew G. Knepley PetscScalar *fintegral; 25419b6f715bSMatthew G. Knepley 25429566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, vals[v], &pointIS)); 25439b6f715bSMatthew G. Knepley if (!pointIS) continue; /* No points with that id on this process */ 25449b6f715bSMatthew G. Knepley { 25459b6f715bSMatthew G. Knepley IS isectIS; 25469b6f715bSMatthew G. Knepley 25479b6f715bSMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 25489566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 25499566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 25509b6f715bSMatthew G. Knepley pointIS = isectIS; 25519b6f715bSMatthew G. Knepley } 25529566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 25539566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(numFaces * Nf, &fintegral)); 25549566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdIntegral_Internal(dm, locX, pointIS, func, fintegral, user)); 25559b6f715bSMatthew G. Knepley /* Sum point contributions into integral */ 25569371c9d4SSatish Balay for (f = 0; f < Nf; ++f) 25579371c9d4SSatish Balay for (face = 0; face < numFaces; ++face) integral[f] += fintegral[face * Nf + f]; 25589566063dSJacob Faibussowitsch PetscCall(PetscFree(fintegral)); 25599566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 25609b6f715bSMatthew G. Knepley } 25619566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &locX)); 25629566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 25639566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 25643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 256564c72086SMatthew G. Knepley } 256664c72086SMatthew G. Knepley 2567d69c5d34SMatthew G. Knepley /*@ 2568a1cb98faSBarry Smith DMPlexComputeInterpolatorNested - Form the local portion of the interpolation matrix I from the coarse `DM` to a uniformly refined `DM`. 2569d69c5d34SMatthew G. Knepley 2570d69c5d34SMatthew G. Knepley Input Parameters: 2571cf51de39SMatthew G. Knepley + dmc - The coarse mesh 2572cf51de39SMatthew G. Knepley . dmf - The fine mesh 2573cf51de39SMatthew G. Knepley . isRefined - Flag indicating regular refinement, rather than the same topology 2574d69c5d34SMatthew G. Knepley - user - The user context 2575d69c5d34SMatthew G. Knepley 2576d69c5d34SMatthew G. Knepley Output Parameter: 2577934789fcSMatthew G. Knepley . In - The interpolation matrix 2578d69c5d34SMatthew G. Knepley 2579d69c5d34SMatthew G. Knepley Level: developer 2580d69c5d34SMatthew G. Knepley 25811cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorGeneral()`, `DMPlexComputeJacobianFEM()` 2582d69c5d34SMatthew G. Knepley @*/ 2583d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, PetscBool isRefined, Mat In, void *user) 2584d71ae5a4SJacob Faibussowitsch { 2585d69c5d34SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmc->data; 2586d69c5d34SMatthew G. Knepley const char *name = "Interpolator"; 2587d69c5d34SMatthew G. Knepley PetscFE *feRef; 258897c42addSMatthew G. Knepley PetscFV *fvRef; 2589d69c5d34SMatthew G. Knepley PetscSection fsection, fglobalSection; 2590d69c5d34SMatthew G. Knepley PetscSection csection, cglobalSection; 2591d69c5d34SMatthew G. Knepley PetscScalar *elemMat; 2592485ad865SMatthew G. Knepley PetscInt dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, c; 25932ea9c922SToby Isaac PetscInt cTotDim = 0, rTotDim = 0; 2594d69c5d34SMatthew G. Knepley 2595d69c5d34SMatthew G. Knepley PetscFunctionBegin; 25969566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 25979566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dmf, &dim)); 25989566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 25999566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &fglobalSection)); 26009566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 26019566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &cglobalSection)); 26029566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(fsection, &Nf)); 26039566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd)); 26049566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &feRef, Nf, &fvRef)); 2605d69c5d34SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 26062ea9c922SToby Isaac PetscObject obj, objc; 26072ea9c922SToby Isaac PetscClassId id, idc; 26082ea9c922SToby Isaac PetscInt rNb = 0, Nc = 0, cNb = 0; 2609d69c5d34SMatthew G. Knepley 26109566063dSJacob Faibussowitsch PetscCall(DMGetField(dmf, f, NULL, &obj)); 26119566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 261297c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 261397c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 261497c42addSMatthew G. Knepley 2615cf51de39SMatthew G. Knepley if (isRefined) { 26169566063dSJacob Faibussowitsch PetscCall(PetscFERefine(fe, &feRef[f])); 2617cf51de39SMatthew G. Knepley } else { 26189566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)fe)); 2619cf51de39SMatthew G. Knepley feRef[f] = fe; 2620cf51de39SMatthew G. Knepley } 26219566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feRef[f], &rNb)); 26229566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 262397c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 262497c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 262597c42addSMatthew G. Knepley PetscDualSpace Q; 262697c42addSMatthew G. Knepley 2627cf51de39SMatthew G. Knepley if (isRefined) { 26289566063dSJacob Faibussowitsch PetscCall(PetscFVRefine(fv, &fvRef[f])); 2629cf51de39SMatthew G. Knepley } else { 26309566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)fv)); 2631cf51de39SMatthew G. Knepley fvRef[f] = fv; 2632cf51de39SMatthew G. Knepley } 26339566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[f], &Q)); 26349566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &rNb)); 26359566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 26369566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 263797c42addSMatthew G. Knepley } 26389566063dSJacob Faibussowitsch PetscCall(DMGetField(dmc, f, NULL, &objc)); 26399566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(objc, &idc)); 26402ea9c922SToby Isaac if (idc == PETSCFE_CLASSID) { 26412ea9c922SToby Isaac PetscFE fe = (PetscFE)objc; 26422ea9c922SToby Isaac 26439566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cNb)); 26442ea9c922SToby Isaac } else if (id == PETSCFV_CLASSID) { 26452ea9c922SToby Isaac PetscFV fv = (PetscFV)obj; 26462ea9c922SToby Isaac PetscDualSpace Q; 26472ea9c922SToby Isaac 26489566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 26499566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &cNb)); 2650d69c5d34SMatthew G. Knepley } 26512ea9c922SToby Isaac rTotDim += rNb; 26522ea9c922SToby Isaac cTotDim += cNb; 26532ea9c922SToby Isaac } 26549566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(rTotDim * cTotDim, &elemMat)); 26559566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, rTotDim * cTotDim)); 2656d69c5d34SMatthew G. Knepley for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) { 2657d69c5d34SMatthew G. Knepley PetscDualSpace Qref; 2658d69c5d34SMatthew G. Knepley PetscQuadrature f; 2659d69c5d34SMatthew G. Knepley const PetscReal *qpoints, *qweights; 2660d69c5d34SMatthew G. Knepley PetscReal *points; 2661d69c5d34SMatthew G. Knepley PetscInt npoints = 0, Nc, Np, fpdim, i, k, p, d; 2662d69c5d34SMatthew G. Knepley 2663d69c5d34SMatthew G. Knepley /* Compose points from all dual basis functionals */ 266497c42addSMatthew G. Knepley if (feRef[fieldI]) { 26659566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feRef[fieldI], &Qref)); 26669566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feRef[fieldI], &Nc)); 266797c42addSMatthew G. Knepley } else { 26689566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[fieldI], &Qref)); 26699566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvRef[fieldI], &Nc)); 267097c42addSMatthew G. Knepley } 26719566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Qref, &fpdim)); 2672d69c5d34SMatthew G. Knepley for (i = 0; i < fpdim; ++i) { 26739566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 26749566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL)); 2675d69c5d34SMatthew G. Knepley npoints += Np; 2676d69c5d34SMatthew G. Knepley } 26779566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(npoints * dim, &points)); 2678d69c5d34SMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 26799566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 26809566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL)); 26819371c9d4SSatish Balay for (p = 0; p < Np; ++p, ++k) 26829371c9d4SSatish Balay for (d = 0; d < dim; ++d) points[k * dim + d] = qpoints[p * dim + d]; 2683d69c5d34SMatthew G. Knepley } 2684d69c5d34SMatthew G. Knepley 2685d69c5d34SMatthew G. Knepley for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) { 268697c42addSMatthew G. Knepley PetscObject obj; 268797c42addSMatthew G. Knepley PetscClassId id; 26889c3cf19fSMatthew G. Knepley PetscInt NcJ = 0, cpdim = 0, j, qNc; 2689d69c5d34SMatthew G. Knepley 26909566063dSJacob Faibussowitsch PetscCall(DMGetField(dmc, fieldJ, NULL, &obj)); 26919566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 269297c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 269397c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 2694ef0bb6c7SMatthew G. Knepley PetscTabulation T = NULL; 2695d69c5d34SMatthew G. Knepley 2696d69c5d34SMatthew G. Knepley /* Evaluate basis at points */ 26979566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &NcJ)); 26989566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cpdim)); 2699ffe73a53SMatthew G. Knepley /* For now, fields only interpolate themselves */ 2700ffe73a53SMatthew G. Knepley if (fieldI == fieldJ) { 270163a3b9bcSJacob 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); 27029566063dSJacob Faibussowitsch PetscCall(PetscFECreateTabulation(fe, 1, npoints, points, 0, &T)); 2703d69c5d34SMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 27049566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 27059566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights)); 270663a3b9bcSJacob 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); 2707d69c5d34SMatthew G. Knepley for (p = 0; p < Np; ++p, ++k) { 270836a6d9c0SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 2709d172c84bSMatthew G. Knepley /* 2710d172c84bSMatthew G. Knepley cTotDim: Total columns in element interpolation matrix, sum of number of dual basis functionals in each field 2711d172c84bSMatthew G. Knepley offsetI, offsetJ: Offsets into the larger element interpolation matrix for different fields 2712d172c84bSMatthew G. Knepley fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals 2713d172c84bSMatthew G. Knepley qNC, Nc, Ncj, c: Number of components in this field 2714d172c84bSMatthew G. Knepley Np, p: Number of quad points in the fine grid functional i 2715d172c84bSMatthew G. Knepley k: i*Np + p, overall point number for the interpolation 2716d172c84bSMatthew G. Knepley */ 2717ef0bb6c7SMatthew 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]; 271836a6d9c0SMatthew G. Knepley } 2719d69c5d34SMatthew G. Knepley } 2720d69c5d34SMatthew G. Knepley } 27219566063dSJacob Faibussowitsch PetscCall(PetscTabulationDestroy(&T)); 2722ffe73a53SMatthew G. Knepley } 272397c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 272497c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 272597c42addSMatthew G. Knepley 272697c42addSMatthew G. Knepley /* Evaluate constant function at points */ 27279566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &NcJ)); 272897c42addSMatthew G. Knepley cpdim = 1; 272997c42addSMatthew G. Knepley /* For now, fields only interpolate themselves */ 273097c42addSMatthew G. Knepley if (fieldI == fieldJ) { 273163a3b9bcSJacob 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); 273297c42addSMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 27339566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 27349566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights)); 273563a3b9bcSJacob 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); 273697c42addSMatthew G. Knepley for (p = 0; p < Np; ++p, ++k) { 273797c42addSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 2738458eb97cSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[(offsetI + i) * cTotDim + offsetJ + j] += 1.0 * qweights[p * qNc + c]; 273997c42addSMatthew G. Knepley } 274097c42addSMatthew G. Knepley } 274197c42addSMatthew G. Knepley } 274297c42addSMatthew G. Knepley } 274397c42addSMatthew G. Knepley } 2744d172c84bSMatthew G. Knepley offsetJ += cpdim; 2745d69c5d34SMatthew G. Knepley } 2746d172c84bSMatthew G. Knepley offsetI += fpdim; 27479566063dSJacob Faibussowitsch PetscCall(PetscFree(points)); 2748d69c5d34SMatthew G. Knepley } 27499566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat)); 27507f5b169aSMatthew G. Knepley /* Preallocate matrix */ 27517f5b169aSMatthew G. Knepley { 2752c094ef40SMatthew G. Knepley Mat preallocator; 2753c094ef40SMatthew G. Knepley PetscScalar *vals; 2754c094ef40SMatthew G. Knepley PetscInt *cellCIndices, *cellFIndices; 2755c094ef40SMatthew G. Knepley PetscInt locRows, locCols, cell; 27567f5b169aSMatthew G. Knepley 27579566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(In, &locRows, &locCols)); 27589566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &preallocator)); 27599566063dSJacob Faibussowitsch PetscCall(MatSetType(preallocator, MATPREALLOCATOR)); 27609566063dSJacob Faibussowitsch PetscCall(MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE)); 27619566063dSJacob Faibussowitsch PetscCall(MatSetUp(preallocator)); 27629566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(rTotDim * cTotDim, &vals, cTotDim, &cellCIndices, rTotDim, &cellFIndices)); 27637f5b169aSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 2764cf51de39SMatthew G. Knepley if (isRefined) { 27659566063dSJacob Faibussowitsch PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices)); 27669566063dSJacob Faibussowitsch PetscCall(MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES)); 2767cf51de39SMatthew G. Knepley } else { 2768*e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, PETSC_FALSE, dmc, csection, cglobalSection, PETSC_FALSE, preallocator, cell, vals, INSERT_VALUES)); 2769cf51de39SMatthew G. Knepley } 27707f5b169aSMatthew G. Knepley } 27719566063dSJacob Faibussowitsch PetscCall(PetscFree3(vals, cellCIndices, cellFIndices)); 27729566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY)); 27739566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY)); 27749566063dSJacob Faibussowitsch PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In)); 27759566063dSJacob Faibussowitsch PetscCall(MatDestroy(&preallocator)); 27767f5b169aSMatthew G. Knepley } 27777f5b169aSMatthew G. Knepley /* Fill matrix */ 27789566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(In)); 2779d69c5d34SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 2780cf51de39SMatthew G. Knepley if (isRefined) { 27819566063dSJacob Faibussowitsch PetscCall(DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES)); 2782cf51de39SMatthew G. Knepley } else { 2783*e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, PETSC_FALSE, dmc, csection, cglobalSection, PETSC_FALSE, In, c, elemMat, INSERT_VALUES)); 2784cf51de39SMatthew G. Knepley } 2785d69c5d34SMatthew G. Knepley } 27869566063dSJacob Faibussowitsch for (f = 0; f < Nf; ++f) PetscCall(PetscFEDestroy(&feRef[f])); 27879566063dSJacob Faibussowitsch PetscCall(PetscFree2(feRef, fvRef)); 27889566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 27899566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY)); 27909566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY)); 27919318fe57SMatthew G. Knepley if (mesh->printFEM > 1) { 27929566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name)); 27932ce66baaSPierre Jolivet PetscCall(MatFilter(In, 1.0e-10, PETSC_FALSE, PETSC_FALSE)); 27949566063dSJacob Faibussowitsch PetscCall(MatView(In, NULL)); 2795d69c5d34SMatthew G. Knepley } 27969566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 27973ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2798d69c5d34SMatthew G. Knepley } 27996c73c22cSMatthew G. Knepley 2800d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user) 2801d71ae5a4SJacob Faibussowitsch { 2802bd041c0cSMatthew G. Knepley SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_SUP, "Laziness"); 2803bd041c0cSMatthew G. Knepley } 2804bd041c0cSMatthew G. Knepley 280568132eb9SMatthew G. Knepley /*@ 2806a1cb98faSBarry Smith DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix I from the coarse `DM` to a non-nested fine `DM`. 280768132eb9SMatthew G. Knepley 280868132eb9SMatthew G. Knepley Input Parameters: 280968132eb9SMatthew G. Knepley + dmf - The fine mesh 281068132eb9SMatthew G. Knepley . dmc - The coarse mesh 281168132eb9SMatthew G. Knepley - user - The user context 281268132eb9SMatthew G. Knepley 281368132eb9SMatthew G. Knepley Output Parameter: 281468132eb9SMatthew G. Knepley . In - The interpolation matrix 281568132eb9SMatthew G. Knepley 281668132eb9SMatthew G. Knepley Level: developer 281768132eb9SMatthew G. Knepley 28181cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeJacobianFEM()` 281968132eb9SMatthew G. Knepley @*/ 2820d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user) 2821d71ae5a4SJacob Faibussowitsch { 282264e98e1dSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmf->data; 282364e98e1dSMatthew G. Knepley const char *name = "Interpolator"; 28244ef9d792SMatthew G. Knepley PetscDS prob; 2825a0806964SMatthew G. Knepley Mat interp; 2826a0806964SMatthew G. Knepley PetscSection fsection, globalFSection; 2827a0806964SMatthew G. Knepley PetscSection csection, globalCSection; 2828a0806964SMatthew G. Knepley PetscInt locRows, locCols; 28294ef9d792SMatthew G. Knepley PetscReal *x, *v0, *J, *invJ, detJ; 28304ef9d792SMatthew G. Knepley PetscReal *v0c, *Jc, *invJc, detJc; 28314ef9d792SMatthew G. Knepley PetscScalar *elemMat; 2832a0806964SMatthew G. Knepley PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell, s; 28334ef9d792SMatthew G. Knepley 28344ef9d792SMatthew G. Knepley PetscFunctionBegin; 28359566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 28369566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dmc, &dim)); 28379566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 28389566063dSJacob Faibussowitsch PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL)); 28399566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 28409566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ)); 28419566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc)); 28429566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 28439566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 28449566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 28459566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 2846a0806964SMatthew G. Knepley PetscCall(DMPlexGetSimplexOrBoxCells(dmf, 0, &cStart, &cEnd)); 28479566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 28489566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totDim, &elemMat)); 28494ef9d792SMatthew G. Knepley 2850a0806964SMatthew G. Knepley PetscCall(MatGetLocalSize(In, &locRows, &locCols)); 2851a0806964SMatthew G. Knepley PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &interp)); 2852a0806964SMatthew G. Knepley PetscCall(MatSetType(interp, MATPREALLOCATOR)); 2853a0806964SMatthew G. Knepley PetscCall(MatSetSizes(interp, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE)); 2854a0806964SMatthew G. Knepley PetscCall(MatSetUp(interp)); 2855a0806964SMatthew G. Knepley for (s = 0; s < 2; ++s) { 28564ef9d792SMatthew G. Knepley for (field = 0; field < Nf; ++field) { 28574ef9d792SMatthew G. Knepley PetscObject obj; 28584ef9d792SMatthew G. Knepley PetscClassId id; 2859c0d7054bSMatthew G. Knepley PetscDualSpace Q = NULL; 2860ef0bb6c7SMatthew G. Knepley PetscTabulation T = NULL; 28614ef9d792SMatthew G. Knepley PetscQuadrature f; 28624ef9d792SMatthew G. Knepley const PetscReal *qpoints, *qweights; 2863d0f6233fSMatthew G. Knepley PetscInt Nc, qNc, Np, fpdim, off, i, d; 28644ef9d792SMatthew G. Knepley 2865d0f6233fSMatthew G. Knepley PetscCall(PetscDSGetFieldOffset(prob, field, &off)); 28669566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 28679566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 28684ef9d792SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 28694ef9d792SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 28704ef9d792SMatthew G. Knepley 28719566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(fe, &Q)); 28729566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 2873a0806964SMatthew G. Knepley if (s) PetscCall(PetscFECreateTabulation(fe, 1, 1, x, 0, &T)); 28744ef9d792SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 28754ef9d792SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 28764ef9d792SMatthew G. Knepley 28779566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 28784ef9d792SMatthew G. Knepley Nc = 1; 287963a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 28809566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &fpdim)); 28814ef9d792SMatthew G. Knepley /* For each fine grid cell */ 28824ef9d792SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 28834ef9d792SMatthew G. Knepley PetscInt *findices, *cindices; 28844ef9d792SMatthew G. Knepley PetscInt numFIndices, numCIndices; 28854ef9d792SMatthew G. Knepley 28869566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 28879566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 2888d0f6233fSMatthew 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); 28894ef9d792SMatthew G. Knepley for (i = 0; i < fpdim; ++i) { 28904ef9d792SMatthew G. Knepley Vec pointVec; 28914ef9d792SMatthew G. Knepley PetscScalar *pV; 289212111d7cSToby Isaac PetscSF coarseCellSF = NULL; 28933a93e3b7SToby Isaac const PetscSFNode *coarseCells; 2894d0f6233fSMatthew G. Knepley PetscInt numCoarseCells, cpdim, row = findices[i + off], q, c, j; 28954ef9d792SMatthew G. Knepley 28964ef9d792SMatthew G. Knepley /* Get points from the dual basis functional quadrature */ 28979566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Q, i, &f)); 28989566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights)); 289963a3b9bcSJacob 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); 29009566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Np * dim, &pointVec)); 29019566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 29029566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 29034ef9d792SMatthew G. Knepley for (q = 0; q < Np; ++q) { 2904c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 2905c330f8ffSToby Isaac 29064ef9d792SMatthew G. Knepley /* Transform point to real space */ 2907c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 29084ef9d792SMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 29094ef9d792SMatthew G. Knepley } 29109566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 29114ef9d792SMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 29121555c271SMatthew G. Knepley /* OPT: Read this out from preallocation information */ 29139566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 29144ef9d792SMatthew G. Knepley /* Update preallocation info */ 29159566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 29165f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Np, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 29179566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 29184ef9d792SMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 2919826eb36dSMatthew G. Knepley PetscReal pVReal[3]; 2920c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 2921826eb36dSMatthew G. Knepley 29229566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 2923a0806964SMatthew G. Knepley if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetDimension((PetscFE)obj, &cpdim)); 2924a0806964SMatthew G. Knepley else cpdim = 1; 2925a0806964SMatthew G. Knepley 2926a0806964SMatthew G. Knepley if (s) { 29274ef9d792SMatthew G. Knepley /* Transform points from real space to coarse reference space */ 29289566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc)); 2929e2d86523SMatthew G. Knepley for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]); 2930c330f8ffSToby Isaac CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 29314ef9d792SMatthew G. Knepley 29324ef9d792SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 29334ef9d792SMatthew G. Knepley /* Evaluate coarse basis on contained point */ 2934a0806964SMatthew G. Knepley PetscCall(PetscFEComputeTabulation((PetscFE)obj, 1, x, 0, T)); 29359566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 29364ef9d792SMatthew G. Knepley /* Get elemMat entries by multiplying by weight */ 29374ef9d792SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 2938ef0bb6c7SMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j * Nc + c] * qweights[ccell * qNc + c]; 29394ef9d792SMatthew G. Knepley } 29404ef9d792SMatthew G. Knepley } else { 29414ef9d792SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 29429c3cf19fSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * qweights[ccell * qNc + c]; 29434ef9d792SMatthew G. Knepley } 29444ef9d792SMatthew G. Knepley } 29459566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 2946a0806964SMatthew G. Knepley } 2947a0806964SMatthew G. Knepley /* Update interpolator */ 2948d0f6233fSMatthew G. Knepley PetscCheck(numCIndices == totDim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, totDim); 2949a0806964SMatthew G. Knepley PetscCall(MatSetValues(interp, 1, &row, cpdim, &cindices[off], elemMat, INSERT_VALUES)); 29509566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 29514ef9d792SMatthew G. Knepley } 29529566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 29539566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 29549566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 29554ef9d792SMatthew G. Knepley } 29569566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 29574ef9d792SMatthew G. Knepley } 2958a0806964SMatthew G. Knepley if (s && id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T)); 2959a0806964SMatthew G. Knepley } 2960a0806964SMatthew G. Knepley if (!s) { 2961a0806964SMatthew G. Knepley PetscCall(MatAssemblyBegin(interp, MAT_FINAL_ASSEMBLY)); 2962a0806964SMatthew G. Knepley PetscCall(MatAssemblyEnd(interp, MAT_FINAL_ASSEMBLY)); 2963a0806964SMatthew G. Knepley PetscCall(MatPreallocatorPreallocate(interp, PETSC_TRUE, In)); 2964a0806964SMatthew G. Knepley PetscCall(MatDestroy(&interp)); 2965a0806964SMatthew G. Knepley interp = In; 2966a0806964SMatthew G. Knepley } 29674ef9d792SMatthew G. Knepley } 29689566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0, J, invJ)); 29699566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0c, Jc, invJc)); 29709566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 29719566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY)); 29729566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY)); 29739566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 29743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 29754ef9d792SMatthew G. Knepley } 29764ef9d792SMatthew G. Knepley 297746fa42a0SMatthew G. Knepley /*@ 2978a1cb98faSBarry Smith DMPlexComputeMassMatrixGeneral - Form the local portion of the mass matrix M from the coarse `DM` to a non-nested fine `DM`. 2979bd041c0cSMatthew G. Knepley 2980bd041c0cSMatthew G. Knepley Input Parameters: 2981bd041c0cSMatthew G. Knepley + dmf - The fine mesh 2982bd041c0cSMatthew G. Knepley . dmc - The coarse mesh 2983bd041c0cSMatthew G. Knepley - user - The user context 2984bd041c0cSMatthew G. Knepley 2985bd041c0cSMatthew G. Knepley Output Parameter: 2986bd041c0cSMatthew G. Knepley . mass - The mass matrix 2987bd041c0cSMatthew G. Knepley 2988bd041c0cSMatthew G. Knepley Level: developer 2989bd041c0cSMatthew G. Knepley 29901cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeMassMatrixNested()`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeInterpolatorGeneral()`, `DMPlexComputeJacobianFEM()` 2991bd041c0cSMatthew G. Knepley @*/ 2992d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, void *user) 2993d71ae5a4SJacob Faibussowitsch { 2994bd041c0cSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmf->data; 2995bd041c0cSMatthew G. Knepley const char *name = "Mass Matrix"; 2996bd041c0cSMatthew G. Knepley PetscDS prob; 2997bd041c0cSMatthew G. Knepley PetscSection fsection, csection, globalFSection, globalCSection; 2998e8f14785SLisandro Dalcin PetscHSetIJ ht; 2999bd041c0cSMatthew G. Knepley PetscLayout rLayout; 3000bd041c0cSMatthew G. Knepley PetscInt *dnz, *onz; 3001bd041c0cSMatthew G. Knepley PetscInt locRows, rStart, rEnd; 3002bd041c0cSMatthew G. Knepley PetscReal *x, *v0, *J, *invJ, detJ; 3003bd041c0cSMatthew G. Knepley PetscReal *v0c, *Jc, *invJc, detJc; 3004bd041c0cSMatthew G. Knepley PetscScalar *elemMat; 3005bd041c0cSMatthew G. Knepley PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell; 3006bd041c0cSMatthew G. Knepley 3007bd041c0cSMatthew G. Knepley PetscFunctionBegin; 30089566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dmc, &dim)); 30099566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 30109566063dSJacob Faibussowitsch PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL)); 30119566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 30129566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ)); 30139566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc)); 30149566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 30159566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 30169566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 30179566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 30189566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd)); 30199566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 30209566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totDim, &elemMat)); 3021bd041c0cSMatthew G. Knepley 30229566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mass, &locRows, NULL)); 30239566063dSJacob Faibussowitsch PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)mass), &rLayout)); 30249566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(rLayout, locRows)); 30259566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetBlockSize(rLayout, 1)); 30269566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(rLayout)); 30279566063dSJacob Faibussowitsch PetscCall(PetscLayoutGetRange(rLayout, &rStart, &rEnd)); 30289566063dSJacob Faibussowitsch PetscCall(PetscLayoutDestroy(&rLayout)); 30299566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz)); 30309566063dSJacob Faibussowitsch PetscCall(PetscHSetIJCreate(&ht)); 3031bd041c0cSMatthew G. Knepley for (field = 0; field < Nf; ++field) { 3032bd041c0cSMatthew G. Knepley PetscObject obj; 3033bd041c0cSMatthew G. Knepley PetscClassId id; 3034bd041c0cSMatthew G. Knepley PetscQuadrature quad; 3035bd041c0cSMatthew G. Knepley const PetscReal *qpoints; 3036bd041c0cSMatthew G. Knepley PetscInt Nq, Nc, i, d; 3037bd041c0cSMatthew G. Knepley 30389566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 30399566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 30409566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad)); 30419566063dSJacob Faibussowitsch else PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad)); 30429566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL)); 3043bd041c0cSMatthew G. Knepley /* For each fine grid cell */ 3044bd041c0cSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 3045bd041c0cSMatthew G. Knepley Vec pointVec; 3046bd041c0cSMatthew G. Knepley PetscScalar *pV; 3047bd041c0cSMatthew G. Knepley PetscSF coarseCellSF = NULL; 3048bd041c0cSMatthew G. Knepley const PetscSFNode *coarseCells; 3049bd041c0cSMatthew G. Knepley PetscInt numCoarseCells, q, c; 3050bd041c0cSMatthew G. Knepley PetscInt *findices, *cindices; 3051bd041c0cSMatthew G. Knepley PetscInt numFIndices, numCIndices; 3052bd041c0cSMatthew G. Knepley 30539566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 30549566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 3055bd041c0cSMatthew G. Knepley /* Get points from the quadrature */ 30569566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec)); 30579566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 30589566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 3059bd041c0cSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 3060c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3061c330f8ffSToby Isaac 3062bd041c0cSMatthew G. Knepley /* Transform point to real space */ 3063c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 3064bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 3065bd041c0cSMatthew G. Knepley } 30669566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 3067bd041c0cSMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 30689566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 30699566063dSJacob Faibussowitsch PetscCall(PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view")); 3070bd041c0cSMatthew G. Knepley /* Update preallocation info */ 30719566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 30725f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 3073bd041c0cSMatthew G. Knepley { 3074e8f14785SLisandro Dalcin PetscHashIJKey key; 3075e8f14785SLisandro Dalcin PetscBool missing; 3076bd041c0cSMatthew G. Knepley 3077bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 3078e8f14785SLisandro Dalcin key.i = findices[i]; 3079e8f14785SLisandro Dalcin if (key.i >= 0) { 3080bd041c0cSMatthew G. Knepley /* Get indices for coarse elements */ 3081bd041c0cSMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 30829566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3083bd041c0cSMatthew G. Knepley for (c = 0; c < numCIndices; ++c) { 3084e8f14785SLisandro Dalcin key.j = cindices[c]; 3085e8f14785SLisandro Dalcin if (key.j < 0) continue; 30869566063dSJacob Faibussowitsch PetscCall(PetscHSetIJQueryAdd(ht, key, &missing)); 3087bd041c0cSMatthew G. Knepley if (missing) { 3088e8f14785SLisandro Dalcin if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i - rStart]; 3089e8f14785SLisandro Dalcin else ++onz[key.i - rStart]; 3090bd041c0cSMatthew G. Knepley } 3091bd041c0cSMatthew G. Knepley } 30929566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3093bd041c0cSMatthew G. Knepley } 3094bd041c0cSMatthew G. Knepley } 3095bd041c0cSMatthew G. Knepley } 3096bd041c0cSMatthew G. Knepley } 30979566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 30989566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 30999566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3100bd041c0cSMatthew G. Knepley } 3101bd041c0cSMatthew G. Knepley } 31029566063dSJacob Faibussowitsch PetscCall(PetscHSetIJDestroy(&ht)); 31039566063dSJacob Faibussowitsch PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL)); 31049566063dSJacob Faibussowitsch PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE)); 31059566063dSJacob Faibussowitsch PetscCall(PetscFree2(dnz, onz)); 3106bd041c0cSMatthew G. Knepley for (field = 0; field < Nf; ++field) { 3107bd041c0cSMatthew G. Knepley PetscObject obj; 3108bd041c0cSMatthew G. Knepley PetscClassId id; 3109ef0bb6c7SMatthew G. Knepley PetscTabulation T, Tfine; 3110bd041c0cSMatthew G. Knepley PetscQuadrature quad; 3111bd041c0cSMatthew G. Knepley const PetscReal *qpoints, *qweights; 3112bd041c0cSMatthew G. Knepley PetscInt Nq, Nc, i, d; 3113bd041c0cSMatthew G. Knepley 31149566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 31159566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 3116ef0bb6c7SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 31179566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad)); 31189566063dSJacob Faibussowitsch PetscCall(PetscFEGetCellTabulation((PetscFE)obj, 1, &Tfine)); 31199566063dSJacob Faibussowitsch PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, 1, x, 0, &T)); 3120ef0bb6c7SMatthew G. Knepley } else { 31219566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad)); 3122ef0bb6c7SMatthew G. Knepley } 31239566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights)); 3124bd041c0cSMatthew G. Knepley /* For each fine grid cell */ 3125bd041c0cSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 3126bd041c0cSMatthew G. Knepley Vec pointVec; 3127bd041c0cSMatthew G. Knepley PetscScalar *pV; 3128bd041c0cSMatthew G. Knepley PetscSF coarseCellSF = NULL; 3129bd041c0cSMatthew G. Knepley const PetscSFNode *coarseCells; 3130bd041c0cSMatthew G. Knepley PetscInt numCoarseCells, cpdim, q, c, j; 3131bd041c0cSMatthew G. Knepley PetscInt *findices, *cindices; 3132bd041c0cSMatthew G. Knepley PetscInt numFIndices, numCIndices; 3133bd041c0cSMatthew G. Knepley 31349566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 31359566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 3136bd041c0cSMatthew G. Knepley /* Get points from the quadrature */ 31379566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec)); 31389566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 31399566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 3140bd041c0cSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 3141c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3142c330f8ffSToby Isaac 3143bd041c0cSMatthew G. Knepley /* Transform point to real space */ 3144c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 3145bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 3146bd041c0cSMatthew G. Knepley } 31479566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 3148bd041c0cSMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 31499566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 3150bd041c0cSMatthew G. Knepley /* Update matrix */ 31519566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 31525f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 31539566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 3154bd041c0cSMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 3155bd041c0cSMatthew G. Knepley PetscReal pVReal[3]; 3156c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3157c330f8ffSToby Isaac 31589566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3159bd041c0cSMatthew G. Knepley /* Transform points from real space to coarse reference space */ 31609566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc)); 3161bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]); 3162c330f8ffSToby Isaac CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 3163bd041c0cSMatthew G. Knepley 3164bd041c0cSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 3165bd041c0cSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 3166bd041c0cSMatthew G. Knepley 3167bd041c0cSMatthew G. Knepley /* Evaluate coarse basis on contained point */ 31689566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cpdim)); 31699566063dSJacob Faibussowitsch PetscCall(PetscFEComputeTabulation(fe, 1, x, 0, T)); 3170bd041c0cSMatthew G. Knepley /* Get elemMat entries by multiplying by weight */ 3171bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 31729566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 3173bd041c0cSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3174ef0bb6c7SMatthew 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; 3175bd041c0cSMatthew G. Knepley } 3176bd041c0cSMatthew G. Knepley /* Update interpolator */ 31779566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 317863a3b9bcSJacob Faibussowitsch PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim); 31799566063dSJacob Faibussowitsch PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES)); 3180bd041c0cSMatthew G. Knepley } 3181bd041c0cSMatthew G. Knepley } else { 3182bd041c0cSMatthew G. Knepley cpdim = 1; 3183bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 31849566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 3185bd041c0cSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3186bd041c0cSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * 1.0 * qweights[ccell * Nc + c] * detJ; 3187bd041c0cSMatthew G. Knepley } 3188bd041c0cSMatthew G. Knepley /* Update interpolator */ 31899566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 319063a3b9bcSJacob 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)); 319163a3b9bcSJacob Faibussowitsch PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim); 31929566063dSJacob Faibussowitsch PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES)); 3193bd041c0cSMatthew G. Knepley } 3194bd041c0cSMatthew G. Knepley } 31959566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3196bd041c0cSMatthew G. Knepley } 31979566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 31989566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 31999566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 32009566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3201bd041c0cSMatthew G. Knepley } 32029566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T)); 3203bd041c0cSMatthew G. Knepley } 32049566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0, J, invJ)); 32059566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0c, Jc, invJc)); 32069566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 32079566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY)); 32089566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY)); 32093ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3210bd041c0cSMatthew G. Knepley } 3211bd041c0cSMatthew G. Knepley 3212bd041c0cSMatthew G. Knepley /*@ 321346fa42a0SMatthew G. Knepley DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns 321446fa42a0SMatthew G. Knepley 321546fa42a0SMatthew G. Knepley Input Parameters: 321646fa42a0SMatthew G. Knepley + dmc - The coarse mesh 321760225df5SJacob Faibussowitsch . dmf - The fine mesh 321846fa42a0SMatthew G. Knepley - user - The user context 321946fa42a0SMatthew G. Knepley 322046fa42a0SMatthew G. Knepley Output Parameter: 322146fa42a0SMatthew G. Knepley . sc - The mapping 322246fa42a0SMatthew G. Knepley 322346fa42a0SMatthew G. Knepley Level: developer 322446fa42a0SMatthew G. Knepley 32251cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeJacobianFEM()` 322646fa42a0SMatthew G. Knepley @*/ 3227d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user) 3228d71ae5a4SJacob Faibussowitsch { 3229e9d4ef1bSMatthew G. Knepley PetscDS prob; 32307c927364SMatthew G. Knepley PetscFE *feRef; 323197c42addSMatthew G. Knepley PetscFV *fvRef; 32327c927364SMatthew G. Knepley Vec fv, cv; 32337c927364SMatthew G. Knepley IS fis, cis; 32347c927364SMatthew G. Knepley PetscSection fsection, fglobalSection, csection, cglobalSection; 32357c927364SMatthew G. Knepley PetscInt *cmap, *cellCIndices, *cellFIndices, *cindices, *findices; 3236485ad865SMatthew G. Knepley PetscInt cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, c, dim, d, startC, endC, offsetC, offsetF, m; 32376f3d3cbcSMatthew G. Knepley PetscBool *needAvg; 32387c927364SMatthew G. Knepley 32397c927364SMatthew G. Knepley PetscFunctionBegin; 32409566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InjectorFEM, dmc, dmf, 0, 0)); 32419566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dmf, &dim)); 32429566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 32439566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &fglobalSection)); 32449566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 32459566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &cglobalSection)); 32469566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(fsection, &Nf)); 32479566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd)); 32489566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 32499566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(Nf, &feRef, Nf, &fvRef, Nf, &needAvg)); 32507c927364SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 325197c42addSMatthew G. Knepley PetscObject obj; 325297c42addSMatthew G. Knepley PetscClassId id; 3253aa7890ccSMatthew G. Knepley PetscInt fNb = 0, Nc = 0; 32547c927364SMatthew G. Knepley 32559566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 32569566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 325797c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 325897c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 32596f3d3cbcSMatthew G. Knepley PetscSpace sp; 32609b2fc754SMatthew G. Knepley PetscInt maxDegree; 326197c42addSMatthew G. Knepley 32629566063dSJacob Faibussowitsch PetscCall(PetscFERefine(fe, &feRef[f])); 32639566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feRef[f], &fNb)); 32649566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 32659566063dSJacob Faibussowitsch PetscCall(PetscFEGetBasisSpace(fe, &sp)); 32669566063dSJacob Faibussowitsch PetscCall(PetscSpaceGetDegree(sp, NULL, &maxDegree)); 32679b2fc754SMatthew G. Knepley if (!maxDegree) needAvg[f] = PETSC_TRUE; 326897c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 326997c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 327097c42addSMatthew G. Knepley PetscDualSpace Q; 327197c42addSMatthew G. Knepley 32729566063dSJacob Faibussowitsch PetscCall(PetscFVRefine(fv, &fvRef[f])); 32739566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[f], &Q)); 32749566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &fNb)); 32759566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 32766f3d3cbcSMatthew G. Knepley needAvg[f] = PETSC_TRUE; 327797c42addSMatthew G. Knepley } 3278d172c84bSMatthew G. Knepley fTotDim += fNb; 32797c927364SMatthew G. Knepley } 32809566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &cTotDim)); 32819566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(cTotDim, &cmap)); 32827c927364SMatthew G. Knepley for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) { 32837c927364SMatthew G. Knepley PetscFE feC; 328497c42addSMatthew G. Knepley PetscFV fvC; 32857c927364SMatthew G. Knepley PetscDualSpace QF, QC; 3286d172c84bSMatthew G. Knepley PetscInt order = -1, NcF, NcC, fpdim, cpdim; 32877c927364SMatthew G. Knepley 328897c42addSMatthew G. Knepley if (feRef[field]) { 32899566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&feC)); 32909566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feC, &NcC)); 32919566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feRef[field], &NcF)); 32929566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feRef[field], &QF)); 32939566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetOrder(QF, &order)); 32949566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QF, &fpdim)); 32959566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feC, &QC)); 32969566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QC, &cpdim)); 329797c42addSMatthew G. Knepley } else { 32989566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fvC)); 32999566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvC, &NcC)); 33009566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvRef[field], &NcF)); 33019566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[field], &QF)); 33029566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QF, &fpdim)); 33039566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvC, &QC)); 33049566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QC, &cpdim)); 330597c42addSMatthew G. Knepley } 330663a3b9bcSJacob 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); 33077c927364SMatthew G. Knepley for (c = 0; c < cpdim; ++c) { 33087c927364SMatthew G. Knepley PetscQuadrature cfunc; 3309d172c84bSMatthew G. Knepley const PetscReal *cqpoints, *cqweights; 3310d172c84bSMatthew G. Knepley PetscInt NqcC, NpC; 331197c42addSMatthew G. Knepley PetscBool found = PETSC_FALSE; 33127c927364SMatthew G. Knepley 33139566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(QC, c, &cfunc)); 33149566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights)); 331563a3b9bcSJacob 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); 33161dca8a05SBarry Smith PetscCheck(NpC == 1 || !feRef[field], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments"); 33177c927364SMatthew G. Knepley for (f = 0; f < fpdim; ++f) { 33187c927364SMatthew G. Knepley PetscQuadrature ffunc; 3319d172c84bSMatthew G. Knepley const PetscReal *fqpoints, *fqweights; 33207c927364SMatthew G. Knepley PetscReal sum = 0.0; 3321d172c84bSMatthew G. Knepley PetscInt NqcF, NpF; 33227c927364SMatthew G. Knepley 33239566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(QF, f, &ffunc)); 33249566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights)); 332563a3b9bcSJacob 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); 33267c927364SMatthew G. Knepley if (NpC != NpF) continue; 33277c927364SMatthew G. Knepley for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]); 33287c927364SMatthew G. Knepley if (sum > 1.0e-9) continue; 3329d172c84bSMatthew G. Knepley for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d] * fqweights[d]); 3330d172c84bSMatthew G. Knepley if (sum < 1.0e-9) continue; 3331d172c84bSMatthew G. Knepley cmap[offsetC + c] = offsetF + f; 333297c42addSMatthew G. Knepley found = PETSC_TRUE; 33337c927364SMatthew G. Knepley break; 33347c927364SMatthew G. Knepley } 333597c42addSMatthew G. Knepley if (!found) { 333697c42addSMatthew G. Knepley /* TODO We really want the average here, but some asshole put VecScatter in the interface */ 3337d172c84bSMatthew G. Knepley if (fvRef[field] || (feRef[field] && order == 0)) { 3338d172c84bSMatthew G. Knepley cmap[offsetC + c] = offsetF + 0; 333997c42addSMatthew G. Knepley } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection"); 334097c42addSMatthew G. Knepley } 33417c927364SMatthew G. Knepley } 3342d172c84bSMatthew G. Knepley offsetC += cpdim; 3343d172c84bSMatthew G. Knepley offsetF += fpdim; 33447c927364SMatthew G. Knepley } 33459371c9d4SSatish Balay for (f = 0; f < Nf; ++f) { 33469371c9d4SSatish Balay PetscCall(PetscFEDestroy(&feRef[f])); 33479371c9d4SSatish Balay PetscCall(PetscFVDestroy(&fvRef[f])); 33489371c9d4SSatish Balay } 33499566063dSJacob Faibussowitsch PetscCall(PetscFree3(feRef, fvRef, needAvg)); 33507c927364SMatthew G. Knepley 33519566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmf, &fv)); 33529566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmc, &cv)); 33539566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(cv, &startC, &endC)); 33549566063dSJacob Faibussowitsch PetscCall(PetscSectionGetConstrainedStorageSize(cglobalSection, &m)); 33559566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(cTotDim, &cellCIndices, fTotDim, &cellFIndices)); 33569566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &cindices)); 33579566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &findices)); 33587c927364SMatthew G. Knepley for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1; 33597c927364SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 33609566063dSJacob Faibussowitsch PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices)); 33617c927364SMatthew G. Knepley for (d = 0; d < cTotDim; ++d) { 33620bd915a7SMatthew G. Knepley if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue; 336363a3b9bcSJacob Faibussowitsch PetscCheck(!(findices[cellCIndices[d] - startC] >= 0) || !(findices[cellCIndices[d] - startC] != cellFIndices[cmap[d]]), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Coarse dof %" PetscInt_FMT " maps to both %" PetscInt_FMT " and %" PetscInt_FMT, cindices[cellCIndices[d] - startC], findices[cellCIndices[d] - startC], cellFIndices[cmap[d]]); 33647c927364SMatthew G. Knepley cindices[cellCIndices[d] - startC] = cellCIndices[d]; 33657c927364SMatthew G. Knepley findices[cellCIndices[d] - startC] = cellFIndices[cmap[d]]; 33667c927364SMatthew G. Knepley } 33677c927364SMatthew G. Knepley } 33689566063dSJacob Faibussowitsch PetscCall(PetscFree(cmap)); 33699566063dSJacob Faibussowitsch PetscCall(PetscFree2(cellCIndices, cellFIndices)); 33707c927364SMatthew G. Knepley 33719566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis)); 33729566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis)); 33739566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(cv, cis, fv, fis, sc)); 33749566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cis)); 33759566063dSJacob Faibussowitsch PetscCall(ISDestroy(&fis)); 33769566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmf, &fv)); 33779566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmc, &cv)); 33789566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InjectorFEM, dmc, dmf, 0, 0)); 33793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3380cb1e1211SMatthew G Knepley } 3381a1cf66bbSMatthew G. Knepley 33822f856554SMatthew G. Knepley /*@C 33832f856554SMatthew G. Knepley DMPlexGetCellFields - Retrieve the field values values for a chunk of cells 33842f856554SMatthew G. Knepley 33852f856554SMatthew G. Knepley Input Parameters: 3386a1cb98faSBarry Smith + dm - The `DM` 33872f856554SMatthew G. Knepley . cellIS - The cells to include 33882f856554SMatthew G. Knepley . locX - A local vector with the solution fields 33892f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 33902f856554SMatthew G. Knepley - locA - A local vector with auxiliary fields, or NULL 33912f856554SMatthew G. Knepley 33922f856554SMatthew G. Knepley Output Parameters: 33932f856554SMatthew G. Knepley + u - The field coefficients 33942f856554SMatthew G. Knepley . u_t - The fields derivative coefficients 33952f856554SMatthew G. Knepley - a - The auxiliary field coefficients 33962f856554SMatthew G. Knepley 33972f856554SMatthew G. Knepley Level: developer 33982f856554SMatthew G. Knepley 33991cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 34002f856554SMatthew G. Knepley @*/ 3401d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3402d71ae5a4SJacob Faibussowitsch { 34032f856554SMatthew G. Knepley DM plex, plexA = NULL; 3404a6e0b375SMatthew G. Knepley DMEnclosureType encAux; 34052f856554SMatthew G. Knepley PetscSection section, sectionAux; 34062f856554SMatthew G. Knepley PetscDS prob; 34072f856554SMatthew G. Knepley const PetscInt *cells; 34082f856554SMatthew G. Knepley PetscInt cStart, cEnd, numCells, totDim, totDimAux, c; 34092f856554SMatthew G. Knepley 34102f856554SMatthew G. Knepley PetscFunctionBegin; 34112f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3412064a246eSJacob Faibussowitsch PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 3413ad540459SPierre Jolivet if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 4); 3414ad540459SPierre Jolivet if (locA) PetscValidHeaderSpecific(locA, VEC_CLASSID, 5); 34154f572ea9SToby Isaac PetscAssertPointer(u, 6); 34164f572ea9SToby Isaac PetscAssertPointer(u_t, 7); 34174f572ea9SToby Isaac PetscAssertPointer(a, 8); 34189566063dSJacob Faibussowitsch PetscCall(DMPlexConvertPlex(dm, &plex, PETSC_FALSE)); 34199566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 34209566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 342107218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL)); 34229566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 34232f856554SMatthew G. Knepley if (locA) { 34242f856554SMatthew G. Knepley DM dmAux; 34252f856554SMatthew G. Knepley PetscDS probAux; 34262f856554SMatthew G. Knepley 34279566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 34289566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 34299566063dSJacob Faibussowitsch PetscCall(DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE)); 34309566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 34319566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 34329566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 34332f856554SMatthew G. Knepley } 34342f856554SMatthew G. Knepley numCells = cEnd - cStart; 34359566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u)); 34369371c9d4SSatish Balay if (locX_t) PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u_t)); 3437ad540459SPierre Jolivet else *u_t = NULL; 34389371c9d4SSatish Balay if (locA) PetscCall(DMGetWorkArray(dm, numCells * totDimAux, MPIU_SCALAR, a)); 3439ad540459SPierre Jolivet else *a = NULL; 34402f856554SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 34412f856554SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 34422f856554SMatthew G. Knepley const PetscInt cind = c - cStart; 34432f856554SMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a; 34442f856554SMatthew G. Knepley PetscInt i; 34452f856554SMatthew G. Knepley 34469566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x)); 34472f856554SMatthew G. Knepley for (i = 0; i < totDim; ++i) ul[cind * totDim + i] = x[i]; 34489566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x)); 34492f856554SMatthew G. Knepley if (locX_t) { 34509566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t)); 34512f856554SMatthew G. Knepley for (i = 0; i < totDim; ++i) ul_t[cind * totDim + i] = x_t[i]; 34529566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t)); 34532f856554SMatthew G. Knepley } 34542f856554SMatthew G. Knepley if (locA) { 34552f856554SMatthew G. Knepley PetscInt subcell; 34569566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell)); 34579566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x)); 34582f856554SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) al[cind * totDimAux + i] = x[i]; 34599566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x)); 34602f856554SMatthew G. Knepley } 34612f856554SMatthew G. Knepley } 34629566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 34639566063dSJacob Faibussowitsch if (locA) PetscCall(DMDestroy(&plexA)); 34649566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 34653ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 34662f856554SMatthew G. Knepley } 34672f856554SMatthew G. Knepley 34682f856554SMatthew G. Knepley /*@C 34692f856554SMatthew G. Knepley DMPlexRestoreCellFields - Restore the field values values for a chunk of cells 34702f856554SMatthew G. Knepley 34712f856554SMatthew G. Knepley Input Parameters: 3472a1cb98faSBarry Smith + dm - The `DM` 34732f856554SMatthew G. Knepley . cellIS - The cells to include 34742f856554SMatthew G. Knepley . locX - A local vector with the solution fields 34752f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 34762f856554SMatthew G. Knepley - locA - A local vector with auxiliary fields, or NULL 34772f856554SMatthew G. Knepley 34782f856554SMatthew G. Knepley Output Parameters: 34792f856554SMatthew G. Knepley + u - The field coefficients 34802f856554SMatthew G. Knepley . u_t - The fields derivative coefficients 34812f856554SMatthew G. Knepley - a - The auxiliary field coefficients 34822f856554SMatthew G. Knepley 34832f856554SMatthew G. Knepley Level: developer 34842f856554SMatthew G. Knepley 34851cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 34862f856554SMatthew G. Knepley @*/ 3487d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3488d71ae5a4SJacob Faibussowitsch { 34892f856554SMatthew G. Knepley PetscFunctionBegin; 34909566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u)); 34919566063dSJacob Faibussowitsch if (locX_t) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t)); 34929566063dSJacob Faibussowitsch if (locA) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a)); 34933ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 34942f856554SMatthew G. Knepley } 34952f856554SMatthew G. Knepley 3496a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexGetHybridCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3497d71ae5a4SJacob Faibussowitsch { 349807218a29SMatthew G. Knepley DM plex, plexA = NULL; 349907218a29SMatthew G. Knepley DMEnclosureType encAux; 350007218a29SMatthew G. Knepley PetscSection section, sectionAux; 350107218a29SMatthew G. Knepley PetscDS ds, dsIn; 35026528b96dSMatthew G. Knepley const PetscInt *cells; 350307218a29SMatthew G. Knepley PetscInt cStart, cEnd, numCells, c, totDim, totDimAux, Nf, f; 35046528b96dSMatthew G. Knepley 35056528b96dSMatthew G. Knepley PetscFunctionBegin; 350607218a29SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 350707218a29SMatthew G. Knepley PetscValidHeaderSpecific(cellIS, IS_CLASSID, 2); 350807218a29SMatthew G. Knepley PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 350907218a29SMatthew G. Knepley if (locX_t) { PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 4); } 351007218a29SMatthew G. Knepley if (locA) { PetscValidHeaderSpecific(locA, VEC_CLASSID, 5); } 35114f572ea9SToby Isaac PetscAssertPointer(u, 6); 35124f572ea9SToby Isaac PetscAssertPointer(u_t, 7); 35134f572ea9SToby Isaac PetscAssertPointer(a, 8); 351407218a29SMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 351507218a29SMatthew G. Knepley numCells = cEnd - cStart; 351607218a29SMatthew G. Knepley PetscCall(DMPlexConvertPlex(dm, &plex, PETSC_FALSE)); 351707218a29SMatthew G. Knepley PetscCall(DMGetLocalSection(dm, §ion)); 351807218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn)); 351907218a29SMatthew G. Knepley PetscCall(PetscDSGetNumFields(dsIn, &Nf)); 352007218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsIn, &totDim)); 352107218a29SMatthew G. Knepley if (locA) { 352207218a29SMatthew G. Knepley DM dmAux; 352307218a29SMatthew G. Knepley PetscDS probAux; 352407218a29SMatthew G. Knepley 352507218a29SMatthew G. Knepley PetscCall(VecGetDM(locA, &dmAux)); 352607218a29SMatthew G. Knepley PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 352707218a29SMatthew G. Knepley PetscCall(DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE)); 352807218a29SMatthew G. Knepley PetscCall(DMGetLocalSection(dmAux, §ionAux)); 352907218a29SMatthew G. Knepley PetscCall(DMGetDS(dmAux, &probAux)); 353007218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 353107218a29SMatthew G. Knepley } 353207218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u)); 353307218a29SMatthew G. Knepley if (locX_t) PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u_t)); 353407218a29SMatthew G. Knepley else { 353507218a29SMatthew G. Knepley *u_t = NULL; 353607218a29SMatthew G. Knepley } 353707218a29SMatthew G. Knepley if (locA) PetscCall(DMGetWorkArray(dm, numCells * totDimAux, MPIU_SCALAR, a)); 353807218a29SMatthew G. Knepley else { 353907218a29SMatthew G. Knepley *a = NULL; 354007218a29SMatthew G. Knepley } 354107218a29SMatthew G. Knepley // Loop over cohesive cells 354207218a29SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 354307218a29SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 354407218a29SMatthew G. Knepley const PetscInt cind = c - cStart; 354574a0c561SMatthew G. Knepley PetscScalar *xf = NULL, *xc = NULL, *x = NULL, *xf_t = NULL, *xc_t = NULL; 354674a0c561SMatthew G. Knepley PetscScalar *ul = &(*u)[cind * totDim], *ul_t = u_t ? &(*u_t)[cind * totDim] : NULL; 354707218a29SMatthew G. Knepley const PetscInt *cone, *ornt; 354807218a29SMatthew G. Knepley PetscInt Nx = 0, Nxf, s; 354907218a29SMatthew G. Knepley 355007218a29SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cell, &cone)); 355107218a29SMatthew G. Knepley PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt)); 355207218a29SMatthew G. Knepley // Put in cohesive unknowns 355307218a29SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, &Nxf, &xf)); 355474a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &xf_t)); 355507218a29SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 355607218a29SMatthew G. Knepley PetscInt fdofIn, foff, foffIn; 355707218a29SMatthew G. Knepley PetscBool cohesive; 355807218a29SMatthew G. Knepley 355907218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(dsIn, f, &cohesive)); 356007218a29SMatthew G. Knepley if (!cohesive) continue; 356107218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsIn, f, &fdofIn)); 356207218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldOffsetCohesive(ds, f, &foff)); 356307218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldOffsetCohesive(dsIn, f, &foffIn)); 356407218a29SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul[foffIn + i] = xf[foff + i]; 356574a0c561SMatthew G. Knepley if (locX_t) 356674a0c561SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul_t[foffIn + i] = xf_t[foff + i]; 356707218a29SMatthew G. Knepley Nx += fdofIn; 356807218a29SMatthew G. Knepley } 356907218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, &Nxf, &xf)); 357074a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &xf_t)); 357107218a29SMatthew G. Knepley // Loop over sides of surface 357207218a29SMatthew G. Knepley for (s = 0; s < 2; ++s) { 357307218a29SMatthew G. Knepley const PetscInt *support; 357407218a29SMatthew G. Knepley const PetscInt face = cone[s]; 357507218a29SMatthew G. Knepley PetscInt ssize, ncell, Nxc; 357607218a29SMatthew G. Knepley 357707218a29SMatthew G. Knepley // I don't think I need the face to have 0 orientation in the hybrid cell 357807218a29SMatthew 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]); 357907218a29SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, face, &support)); 358007218a29SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, face, &ssize)); 358107218a29SMatthew G. Knepley if (support[0] == cell) ncell = support[1]; 358207218a29SMatthew G. Knepley else if (support[1] == cell) ncell = support[0]; 358307218a29SMatthew 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); 358407218a29SMatthew G. Knepley // Get closure of both face and cell, stick in cell for normal fields and face for cohesive fields 358507218a29SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plex, section, locX, ncell, &Nxc, &xc)); 358674a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecGetClosure(plex, section, locX_t, ncell, NULL, &xc_t)); 358707218a29SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 358807218a29SMatthew G. Knepley PetscInt fdofIn, foffIn; 358907218a29SMatthew G. Knepley PetscBool cohesive; 359007218a29SMatthew G. Knepley 359107218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(dsIn, f, &cohesive)); 359207218a29SMatthew G. Knepley if (cohesive) continue; 359307218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsIn, f, &fdofIn)); 359407218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldOffsetCohesive(dsIn, f, &foffIn)); 359507218a29SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul[foffIn + s * fdofIn + i] = xc[foffIn + i]; 359674a0c561SMatthew G. Knepley if (locX_t) 359774a0c561SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul_t[foffIn + s * fdofIn + i] = xc_t[foffIn + i]; 359807218a29SMatthew G. Knepley Nx += fdofIn; 359907218a29SMatthew G. Knepley } 360007218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plex, section, locX, ncell, &Nxc, &xc)); 360174a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, ncell, NULL, &xc_t)); 360207218a29SMatthew G. Knepley } 360307218a29SMatthew 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); 360407218a29SMatthew G. Knepley 360507218a29SMatthew G. Knepley if (locA) { 360607218a29SMatthew G. Knepley PetscScalar *al = &(*a)[cind * totDimAux]; 360707218a29SMatthew G. Knepley PetscInt subcell; 360807218a29SMatthew G. Knepley 360907218a29SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell)); 361007218a29SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, &Nx, &x)); 361107218a29SMatthew 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); 361207218a29SMatthew G. Knepley for (PetscInt i = 0; i < totDimAux; ++i) al[i] = x[i]; 361307218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, &Nx, &x)); 361407218a29SMatthew G. Knepley } 361507218a29SMatthew G. Knepley } 361607218a29SMatthew G. Knepley PetscCall(DMDestroy(&plex)); 361707218a29SMatthew G. Knepley PetscCall(DMDestroy(&plexA)); 361807218a29SMatthew G. Knepley PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 361907218a29SMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 362007218a29SMatthew G. Knepley } 362107218a29SMatthew G. Knepley 362207218a29SMatthew G. Knepley /* 36233e2b0218SMatthew G. Knepley DMPlexGetHybridFields - Get the field values for the negative side (s = 0) and positive side (s = 1) of the interface 362407218a29SMatthew G. Knepley 362507218a29SMatthew G. Knepley Input Parameters: 362607218a29SMatthew G. Knepley + dm - The full domain DM 362707218a29SMatthew G. Knepley . dmX - An array of DM for the field, say an auxiliary DM, indexed by s 362807218a29SMatthew G. Knepley . dsX - An array of PetscDS for the field, indexed by s 362907218a29SMatthew G. Knepley . cellIS - The interface cells for which we want values 363007218a29SMatthew G. Knepley . locX - An array of local vectors with the field values, indexed by s 363107218a29SMatthew G. Knepley - useCell - Flag to have values come from neighboring cell rather than endcap face 363207218a29SMatthew G. Knepley 363307218a29SMatthew G. Knepley Output Parameter: 363407218a29SMatthew G. Knepley . x - An array of field values, indexed by s 363507218a29SMatthew G. Knepley 363607218a29SMatthew G. Knepley Note: 363776fbde31SPierre Jolivet The arrays in `x` will be allocated using `DMGetWorkArray()`, and must be returned using `DMPlexRestoreHybridFields()`. 363807218a29SMatthew G. Knepley 363907218a29SMatthew G. Knepley Level: advanced 364007218a29SMatthew G. Knepley 364176fbde31SPierre Jolivet .seealso: `DMPlexRestoreHybridFields()`, `DMGetWorkArray()` 364207218a29SMatthew G. Knepley */ 364307218a29SMatthew G. Knepley static PetscErrorCode DMPlexGetHybridFields(DM dm, DM dmX[], PetscDS dsX[], IS cellIS, Vec locX[], PetscBool useCell, PetscScalar *x[]) 364407218a29SMatthew G. Knepley { 364507218a29SMatthew G. Knepley DM plexX[2]; 364607218a29SMatthew G. Knepley DMEnclosureType encX[2]; 364707218a29SMatthew G. Knepley PetscSection sectionX[2]; 364807218a29SMatthew G. Knepley const PetscInt *cells; 364907218a29SMatthew G. Knepley PetscInt cStart, cEnd, numCells, c, s, totDimX[2]; 365007218a29SMatthew G. Knepley 365107218a29SMatthew G. Knepley PetscFunctionBegin; 36524f572ea9SToby Isaac PetscAssertPointer(locX, 5); 365307218a29SMatthew G. Knepley if (!locX[0] || !locX[1]) PetscFunctionReturn(PETSC_SUCCESS); 36544f572ea9SToby Isaac PetscAssertPointer(dmX, 2); 36554f572ea9SToby Isaac PetscAssertPointer(dsX, 3); 365607218a29SMatthew G. Knepley PetscValidHeaderSpecific(cellIS, IS_CLASSID, 4); 36574f572ea9SToby Isaac PetscAssertPointer(x, 7); 36589566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 36596528b96dSMatthew G. Knepley numCells = cEnd - cStart; 3660148442b3SMatthew G. Knepley for (s = 0; s < 2; ++s) { 366107218a29SMatthew G. Knepley PetscValidHeaderSpecific(dmX[s], DM_CLASSID, 2); 366207218a29SMatthew G. Knepley PetscValidHeaderSpecific(dsX[s], PETSCDS_CLASSID, 3); 366307218a29SMatthew G. Knepley PetscValidHeaderSpecific(locX[s], VEC_CLASSID, 5); 366407218a29SMatthew G. Knepley PetscCall(DMPlexConvertPlex(dmX[s], &plexX[s], PETSC_FALSE)); 366507218a29SMatthew G. Knepley PetscCall(DMGetEnclosureRelation(dmX[s], dm, &encX[s])); 366607218a29SMatthew G. Knepley PetscCall(DMGetLocalSection(dmX[s], §ionX[s])); 366707218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsX[s], &totDimX[s])); 366807218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dmX[s], numCells * totDimX[s], MPIU_SCALAR, &x[s])); 366904c51a94SMatthew G. Knepley } 3670148442b3SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 36716528b96dSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 36726528b96dSMatthew G. Knepley const PetscInt cind = c - cStart; 36736528b96dSMatthew G. Knepley const PetscInt *cone, *ornt; 36746528b96dSMatthew G. Knepley 36759566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cell, &cone)); 36769566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt)); 367707218a29SMatthew 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]); 3678148442b3SMatthew G. Knepley for (s = 0; s < 2; ++s) { 367907218a29SMatthew G. Knepley const PetscInt tdX = totDimX[s]; 368007218a29SMatthew G. Knepley PetscScalar *closure = NULL, *xl = &x[s][cind * tdX]; 368107218a29SMatthew G. Knepley PetscInt face = cone[s], point = face, subpoint, Nx, i; 368207218a29SMatthew G. Knepley 368307218a29SMatthew G. Knepley if (useCell) { 36845fedec97SMatthew G. Knepley const PetscInt *support; 368507218a29SMatthew G. Knepley PetscInt ssize; 36866528b96dSMatthew G. Knepley 368707218a29SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, face, &support)); 368807218a29SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, face, &ssize)); 368907218a29SMatthew 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); 369007218a29SMatthew G. Knepley if (support[0] == cell) point = support[1]; 369107218a29SMatthew G. Knepley else if (support[1] == cell) point = support[0]; 369207218a29SMatthew 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); 369307218a29SMatthew G. Knepley } 369407218a29SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(plexX[s], dm, encX[s], point, &subpoint)); 3695*e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(plexX[s], sectionX[s], PETSC_FALSE, locX[s], subpoint, ornt[s], &Nx, &closure)); 369607218a29SMatthew 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); 369707218a29SMatthew G. Knepley for (i = 0; i < Nx; ++i) xl[i] = closure[i]; 369807218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plexX[s], sectionX[s], locX[s], subpoint, &Nx, &closure)); 36996528b96dSMatthew G. Knepley } 37006528b96dSMatthew G. Knepley } 370107218a29SMatthew G. Knepley for (s = 0; s < 2; ++s) PetscCall(DMDestroy(&plexX[s])); 37029566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 37033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 37046528b96dSMatthew G. Knepley } 37056528b96dSMatthew G. Knepley 370607218a29SMatthew G. Knepley static PetscErrorCode DMPlexRestoreHybridFields(DM dm, DM dmX[], PetscDS dsX[], IS cellIS, Vec locX[], PetscBool useCell, PetscScalar *x[]) 3707d71ae5a4SJacob Faibussowitsch { 37086528b96dSMatthew G. Knepley PetscFunctionBegin; 370907218a29SMatthew G. Knepley if (!locX[0] || !locX[1]) PetscFunctionReturn(PETSC_SUCCESS); 371007218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dmX[0], 0, MPIU_SCALAR, &x[0])); 371107218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dmX[1], 0, MPIU_SCALAR, &x[1])); 37123ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 37136528b96dSMatthew G. Knepley } 37146528b96dSMatthew G. Knepley 37152f856554SMatthew G. Knepley /*@C 37162f856554SMatthew G. Knepley DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces 37172f856554SMatthew G. Knepley 37182f856554SMatthew G. Knepley Input Parameters: 3719a1cb98faSBarry Smith + dm - The `DM` 37202f856554SMatthew G. Knepley . fStart - The first face to include 37212f856554SMatthew G. Knepley . fEnd - The first face to exclude 37222f856554SMatthew G. Knepley . locX - A local vector with the solution fields 37232f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 37242f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 37252f856554SMatthew G. Knepley . cellGeometry - A local vector with cell geometry 372660225df5SJacob Faibussowitsch - locGrad - A local vector with field gradients, or NULL 37272f856554SMatthew G. Knepley 37282f856554SMatthew G. Knepley Output Parameters: 37292f856554SMatthew G. Knepley + Nface - The number of faces with field values 37302f856554SMatthew G. Knepley . uL - The field values at the left side of the face 37312f856554SMatthew G. Knepley - uR - The field values at the right side of the face 37322f856554SMatthew G. Knepley 37332f856554SMatthew G. Knepley Level: developer 37342f856554SMatthew G. Knepley 37351cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()` 37362f856554SMatthew G. Knepley @*/ 3737d71ae5a4SJacob 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) 3738d71ae5a4SJacob Faibussowitsch { 37392f856554SMatthew G. Knepley DM dmFace, dmCell, dmGrad = NULL; 37402f856554SMatthew G. Knepley PetscSection section; 37412f856554SMatthew G. Knepley PetscDS prob; 37422f856554SMatthew G. Knepley DMLabel ghostLabel; 37432f856554SMatthew G. Knepley const PetscScalar *facegeom, *cellgeom, *x, *lgrad; 37442f856554SMatthew G. Knepley PetscBool *isFE; 37452f856554SMatthew G. Knepley PetscInt dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face; 37462f856554SMatthew G. Knepley 37472f856554SMatthew G. Knepley PetscFunctionBegin; 37482f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 37492f856554SMatthew G. Knepley PetscValidHeaderSpecific(locX, VEC_CLASSID, 4); 3750ad540459SPierre Jolivet if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 5); 37512f856554SMatthew G. Knepley PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 6); 37522f856554SMatthew G. Knepley PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 7); 3753ad540459SPierre Jolivet if (locGrad) PetscValidHeaderSpecific(locGrad, VEC_CLASSID, 8); 37544f572ea9SToby Isaac PetscAssertPointer(uL, 10); 37554f572ea9SToby Isaac PetscAssertPointer(uR, 11); 37569566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 37579566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 37589566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 37599566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 37609566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalComponents(prob, &Nc)); 37619566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nf, &isFE)); 37622f856554SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 37632f856554SMatthew G. Knepley PetscObject obj; 37642f856554SMatthew G. Knepley PetscClassId id; 37652f856554SMatthew G. Knepley 37669566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 37679566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 37689371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 37699371c9d4SSatish Balay isFE[f] = PETSC_TRUE; 37709371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 37719371c9d4SSatish Balay isFE[f] = PETSC_FALSE; 37729371c9d4SSatish Balay } else { 37739371c9d4SSatish Balay isFE[f] = PETSC_FALSE; 37749371c9d4SSatish Balay } 37752f856554SMatthew G. Knepley } 37769566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 37779566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locX, &x)); 37789566063dSJacob Faibussowitsch PetscCall(VecGetDM(faceGeometry, &dmFace)); 37799566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 37809566063dSJacob Faibussowitsch PetscCall(VecGetDM(cellGeometry, &dmCell)); 37819566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 37822f856554SMatthew G. Knepley if (locGrad) { 37839566063dSJacob Faibussowitsch PetscCall(VecGetDM(locGrad, &dmGrad)); 37849566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locGrad, &lgrad)); 37852f856554SMatthew G. Knepley } 37869566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uL)); 37879566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uR)); 37882f856554SMatthew G. Knepley /* Right now just eat the extra work for FE (could make a cell loop) */ 37892f856554SMatthew G. Knepley for (face = fStart, iface = 0; face < fEnd; ++face) { 37902f856554SMatthew G. Knepley const PetscInt *cells; 37912f856554SMatthew G. Knepley PetscFVFaceGeom *fg; 37922f856554SMatthew G. Knepley PetscFVCellGeom *cgL, *cgR; 37932f856554SMatthew G. Knepley PetscScalar *xL, *xR, *gL, *gR; 37942f856554SMatthew G. Knepley PetscScalar *uLl = *uL, *uRl = *uR; 37952f856554SMatthew G. Knepley PetscInt ghost, nsupp, nchild; 37962f856554SMatthew G. Knepley 37979566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 37989566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 37999566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 38002f856554SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 38019566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 38029566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &cells)); 38039566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL)); 38049566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR)); 38052f856554SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 38062f856554SMatthew G. Knepley PetscInt off; 38072f856554SMatthew G. Knepley 38089566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffset(prob, f, &off)); 38092f856554SMatthew G. Knepley if (isFE[f]) { 38102f856554SMatthew G. Knepley const PetscInt *cone; 38112f856554SMatthew G. Knepley PetscInt comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d; 38122f856554SMatthew G. Knepley 38132f856554SMatthew G. Knepley xL = xR = NULL; 38149566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldComponents(section, f, &comp)); 38159566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **)&xL)); 38169566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **)&xR)); 38179566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cells[0], &cone)); 38189566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, cells[0], &coneSizeL)); 38199371c9d4SSatish Balay for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL) 38209371c9d4SSatish Balay if (cone[faceLocL] == face) break; 38219566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cells[1], &cone)); 38229566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, cells[1], &coneSizeR)); 38239371c9d4SSatish Balay for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR) 38249371c9d4SSatish Balay if (cone[faceLocR] == face) break; 38251dca8a05SBarry 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]); 38262f856554SMatthew G. Knepley /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */ 38272f856554SMatthew G. Knepley /* TODO: this is a hack that might not be right for nonconforming */ 38282f856554SMatthew G. Knepley if (faceLocL < coneSizeL) { 38299566063dSJacob Faibussowitsch PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface * Nc + off])); 38309566063dSJacob Faibussowitsch if (rdof == ldof && faceLocR < coneSizeR) PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off])); 38312f856554SMatthew G. Knepley else { 38329371c9d4SSatish Balay for (d = 0; d < comp; ++d) uRl[iface * Nc + off + d] = uLl[iface * Nc + off + d]; 38339371c9d4SSatish Balay } 38349371c9d4SSatish Balay } else { 38359566063dSJacob Faibussowitsch PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off])); 38369566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldComponents(section, f, &comp)); 38372f856554SMatthew G. Knepley for (d = 0; d < comp; ++d) uLl[iface * Nc + off + d] = uRl[iface * Nc + off + d]; 38382f856554SMatthew G. Knepley } 38399566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **)&xL)); 38409566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **)&xR)); 38412f856554SMatthew G. Knepley } else { 38422f856554SMatthew G. Knepley PetscFV fv; 38432f856554SMatthew G. Knepley PetscInt numComp, c; 38442f856554SMatthew G. Knepley 38459566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, (PetscObject *)&fv)); 38469566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &numComp)); 38479566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL)); 38489566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR)); 38492f856554SMatthew G. Knepley if (dmGrad) { 38502f856554SMatthew G. Knepley PetscReal dxL[3], dxR[3]; 38512f856554SMatthew G. Knepley 38529566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL)); 38539566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR)); 38542f856554SMatthew G. Knepley DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL); 38552f856554SMatthew G. Knepley DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR); 38562f856554SMatthew G. Knepley for (c = 0; c < numComp; ++c) { 38572f856554SMatthew G. Knepley uLl[iface * Nc + off + c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c * dim], dxL); 38582f856554SMatthew G. Knepley uRl[iface * Nc + off + c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c * dim], dxR); 38592f856554SMatthew G. Knepley } 38602f856554SMatthew G. Knepley } else { 38612f856554SMatthew G. Knepley for (c = 0; c < numComp; ++c) { 38622f856554SMatthew G. Knepley uLl[iface * Nc + off + c] = xL[c]; 38632f856554SMatthew G. Knepley uRl[iface * Nc + off + c] = xR[c]; 38642f856554SMatthew G. Knepley } 38652f856554SMatthew G. Knepley } 38662f856554SMatthew G. Knepley } 38672f856554SMatthew G. Knepley } 38682f856554SMatthew G. Knepley ++iface; 38692f856554SMatthew G. Knepley } 38702f856554SMatthew G. Knepley *Nface = iface; 38719566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(locX, &x)); 38729566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 38739566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 387448a46eb9SPierre Jolivet if (locGrad) PetscCall(VecRestoreArrayRead(locGrad, &lgrad)); 38759566063dSJacob Faibussowitsch PetscCall(PetscFree(isFE)); 38763ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 38772f856554SMatthew G. Knepley } 38782f856554SMatthew G. Knepley 38792f856554SMatthew G. Knepley /*@C 38802f856554SMatthew G. Knepley DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces 38812f856554SMatthew G. Knepley 38822f856554SMatthew G. Knepley Input Parameters: 3883a1cb98faSBarry Smith + dm - The `DM` 38842f856554SMatthew G. Knepley . fStart - The first face to include 38852f856554SMatthew G. Knepley . fEnd - The first face to exclude 38862f856554SMatthew G. Knepley . locX - A local vector with the solution fields 38872f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 38882f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 38892f856554SMatthew G. Knepley . cellGeometry - A local vector with cell geometry 389060225df5SJacob Faibussowitsch - locGrad - A local vector with field gradients, or NULL 38912f856554SMatthew G. Knepley 38922f856554SMatthew G. Knepley Output Parameters: 38932f856554SMatthew G. Knepley + Nface - The number of faces with field values 38942f856554SMatthew G. Knepley . uL - The field values at the left side of the face 38952f856554SMatthew G. Knepley - uR - The field values at the right side of the face 38962f856554SMatthew G. Knepley 38972f856554SMatthew G. Knepley Level: developer 38982f856554SMatthew G. Knepley 38991cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 39002f856554SMatthew G. Knepley @*/ 3901d71ae5a4SJacob 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) 3902d71ae5a4SJacob Faibussowitsch { 39032f856554SMatthew G. Knepley PetscFunctionBegin; 39049566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL)); 39059566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR)); 39063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 39072f856554SMatthew G. Knepley } 39082f856554SMatthew G. Knepley 39092f856554SMatthew G. Knepley /*@C 39102f856554SMatthew G. Knepley DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces 39112f856554SMatthew G. Knepley 39122f856554SMatthew G. Knepley Input Parameters: 3913a1cb98faSBarry Smith + dm - The `DM` 39142f856554SMatthew G. Knepley . fStart - The first face to include 39152f856554SMatthew G. Knepley . fEnd - The first face to exclude 39162f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 39172f856554SMatthew G. Knepley - cellGeometry - A local vector with cell geometry 39182f856554SMatthew G. Knepley 39192f856554SMatthew G. Knepley Output Parameters: 39202f856554SMatthew G. Knepley + Nface - The number of faces with field values 39212f856554SMatthew G. Knepley . fgeom - The extract the face centroid and normal 39222f856554SMatthew G. Knepley - vol - The cell volume 39232f856554SMatthew G. Knepley 39242f856554SMatthew G. Knepley Level: developer 39252f856554SMatthew G. Knepley 39261cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()` 39272f856554SMatthew G. Knepley @*/ 3928d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 3929d71ae5a4SJacob Faibussowitsch { 39302f856554SMatthew G. Knepley DM dmFace, dmCell; 39312f856554SMatthew G. Knepley DMLabel ghostLabel; 39322f856554SMatthew G. Knepley const PetscScalar *facegeom, *cellgeom; 39332f856554SMatthew G. Knepley PetscInt dim, numFaces = fEnd - fStart, iface, face; 39342f856554SMatthew G. Knepley 39352f856554SMatthew G. Knepley PetscFunctionBegin; 39362f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 39372f856554SMatthew G. Knepley PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 4); 39382f856554SMatthew G. Knepley PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 5); 39394f572ea9SToby Isaac PetscAssertPointer(fgeom, 7); 39404f572ea9SToby Isaac PetscAssertPointer(vol, 8); 39419566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 39429566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 39439566063dSJacob Faibussowitsch PetscCall(VecGetDM(faceGeometry, &dmFace)); 39449566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 39459566063dSJacob Faibussowitsch PetscCall(VecGetDM(cellGeometry, &dmCell)); 39469566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 39479566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(numFaces, fgeom)); 39489566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * 2, MPIU_SCALAR, vol)); 39492f856554SMatthew G. Knepley for (face = fStart, iface = 0; face < fEnd; ++face) { 39502f856554SMatthew G. Knepley const PetscInt *cells; 39512f856554SMatthew G. Knepley PetscFVFaceGeom *fg; 39522f856554SMatthew G. Knepley PetscFVCellGeom *cgL, *cgR; 39532f856554SMatthew G. Knepley PetscFVFaceGeom *fgeoml = *fgeom; 39542f856554SMatthew G. Knepley PetscReal *voll = *vol; 39552f856554SMatthew G. Knepley PetscInt ghost, d, nchild, nsupp; 39562f856554SMatthew G. Knepley 39579566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 39589566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 39599566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 39602f856554SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 39619566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 39629566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &cells)); 39639566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL)); 39649566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR)); 39652f856554SMatthew G. Knepley for (d = 0; d < dim; ++d) { 39662f856554SMatthew G. Knepley fgeoml[iface].centroid[d] = fg->centroid[d]; 39672f856554SMatthew G. Knepley fgeoml[iface].normal[d] = fg->normal[d]; 39682f856554SMatthew G. Knepley } 39692f856554SMatthew G. Knepley voll[iface * 2 + 0] = cgL->volume; 39702f856554SMatthew G. Knepley voll[iface * 2 + 1] = cgR->volume; 39712f856554SMatthew G. Knepley ++iface; 39722f856554SMatthew G. Knepley } 39732f856554SMatthew G. Knepley *Nface = iface; 39749566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 39759566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 39763ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 39772f856554SMatthew G. Knepley } 39782f856554SMatthew G. Knepley 39792f856554SMatthew G. Knepley /*@C 39802f856554SMatthew G. Knepley DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces 39812f856554SMatthew G. Knepley 39822f856554SMatthew G. Knepley Input Parameters: 3983a1cb98faSBarry Smith + dm - The `DM` 39842f856554SMatthew G. Knepley . fStart - The first face to include 39852f856554SMatthew G. Knepley . fEnd - The first face to exclude 39862f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 39872f856554SMatthew G. Knepley - cellGeometry - A local vector with cell geometry 39882f856554SMatthew G. Knepley 39892f856554SMatthew G. Knepley Output Parameters: 39902f856554SMatthew G. Knepley + Nface - The number of faces with field values 39912f856554SMatthew G. Knepley . fgeom - The extract the face centroid and normal 39922f856554SMatthew G. Knepley - vol - The cell volume 39932f856554SMatthew G. Knepley 39942f856554SMatthew G. Knepley Level: developer 39952f856554SMatthew G. Knepley 39961cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 39972f856554SMatthew G. Knepley @*/ 3998d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 3999d71ae5a4SJacob Faibussowitsch { 40002f856554SMatthew G. Knepley PetscFunctionBegin; 40019566063dSJacob Faibussowitsch PetscCall(PetscFree(*fgeom)); 40029566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_REAL, vol)); 40033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 40042f856554SMatthew G. Knepley } 40052f856554SMatthew G. Knepley 4006d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 4007d71ae5a4SJacob Faibussowitsch { 4008a1cf66bbSMatthew G. Knepley char composeStr[33] = {0}; 4009a1cf66bbSMatthew G. Knepley PetscObjectId id; 4010a1cf66bbSMatthew G. Knepley PetscContainer container; 4011a1cf66bbSMatthew G. Knepley 4012a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 40139566063dSJacob Faibussowitsch PetscCall(PetscObjectGetId((PetscObject)quad, &id)); 401463a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%" PetscInt64_FMT "\n", id)); 40159566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)pointIS, composeStr, (PetscObject *)&container)); 4016a1cf66bbSMatthew G. Knepley if (container) { 40179566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(container, (void **)geom)); 4018a1cf66bbSMatthew G. Knepley } else { 40199566063dSJacob Faibussowitsch PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom)); 40209566063dSJacob Faibussowitsch PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container)); 40219566063dSJacob Faibussowitsch PetscCall(PetscContainerSetPointer(container, (void *)*geom)); 40229566063dSJacob Faibussowitsch PetscCall(PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom)); 40239566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)pointIS, composeStr, (PetscObject)container)); 40249566063dSJacob Faibussowitsch PetscCall(PetscContainerDestroy(&container)); 4025a1cf66bbSMatthew G. Knepley } 40263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4027a1cf66bbSMatthew G. Knepley } 4028a1cf66bbSMatthew G. Knepley 4029d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 4030d71ae5a4SJacob Faibussowitsch { 4031a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 4032a1cf66bbSMatthew G. Knepley *geom = NULL; 40333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4034a1cf66bbSMatthew G. Knepley } 4035a1cf66bbSMatthew G. Knepley 4036d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user) 4037d71ae5a4SJacob Faibussowitsch { 403892d50984SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 403992d50984SMatthew G. Knepley const char *name = "Residual"; 404092d50984SMatthew G. Knepley DM dmAux = NULL; 404192d50984SMatthew G. Knepley DMLabel ghostLabel = NULL; 404292d50984SMatthew G. Knepley PetscDS prob = NULL; 404392d50984SMatthew G. Knepley PetscDS probAux = NULL; 404492d50984SMatthew G. Knepley PetscBool useFEM = PETSC_FALSE; 404592d50984SMatthew G. Knepley PetscBool isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 404692d50984SMatthew G. Knepley DMField coordField = NULL; 4047c0006e53SPatrick Farrell Vec locA; 4048c0006e53SPatrick Farrell PetscScalar *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL; 404992d50984SMatthew G. Knepley IS chunkIS; 405092d50984SMatthew G. Knepley const PetscInt *cells; 405192d50984SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 4052364207b6SKarl Rupp PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd; 405392d50984SMatthew G. Knepley PetscInt maxDegree = PETSC_MAX_INT; 405406ad1575SMatthew G. Knepley PetscFormKey key; 405592d50984SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 405692d50984SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 405792d50984SMatthew G. Knepley 405892d50984SMatthew G. Knepley PetscFunctionBegin; 40599566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 406092d50984SMatthew G. Knepley /* FEM+FVM */ 406192d50984SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 40629566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 40639566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 40649566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 40659566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 40669566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 406792d50984SMatthew G. Knepley if (locA) { 40689566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 40699566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 40709566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 407192d50984SMatthew G. Knepley } 407292d50984SMatthew G. Knepley /* 2: Get geometric data */ 407392d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 407492d50984SMatthew G. Knepley PetscObject obj; 407592d50984SMatthew G. Knepley PetscClassId id; 407692d50984SMatthew G. Knepley PetscBool fimp; 407792d50984SMatthew G. Knepley 40789566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 407992d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 40809566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 40819566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 4082ad540459SPierre Jolivet if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE; 40835f80ce2aSJacob Faibussowitsch PetscCheck(id != PETSCFV_CLASSID, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Use of FVM with PCPATCH not yet implemented"); 408492d50984SMatthew G. Knepley } 408592d50984SMatthew G. Knepley if (useFEM) { 40869566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 40879566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 408892d50984SMatthew G. Knepley if (maxDegree <= 1) { 40899566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 409048a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 409192d50984SMatthew G. Knepley } else { 40929566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 409392d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 409492d50984SMatthew G. Knepley PetscObject obj; 409592d50984SMatthew G. Knepley PetscClassId id; 409692d50984SMatthew G. Knepley PetscBool fimp; 409792d50984SMatthew G. Knepley 40989566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 409992d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 41009566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 41019566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 410292d50984SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 410392d50984SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 410492d50984SMatthew G. Knepley 41059566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 41069566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 41079566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 410892d50984SMatthew G. Knepley } 410992d50984SMatthew G. Knepley } 411092d50984SMatthew G. Knepley } 411192d50984SMatthew G. Knepley } 411292d50984SMatthew G. Knepley /* Loop over chunks */ 41139566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 41149566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 41159566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS)); 411692d50984SMatthew G. Knepley numCells = cEnd - cStart; 411792d50984SMatthew G. Knepley numChunks = 1; 411892d50984SMatthew G. Knepley cellChunkSize = numCells / numChunks; 411992d50984SMatthew G. Knepley numChunks = PetscMin(1, numCells); 41206528b96dSMatthew G. Knepley key.label = NULL; 41216528b96dSMatthew G. Knepley key.value = 0; 412206ad1575SMatthew G. Knepley key.part = 0; 412392d50984SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 4124c0006e53SPatrick Farrell PetscScalar *elemVec, *fluxL = NULL, *fluxR = NULL; 4125c0006e53SPatrick Farrell PetscReal *vol = NULL; 4126c0006e53SPatrick Farrell PetscFVFaceGeom *fgeom = NULL; 412792d50984SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 4128c0006e53SPatrick Farrell PetscInt numFaces = 0; 412992d50984SMatthew G. Knepley 413092d50984SMatthew G. Knepley /* Extract field coefficients */ 413192d50984SMatthew G. Knepley if (useFEM) { 41329566063dSJacob Faibussowitsch PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells)); 41339566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 41349566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 41359566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numCells * totDim)); 413692d50984SMatthew G. Knepley } 413792d50984SMatthew 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 */ 413892d50984SMatthew G. Knepley /* Loop over fields */ 413992d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 414092d50984SMatthew G. Knepley PetscObject obj; 414192d50984SMatthew G. Knepley PetscClassId id; 414292d50984SMatthew G. Knepley PetscBool fimp; 414392d50984SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 414492d50984SMatthew G. Knepley 41456528b96dSMatthew G. Knepley key.field = f; 41469566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 414792d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 41489566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 41499566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 415092d50984SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 415192d50984SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 415292d50984SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 415392d50984SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 415492d50984SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 415592d50984SMatthew G. Knepley PetscInt Nq, Nb; 415692d50984SMatthew G. Knepley 41579566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 41589566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 41599566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 416092d50984SMatthew G. Knepley blockSize = Nb; 416192d50984SMatthew G. Knepley batchSize = numBlocks * blockSize; 41629566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 416392d50984SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 416492d50984SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 416592d50984SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 416692d50984SMatthew G. Knepley offset = numCells - Nr; 416792d50984SMatthew G. Knepley /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 416892d50984SMatthew 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) */ 41699566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom)); 41709566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateResidual(prob, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec)); 41719566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom)); 41729566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateResidual(prob, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, &elemVec[offset * totDim])); 41739566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom)); 417492d50984SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 417592d50984SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 417692d50984SMatthew G. Knepley 417792d50984SMatthew G. Knepley Ne = numFaces; 417892d50984SMatthew G. Knepley /* Riemann solve over faces (need fields at face centroids) */ 417992d50984SMatthew G. Knepley /* We need to evaluate FE fields at those coordinates */ 41809566063dSJacob Faibussowitsch PetscCall(PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR)); 418163a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 418292d50984SMatthew G. Knepley } 418392d50984SMatthew G. Knepley /* Loop over domain */ 418492d50984SMatthew G. Knepley if (useFEM) { 418592d50984SMatthew G. Knepley /* Add elemVec to locX */ 418692d50984SMatthew G. Knepley for (c = cS; c < cE; ++c) { 418792d50984SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 418892d50984SMatthew G. Knepley const PetscInt cind = c - cStart; 418992d50984SMatthew G. Knepley 41909566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim])); 419192d50984SMatthew G. Knepley if (ghostLabel) { 419292d50984SMatthew G. Knepley PetscInt ghostVal; 419392d50984SMatthew G. Knepley 41949566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 419592d50984SMatthew G. Knepley if (ghostVal > 0) continue; 419692d50984SMatthew G. Knepley } 41979566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES)); 419892d50984SMatthew G. Knepley } 419992d50984SMatthew G. Knepley } 420092d50984SMatthew G. Knepley /* Handle time derivative */ 420192d50984SMatthew G. Knepley if (locX_t) { 420292d50984SMatthew G. Knepley PetscScalar *x_t, *fa; 420392d50984SMatthew G. Knepley 42049566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 42059566063dSJacob Faibussowitsch PetscCall(VecGetArray(locX_t, &x_t)); 420692d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 420792d50984SMatthew G. Knepley PetscFV fv; 420892d50984SMatthew G. Knepley PetscObject obj; 420992d50984SMatthew G. Knepley PetscClassId id; 421092d50984SMatthew G. Knepley PetscInt pdim, d; 421192d50984SMatthew G. Knepley 42129566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 42139566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 421492d50984SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 421592d50984SMatthew G. Knepley fv = (PetscFV)obj; 42169566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 421792d50984SMatthew G. Knepley for (c = cS; c < cE; ++c) { 421892d50984SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 421992d50984SMatthew G. Knepley PetscScalar *u_t, *r; 422092d50984SMatthew G. Knepley 422192d50984SMatthew G. Knepley if (ghostLabel) { 422292d50984SMatthew G. Knepley PetscInt ghostVal; 422392d50984SMatthew G. Knepley 42249566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 422592d50984SMatthew G. Knepley if (ghostVal > 0) continue; 422692d50984SMatthew G. Knepley } 42279566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t)); 42289566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r)); 422992d50984SMatthew G. Knepley for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 423092d50984SMatthew G. Knepley } 423192d50984SMatthew G. Knepley } 42329566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locX_t, &x_t)); 42339566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 423492d50984SMatthew G. Knepley } 423592d50984SMatthew G. Knepley if (useFEM) { 42369566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 42379566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 423892d50984SMatthew G. Knepley } 423992d50984SMatthew G. Knepley } 42409566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISDestroy(&chunkIS)); 42419566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 424292d50984SMatthew G. Knepley /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */ 424392d50984SMatthew G. Knepley if (useFEM) { 424492d50984SMatthew G. Knepley if (maxDegree <= 1) { 42459566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 42469566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 424792d50984SMatthew G. Knepley } else { 424892d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 42499566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 42509566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&quads[f])); 425192d50984SMatthew G. Knepley } 42529566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 425392d50984SMatthew G. Knepley } 425492d50984SMatthew G. Knepley } 42559566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 42563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 425792d50984SMatthew G. Knepley } 425892d50984SMatthew G. Knepley 4259a1cf66bbSMatthew G. Knepley /* 4260a1cf66bbSMatthew 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 4261a1cf66bbSMatthew G. Knepley 4262a1cf66bbSMatthew G. Knepley X - The local solution vector 4263a5b23f4aSJose E. Roman X_t - The local solution time derivative vector, or NULL 4264a1cf66bbSMatthew G. Knepley */ 4265d71ae5a4SJacob 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) 4266d71ae5a4SJacob Faibussowitsch { 4267a1cf66bbSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 4268a1cf66bbSMatthew G. Knepley const char *name = "Jacobian", *nameP = "JacobianPre"; 4269a1cf66bbSMatthew G. Knepley DM dmAux = NULL; 4270a1cf66bbSMatthew G. Knepley PetscDS prob, probAux = NULL; 4271a1cf66bbSMatthew G. Knepley PetscSection sectionAux = NULL; 4272a1cf66bbSMatthew G. Knepley Vec A; 4273a1cf66bbSMatthew G. Knepley DMField coordField; 4274a1cf66bbSMatthew G. Knepley PetscFEGeom *cgeomFEM; 4275a1cf66bbSMatthew G. Knepley PetscQuadrature qGeom = NULL; 4276a1cf66bbSMatthew G. Knepley Mat J = Jac, JP = JacP; 4277a1cf66bbSMatthew G. Knepley PetscScalar *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL; 4278e432b41dSStefano Zampini PetscBool hasJac, hasPrec, hasDyn, assembleJac, *isFE, hasFV = PETSC_FALSE; 4279a1cf66bbSMatthew G. Knepley const PetscInt *cells; 428006ad1575SMatthew G. Knepley PetscFormKey key; 42819b2fc754SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0; 4282a1cf66bbSMatthew G. Knepley 4283a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 42849566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(cellIS, &numCells)); 42859566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 42869566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 42879566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 42889566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &A)); 42899a2a23afSMatthew G. Knepley if (A) { 42909566063dSJacob Faibussowitsch PetscCall(VecGetDM(A, &dmAux)); 42919566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 42929566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 4293a1cf66bbSMatthew G. Knepley } 4294a1cf66bbSMatthew G. Knepley /* Get flags */ 42959566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 42969566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE)); 4297a1cf66bbSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 4298a1cf66bbSMatthew G. Knepley PetscObject disc; 4299a1cf66bbSMatthew G. Knepley PetscClassId id; 43009566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, &disc)); 43019566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(disc, &id)); 43029371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 43039371c9d4SSatish Balay isFE[fieldI] = PETSC_TRUE; 43049371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 43059371c9d4SSatish Balay hasFV = PETSC_TRUE; 43069371c9d4SSatish Balay isFE[fieldI] = PETSC_FALSE; 43079371c9d4SSatish Balay } 4308a1cf66bbSMatthew G. Knepley } 43099566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobian(prob, &hasJac)); 43109566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec)); 43119566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 4312a1cf66bbSMatthew G. Knepley assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE; 4313a1cf66bbSMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 43149566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); /* No allocated space for FV stuff, so ignore the zero entries */ 43159566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 43169566063dSJacob Faibussowitsch if (probAux) PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 4317a1cf66bbSMatthew G. Knepley /* Compute batch sizes */ 4318a1cf66bbSMatthew G. Knepley if (isFE[0]) { 4319a1cf66bbSMatthew G. Knepley PetscFE fe; 4320a1cf66bbSMatthew G. Knepley PetscQuadrature q; 4321a1cf66bbSMatthew G. Knepley PetscInt numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb; 4322a1cf66bbSMatthew G. Knepley 43239566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe)); 43249566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 43259566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL)); 43269566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 43279566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 4328a1cf66bbSMatthew G. Knepley blockSize = Nb * numQuadPoints; 4329a1cf66bbSMatthew G. Knepley batchSize = numBlocks * blockSize; 4330a1cf66bbSMatthew G. Knepley chunkSize = numBatches * batchSize; 4331a1cf66bbSMatthew G. Knepley numChunks = numCells / chunkSize + numCells % chunkSize; 43329566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 4333a1cf66bbSMatthew G. Knepley } else { 4334a1cf66bbSMatthew G. Knepley chunkSize = numCells; 4335a1cf66bbSMatthew G. Knepley numChunks = 1; 4336a1cf66bbSMatthew G. Knepley } 4337a1cf66bbSMatthew G. Knepley /* Get work space */ 4338a1cf66bbSMatthew 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; 43399566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work)); 43409566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(work, wsz)); 4341a1cf66bbSMatthew G. Knepley off = 0; 4342a1cf66bbSMatthew G. Knepley u = X ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL; 4343a1cf66bbSMatthew G. Knepley u_t = X_t ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL; 4344a1cf66bbSMatthew G. Knepley a = dmAux ? (sz = chunkSize * totDimAux, off += sz, work + off - sz) : NULL; 4345a1cf66bbSMatthew G. Knepley elemMat = hasJac ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 4346a1cf66bbSMatthew G. Knepley elemMatP = hasPrec ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 4347a1cf66bbSMatthew G. Knepley elemMatD = hasDyn ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 434863a3b9bcSJacob Faibussowitsch PetscCheck(off == wsz, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %" PetscInt_FMT " should be %" PetscInt_FMT, off, wsz); 4349a1cf66bbSMatthew G. Knepley /* Setup geometry */ 43509566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 43519566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 43529566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 4353a1cf66bbSMatthew G. Knepley if (!qGeom) { 4354a1cf66bbSMatthew G. Knepley PetscFE fe; 4355a1cf66bbSMatthew G. Knepley 43569566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe)); 43579566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 43589566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 4359a1cf66bbSMatthew G. Knepley } 43609566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 4361a1cf66bbSMatthew G. Knepley /* Compute volume integrals */ 43629566063dSJacob Faibussowitsch if (assembleJac) PetscCall(MatZeroEntries(J)); 43639566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(JP)); 43646528b96dSMatthew G. Knepley key.label = NULL; 43656528b96dSMatthew G. Knepley key.value = 0; 436606ad1575SMatthew G. Knepley key.part = 0; 4367a1cf66bbSMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) { 4368a1cf66bbSMatthew G. Knepley const PetscInt Ncell = PetscMin(chunkSize, numCells - offCell); 4369a1cf66bbSMatthew G. Knepley PetscInt c; 4370a1cf66bbSMatthew G. Knepley 4371a1cf66bbSMatthew G. Knepley /* Extract values */ 4372a1cf66bbSMatthew G. Knepley for (c = 0; c < Ncell; ++c) { 4373a1cf66bbSMatthew G. Knepley const PetscInt cell = cells ? cells[c + offCell] : c + offCell; 4374a1cf66bbSMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 4375a1cf66bbSMatthew G. Knepley PetscInt i; 4376a1cf66bbSMatthew G. Knepley 4377a1cf66bbSMatthew G. Knepley if (X) { 43789566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x)); 4379a1cf66bbSMatthew G. Knepley for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i]; 43809566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x)); 4381a1cf66bbSMatthew G. Knepley } 4382a1cf66bbSMatthew G. Knepley if (X_t) { 43839566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t)); 4384a1cf66bbSMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[c * totDim + i] = x_t[i]; 43859566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t)); 4386a1cf66bbSMatthew G. Knepley } 4387a1cf66bbSMatthew G. Knepley if (dmAux) { 43889566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x)); 4389a1cf66bbSMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i]; 43909566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x)); 4391a1cf66bbSMatthew G. Knepley } 4392a1cf66bbSMatthew G. Knepley } 4393a1cf66bbSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 4394a1cf66bbSMatthew G. Knepley PetscFE fe; 43959566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 4396a1cf66bbSMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 43976528b96dSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 43989566063dSJacob Faibussowitsch if (hasJac) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat)); 43999566063dSJacob Faibussowitsch if (hasPrec) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP)); 44009566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD)); 4401a1cf66bbSMatthew G. Knepley } 4402a1cf66bbSMatthew G. Knepley /* For finite volume, add the identity */ 4403a1cf66bbSMatthew G. Knepley if (!isFE[fieldI]) { 4404a1cf66bbSMatthew G. Knepley PetscFV fv; 4405a1cf66bbSMatthew G. Knepley PetscInt eOffset = 0, Nc, fc, foff; 4406a1cf66bbSMatthew G. Knepley 44079566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, fieldI, &foff)); 44089566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv)); 44099566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 4410a1cf66bbSMatthew G. Knepley for (c = 0; c < chunkSize; ++c, eOffset += totDim * totDim) { 4411a1cf66bbSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 4412a1cf66bbSMatthew G. Knepley const PetscInt i = foff + fc; 4413ad540459SPierre Jolivet if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0; 4414ad540459SPierre Jolivet if (hasPrec) elemMatP[eOffset + i * totDim + i] = 1.0; 4415a1cf66bbSMatthew G. Knepley } 4416a1cf66bbSMatthew G. Knepley } 4417a1cf66bbSMatthew G. Knepley } 4418a1cf66bbSMatthew G. Knepley } 4419a1cf66bbSMatthew G. Knepley /* Add contribution from X_t */ 44209371c9d4SSatish Balay if (hasDyn) { 44219371c9d4SSatish Balay for (c = 0; c < chunkSize * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 44229371c9d4SSatish Balay } 4423a1cf66bbSMatthew G. Knepley /* Insert values into matrix */ 4424a1cf66bbSMatthew G. Knepley for (c = 0; c < Ncell; ++c) { 4425a1cf66bbSMatthew G. Knepley const PetscInt cell = cells ? cells[c + offCell] : c + offCell; 4426a1cf66bbSMatthew G. Knepley if (mesh->printFEM > 1) { 44279566063dSJacob Faibussowitsch if (hasJac) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[(c - cStart) * totDim * totDim])); 44289566063dSJacob Faibussowitsch if (hasPrec) PetscCall(DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c - cStart) * totDim * totDim])); 4429a1cf66bbSMatthew G. Knepley } 4430*e8e188d2SZach Atkins if (assembleJac) PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES)); 4431*e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, JP, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES)); 4432a1cf66bbSMatthew G. Knepley } 4433a1cf66bbSMatthew G. Knepley } 4434a1cf66bbSMatthew G. Knepley /* Cleanup */ 44359566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 44369566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 44379566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE)); 44389566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE)); 44399566063dSJacob 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)); 4440a1cf66bbSMatthew G. Knepley /* Compute boundary integrals */ 44419566063dSJacob Faibussowitsch /* PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx)); */ 4442a1cf66bbSMatthew G. Knepley /* Assemble matrix */ 44439371c9d4SSatish Balay if (assembleJac) { 44449371c9d4SSatish Balay PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY)); 44459371c9d4SSatish Balay PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY)); 44469371c9d4SSatish Balay } 44479371c9d4SSatish Balay PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY)); 44489371c9d4SSatish Balay PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 44499566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 44503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4451a1cf66bbSMatthew G. Knepley } 44523e9753d6SMatthew G. Knepley 44533e9753d6SMatthew G. Knepley /******** FEM Assembly Function ********/ 44543e9753d6SMatthew G. Knepley 4455d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMConvertPlex_Internal(DM dm, DM *plex, PetscBool copy) 4456d71ae5a4SJacob Faibussowitsch { 44573e9753d6SMatthew G. Knepley PetscBool isPlex; 44583e9753d6SMatthew G. Knepley 44593e9753d6SMatthew G. Knepley PetscFunctionBegin; 44609566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex)); 44613e9753d6SMatthew G. Knepley if (isPlex) { 44623e9753d6SMatthew G. Knepley *plex = dm; 44639566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)dm)); 44643e9753d6SMatthew G. Knepley } else { 44659566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex)); 44663e9753d6SMatthew G. Knepley if (!*plex) { 44679566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, plex)); 44689566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex)); 44691baa6e33SBarry Smith if (copy) PetscCall(DMCopyAuxiliaryVec(dm, *plex)); 44703e9753d6SMatthew G. Knepley } else { 44719566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)*plex)); 44723e9753d6SMatthew G. Knepley } 44733e9753d6SMatthew G. Knepley } 44743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 44753e9753d6SMatthew G. Knepley } 44763e9753d6SMatthew G. Knepley 44773e9753d6SMatthew G. Knepley /*@ 44783e9753d6SMatthew G. Knepley DMPlexGetGeometryFVM - Return precomputed geometric data 44793e9753d6SMatthew G. Knepley 448020f4b53cSBarry Smith Collective 44813e9753d6SMatthew G. Knepley 44823e9753d6SMatthew G. Knepley Input Parameter: 4483a1cb98faSBarry Smith . dm - The `DM` 44843e9753d6SMatthew G. Knepley 44853e9753d6SMatthew G. Knepley Output Parameters: 44863e9753d6SMatthew G. Knepley + facegeom - The values precomputed from face geometry 44873e9753d6SMatthew G. Knepley . cellgeom - The values precomputed from cell geometry 44883e9753d6SMatthew G. Knepley - minRadius - The minimum radius over the mesh of an inscribed sphere in a cell 44893e9753d6SMatthew G. Knepley 44903e9753d6SMatthew G. Knepley Level: developer 44913e9753d6SMatthew G. Knepley 44921cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMTSSetRHSFunctionLocal()` 44933e9753d6SMatthew G. Knepley @*/ 4494d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGeometryFVM(DM dm, Vec *facegeom, Vec *cellgeom, PetscReal *minRadius) 4495d71ae5a4SJacob Faibussowitsch { 44963e9753d6SMatthew G. Knepley DM plex; 44973e9753d6SMatthew G. Knepley 44983e9753d6SMatthew G. Knepley PetscFunctionBegin; 44993e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 45009566063dSJacob Faibussowitsch PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE)); 45019566063dSJacob Faibussowitsch PetscCall(DMPlexGetDataFVM(plex, NULL, cellgeom, facegeom, NULL)); 45029566063dSJacob Faibussowitsch if (minRadius) PetscCall(DMPlexGetMinRadius(plex, minRadius)); 45039566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 45043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 45053e9753d6SMatthew G. Knepley } 45063e9753d6SMatthew G. Knepley 45073e9753d6SMatthew G. Knepley /*@ 45083e9753d6SMatthew G. Knepley DMPlexGetGradientDM - Return gradient data layout 45093e9753d6SMatthew G. Knepley 451020f4b53cSBarry Smith Collective 45113e9753d6SMatthew G. Knepley 45123e9753d6SMatthew G. Knepley Input Parameters: 4513a1cb98faSBarry Smith + dm - The `DM` 451420f4b53cSBarry Smith - fv - The `PetscFV` 45153e9753d6SMatthew G. Knepley 45163e9753d6SMatthew G. Knepley Output Parameter: 45173e9753d6SMatthew G. Knepley . dmGrad - The layout for gradient values 45183e9753d6SMatthew G. Knepley 45193e9753d6SMatthew G. Knepley Level: developer 45203e9753d6SMatthew G. Knepley 45211cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetGeometryFVM()` 45223e9753d6SMatthew G. Knepley @*/ 4523d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGradientDM(DM dm, PetscFV fv, DM *dmGrad) 4524d71ae5a4SJacob Faibussowitsch { 45253e9753d6SMatthew G. Knepley DM plex; 45263e9753d6SMatthew G. Knepley PetscBool computeGradients; 45273e9753d6SMatthew G. Knepley 45283e9753d6SMatthew G. Knepley PetscFunctionBegin; 45293e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 45303e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 45314f572ea9SToby Isaac PetscAssertPointer(dmGrad, 3); 45329566063dSJacob Faibussowitsch PetscCall(PetscFVGetComputeGradients(fv, &computeGradients)); 45339371c9d4SSatish Balay if (!computeGradients) { 45349371c9d4SSatish Balay *dmGrad = NULL; 45353ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 45369371c9d4SSatish Balay } 45379566063dSJacob Faibussowitsch PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE)); 45389566063dSJacob Faibussowitsch PetscCall(DMPlexGetDataFVM(plex, fv, NULL, NULL, dmGrad)); 45399566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 45403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 45413e9753d6SMatthew G. Knepley } 45423e9753d6SMatthew G. Knepley 4543d71ae5a4SJacob 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) 4544d71ae5a4SJacob Faibussowitsch { 45453e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 45463e9753d6SMatthew G. Knepley DM plex = NULL, plexA = NULL; 45473e9753d6SMatthew G. Knepley DMEnclosureType encAux; 45483e9753d6SMatthew G. Knepley PetscDS prob, probAux = NULL; 45493e9753d6SMatthew G. Knepley PetscSection section, sectionAux = NULL; 45503e9753d6SMatthew G. Knepley Vec locA = NULL; 45513e9753d6SMatthew G. Knepley PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemVec = NULL; 45523e9753d6SMatthew G. Knepley PetscInt totDim, totDimAux = 0; 45533e9753d6SMatthew G. Knepley 45543e9753d6SMatthew G. Knepley PetscFunctionBegin; 45559566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 45569566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 45579566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 45589566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 45599566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA)); 45603e9753d6SMatthew G. Knepley if (locA) { 45613e9753d6SMatthew G. Knepley DM dmAux; 45623e9753d6SMatthew G. Knepley 45639566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 45649566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 45659566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 45669566063dSJacob Faibussowitsch PetscCall(DMGetDS(plexA, &probAux)); 45679566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 45689566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexA, §ionAux)); 45693e9753d6SMatthew G. Knepley } 45700c290148SMatthew G. Knepley { 45713e9753d6SMatthew G. Knepley PetscFEGeom *fgeom; 45723e9753d6SMatthew G. Knepley PetscInt maxDegree; 45733e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 45743e9753d6SMatthew G. Knepley IS pointIS; 45753e9753d6SMatthew G. Knepley const PetscInt *points; 45763e9753d6SMatthew G. Knepley PetscInt numFaces, face, Nq; 45773e9753d6SMatthew G. Knepley 45789566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS)); 45790c290148SMatthew G. Knepley if (!pointIS) goto end; /* No points with that id on this process */ 45803e9753d6SMatthew G. Knepley { 45813e9753d6SMatthew G. Knepley IS isectIS; 45823e9753d6SMatthew G. Knepley 45833e9753d6SMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 45849566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 45859566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 45863e9753d6SMatthew G. Knepley pointIS = isectIS; 45873e9753d6SMatthew G. Knepley } 45889566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 45899566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 45909566063dSJacob Faibussowitsch PetscCall(PetscMalloc4(numFaces * totDim, &u, locX_t ? numFaces * totDim : 0, &u_t, numFaces * totDim, &elemVec, locA ? numFaces * totDimAux : 0, &a)); 45919566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 459248a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 45933e9753d6SMatthew G. Knepley if (!qGeom) { 45943e9753d6SMatthew G. Knepley PetscFE fe; 45953e9753d6SMatthew G. Knepley 45969566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe)); 45979566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 45989566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 45993e9753d6SMatthew G. Knepley } 46009566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 46019566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 46023e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 4603f15274beSMatthew Knepley const PetscInt point = points[face], *support; 46043e9753d6SMatthew G. Knepley PetscScalar *x = NULL; 4605f15274beSMatthew Knepley PetscInt i; 46063e9753d6SMatthew G. Knepley 46079566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, point, &support)); 46089566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 46093e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 46109566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 46113e9753d6SMatthew G. Knepley if (locX_t) { 46129566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x)); 46133e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i]; 46149566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x)); 46153e9753d6SMatthew G. Knepley } 46163e9753d6SMatthew G. Knepley if (locA) { 46173e9753d6SMatthew G. Knepley PetscInt subp; 46183e9753d6SMatthew G. Knepley 46199566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 46209566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 46213e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i]; 46229566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 46233e9753d6SMatthew G. Knepley } 46243e9753d6SMatthew G. Knepley } 46259566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numFaces * totDim)); 46263e9753d6SMatthew G. Knepley { 46273e9753d6SMatthew G. Knepley PetscFE fe; 46283e9753d6SMatthew G. Knepley PetscInt Nb; 46293e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 46303e9753d6SMatthew G. Knepley /* Conforming batches */ 46313e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 46323e9753d6SMatthew G. Knepley /* Remainder */ 46333e9753d6SMatthew G. Knepley PetscInt Nr, offset; 46343e9753d6SMatthew G. Knepley 46359566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe)); 46369566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 46379566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 46383e9753d6SMatthew G. Knepley /* TODO: documentation is unclear about what is going on with these numbers: how should Nb / Nq factor in ? */ 46393e9753d6SMatthew G. Knepley blockSize = Nb; 46403e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 46419566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 46423e9753d6SMatthew G. Knepley numChunks = numFaces / (numBatches * batchSize); 46433e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 46443e9753d6SMatthew G. Knepley Nr = numFaces % (numBatches * batchSize); 46453e9753d6SMatthew G. Knepley offset = numFaces - Nr; 46469566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom)); 46479566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBdResidual(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec)); 46489566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom)); 46499566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 46509566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBdResidual(prob, wf, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, &elemVec[offset * totDim])); 46519566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 46523e9753d6SMatthew G. Knepley } 46533e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 46543e9753d6SMatthew G. Knepley const PetscInt point = points[face], *support; 46553e9753d6SMatthew G. Knepley 46569566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(point, "BdResidual", totDim, &elemVec[face * totDim])); 46579566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(plex, point, &support)); 46589566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(plex, NULL, locF, support[0], &elemVec[face * totDim], ADD_ALL_VALUES)); 46593e9753d6SMatthew G. Knepley } 46609566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 46619566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 46629566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 46639566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 46649566063dSJacob Faibussowitsch PetscCall(PetscFree4(u, u_t, elemVec, a)); 46653e9753d6SMatthew G. Knepley } 46660c290148SMatthew G. Knepley end: 46679566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 46689566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plexA)); 46693ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 46703e9753d6SMatthew G. Knepley } 46713e9753d6SMatthew G. Knepley 4672d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeBdResidualSingle(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF) 4673d71ae5a4SJacob Faibussowitsch { 46743e9753d6SMatthew G. Knepley DMField coordField; 46753e9753d6SMatthew G. Knepley DMLabel depthLabel; 46763e9753d6SMatthew G. Knepley IS facetIS; 46773e9753d6SMatthew G. Knepley PetscInt dim; 46783e9753d6SMatthew G. Knepley 46793e9753d6SMatthew G. Knepley PetscFunctionBegin; 46809566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 46819566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 46829566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 46839566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 46849566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS)); 46859566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 46863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 46873e9753d6SMatthew G. Knepley } 46883e9753d6SMatthew G. Knepley 4689a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexComputeBdResidual_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4690d71ae5a4SJacob Faibussowitsch { 46913e9753d6SMatthew G. Knepley PetscDS prob; 46923e9753d6SMatthew G. Knepley PetscInt numBd, bd; 46933e9753d6SMatthew G. Knepley DMField coordField = NULL; 46943e9753d6SMatthew G. Knepley IS facetIS = NULL; 46953e9753d6SMatthew G. Knepley DMLabel depthLabel; 46963e9753d6SMatthew G. Knepley PetscInt dim; 46973e9753d6SMatthew G. Knepley 46983e9753d6SMatthew G. Knepley PetscFunctionBegin; 46999566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 47009566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 47019566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 47029566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 47039566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 47043e9753d6SMatthew G. Knepley for (bd = 0; bd < numBd; ++bd) { 470545480ffeSMatthew G. Knepley PetscWeakForm wf; 47063e9753d6SMatthew G. Knepley DMBoundaryConditionType type; 47073e9753d6SMatthew G. Knepley DMLabel label; 47083e9753d6SMatthew G. Knepley const PetscInt *values; 47090c290148SMatthew G. Knepley PetscInt field, numValues, v; 47103e9753d6SMatthew G. Knepley PetscObject obj; 47113e9753d6SMatthew G. Knepley PetscClassId id; 47120c290148SMatthew G. Knepley PetscFormKey key; 47133e9753d6SMatthew G. Knepley 47149566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &field, NULL, NULL, NULL, NULL, NULL)); 47153d3e5d66SMatthew G. Knepley if (type & DM_BC_ESSENTIAL) continue; 47169566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 47179566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 47183d3e5d66SMatthew G. Knepley if (id != PETSCFE_CLASSID) continue; 47193e9753d6SMatthew G. Knepley if (!facetIS) { 47203e9753d6SMatthew G. Knepley DMLabel depthLabel; 47213e9753d6SMatthew G. Knepley PetscInt dim; 47223e9753d6SMatthew G. Knepley 47239566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 47249566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 47259566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 47263e9753d6SMatthew G. Knepley } 47279566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 47280c290148SMatthew G. Knepley for (v = 0; v < numValues; ++v) { 47290c290148SMatthew G. Knepley key.label = label; 47300c290148SMatthew G. Knepley key.value = values[v]; 47310c290148SMatthew G. Knepley key.field = field; 47320c290148SMatthew G. Knepley key.part = 0; 47339566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS)); 47340c290148SMatthew G. Knepley } 47353e9753d6SMatthew G. Knepley } 47369566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 47373ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 47383e9753d6SMatthew G. Knepley } 47393e9753d6SMatthew G. Knepley 4740d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4741d71ae5a4SJacob Faibussowitsch { 47423e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 47433e9753d6SMatthew G. Knepley const char *name = "Residual"; 47443e9753d6SMatthew G. Knepley DM dmAux = NULL; 47453e9753d6SMatthew G. Knepley DM dmGrad = NULL; 47463e9753d6SMatthew G. Knepley DMLabel ghostLabel = NULL; 47476528b96dSMatthew G. Knepley PetscDS ds = NULL; 47486528b96dSMatthew G. Knepley PetscDS dsAux = NULL; 47493e9753d6SMatthew G. Knepley PetscSection section = NULL; 47503e9753d6SMatthew G. Knepley PetscBool useFEM = PETSC_FALSE; 47513e9753d6SMatthew G. Knepley PetscBool useFVM = PETSC_FALSE; 47523e9753d6SMatthew G. Knepley PetscBool isImplicit = (locX_t || time == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 47533e9753d6SMatthew G. Knepley PetscFV fvm = NULL; 47543e9753d6SMatthew G. Knepley PetscFVCellGeom *cgeomFVM = NULL; 47553e9753d6SMatthew G. Knepley PetscFVFaceGeom *fgeomFVM = NULL; 47563e9753d6SMatthew G. Knepley DMField coordField = NULL; 47573e9753d6SMatthew G. Knepley Vec locA, cellGeometryFVM = NULL, faceGeometryFVM = NULL, grad, locGrad = NULL; 47583e9753d6SMatthew G. Knepley PetscScalar *u = NULL, *u_t, *a, *uL, *uR; 47593e9753d6SMatthew G. Knepley IS chunkIS; 47603e9753d6SMatthew G. Knepley const PetscInt *cells; 47613e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 47623e9753d6SMatthew G. Knepley PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, faceChunkSize, chunk, fStart, fEnd; 47633e9753d6SMatthew G. Knepley PetscInt maxDegree = PETSC_MAX_INT; 47643e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 47653e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 47663e9753d6SMatthew G. Knepley 47673e9753d6SMatthew G. Knepley PetscFunctionBegin; 47683ba16761SJacob Faibussowitsch if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS); 4769437e83fbSMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 47703ba16761SJacob Faibussowitsch if (cStart >= cEnd) PetscFunctionReturn(PETSC_SUCCESS); 47719566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 47723e9753d6SMatthew G. Knepley /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 47733e9753d6SMatthew G. Knepley /* TODO The FVM geometry is over-manipulated. Make the precalc functions return exactly what we need */ 47743e9753d6SMatthew G. Knepley /* FEM+FVM */ 47759566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 47763e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 47779566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 47789566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 477907218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, NULL)); 47809566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 47819566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 47829566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA)); 47833e9753d6SMatthew G. Knepley if (locA) { 47843e9753d6SMatthew G. Knepley PetscInt subcell; 47859566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 47861059d808SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(dmAux, dm, DM_ENC_UNKNOWN, cells ? cells[cStart] : cStart, &subcell)); 478707218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux, subcell, &dsAux, NULL)); 47889566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux)); 47893e9753d6SMatthew G. Knepley } 47903e9753d6SMatthew G. Knepley /* 2: Get geometric data */ 47913e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 47923e9753d6SMatthew G. Knepley PetscObject obj; 47933e9753d6SMatthew G. Knepley PetscClassId id; 47943e9753d6SMatthew G. Knepley PetscBool fimp; 47953e9753d6SMatthew G. Knepley 47969566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 47973e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 47989566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 47999566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 4800ad540459SPierre Jolivet if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE; 48019371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 48029371c9d4SSatish Balay useFVM = PETSC_TRUE; 48039371c9d4SSatish Balay fvm = (PetscFV)obj; 48049371c9d4SSatish Balay } 48053e9753d6SMatthew G. Knepley } 48063e9753d6SMatthew G. Knepley if (useFEM) { 48079566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 48089566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 48093e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 48109566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 481148a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 48123e9753d6SMatthew G. Knepley } else { 48139566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 48143e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 48153e9753d6SMatthew G. Knepley PetscObject obj; 48163e9753d6SMatthew G. Knepley PetscClassId id; 48173e9753d6SMatthew G. Knepley PetscBool fimp; 48183e9753d6SMatthew G. Knepley 48199566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 48203e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 48219566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 48229566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 48233e9753d6SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 48243e9753d6SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 48253e9753d6SMatthew G. Knepley 48269566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 48279566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 48289566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 48293e9753d6SMatthew G. Knepley } 48303e9753d6SMatthew G. Knepley } 48313e9753d6SMatthew G. Knepley } 48323e9753d6SMatthew G. Knepley } 48333e9753d6SMatthew G. Knepley if (useFVM) { 48349566063dSJacob Faibussowitsch PetscCall(DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL)); 48359566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometryFVM, (const PetscScalar **)&fgeomFVM)); 48369566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM)); 48373e9753d6SMatthew G. Knepley /* Reconstruct and limit cell gradients */ 48389566063dSJacob Faibussowitsch PetscCall(DMPlexGetGradientDM(dm, fvm, &dmGrad)); 48393e9753d6SMatthew G. Knepley if (dmGrad) { 48409566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 48419566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmGrad, &grad)); 48429566063dSJacob Faibussowitsch PetscCall(DMPlexReconstructGradients_Internal(dm, fvm, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad)); 48433e9753d6SMatthew G. Knepley /* Communicate gradient values */ 48449566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dmGrad, &locGrad)); 48459566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad)); 48469566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad)); 48479566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmGrad, &grad)); 48483e9753d6SMatthew G. Knepley } 48493e9753d6SMatthew G. Knepley /* Handle non-essential (e.g. outflow) boundary values */ 48509566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, time, faceGeometryFVM, cellGeometryFVM, locGrad)); 48513e9753d6SMatthew G. Knepley } 48523e9753d6SMatthew G. Knepley /* Loop over chunks */ 48539566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS)); 48543e9753d6SMatthew G. Knepley numCells = cEnd - cStart; 48553e9753d6SMatthew G. Knepley numChunks = 1; 48563e9753d6SMatthew G. Knepley cellChunkSize = numCells / numChunks; 48573e9753d6SMatthew G. Knepley faceChunkSize = (fEnd - fStart) / numChunks; 48583e9753d6SMatthew G. Knepley numChunks = PetscMin(1, numCells); 48593e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 48603e9753d6SMatthew G. Knepley PetscScalar *elemVec, *fluxL, *fluxR; 48613e9753d6SMatthew G. Knepley PetscReal *vol; 48623e9753d6SMatthew G. Knepley PetscFVFaceGeom *fgeom; 48633e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 48643e9753d6SMatthew G. Knepley PetscInt fS = fStart + chunk * faceChunkSize, fE = PetscMin(fS + faceChunkSize, fEnd), numFaces = 0, face; 48653e9753d6SMatthew G. Knepley 48663e9753d6SMatthew G. Knepley /* Extract field coefficients */ 48673e9753d6SMatthew G. Knepley if (useFEM) { 48689566063dSJacob Faibussowitsch PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells)); 48699566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 48709566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 48719566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numCells * totDim)); 48723e9753d6SMatthew G. Knepley } 48733e9753d6SMatthew G. Knepley if (useFVM) { 48749566063dSJacob Faibussowitsch PetscCall(DMPlexGetFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR)); 48759566063dSJacob Faibussowitsch PetscCall(DMPlexGetFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol)); 48769566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL)); 48779566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR)); 48789566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(fluxL, numFaces * totDim)); 48799566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(fluxR, numFaces * totDim)); 48803e9753d6SMatthew G. Knepley } 48813e9753d6SMatthew 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 */ 48823e9753d6SMatthew G. Knepley /* Loop over fields */ 48833e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 48843e9753d6SMatthew G. Knepley PetscObject obj; 48853e9753d6SMatthew G. Knepley PetscClassId id; 48863e9753d6SMatthew G. Knepley PetscBool fimp; 48873e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 48883e9753d6SMatthew G. Knepley 48896528b96dSMatthew G. Knepley key.field = f; 48909566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 48913e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 48929566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 48939566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 48943e9753d6SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 48953e9753d6SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 48963e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 48973e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 48983e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 48993e9753d6SMatthew G. Knepley PetscInt Nq, Nb; 49003e9753d6SMatthew G. Knepley 49019566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 49029566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 49039566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 49043e9753d6SMatthew G. Knepley blockSize = Nb; 49053e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 49069566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 49073e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 49083e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 49093e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 49103e9753d6SMatthew G. Knepley offset = numCells - Nr; 49113e9753d6SMatthew G. Knepley /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 49123e9753d6SMatthew 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) */ 49139566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom)); 49149566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateResidual(ds, key, Ne, chunkGeom, u, u_t, dsAux, a, t, elemVec)); 49159566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom)); 4916072f5ffdSStefano Zampini PetscCall(PetscFEIntegrateResidual(ds, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux, a ? &a[offset * totDimAux] : NULL, t, &elemVec[offset * totDim])); 49179566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom)); 49183e9753d6SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 49193e9753d6SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 49203e9753d6SMatthew G. Knepley 49213e9753d6SMatthew G. Knepley Ne = numFaces; 49223e9753d6SMatthew G. Knepley /* Riemann solve over faces (need fields at face centroids) */ 49233e9753d6SMatthew G. Knepley /* We need to evaluate FE fields at those coordinates */ 49249566063dSJacob Faibussowitsch PetscCall(PetscFVIntegrateRHSFunction(fv, ds, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR)); 492563a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 49263e9753d6SMatthew G. Knepley } 49273e9753d6SMatthew G. Knepley /* Loop over domain */ 49283e9753d6SMatthew G. Knepley if (useFEM) { 49293e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 49303e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 49313e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 49323e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 49333e9753d6SMatthew G. Knepley 49349566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim])); 49353e9753d6SMatthew G. Knepley if (ghostLabel) { 49363e9753d6SMatthew G. Knepley PetscInt ghostVal; 49373e9753d6SMatthew G. Knepley 49389566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 49393e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 49403e9753d6SMatthew G. Knepley } 49419566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES)); 49423e9753d6SMatthew G. Knepley } 49433e9753d6SMatthew G. Knepley } 49443e9753d6SMatthew G. Knepley if (useFVM) { 49453e9753d6SMatthew G. Knepley PetscScalar *fa; 49463e9753d6SMatthew G. Knepley PetscInt iface; 49473e9753d6SMatthew G. Knepley 49489566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 49493e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 49503e9753d6SMatthew G. Knepley PetscFV fv; 49513e9753d6SMatthew G. Knepley PetscObject obj; 49523e9753d6SMatthew G. Knepley PetscClassId id; 49533e9753d6SMatthew G. Knepley PetscInt foff, pdim; 49543e9753d6SMatthew G. Knepley 49559566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 49569566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(ds, f, &foff)); 49579566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 49583e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 49593e9753d6SMatthew G. Knepley fv = (PetscFV)obj; 49609566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 49613e9753d6SMatthew G. Knepley /* Accumulate fluxes to cells */ 49623e9753d6SMatthew G. Knepley for (face = fS, iface = 0; face < fE; ++face) { 49633e9753d6SMatthew G. Knepley const PetscInt *scells; 49643e9753d6SMatthew G. Knepley PetscScalar *fL = NULL, *fR = NULL; 49653e9753d6SMatthew G. Knepley PetscInt ghost, d, nsupp, nchild; 49663e9753d6SMatthew G. Knepley 49679566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 49689566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 49699566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 49703e9753d6SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 49719566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &scells)); 49729566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, scells[0], &ghost)); 49739566063dSJacob Faibussowitsch if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[0], f, fa, &fL)); 49749566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, scells[1], &ghost)); 49759566063dSJacob Faibussowitsch if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[1], f, fa, &fR)); 49763e9753d6SMatthew G. Knepley for (d = 0; d < pdim; ++d) { 49773e9753d6SMatthew G. Knepley if (fL) fL[d] -= fluxL[iface * totDim + foff + d]; 49783e9753d6SMatthew G. Knepley if (fR) fR[d] += fluxR[iface * totDim + foff + d]; 49793e9753d6SMatthew G. Knepley } 49803e9753d6SMatthew G. Knepley ++iface; 49813e9753d6SMatthew G. Knepley } 49823e9753d6SMatthew G. Knepley } 49839566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 49843e9753d6SMatthew G. Knepley } 49853e9753d6SMatthew G. Knepley /* Handle time derivative */ 49863e9753d6SMatthew G. Knepley if (locX_t) { 49873e9753d6SMatthew G. Knepley PetscScalar *x_t, *fa; 49883e9753d6SMatthew G. Knepley 49899566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 49909566063dSJacob Faibussowitsch PetscCall(VecGetArray(locX_t, &x_t)); 49913e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 49923e9753d6SMatthew G. Knepley PetscFV fv; 49933e9753d6SMatthew G. Knepley PetscObject obj; 49943e9753d6SMatthew G. Knepley PetscClassId id; 49953e9753d6SMatthew G. Knepley PetscInt pdim, d; 49963e9753d6SMatthew G. Knepley 49979566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 49989566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 49993e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 50003e9753d6SMatthew G. Knepley fv = (PetscFV)obj; 50019566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 50023e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 50033e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 50043e9753d6SMatthew G. Knepley PetscScalar *u_t, *r; 50053e9753d6SMatthew G. Knepley 50063e9753d6SMatthew G. Knepley if (ghostLabel) { 50073e9753d6SMatthew G. Knepley PetscInt ghostVal; 50083e9753d6SMatthew G. Knepley 50099566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 50103e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 50113e9753d6SMatthew G. Knepley } 50129566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t)); 50139566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r)); 50143e9753d6SMatthew G. Knepley for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 50153e9753d6SMatthew G. Knepley } 50163e9753d6SMatthew G. Knepley } 50179566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locX_t, &x_t)); 50189566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 50193e9753d6SMatthew G. Knepley } 50203e9753d6SMatthew G. Knepley if (useFEM) { 50219566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 50229566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 50233e9753d6SMatthew G. Knepley } 50243e9753d6SMatthew G. Knepley if (useFVM) { 50259566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR)); 50269566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol)); 50279566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL)); 50289566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR)); 50299566063dSJacob Faibussowitsch if (dmGrad) PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 50303e9753d6SMatthew G. Knepley } 50313e9753d6SMatthew G. Knepley } 50329566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISDestroy(&chunkIS)); 50339566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 50343e9753d6SMatthew G. Knepley 50353e9753d6SMatthew G. Knepley if (useFEM) { 50369566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Internal(dm, locX, locX_t, t, locF, user)); 50373e9753d6SMatthew G. Knepley 50383e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 50399566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 50409566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 50413e9753d6SMatthew G. Knepley } else { 50423e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 50439566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 50449566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&quads[f])); 50453e9753d6SMatthew G. Knepley } 50469566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 50473e9753d6SMatthew G. Knepley } 50483e9753d6SMatthew G. Knepley } 50493e9753d6SMatthew G. Knepley 50503e9753d6SMatthew G. Knepley /* FEM */ 50513e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 50523e9753d6SMatthew G. Knepley /* 2: Get geometric data */ 50533e9753d6SMatthew G. Knepley /* 3: Handle boundary values */ 50543e9753d6SMatthew G. Knepley /* 4: Loop over domain */ 50553e9753d6SMatthew G. Knepley /* Extract coefficients */ 50563e9753d6SMatthew G. Knepley /* Loop over fields */ 50573e9753d6SMatthew G. Knepley /* Set tiling for FE*/ 50583e9753d6SMatthew G. Knepley /* Integrate FE residual to get elemVec */ 50593e9753d6SMatthew G. Knepley /* Loop over subdomain */ 50603e9753d6SMatthew G. Knepley /* Loop over quad points */ 50613e9753d6SMatthew G. Knepley /* Transform coords to real space */ 50623e9753d6SMatthew G. Knepley /* Evaluate field and aux fields at point */ 50633e9753d6SMatthew G. Knepley /* Evaluate residual at point */ 50643e9753d6SMatthew G. Knepley /* Transform residual to real space */ 50653e9753d6SMatthew G. Knepley /* Add residual to elemVec */ 50663e9753d6SMatthew G. Knepley /* Loop over domain */ 50673e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 50683e9753d6SMatthew G. Knepley 50693e9753d6SMatthew G. Knepley /* FVM */ 50703e9753d6SMatthew G. Knepley /* Get geometric data */ 50713e9753d6SMatthew G. Knepley /* If using gradients */ 50723e9753d6SMatthew G. Knepley /* Compute gradient data */ 50733e9753d6SMatthew G. Knepley /* Loop over domain faces */ 50743e9753d6SMatthew G. Knepley /* Count computational faces */ 50753e9753d6SMatthew G. Knepley /* Reconstruct cell gradient */ 50763e9753d6SMatthew G. Knepley /* Loop over domain cells */ 50773e9753d6SMatthew G. Knepley /* Limit cell gradients */ 50783e9753d6SMatthew G. Knepley /* Handle boundary values */ 50793e9753d6SMatthew G. Knepley /* Loop over domain faces */ 50803e9753d6SMatthew G. Knepley /* Read out field, centroid, normal, volume for each side of face */ 50813e9753d6SMatthew G. Knepley /* Riemann solve over faces */ 50823e9753d6SMatthew G. Knepley /* Loop over domain faces */ 50833e9753d6SMatthew G. Knepley /* Accumulate fluxes to cells */ 50843e9753d6SMatthew G. Knepley /* TODO Change printFEM to printDisc here */ 50853e9753d6SMatthew G. Knepley if (mesh->printFEM) { 50863e9753d6SMatthew G. Knepley Vec locFbc; 50873e9753d6SMatthew G. Knepley PetscInt pStart, pEnd, p, maxDof; 50883e9753d6SMatthew G. Knepley PetscScalar *zeroes; 50893e9753d6SMatthew G. Knepley 50909566063dSJacob Faibussowitsch PetscCall(VecDuplicate(locF, &locFbc)); 50919566063dSJacob Faibussowitsch PetscCall(VecCopy(locF, locFbc)); 50929566063dSJacob Faibussowitsch PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 50939566063dSJacob Faibussowitsch PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 50949566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(maxDof, &zeroes)); 509548a46eb9SPierre Jolivet for (p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES)); 50969566063dSJacob Faibussowitsch PetscCall(PetscFree(zeroes)); 50979566063dSJacob Faibussowitsch PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc)); 50989566063dSJacob Faibussowitsch PetscCall(VecDestroy(&locFbc)); 50993e9753d6SMatthew G. Knepley } 51009566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 51013ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 51023e9753d6SMatthew G. Knepley } 51033e9753d6SMatthew G. Knepley 51046528b96dSMatthew G. Knepley /* 51056528b96dSMatthew G. Knepley 1) Allow multiple kernels for BdResidual for hybrid DS 51066528b96dSMatthew G. Knepley 51076528b96dSMatthew G. Knepley DONE 2) Get out dsAux for either side at the same time as cohesive cell dsAux 51086528b96dSMatthew G. Knepley 51096528b96dSMatthew G. Knepley DONE 3) Change DMGetCellFields() to get different aux data a[] for each side 51106528b96dSMatthew G. Knepley - I think I just need to replace a[] with the closure from each face 51116528b96dSMatthew G. Knepley 51126528b96dSMatthew G. Knepley 4) Run both kernels for each non-hybrid field with correct dsAux, and then hybrid field as before 51136528b96dSMatthew G. Knepley */ 5114d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Hybrid_Internal(DM dm, PetscFormKey key[], IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 5115d71ae5a4SJacob Faibussowitsch { 51163e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 51173e9753d6SMatthew G. Knepley const char *name = "Hybrid Residual"; 511804c51a94SMatthew G. Knepley DM dmAux[3] = {NULL, NULL, NULL}; 51193e9753d6SMatthew G. Knepley DMLabel ghostLabel = NULL; 51206528b96dSMatthew G. Knepley PetscDS ds = NULL; 512107218a29SMatthew G. Knepley PetscDS dsIn = NULL; 51226528b96dSMatthew G. Knepley PetscDS dsAux[3] = {NULL, NULL, NULL}; 512304c51a94SMatthew G. Knepley Vec locA[3] = {NULL, NULL, NULL}; 512407218a29SMatthew G. Knepley DM dmScale[3] = {NULL, NULL, NULL}; 512507218a29SMatthew G. Knepley PetscDS dsScale[3] = {NULL, NULL, NULL}; 512607218a29SMatthew G. Knepley Vec locS[3] = {NULL, NULL, NULL}; 51273e9753d6SMatthew G. Knepley PetscSection section = NULL; 51283e9753d6SMatthew G. Knepley DMField coordField = NULL; 512907218a29SMatthew G. Knepley PetscScalar *a[3] = {NULL, NULL, NULL}; 513007218a29SMatthew G. Knepley PetscScalar *s[3] = {NULL, NULL, NULL}; 5131b2ab40e6SMatthew G. Knepley PetscScalar *u = NULL, *u_t; 513207218a29SMatthew G. Knepley PetscScalar *elemVecNeg, *elemVecPos, *elemVecCoh; 51333e9753d6SMatthew G. Knepley IS chunkIS; 51343e9753d6SMatthew G. Knepley const PetscInt *cells; 51353e9753d6SMatthew G. Knepley PetscInt *faces; 51363e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 51373e2b0218SMatthew G. Knepley PetscInt Nf, f, totDim, totDimIn, totDimAux[3], totDimScale[3], numChunks, cellChunkSize, chunk; 51383e9753d6SMatthew G. Knepley PetscInt maxDegree = PETSC_MAX_INT; 51393e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 51403e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 51413e9753d6SMatthew G. Knepley 51423e9753d6SMatthew G. Knepley PetscFunctionBegin; 51433ba16761SJacob Faibussowitsch if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS); 5144437e83fbSMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5145437e83fbSMatthew G. Knepley PetscCall(ISGetLocalSize(cellIS, &numCells)); 51463ba16761SJacob Faibussowitsch if (cStart >= cEnd) PetscFunctionReturn(PETSC_SUCCESS); 51475fedec97SMatthew G. Knepley if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) { 51485fedec97SMatthew G. Knepley const char *name; 51499566063dSJacob Faibussowitsch PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name)); 515063a3b9bcSJacob 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); 51515fedec97SMatthew G. Knepley } 51529566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 51533e9753d6SMatthew G. Knepley /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 51543e9753d6SMatthew G. Knepley /* FEM */ 51553e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 51569566063dSJacob Faibussowitsch PetscCall(DMGetSection(dm, §ion)); 51579566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 515807218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn)); 51599566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 51609566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 516107218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsIn, &totDimIn)); 51629566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2])); 516304c51a94SMatthew G. Knepley if (locA[2]) { 51641059d808SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 51651059d808SMatthew G. Knepley 51669566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA[2], &dmAux[2])); 516707218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2], NULL)); 51689566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2])); 51696528b96dSMatthew G. Knepley { 51706528b96dSMatthew G. Knepley const PetscInt *cone; 51716528b96dSMatthew G. Knepley PetscInt c; 51726528b96dSMatthew G. Knepley 51731059d808SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 51746528b96dSMatthew G. Knepley for (c = 0; c < 2; ++c) { 51756528b96dSMatthew G. Knepley const PetscInt *support; 51766528b96dSMatthew G. Knepley PetscInt ssize, s; 51776528b96dSMatthew G. Knepley 51789566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 51799566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 51801059d808SMatthew 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); 51811059d808SMatthew G. Knepley if (support[0] == cellStart) s = 1; 51821059d808SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 51831059d808SMatthew 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); 51849566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c])); 5185c75bfeddSPierre 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); 51869566063dSJacob Faibussowitsch if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c])); 5187ad540459SPierre Jolivet else dmAux[c] = dmAux[2]; 518807218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c], NULL)); 51899566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c])); 51906528b96dSMatthew G. Knepley } 51916528b96dSMatthew G. Knepley } 51923e9753d6SMatthew G. Knepley } 519307218a29SMatthew G. Knepley /* Handle mass matrix scaling 519407218a29SMatthew G. Knepley The field in key[2] is the field to be scaled, and the scaling field is the first in the dsScale */ 519507218a29SMatthew G. Knepley PetscCall(DMGetAuxiliaryVec(dm, key[2].label, -key[2].value, key[2].part, &locS[2])); 519607218a29SMatthew G. Knepley if (locS[2]) { 51973e2b0218SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 519807218a29SMatthew G. Knepley PetscInt Nb, Nbs; 519907218a29SMatthew G. Knepley 520007218a29SMatthew G. Knepley PetscCall(VecGetDM(locS[2], &dmScale[2])); 52013e2b0218SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[2], cellStart, &dsScale[2], NULL)); 52023e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[2], &totDimScale[2])); 520307218a29SMatthew G. Knepley // BRAD: This is not set correctly 520407218a29SMatthew G. Knepley key[2].field = 2; 520507218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, key[2].field, &Nb)); 520607218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsScale[2], 0, &Nbs)); 520707218a29SMatthew 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); 52083e2b0218SMatthew G. Knepley { 52093e2b0218SMatthew G. Knepley const PetscInt *cone; 52103e2b0218SMatthew G. Knepley PetscInt c; 52113e2b0218SMatthew G. Knepley 52123e2b0218SMatthew G. Knepley locS[1] = locS[0] = locS[2]; 52133e2b0218SMatthew G. Knepley dmScale[1] = dmScale[0] = dmScale[2]; 52143e2b0218SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 52153e2b0218SMatthew G. Knepley for (c = 0; c < 2; ++c) { 52163e2b0218SMatthew G. Knepley const PetscInt *support; 52173e2b0218SMatthew G. Knepley PetscInt ssize, s; 52183e2b0218SMatthew G. Knepley 52193e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 52203e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 52213e2b0218SMatthew 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); 52223e2b0218SMatthew G. Knepley if (support[0] == cellStart) s = 1; 52233e2b0218SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 52243e2b0218SMatthew 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); 52253e2b0218SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[c], support[s], &dsScale[c], NULL)); 52263e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[c], &totDimScale[c])); 52273e2b0218SMatthew G. Knepley } 52283e2b0218SMatthew G. Knepley } 522907218a29SMatthew G. Knepley } 52303e9753d6SMatthew G. Knepley /* 2: Setup geometric data */ 52319566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 52329566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 52333e9753d6SMatthew G. Knepley if (maxDegree > 1) { 52349566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 52353e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 52363e9753d6SMatthew G. Knepley PetscFE fe; 52373e9753d6SMatthew G. Knepley 52389566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 52393e9753d6SMatthew G. Knepley if (fe) { 52409566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 52419566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 52423e9753d6SMatthew G. Knepley } 52433e9753d6SMatthew G. Knepley } 52443e9753d6SMatthew G. Knepley } 52453e9753d6SMatthew G. Knepley /* Loop over chunks */ 52463e9753d6SMatthew G. Knepley cellChunkSize = numCells; 52473e9753d6SMatthew G. Knepley numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize); 524807218a29SMatthew G. Knepley PetscCall(PetscCalloc1(2 * cellChunkSize, &faces)); 524907218a29SMatthew G. Knepley PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS)); 52503e9753d6SMatthew G. Knepley /* Extract field coefficients */ 52513e9753d6SMatthew G. Knepley /* NOTE This needs the end cap faces to have identical orientations */ 525207218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 525307218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 52543e2b0218SMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s)); 525507218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecNeg)); 525607218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecPos)); 525707218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecCoh)); 52583e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 52593e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 52603e9753d6SMatthew G. Knepley 526107218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemVecNeg, cellChunkSize * totDim)); 526207218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemVecPos, cellChunkSize * totDim)); 526307218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemVecCoh, cellChunkSize * totDim)); 52643e9753d6SMatthew G. Knepley /* Get faces */ 52653e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 52663e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 52673e9753d6SMatthew G. Knepley const PetscInt *cone; 52689566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cell, &cone)); 526907218a29SMatthew G. Knepley faces[(c - cS) * 2 + 0] = cone[0]; 527007218a29SMatthew G. Knepley faces[(c - cS) * 2 + 1] = cone[1]; 52713e9753d6SMatthew G. Knepley } 527207218a29SMatthew G. Knepley PetscCall(ISGeneralSetIndices(chunkIS, 2 * cellChunkSize, faces, PETSC_USE_POINTER)); 52733e9753d6SMatthew G. Knepley /* Get geometric data */ 52743e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 52759566063dSJacob Faibussowitsch if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad)); 52769566063dSJacob Faibussowitsch if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom)); 52773e9753d6SMatthew G. Knepley } else { 52783e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 52799566063dSJacob Faibussowitsch if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f])); 52803e9753d6SMatthew G. Knepley } 52813e9753d6SMatthew G. Knepley } 52823e9753d6SMatthew G. Knepley /* Loop over fields */ 52833e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 52843e9753d6SMatthew G. Knepley PetscFE fe; 52853e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 5286148442b3SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 52873e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 52883e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 52895fedec97SMatthew G. Knepley PetscBool isCohesiveField; 52903e9753d6SMatthew G. Knepley 52919566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 52923e9753d6SMatthew G. Knepley if (!fe) continue; 52939566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 52949566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 52959566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 52963e9753d6SMatthew G. Knepley blockSize = Nb; 52973e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 52989566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 52993e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 53003e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 53013e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 53023e9753d6SMatthew G. Knepley offset = numCells - Nr; 530307218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, 0, offset * 2, &chunkGeom)); 530407218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, offset * 2, numCells * 2, &remGeom)); 53059566063dSJacob Faibussowitsch PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField)); 53065fedec97SMatthew G. Knepley chunkGeom->isCohesive = remGeom->isCohesive = PETSC_TRUE; 53076528b96dSMatthew G. Knepley key[0].field = f; 53086528b96dSMatthew G. Knepley key[1].field = f; 53095fedec97SMatthew G. Knepley key[2].field = f; 531007218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, elemVecNeg)); 531107218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[0], 0, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, &elemVecNeg[offset * totDim])); 531207218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, elemVecPos)); 531307218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[1], 1, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, &elemVecPos[offset * totDim])); 531407218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, elemVecCoh)); 531507218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[2], 2, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, &elemVecCoh[offset * totDim])); 53169566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom)); 53179566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom)); 53183e9753d6SMatthew G. Knepley } 53193e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 53203e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 53213e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 53223e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 532307218a29SMatthew G. Knepley PetscInt i; 53243e9753d6SMatthew G. Knepley 532507218a29SMatthew G. Knepley /* Scale element values */ 532607218a29SMatthew G. Knepley if (locS[0]) { 53273e2b0218SMatthew G. Knepley PetscInt Nb, off = cind * totDim, soff = cind * totDimScale[0]; 532807218a29SMatthew G. Knepley PetscBool cohesive; 532907218a29SMatthew G. Knepley 533007218a29SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 533107218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, f, &Nb)); 533207218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(ds, f, &cohesive)); 533307218a29SMatthew G. Knepley if (f == key[2].field) { 533407218a29SMatthew G. Knepley PetscCheck(cohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Scaling should not happen for face fields"); 533507218a29SMatthew G. Knepley // No cohesive scaling field is currently input 533607218a29SMatthew 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]; 533707218a29SMatthew G. Knepley off += Nb; 533807218a29SMatthew G. Knepley } else { 533907218a29SMatthew G. Knepley const PetscInt N = cohesive ? Nb : Nb * 2; 534007218a29SMatthew G. Knepley 534107218a29SMatthew G. Knepley for (i = 0; i < N; ++i) elemVecCoh[off + i] += elemVecNeg[off + i] + elemVecPos[off + i]; 534207218a29SMatthew G. Knepley off += N; 534307218a29SMatthew G. Knepley } 534407218a29SMatthew G. Knepley } 534507218a29SMatthew G. Knepley } else { 534607218a29SMatthew G. Knepley for (i = cind * totDim; i < (cind + 1) * totDim; ++i) elemVecCoh[i] += elemVecNeg[i] + elemVecPos[i]; 534707218a29SMatthew G. Knepley } 534807218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVecCoh[cind * totDim])); 53493e9753d6SMatthew G. Knepley if (ghostLabel) { 53503e9753d6SMatthew G. Knepley PetscInt ghostVal; 53513e9753d6SMatthew G. Knepley 53529566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 53533e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 53543e9753d6SMatthew G. Knepley } 535507218a29SMatthew G. Knepley PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVecCoh[cind * totDim], ADD_ALL_VALUES)); 53563e9753d6SMatthew G. Knepley } 53573e9753d6SMatthew G. Knepley } 53589566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 535907218a29SMatthew G. Knepley PetscCall(DMPlexRestoreHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 53603e2b0218SMatthew G. Knepley PetscCall(DMPlexRestoreHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s)); 536107218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecNeg)); 536207218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecPos)); 536307218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecCoh)); 53649566063dSJacob Faibussowitsch PetscCall(PetscFree(faces)); 53659566063dSJacob Faibussowitsch PetscCall(ISDestroy(&chunkIS)); 53669566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 53673e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 53689566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 53699566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 53703e9753d6SMatthew G. Knepley } else { 53713e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 53729566063dSJacob Faibussowitsch if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 53739566063dSJacob Faibussowitsch if (quads) PetscCall(PetscQuadratureDestroy(&quads[f])); 53743e9753d6SMatthew G. Knepley } 53759566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 53763e9753d6SMatthew G. Knepley } 537785cc2951SMatthew G. Knepley if (mesh->printFEM) { 537885cc2951SMatthew G. Knepley Vec locFbc; 537985cc2951SMatthew G. Knepley PetscInt pStart, pEnd, p, maxDof; 538085cc2951SMatthew G. Knepley PetscScalar *zeroes; 538185cc2951SMatthew G. Knepley 538285cc2951SMatthew G. Knepley PetscCall(VecDuplicate(locF, &locFbc)); 538385cc2951SMatthew G. Knepley PetscCall(VecCopy(locF, locFbc)); 538485cc2951SMatthew G. Knepley PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 538585cc2951SMatthew G. Knepley PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 538685cc2951SMatthew G. Knepley PetscCall(PetscCalloc1(maxDof, &zeroes)); 538785cc2951SMatthew G. Knepley for (p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES)); 538885cc2951SMatthew G. Knepley PetscCall(PetscFree(zeroes)); 538985cc2951SMatthew G. Knepley PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc)); 539085cc2951SMatthew G. Knepley PetscCall(VecDestroy(&locFbc)); 539185cc2951SMatthew G. Knepley } 53929566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 53933ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 53943e9753d6SMatthew G. Knepley } 53953e9753d6SMatthew G. Knepley 5396a4e35b19SJacob 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) 5397d71ae5a4SJacob Faibussowitsch { 53983e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 53993e9753d6SMatthew G. Knepley DM plex = NULL, plexA = NULL, tdm; 54003e9753d6SMatthew G. Knepley DMEnclosureType encAux; 54013e9753d6SMatthew G. Knepley PetscDS prob, probAux = NULL; 54023e9753d6SMatthew G. Knepley PetscSection section, sectionAux = NULL; 5403e432b41dSStefano Zampini PetscSection globalSection; 54043e9753d6SMatthew G. Knepley Vec locA = NULL, tv; 54053e9753d6SMatthew G. Knepley PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL; 54063e9753d6SMatthew G. Knepley PetscInt v; 54073e9753d6SMatthew G. Knepley PetscInt Nf, totDim, totDimAux = 0; 5408e432b41dSStefano Zampini PetscBool transform; 54093e9753d6SMatthew G. Knepley 54103e9753d6SMatthew G. Knepley PetscFunctionBegin; 54119566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 54129566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 54139566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 54149566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 54159566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 54169566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 54179566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 54189566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 54199566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, label, values[0], 0, &locA)); 54203e9753d6SMatthew G. Knepley if (locA) { 54213e9753d6SMatthew G. Knepley DM dmAux; 54223e9753d6SMatthew G. Knepley 54239566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 54249566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 54259566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 54269566063dSJacob Faibussowitsch PetscCall(DMGetDS(plexA, &probAux)); 54279566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 54289566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexA, §ionAux)); 54293e9753d6SMatthew G. Knepley } 54303e9753d6SMatthew G. Knepley 54319566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 54323e9753d6SMatthew G. Knepley for (v = 0; v < numValues; ++v) { 54333e9753d6SMatthew G. Knepley PetscFEGeom *fgeom; 54343e9753d6SMatthew G. Knepley PetscInt maxDegree; 54353e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 54363e9753d6SMatthew G. Knepley IS pointIS; 54373e9753d6SMatthew G. Knepley const PetscInt *points; 543806ad1575SMatthew G. Knepley PetscFormKey key; 54393e9753d6SMatthew G. Knepley PetscInt numFaces, face, Nq; 54403e9753d6SMatthew G. Knepley 544145480ffeSMatthew G. Knepley key.label = label; 544245480ffeSMatthew G. Knepley key.value = values[v]; 544306ad1575SMatthew G. Knepley key.part = 0; 54449566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS)); 54453e9753d6SMatthew G. Knepley if (!pointIS) continue; /* No points with that id on this process */ 54463e9753d6SMatthew G. Knepley { 54473e9753d6SMatthew G. Knepley IS isectIS; 54483e9753d6SMatthew G. Knepley 54493e9753d6SMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a prior if one is a superset of the other */ 54509566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 54519566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 54523e9753d6SMatthew G. Knepley pointIS = isectIS; 54533e9753d6SMatthew G. Knepley } 54549566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 54559566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 54569566063dSJacob Faibussowitsch PetscCall(PetscMalloc4(numFaces * totDim, &u, locX_t ? numFaces * totDim : 0, &u_t, numFaces * totDim * totDim, &elemMat, locA ? numFaces * totDimAux : 0, &a)); 54579566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 545848a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 54593e9753d6SMatthew G. Knepley if (!qGeom) { 54603e9753d6SMatthew G. Knepley PetscFE fe; 54613e9753d6SMatthew G. Knepley 54629566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 54639566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 54649566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 54653e9753d6SMatthew G. Knepley } 54669566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 54679566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 54683e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 5469f15274beSMatthew Knepley const PetscInt point = points[face], *support; 54703e9753d6SMatthew G. Knepley PetscScalar *x = NULL; 5471f15274beSMatthew Knepley PetscInt i; 54723e9753d6SMatthew G. Knepley 54739566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, point, &support)); 54749566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 54753e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 54769566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 54773e9753d6SMatthew G. Knepley if (locX_t) { 54789566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x)); 54793e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i]; 54809566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x)); 54813e9753d6SMatthew G. Knepley } 54823e9753d6SMatthew G. Knepley if (locA) { 54833e9753d6SMatthew G. Knepley PetscInt subp; 54849566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 54859566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 54863e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i]; 54879566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 54883e9753d6SMatthew G. Knepley } 54893e9753d6SMatthew G. Knepley } 54909566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, numFaces * totDim * totDim)); 54913e9753d6SMatthew G. Knepley { 54923e9753d6SMatthew G. Knepley PetscFE fe; 54933e9753d6SMatthew G. Knepley PetscInt Nb; 54943e9753d6SMatthew G. Knepley /* Conforming batches */ 54953e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 54963e9753d6SMatthew G. Knepley /* Remainder */ 54973e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 54983e9753d6SMatthew G. Knepley PetscInt fieldJ, Nr, offset; 54993e9753d6SMatthew G. Knepley 55009566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 55019566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 55029566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 55033e9753d6SMatthew G. Knepley blockSize = Nb; 55043e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 55059566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 55063e9753d6SMatthew G. Knepley numChunks = numFaces / (numBatches * batchSize); 55073e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 55083e9753d6SMatthew G. Knepley Nr = numFaces % (numBatches * batchSize); 55093e9753d6SMatthew G. Knepley offset = numFaces - Nr; 55109566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom)); 55113e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 551245480ffeSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 55139566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBdJacobian(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 55143e9753d6SMatthew G. Knepley } 55159566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 55163e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 551745480ffeSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 55189566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBdJacobian(prob, wf, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, X_tShift, &elemMat[offset * totDim * totDim])); 55193e9753d6SMatthew G. Knepley } 55209566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 55213e9753d6SMatthew G. Knepley } 55223e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 55233e9753d6SMatthew G. Knepley const PetscInt point = points[face], *support; 55243e9753d6SMatthew G. Knepley 55253e9753d6SMatthew G. Knepley /* Transform to global basis before insertion in Jacobian */ 55269566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(plex, point, &support)); 55279566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMat[face * totDim * totDim])); 55289566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face * totDim * totDim])); 5529*e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, JacP, support[0], &elemMat[face * totDim * totDim], ADD_VALUES)); 55303e9753d6SMatthew G. Knepley } 55319566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 55329566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 55339566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 55349566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 55359566063dSJacob Faibussowitsch PetscCall(PetscFree4(u, u_t, elemMat, a)); 55363e9753d6SMatthew G. Knepley } 55379566063dSJacob Faibussowitsch if (plex) PetscCall(DMDestroy(&plex)); 55389566063dSJacob Faibussowitsch if (plexA) PetscCall(DMDestroy(&plexA)); 55393ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 55403e9753d6SMatthew G. Knepley } 55413e9753d6SMatthew G. Knepley 5542d71ae5a4SJacob 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) 5543d71ae5a4SJacob Faibussowitsch { 55443e9753d6SMatthew G. Knepley DMField coordField; 55453e9753d6SMatthew G. Knepley DMLabel depthLabel; 55463e9753d6SMatthew G. Knepley IS facetIS; 55473e9753d6SMatthew G. Knepley PetscInt dim; 55483e9753d6SMatthew G. Knepley 55493e9753d6SMatthew G. Knepley PetscFunctionBegin; 55509566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 55519566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 55529566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 55539566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 55549566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, field, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS)); 55559566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 55563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 55573e9753d6SMatthew G. Knepley } 55583e9753d6SMatthew G. Knepley 5559a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexComputeBdJacobian_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP, void *user) 5560d71ae5a4SJacob Faibussowitsch { 55613e9753d6SMatthew G. Knepley PetscDS prob; 55623e9753d6SMatthew G. Knepley PetscInt dim, numBd, bd; 55633e9753d6SMatthew G. Knepley DMLabel depthLabel; 55643e9753d6SMatthew G. Knepley DMField coordField = NULL; 55653e9753d6SMatthew G. Knepley IS facetIS; 55663e9753d6SMatthew G. Knepley 55673e9753d6SMatthew G. Knepley PetscFunctionBegin; 55689566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 55699566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 55709566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 55719566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 55729566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 55739566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 55743e9753d6SMatthew G. Knepley for (bd = 0; bd < numBd; ++bd) { 557545480ffeSMatthew G. Knepley PetscWeakForm wf; 55763e9753d6SMatthew G. Knepley DMBoundaryConditionType type; 55773e9753d6SMatthew G. Knepley DMLabel label; 55783e9753d6SMatthew G. Knepley const PetscInt *values; 55793e9753d6SMatthew G. Knepley PetscInt fieldI, numValues; 55803e9753d6SMatthew G. Knepley PetscObject obj; 55813e9753d6SMatthew G. Knepley PetscClassId id; 55823e9753d6SMatthew G. Knepley 55839566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &fieldI, NULL, NULL, NULL, NULL, NULL)); 55843d3e5d66SMatthew G. Knepley if (type & DM_BC_ESSENTIAL) continue; 55859566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, &obj)); 55869566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 55873d3e5d66SMatthew G. Knepley if (id != PETSCFE_CLASSID) continue; 55889566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, fieldI, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS)); 55893e9753d6SMatthew G. Knepley } 55909566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 55913ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 55923e9753d6SMatthew G. Knepley } 55933e9753d6SMatthew G. Knepley 5594d71ae5a4SJacob 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) 5595d71ae5a4SJacob Faibussowitsch { 55963e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 55973e9753d6SMatthew G. Knepley const char *name = "Jacobian"; 55989a2a23afSMatthew G. Knepley DM dmAux = NULL, plex, tdm; 55993e9753d6SMatthew G. Knepley DMEnclosureType encAux; 56003e9753d6SMatthew G. Knepley Vec A, tv; 56013e9753d6SMatthew G. Knepley DMField coordField; 56023e9753d6SMatthew G. Knepley PetscDS prob, probAux = NULL; 5603e432b41dSStefano Zampini PetscSection section, globalSection, sectionAux; 56043e9753d6SMatthew G. Knepley PetscScalar *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL; 56053e9753d6SMatthew G. Knepley const PetscInt *cells; 56063e9753d6SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ; 560728351e22SJed Brown PetscInt totDim, totDimAux = 0, cStart, cEnd, numCells, c; 5608e04ae0b4SMatthew G. Knepley PetscBool hasJac = PETSC_FALSE, hasPrec = PETSC_FALSE, hasDyn, hasFV = PETSC_FALSE, transform; 56093e9753d6SMatthew G. Knepley 56103e9753d6SMatthew G. Knepley PetscFunctionBegin; 5611af18b51aSmarkadams4 PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 5612e04ae0b4SMatthew G. Knepley if (!cellIS) goto end; 56139566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5614437e83fbSMatthew G. Knepley PetscCall(ISGetLocalSize(cellIS, &numCells)); 5615437e83fbSMatthew G. Knepley if (cStart >= cEnd) goto end; 56169566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 56179566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 56189566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 56199566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 56209566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 562107218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL)); 56229566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 56239566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 56249566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobian(prob, &hasJac)); 56259566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec)); 56263e9753d6SMatthew G. Knepley /* user passed in the same matrix, avoid double contributions and 56273e9753d6SMatthew G. Knepley only assemble the Jacobian */ 56283e9753d6SMatthew G. Knepley if (hasJac && Jac == JacP) hasPrec = PETSC_FALSE; 56299566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 56303e9753d6SMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 56319566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A)); 56329a2a23afSMatthew G. Knepley if (A) { 56339566063dSJacob Faibussowitsch PetscCall(VecGetDM(A, &dmAux)); 56349566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 56359566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plex)); 56369566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plex, §ionAux)); 56379566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 56389566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 56393e9753d6SMatthew G. Knepley } 56409566063dSJacob Faibussowitsch PetscCall(PetscMalloc5(numCells * totDim, &u, X_t ? numCells * totDim : 0, &u_t, hasJac ? numCells * totDim * totDim : 0, &elemMat, hasPrec ? numCells * totDim * totDim : 0, &elemMatP, hasDyn ? numCells * totDim * totDim : 0, &elemMatD)); 56419566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 56429566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 56433e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 56443e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 56453e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 56463e9753d6SMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 56473e9753d6SMatthew G. Knepley PetscInt i; 56483e9753d6SMatthew G. Knepley 56499566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x)); 56503e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i]; 56519566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x)); 56523e9753d6SMatthew G. Knepley if (X_t) { 56539566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t)); 56543e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i]; 56559566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t)); 56563e9753d6SMatthew G. Knepley } 56573e9753d6SMatthew G. Knepley if (dmAux) { 56583e9753d6SMatthew G. Knepley PetscInt subcell; 56599566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell)); 56609566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x)); 56613e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i]; 56629566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x)); 56633e9753d6SMatthew G. Knepley } 56643e9753d6SMatthew G. Knepley } 56659566063dSJacob Faibussowitsch if (hasJac) PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim)); 56669566063dSJacob Faibussowitsch if (hasPrec) PetscCall(PetscArrayzero(elemMatP, numCells * totDim * totDim)); 56679566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim)); 56683e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 56693e9753d6SMatthew G. Knepley PetscClassId id; 56703e9753d6SMatthew G. Knepley PetscFE fe; 56713e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 56723e9753d6SMatthew G. Knepley PetscInt Nb; 56733e9753d6SMatthew G. Knepley /* Conforming batches */ 56743e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 56753e9753d6SMatthew G. Knepley /* Remainder */ 56763e9753d6SMatthew G. Knepley PetscInt Nr, offset, Nq; 56773e9753d6SMatthew G. Knepley PetscInt maxDegree; 56783e9753d6SMatthew G. Knepley PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 56793e9753d6SMatthew G. Knepley 56809566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 56819566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 56829371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 56839371c9d4SSatish Balay hasFV = PETSC_TRUE; 56849371c9d4SSatish Balay continue; 56859371c9d4SSatish Balay } 56869566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 56879566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 56889566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 568948a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 56903e9753d6SMatthew G. Knepley if (!qGeom) { 56919566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 56929566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 56933e9753d6SMatthew G. Knepley } 56949566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 56959566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 56963e9753d6SMatthew G. Knepley blockSize = Nb; 56973e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 56989566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 56993e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 57003e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 57013e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 57023e9753d6SMatthew G. Knepley offset = numCells - Nr; 57039566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 57049566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom)); 57053e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 57066528b96dSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 57073e9753d6SMatthew G. Knepley if (hasJac) { 57089566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 5709072f5ffdSStefano Zampini PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, X_tShift, &elemMat[offset * totDim * totDim])); 57103e9753d6SMatthew G. Knepley } 57113e9753d6SMatthew G. Knepley if (hasPrec) { 57129566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP)); 5713072f5ffdSStefano Zampini PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, X_tShift, &elemMatP[offset * totDim * totDim])); 57143e9753d6SMatthew G. Knepley } 57153e9753d6SMatthew G. Knepley if (hasDyn) { 57169566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD)); 5717072f5ffdSStefano Zampini PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, X_tShift, &elemMatD[offset * totDim * totDim])); 57183e9753d6SMatthew G. Knepley } 57193e9753d6SMatthew G. Knepley } 57209566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom)); 57219566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom)); 57229566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 57239566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 57243e9753d6SMatthew G. Knepley } 57253e9753d6SMatthew G. Knepley /* Add contribution from X_t */ 57269371c9d4SSatish Balay if (hasDyn) { 57279371c9d4SSatish Balay for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 57289371c9d4SSatish Balay } 57293e9753d6SMatthew G. Knepley if (hasFV) { 57303e9753d6SMatthew G. Knepley PetscClassId id; 57313e9753d6SMatthew G. Knepley PetscFV fv; 57323e9753d6SMatthew G. Knepley PetscInt offsetI, NcI, NbI = 1, fc, f; 57333e9753d6SMatthew G. Knepley 57343e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 57359566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv)); 57369566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, fieldI, &offsetI)); 57379566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId((PetscObject)fv, &id)); 57383e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 57393e9753d6SMatthew G. Knepley /* Put in the identity */ 57409566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &NcI)); 57413e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 57423e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 57433e9753d6SMatthew G. Knepley const PetscInt eOffset = cind * totDim * totDim; 57443e9753d6SMatthew G. Knepley for (fc = 0; fc < NcI; ++fc) { 57453e9753d6SMatthew G. Knepley for (f = 0; f < NbI; ++f) { 57463e9753d6SMatthew G. Knepley const PetscInt i = offsetI + f * NcI + fc; 57473e9753d6SMatthew G. Knepley if (hasPrec) { 5748ad540459SPierre Jolivet if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0; 57493e9753d6SMatthew G. Knepley elemMatP[eOffset + i * totDim + i] = 1.0; 57509371c9d4SSatish Balay } else { 57519371c9d4SSatish Balay elemMat[eOffset + i * totDim + i] = 1.0; 57529371c9d4SSatish Balay } 57533e9753d6SMatthew G. Knepley } 57543e9753d6SMatthew G. Knepley } 57553e9753d6SMatthew G. Knepley } 57563e9753d6SMatthew G. Knepley } 57573e9753d6SMatthew G. Knepley /* No allocated space for FV stuff, so ignore the zero entries */ 57589566063dSJacob Faibussowitsch PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); 57593e9753d6SMatthew G. Knepley } 57603e9753d6SMatthew G. Knepley /* Insert values into matrix */ 57613e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 57623e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 57633e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 57643e9753d6SMatthew G. Knepley 57653e9753d6SMatthew G. Knepley /* Transform to global basis before insertion in Jacobian */ 57669566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind * totDim * totDim])); 57673e9753d6SMatthew G. Knepley if (hasPrec) { 57683e9753d6SMatthew G. Knepley if (hasJac) { 57699566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 5770*e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMat[cind * totDim * totDim], ADD_VALUES)); 57713e9753d6SMatthew G. Knepley } 57729566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind * totDim * totDim])); 57739566063dSJacob Faibussowitsch PetscCall(DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMatP[cind * totDim * totDim], ADD_VALUES)); 57743e9753d6SMatthew G. Knepley } else { 57753e9753d6SMatthew G. Knepley if (hasJac) { 57769566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 5777*e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, JacP, cell, &elemMat[cind * totDim * totDim], ADD_VALUES)); 57783e9753d6SMatthew G. Knepley } 57793e9753d6SMatthew G. Knepley } 57803e9753d6SMatthew G. Knepley } 57819566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 57829566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE)); 57839566063dSJacob Faibussowitsch PetscCall(PetscFree5(u, u_t, elemMat, elemMatP, elemMatD)); 57843e9753d6SMatthew G. Knepley if (dmAux) { 57859566063dSJacob Faibussowitsch PetscCall(PetscFree(a)); 57869566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 57873e9753d6SMatthew G. Knepley } 57883e9753d6SMatthew G. Knepley /* Compute boundary integrals */ 57899566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, user)); 57903e9753d6SMatthew G. Knepley /* Assemble matrix */ 57919371c9d4SSatish Balay end : { 5792e04ae0b4SMatthew G. Knepley PetscBool assOp = hasJac && hasPrec ? PETSC_TRUE : PETSC_FALSE, gassOp; 5793e04ae0b4SMatthew G. Knepley 5794712fec58SPierre Jolivet PetscCall(MPIU_Allreduce(&assOp, &gassOp, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 57953e9753d6SMatthew G. Knepley if (hasJac && hasPrec) { 57969566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY)); 57979566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY)); 57983e9753d6SMatthew G. Knepley } 5799e04ae0b4SMatthew G. Knepley } 58009566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY)); 58019566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 58029566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 58033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 58043e9753d6SMatthew G. Knepley } 58053e9753d6SMatthew G. Knepley 5806d71ae5a4SJacob 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) 5807d71ae5a4SJacob Faibussowitsch { 58083e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 58093e9753d6SMatthew G. Knepley const char *name = "Hybrid Jacobian"; 5810148442b3SMatthew G. Knepley DM dmAux[3] = {NULL, NULL, NULL}; 5811148442b3SMatthew G. Knepley DMLabel ghostLabel = NULL; 58123e9753d6SMatthew G. Knepley DM plex = NULL; 58133e9753d6SMatthew G. Knepley DM plexA = NULL; 5814148442b3SMatthew G. Knepley PetscDS ds = NULL; 581507218a29SMatthew G. Knepley PetscDS dsIn = NULL; 5816148442b3SMatthew G. Knepley PetscDS dsAux[3] = {NULL, NULL, NULL}; 5817148442b3SMatthew G. Knepley Vec locA[3] = {NULL, NULL, NULL}; 581807218a29SMatthew G. Knepley DM dmScale[3] = {NULL, NULL, NULL}; 581907218a29SMatthew G. Knepley PetscDS dsScale[3] = {NULL, NULL, NULL}; 582007218a29SMatthew G. Knepley Vec locS[3] = {NULL, NULL, NULL}; 58213e9753d6SMatthew G. Knepley PetscSection section = NULL; 5822148442b3SMatthew G. Knepley PetscSection sectionAux[3] = {NULL, NULL, NULL}; 58233e9753d6SMatthew G. Knepley DMField coordField = NULL; 582407218a29SMatthew G. Knepley PetscScalar *a[3] = {NULL, NULL, NULL}; 582507218a29SMatthew G. Knepley PetscScalar *s[3] = {NULL, NULL, NULL}; 582607218a29SMatthew G. Knepley PetscScalar *u = NULL, *u_t; 582707218a29SMatthew G. Knepley PetscScalar *elemMatNeg, *elemMatPos, *elemMatCoh; 582807218a29SMatthew G. Knepley PetscScalar *elemMatNegP, *elemMatPosP, *elemMatCohP; 5829e432b41dSStefano Zampini PetscSection globalSection; 58303e9753d6SMatthew G. Knepley IS chunkIS; 58313e9753d6SMatthew G. Knepley const PetscInt *cells; 58323e9753d6SMatthew G. Knepley PetscInt *faces; 58333e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 58343e2b0218SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ, totDim, totDimIn, totDimAux[3], totDimScale[3], numChunks, cellChunkSize, chunk; 58353e9753d6SMatthew G. Knepley PetscInt maxDegree = PETSC_MAX_INT; 58363e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 58373e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 5838e432b41dSStefano Zampini PetscBool hasBdJac, hasBdPrec; 58393e9753d6SMatthew G. Knepley 58403e9753d6SMatthew G. Knepley PetscFunctionBegin; 58413ba16761SJacob Faibussowitsch if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS); 5842437e83fbSMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5843437e83fbSMatthew G. Knepley PetscCall(ISGetLocalSize(cellIS, &numCells)); 58443ba16761SJacob Faibussowitsch if (cStart >= cEnd) PetscFunctionReturn(PETSC_SUCCESS); 58455fedec97SMatthew G. Knepley if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) { 58465fedec97SMatthew G. Knepley const char *name; 58479566063dSJacob Faibussowitsch PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name)); 584863a3b9bcSJacob 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); 58495fedec97SMatthew G. Knepley } 58509566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 58519566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 58529566063dSJacob Faibussowitsch PetscCall(DMGetSection(dm, §ion)); 58539566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 58549566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 585507218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn)); 58569566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 58579566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 585807218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsIn, &totDimIn)); 58599566063dSJacob Faibussowitsch PetscCall(PetscDSHasBdJacobian(ds, &hasBdJac)); 58609566063dSJacob Faibussowitsch PetscCall(PetscDSHasBdJacobianPreconditioner(ds, &hasBdPrec)); 58619566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2])); 5862148442b3SMatthew G. Knepley if (locA[2]) { 58631059d808SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 58641059d808SMatthew G. Knepley 58659566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA[2], &dmAux[2])); 58669566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux[2], DMPLEX, &plexA)); 58679566063dSJacob Faibussowitsch PetscCall(DMGetSection(dmAux[2], §ionAux[2])); 586807218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2], NULL)); 58699566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2])); 5870148442b3SMatthew G. Knepley { 5871148442b3SMatthew G. Knepley const PetscInt *cone; 5872148442b3SMatthew G. Knepley PetscInt c; 5873148442b3SMatthew G. Knepley 58741059d808SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 5875148442b3SMatthew G. Knepley for (c = 0; c < 2; ++c) { 5876148442b3SMatthew G. Knepley const PetscInt *support; 5877148442b3SMatthew G. Knepley PetscInt ssize, s; 5878148442b3SMatthew G. Knepley 58799566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 58809566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 58811059d808SMatthew 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); 58821059d808SMatthew G. Knepley if (support[0] == cellStart) s = 1; 58831059d808SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 58841059d808SMatthew 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); 58859566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c])); 58869566063dSJacob Faibussowitsch if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c])); 5887ad540459SPierre Jolivet else dmAux[c] = dmAux[2]; 588807218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c], NULL)); 58899566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c])); 5890148442b3SMatthew G. Knepley } 5891148442b3SMatthew G. Knepley } 58923e9753d6SMatthew G. Knepley } 589307218a29SMatthew G. Knepley /* Handle mass matrix scaling 589407218a29SMatthew G. Knepley The field in key[2] is the field to be scaled, and the scaling field is the first in the dsScale */ 589507218a29SMatthew G. Knepley PetscCall(DMGetAuxiliaryVec(dm, key[2].label, -key[2].value, key[2].part, &locS[2])); 589607218a29SMatthew G. Knepley if (locS[2]) { 58973e2b0218SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 589807218a29SMatthew G. Knepley PetscInt Nb, Nbs; 589907218a29SMatthew G. Knepley 590007218a29SMatthew G. Knepley PetscCall(VecGetDM(locS[2], &dmScale[2])); 590107218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[2], cells ? cells[cStart] : cStart, &dsScale[2], NULL)); 59023e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[2], &totDimScale[2])); 590307218a29SMatthew G. Knepley // BRAD: This is not set correctly 590407218a29SMatthew G. Knepley key[2].field = 2; 590507218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, key[2].field, &Nb)); 590607218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsScale[2], 0, &Nbs)); 590707218a29SMatthew 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); 59083e2b0218SMatthew G. Knepley { 59093e2b0218SMatthew G. Knepley const PetscInt *cone; 59103e2b0218SMatthew G. Knepley PetscInt c; 59113e2b0218SMatthew G. Knepley 59123e2b0218SMatthew G. Knepley locS[1] = locS[0] = locS[2]; 59133e2b0218SMatthew G. Knepley dmScale[1] = dmScale[0] = dmScale[2]; 59143e2b0218SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 59153e2b0218SMatthew G. Knepley for (c = 0; c < 2; ++c) { 59163e2b0218SMatthew G. Knepley const PetscInt *support; 59173e2b0218SMatthew G. Knepley PetscInt ssize, s; 59183e2b0218SMatthew G. Knepley 59193e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 59203e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 59213e2b0218SMatthew 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); 59223e2b0218SMatthew G. Knepley if (support[0] == cellStart) s = 1; 59233e2b0218SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 59243e2b0218SMatthew 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); 59253e2b0218SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[c], support[s], &dsScale[c], NULL)); 59263e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[c], &totDimScale[c])); 59273e2b0218SMatthew G. Knepley } 59283e2b0218SMatthew G. Knepley } 592907218a29SMatthew G. Knepley } 593007218a29SMatthew G. Knepley /* 2: Setup geometric data */ 59319566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 59329566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 59333e9753d6SMatthew G. Knepley if (maxDegree > 1) { 59343e9753d6SMatthew G. Knepley PetscInt f; 59359566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 59363e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 59373e9753d6SMatthew G. Knepley PetscFE fe; 59383e9753d6SMatthew G. Knepley 59399566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 59403e9753d6SMatthew G. Knepley if (fe) { 59419566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 59429566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 59433e9753d6SMatthew G. Knepley } 59443e9753d6SMatthew G. Knepley } 59453e9753d6SMatthew G. Knepley } 594607218a29SMatthew G. Knepley /* Loop over chunks */ 59473e9753d6SMatthew G. Knepley cellChunkSize = numCells; 59483e9753d6SMatthew G. Knepley numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize); 594907218a29SMatthew G. Knepley PetscCall(PetscCalloc1(2 * cellChunkSize, &faces)); 5950a4158a15SMatthew G. Knepley PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 1 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS)); 595107218a29SMatthew G. Knepley /* Extract field coefficients */ 595207218a29SMatthew G. Knepley /* NOTE This needs the end cap faces to have identical orientations */ 595307218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 595407218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 59558bf0a22dSMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s)); 595607218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNeg)); 595707218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPos)); 595807218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCoh)); 595907218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNegP)); 596007218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPosP)); 596107218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCohP)); 59623e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 59633e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 59643e9753d6SMatthew G. Knepley 596507218a29SMatthew G. Knepley if (hasBdJac) { 596607218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatNeg, cellChunkSize * totDim * totDim)); 596707218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatPos, cellChunkSize * totDim * totDim)); 596807218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatCoh, cellChunkSize * totDim * totDim)); 596907218a29SMatthew G. Knepley } 597007218a29SMatthew G. Knepley if (hasBdPrec) { 597107218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatNegP, cellChunkSize * totDim * totDim)); 597207218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatPosP, cellChunkSize * totDim * totDim)); 597307218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatCohP, cellChunkSize * totDim * totDim)); 597407218a29SMatthew G. Knepley } 59753e9753d6SMatthew G. Knepley /* Get faces */ 59763e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 59773e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 59783e9753d6SMatthew G. Knepley const PetscInt *cone; 59799566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(plex, cell, &cone)); 598007218a29SMatthew G. Knepley faces[(c - cS) * 2 + 0] = cone[0]; 598107218a29SMatthew G. Knepley faces[(c - cS) * 2 + 1] = cone[1]; 59823e9753d6SMatthew G. Knepley } 598307218a29SMatthew G. Knepley PetscCall(ISGeneralSetIndices(chunkIS, 2 * cellChunkSize, faces, PETSC_USE_POINTER)); 59843e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 59859566063dSJacob Faibussowitsch if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad)); 59869566063dSJacob Faibussowitsch if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom)); 59873e9753d6SMatthew G. Knepley } else { 59883e9753d6SMatthew G. Knepley PetscInt f; 59893e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 59909566063dSJacob Faibussowitsch if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f])); 59913e9753d6SMatthew G. Knepley } 59923e9753d6SMatthew G. Knepley } 59933e9753d6SMatthew G. Knepley 59943e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 59953e9753d6SMatthew G. Knepley PetscFE feI; 59963e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[fieldI]; 59973e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 59983e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[fieldI]; 59993e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 60005fedec97SMatthew G. Knepley PetscBool isCohesiveField; 60013e9753d6SMatthew G. Knepley 60029566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&feI)); 60033e9753d6SMatthew G. Knepley if (!feI) continue; 60049566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(feI, NULL, &numBlocks, NULL, &numBatches)); 60059566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 60069566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feI, &Nb)); 60073e9753d6SMatthew G. Knepley blockSize = Nb; 60083e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 60099566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(feI, blockSize, numBlocks, batchSize, numBatches)); 60103e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 60113e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 60123e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 60133e9753d6SMatthew G. Knepley offset = numCells - Nr; 601407218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, 0, offset * 2, &chunkGeom)); 601507218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, offset * 2, numCells * 2, &remGeom)); 60169566063dSJacob Faibussowitsch PetscCall(PetscDSGetCohesive(ds, fieldI, &isCohesiveField)); 60173e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 60183e9753d6SMatthew G. Knepley PetscFE feJ; 60193e9753d6SMatthew G. Knepley 60209566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *)&feJ)); 60213e9753d6SMatthew G. Knepley if (!feJ) continue; 6022148442b3SMatthew G. Knepley key[0].field = fieldI * Nf + fieldJ; 6023148442b3SMatthew G. Knepley key[1].field = fieldI * Nf + fieldJ; 60245fedec97SMatthew G. Knepley key[2].field = fieldI * Nf + fieldJ; 6025148442b3SMatthew G. Knepley if (hasBdJac) { 602607218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMatNeg)); 602707218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[0], 0, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, X_tShift, &elemMatNeg[offset * totDim * totDim])); 602807218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMatPos)); 602907218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[1], 1, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, X_tShift, &elemMatPos[offset * totDim * totDim])); 6030148442b3SMatthew G. Knepley } 6031148442b3SMatthew G. Knepley if (hasBdPrec) { 603207218a29SMatthew 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)); 603307218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[0], 0, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, X_tShift, &elemMatNegP[offset * totDim * totDim])); 603407218a29SMatthew 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)); 603507218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[1], 1, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, X_tShift, &elemMatPosP[offset * totDim * totDim])); 6036148442b3SMatthew G. Knepley } 60375fedec97SMatthew G. Knepley if (hasBdJac) { 603807218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMatCoh)); 603907218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[2], 2, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, X_tShift, &elemMatCoh[offset * totDim * totDim])); 6040148442b3SMatthew G. Knepley } 60415fedec97SMatthew G. Knepley if (hasBdPrec) { 604207218a29SMatthew 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)); 604307218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[2], 2, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, X_tShift, &elemMatCohP[offset * totDim * totDim])); 60443e9753d6SMatthew G. Knepley } 60453e9753d6SMatthew G. Knepley } 60469566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom)); 60479566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom)); 60483e9753d6SMatthew G. Knepley } 60493e9753d6SMatthew G. Knepley /* Insert values into matrix */ 60503e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 60513e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 605207218a29SMatthew G. Knepley const PetscInt cind = c - cS, coff = cind * totDim * totDim; 605307218a29SMatthew G. Knepley PetscInt i, j; 60543e9753d6SMatthew G. Knepley 605507218a29SMatthew G. Knepley /* Scale element values */ 605607218a29SMatthew G. Knepley if (locS[0]) { 60573e2b0218SMatthew G. Knepley PetscInt Nb, soff = cind * totDimScale[0], off = 0; 605807218a29SMatthew G. Knepley PetscBool cohesive; 605907218a29SMatthew G. Knepley 606007218a29SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 606107218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, fieldI, &Nb)); 606207218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(ds, fieldI, &cohesive)); 606307218a29SMatthew G. Knepley 606407218a29SMatthew G. Knepley if (fieldI == key[2].field) { 606507218a29SMatthew G. Knepley PetscCheck(cohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Scaling should not happen for face fields"); 60668bf0a22dSMatthew G. Knepley for (i = 0; i < Nb; ++i) { 606707218a29SMatthew 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]; 60688bf0a22dSMatthew G. Knepley if (hasBdPrec) 60698bf0a22dSMatthew 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]; 60708bf0a22dSMatthew G. Knepley } 607107218a29SMatthew G. Knepley off += Nb; 607207218a29SMatthew G. Knepley } else { 607307218a29SMatthew G. Knepley const PetscInt N = cohesive ? Nb : Nb * 2; 607407218a29SMatthew G. Knepley 60758bf0a22dSMatthew G. Knepley for (i = 0; i < N; ++i) { 607607218a29SMatthew 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]; 60778bf0a22dSMatthew G. Knepley if (hasBdPrec) 60788bf0a22dSMatthew 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]; 60798bf0a22dSMatthew G. Knepley } 608007218a29SMatthew G. Knepley off += N; 608107218a29SMatthew G. Knepley } 608207218a29SMatthew G. Knepley } 608307218a29SMatthew G. Knepley } else { 608407218a29SMatthew G. Knepley for (i = 0; i < totDim * totDim; ++i) elemMatCoh[coff + i] += elemMatNeg[coff + i] + elemMatPos[coff + i]; 60858bf0a22dSMatthew G. Knepley if (hasBdPrec) 60868bf0a22dSMatthew G. Knepley for (i = 0; i < totDim * totDim; ++i) elemMatCohP[coff + i] += elemMatNegP[coff + i] + elemMatPosP[coff + i]; 608707218a29SMatthew G. Knepley } 60883e9753d6SMatthew G. Knepley if (hasBdPrec) { 60893e9753d6SMatthew G. Knepley if (hasBdJac) { 609007218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCoh[cind * totDim * totDim])); 6091*e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMatCoh[cind * totDim * totDim], ADD_VALUES)); 60923e9753d6SMatthew G. Knepley } 609307218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCohP[cind * totDim * totDim])); 609407218a29SMatthew G. Knepley PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMatCohP[cind * totDim * totDim], ADD_VALUES)); 60953e9753d6SMatthew G. Knepley } else if (hasBdJac) { 609607218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCoh[cind * totDim * totDim])); 6097*e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, JacP, cell, &elemMatCoh[cind * totDim * totDim], ADD_VALUES)); 60983e9753d6SMatthew G. Knepley } 60993e9753d6SMatthew G. Knepley } 61003e9753d6SMatthew G. Knepley } 61019566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 610207218a29SMatthew G. Knepley PetscCall(DMPlexRestoreHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 610307218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNeg)); 610407218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPos)); 610507218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCoh)); 610607218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNegP)); 610707218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPosP)); 610807218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCohP)); 61099566063dSJacob Faibussowitsch PetscCall(PetscFree(faces)); 61109566063dSJacob Faibussowitsch PetscCall(ISDestroy(&chunkIS)); 61119566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 61123e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 61139566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 61149566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 61153e9753d6SMatthew G. Knepley } else { 61163e9753d6SMatthew G. Knepley PetscInt f; 61173e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 61189566063dSJacob Faibussowitsch if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 61199566063dSJacob Faibussowitsch if (quads) PetscCall(PetscQuadratureDestroy(&quads[f])); 61203e9753d6SMatthew G. Knepley } 61219566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 61223e9753d6SMatthew G. Knepley } 61239566063dSJacob Faibussowitsch if (dmAux[2]) PetscCall(DMDestroy(&plexA)); 61249566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 61259566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 61263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 61273e9753d6SMatthew G. Knepley } 61288e3a2eefSMatthew G. Knepley 61298e3a2eefSMatthew G. Knepley /* 61308e3a2eefSMatthew 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. 61318e3a2eefSMatthew G. Knepley 61328e3a2eefSMatthew G. Knepley Input Parameters: 61338e3a2eefSMatthew G. Knepley + dm - The mesh 61348e3a2eefSMatthew G. Knepley . key - The PetscWeakFormKey indcating where integration should happen 613506ad1575SMatthew G. Knepley . cellIS - The cells to integrate over 61368e3a2eefSMatthew G. Knepley . t - The time 6137145b44c9SPierre Jolivet . X_tShift - The multiplier for the Jacobian with respect to X_t 61388e3a2eefSMatthew G. Knepley . X - Local solution vector 61398e3a2eefSMatthew G. Knepley . X_t - Time-derivative of the local solution vector 61408e3a2eefSMatthew G. Knepley . Y - Local input vector 614106ad1575SMatthew G. Knepley - user - the user context 61428e3a2eefSMatthew G. Knepley 61438e3a2eefSMatthew G. Knepley Output Parameter: 61448e3a2eefSMatthew G. Knepley . Z - Local output vector 61458e3a2eefSMatthew G. Knepley 61468e3a2eefSMatthew G. Knepley Note: 61478e3a2eefSMatthew G. Knepley We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator, 61488e3a2eefSMatthew G. Knepley like a GPU, or vectorize on a multicore machine. 61498e3a2eefSMatthew G. Knepley */ 6150d71ae5a4SJacob 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) 6151d71ae5a4SJacob Faibussowitsch { 61528e3a2eefSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 61538e3a2eefSMatthew G. Knepley const char *name = "Jacobian"; 61548e3a2eefSMatthew G. Knepley DM dmAux = NULL, plex, plexAux = NULL; 61558e3a2eefSMatthew G. Knepley DMEnclosureType encAux; 61568e3a2eefSMatthew G. Knepley Vec A; 61578e3a2eefSMatthew G. Knepley DMField coordField; 61588e3a2eefSMatthew G. Knepley PetscDS prob, probAux = NULL; 61598e3a2eefSMatthew G. Knepley PetscQuadrature quad; 61608e3a2eefSMatthew G. Knepley PetscSection section, globalSection, sectionAux; 61618e3a2eefSMatthew G. Knepley PetscScalar *elemMat, *elemMatD, *u, *u_t, *a = NULL, *y, *z; 61628e3a2eefSMatthew G. Knepley const PetscInt *cells; 61638e3a2eefSMatthew G. Knepley PetscInt Nf, fieldI, fieldJ; 61648e3a2eefSMatthew G. Knepley PetscInt totDim, totDimAux = 0, cStart, cEnd, numCells, c; 61658e3a2eefSMatthew G. Knepley PetscBool hasDyn; 61668e3a2eefSMatthew G. Knepley 61678e3a2eefSMatthew G. Knepley PetscFunctionBegin; 616821d77094SMatthew G. Knepley if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS); 61699566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 61709566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 61719566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(cellIS, &numCells)); 61729566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 61739566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 61749566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 617507218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL)); 61769566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 61779566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 61789566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 61798e3a2eefSMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 61809566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A)); 61818e3a2eefSMatthew G. Knepley if (A) { 61829566063dSJacob Faibussowitsch PetscCall(VecGetDM(A, &dmAux)); 61839566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 61849566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexAux)); 61859566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexAux, §ionAux)); 61869566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 61879566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 61888e3a2eefSMatthew G. Knepley } 61899566063dSJacob Faibussowitsch PetscCall(VecSet(Z, 0.0)); 61909566063dSJacob Faibussowitsch PetscCall(PetscMalloc6(numCells * totDim, &u, X_t ? numCells * totDim : 0, &u_t, numCells * totDim * totDim, &elemMat, hasDyn ? numCells * totDim * totDim : 0, &elemMatD, numCells * totDim, &y, totDim, &z)); 61919566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 61929566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 61938e3a2eefSMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 61948e3a2eefSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 61958e3a2eefSMatthew G. Knepley const PetscInt cind = c - cStart; 61968e3a2eefSMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 61978e3a2eefSMatthew G. Knepley PetscInt i; 61988e3a2eefSMatthew G. Knepley 61999566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, X, cell, NULL, &x)); 62008e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i]; 62019566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, X, cell, NULL, &x)); 62028e3a2eefSMatthew G. Knepley if (X_t) { 62039566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, X_t, cell, NULL, &x_t)); 62048e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i]; 62059566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, X_t, cell, NULL, &x_t)); 62068e3a2eefSMatthew G. Knepley } 62078e3a2eefSMatthew G. Knepley if (dmAux) { 62088e3a2eefSMatthew G. Knepley PetscInt subcell; 62099566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell)); 62109566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexAux, sectionAux, A, subcell, NULL, &x)); 62118e3a2eefSMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i]; 62129566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexAux, sectionAux, A, subcell, NULL, &x)); 62138e3a2eefSMatthew G. Knepley } 62149566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, Y, cell, NULL, &x)); 62158e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) y[cind * totDim + i] = x[i]; 62169566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, Y, cell, NULL, &x)); 62178e3a2eefSMatthew G. Knepley } 62189566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim)); 62199566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim)); 62208e3a2eefSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 62218e3a2eefSMatthew G. Knepley PetscFE fe; 62228e3a2eefSMatthew G. Knepley PetscInt Nb; 62238e3a2eefSMatthew G. Knepley /* Conforming batches */ 62248e3a2eefSMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 62258e3a2eefSMatthew G. Knepley /* Remainder */ 62268e3a2eefSMatthew G. Knepley PetscInt Nr, offset, Nq; 62278e3a2eefSMatthew G. Knepley PetscQuadrature qGeom = NULL; 62288e3a2eefSMatthew G. Knepley PetscInt maxDegree; 62298e3a2eefSMatthew G. Knepley PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 62308e3a2eefSMatthew G. Knepley 62319566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 62329566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 62339566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 62349566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 62359566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 62369566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 62378e3a2eefSMatthew G. Knepley if (!qGeom) { 62389566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 62399566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 62408e3a2eefSMatthew G. Knepley } 62419566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 62429566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 62438e3a2eefSMatthew G. Knepley blockSize = Nb; 62448e3a2eefSMatthew G. Knepley batchSize = numBlocks * blockSize; 62459566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 62468e3a2eefSMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 62478e3a2eefSMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 62488e3a2eefSMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 62498e3a2eefSMatthew G. Knepley offset = numCells - Nr; 62509566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 62519566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom)); 62528e3a2eefSMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 62538e3a2eefSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 62549566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 62559566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, X_tShift, &elemMat[offset * totDim * totDim])); 62568e3a2eefSMatthew G. Knepley if (hasDyn) { 62579566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD)); 62589566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, X_tShift, &elemMatD[offset * totDim * totDim])); 62598e3a2eefSMatthew G. Knepley } 62608e3a2eefSMatthew G. Knepley } 62619566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom)); 62629566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom)); 62639566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 62649566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 62658e3a2eefSMatthew G. Knepley } 62668e3a2eefSMatthew G. Knepley if (hasDyn) { 62678e3a2eefSMatthew G. Knepley for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 62688e3a2eefSMatthew G. Knepley } 62698e3a2eefSMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 62708e3a2eefSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 62718e3a2eefSMatthew G. Knepley const PetscInt cind = c - cStart; 62728e3a2eefSMatthew G. Knepley const PetscBLASInt M = totDim, one = 1; 62738e3a2eefSMatthew G. Knepley const PetscScalar a = 1.0, b = 0.0; 62748e3a2eefSMatthew G. Knepley 6275792fecdfSBarry Smith PetscCallBLAS("BLASgemv", BLASgemv_("N", &M, &M, &a, &elemMat[cind * totDim * totDim], &M, &y[cind * totDim], &one, &b, z, &one)); 62768e3a2eefSMatthew G. Knepley if (mesh->printFEM > 1) { 62779566063dSJacob Faibussowitsch PetscCall(DMPrintCellMatrix(c, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 62789566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, "Y", totDim, &y[cind * totDim])); 62799566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, "Z", totDim, z)); 62808e3a2eefSMatthew G. Knepley } 62819566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, Z, cell, z, ADD_VALUES)); 62828e3a2eefSMatthew G. Knepley } 62839566063dSJacob Faibussowitsch PetscCall(PetscFree6(u, u_t, elemMat, elemMatD, y, z)); 62848e3a2eefSMatthew G. Knepley if (mesh->printFEM) { 62859566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)Z), "Z:\n")); 62869566063dSJacob Faibussowitsch PetscCall(VecView(Z, NULL)); 62878e3a2eefSMatthew G. Knepley } 62881059d808SMatthew G. Knepley PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 62899566063dSJacob Faibussowitsch PetscCall(PetscFree(a)); 62909566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plexAux)); 62919566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 62929566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 62933ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 62948e3a2eefSMatthew G. Knepley } 6295