Actual source code: plexfem.c
petsc-3.11.1 2019-04-12
1: #include <petsc/private/dmpleximpl.h>
2: #include <petscsf.h>
3: #include <petscsnes.h>
5: #include <petsc/private/hashsetij.h>
6: #include <petsc/private/petscfeimpl.h>
7: #include <petsc/private/petscfvimpl.h>
9: static PetscErrorCode DMPlexConvertPlex(DM dm, DM *plex, PetscBool copy)
10: {
11: PetscBool isPlex;
15: PetscObjectTypeCompare((PetscObject) dm, DMPLEX, &isPlex);
16: if (isPlex) {
17: *plex = dm;
18: PetscObjectReference((PetscObject) dm);
19: } else {
20: PetscObjectQuery((PetscObject) dm, "dm_plex", (PetscObject *) plex);
21: if (!*plex) {
22: DMConvert(dm,DMPLEX,plex);
23: PetscObjectCompose((PetscObject) dm, "dm_plex", (PetscObject) *plex);
24: if (copy) {
25: const char *comps[3] = {"A", "dmAux"};
26: PetscObject obj;
27: PetscInt i;
29: {
30: /* Run the subdomain hook (this will copy the DMSNES/DMTS) */
31: DMSubDomainHookLink link;
32: for (link = dm->subdomainhook; link; link = link->next) {
33: if (link->ddhook) {(*link->ddhook)(dm, *plex, link->ctx);}
34: }
35: }
36: for (i = 0; i < 3; i++) {
37: PetscObjectQuery((PetscObject) dm, comps[i], &obj);
38: PetscObjectCompose((PetscObject) *plex, comps[i], obj);
39: }
40: }
41: } else {
42: PetscObjectReference((PetscObject) *plex);
43: }
44: }
45: return(0);
46: }
48: static PetscErrorCode PetscContainerUserDestroy_PetscFEGeom (void *ctx)
49: {
50: PetscFEGeom *geom = (PetscFEGeom *) ctx;
54: PetscFEGeomDestroy(&geom);
55: return(0);
56: }
58: static PetscErrorCode DMPlexGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
59: {
60: char composeStr[33] = {0};
61: PetscObjectId id;
62: PetscContainer container;
63: PetscErrorCode ierr;
66: PetscObjectGetId((PetscObject)quad,&id);
67: PetscSNPrintf(composeStr, 32, "DMPlexGetFEGeom_%x\n", id);
68: PetscObjectQuery((PetscObject) pointIS, composeStr, (PetscObject *) &container);
69: if (container) {
70: PetscContainerGetPointer(container, (void **) geom);
71: } else {
72: DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom);
73: PetscContainerCreate(PETSC_COMM_SELF,&container);
74: PetscContainerSetPointer(container, (void *) *geom);
75: PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom);
76: PetscObjectCompose((PetscObject) pointIS, composeStr, (PetscObject) container);
77: PetscContainerDestroy(&container);
78: }
79: return(0);
80: }
82: static PetscErrorCode DMPlexRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
83: {
85: *geom = NULL;
86: return(0);
87: }
89: /*@
90: DMPlexGetScale - Get the scale for the specified fundamental unit
92: Not collective
94: Input Arguments:
95: + dm - the DM
96: - unit - The SI unit
98: Output Argument:
99: . scale - The value used to scale all quantities with this unit
101: Level: advanced
103: .seealso: DMPlexSetScale(), PetscUnit
104: @*/
105: PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
106: {
107: DM_Plex *mesh = (DM_Plex*) dm->data;
112: *scale = mesh->scale[unit];
113: return(0);
114: }
116: /*@
117: DMPlexSetScale - Set the scale for the specified fundamental unit
119: Not collective
121: Input Arguments:
122: + dm - the DM
123: . unit - The SI unit
124: - scale - The value used to scale all quantities with this unit
126: Level: advanced
128: .seealso: DMPlexGetScale(), PetscUnit
129: @*/
130: PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
131: {
132: DM_Plex *mesh = (DM_Plex*) dm->data;
136: mesh->scale[unit] = scale;
137: return(0);
138: }
140: static PetscErrorCode DMPlexProjectRigidBody_Private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nf, PetscScalar *mode, void *ctx)
141: {
142: const PetscInt eps[3][3][3] = {{{0, 0, 0}, {0, 0, 1}, {0, -1, 0}}, {{0, 0, -1}, {0, 0, 0}, {1, 0, 0}}, {{0, 1, 0}, {-1, 0, 0}, {0, 0, 0}}};
143: PetscInt *ctxInt = (PetscInt *) ctx;
144: PetscInt dim2 = ctxInt[0];
145: PetscInt d = ctxInt[1];
146: PetscInt i, j, k = dim > 2 ? d - dim : d;
149: if (dim != dim2) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Input dimension %d does not match context dimension %d", dim, dim2);
150: for (i = 0; i < dim; i++) mode[i] = 0.;
151: if (d < dim) {
152: mode[d] = 1.; /* Translation along axis d */
153: } else {
154: for (i = 0; i < dim; i++) {
155: for (j = 0; j < dim; j++) {
156: mode[j] += eps[i][j][k]*X[i]; /* Rotation about axis d */
157: }
158: }
159: }
160: return(0);
161: }
163: /*@
164: DMPlexCreateRigidBody - For the default global section, create rigid body modes by function space interpolation
166: Collective on DM
168: Input Arguments:
169: . dm - the DM
171: Output Argument:
172: . sp - the null space
174: Note: This is necessary to provide a suitable coarse space for algebraic multigrid
176: Level: advanced
178: .seealso: MatNullSpaceCreate(), PCGAMG
179: @*/
180: PetscErrorCode DMPlexCreateRigidBody(DM dm, MatNullSpace *sp)
181: {
182: MPI_Comm comm;
183: Vec mode[6];
184: PetscSection section, globalSection;
185: PetscInt dim, dimEmbed, n, m, mmin, d, i, j;
189: PetscObjectGetComm((PetscObject)dm,&comm);
190: DMGetDimension(dm, &dim);
191: DMGetCoordinateDim(dm, &dimEmbed);
192: if (dim == 1) {
193: MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);
194: return(0);
195: }
196: DMGetSection(dm, §ion);
197: DMGetGlobalSection(dm, &globalSection);
198: PetscSectionGetConstrainedStorageSize(globalSection, &n);
199: m = (dim*(dim+1))/2;
200: VecCreate(comm, &mode[0]);
201: VecSetSizes(mode[0], n, PETSC_DETERMINE);
202: VecSetUp(mode[0]);
203: VecGetSize(mode[0], &n);
204: mmin = PetscMin(m, n);
205: for (i = 1; i < m; ++i) {VecDuplicate(mode[0], &mode[i]);}
206: for (d = 0; d < m; d++) {
207: PetscInt ctx[2];
208: PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *) = DMPlexProjectRigidBody_Private;
209: void *voidctx = (void *) (&ctx[0]);
211: ctx[0] = dimEmbed;
212: ctx[1] = d;
213: DMProjectFunction(dm, 0.0, &func, &voidctx, INSERT_VALUES, mode[d]);
214: }
215: for (i = 0; i < PetscMin(dim, mmin); ++i) {VecNormalize(mode[i], NULL);}
216: /* Orthonormalize system */
217: for (i = dim; i < mmin; ++i) {
218: PetscScalar dots[6];
220: VecMDot(mode[i], i, mode, dots);
221: for (j = 0; j < i; ++j) dots[j] *= -1.0;
222: VecMAXPY(mode[i], i, dots, mode);
223: VecNormalize(mode[i], NULL);
224: }
225: MatNullSpaceCreate(comm, PETSC_FALSE, mmin, mode, sp);
226: for (i = 0; i < m; ++i) {VecDestroy(&mode[i]);}
227: return(0);
228: }
230: /*@
231: DMPlexCreateRigidBodies - For the default global section, create rigid body modes by function space interpolation
233: Collective on DM
235: Input Arguments:
236: + dm - the DM
237: . nb - The number of bodies
238: . label - The DMLabel marking each domain
239: . nids - The number of ids per body
240: - ids - An array of the label ids in sequence for each domain
242: Output Argument:
243: . sp - the null space
245: Note: This is necessary to provide a suitable coarse space for algebraic multigrid
247: Level: advanced
249: .seealso: MatNullSpaceCreate()
250: @*/
251: PetscErrorCode DMPlexCreateRigidBodies(DM dm, PetscInt nb, DMLabel label, const PetscInt nids[], const PetscInt ids[], MatNullSpace *sp)
252: {
253: MPI_Comm comm;
254: PetscSection section, globalSection;
255: Vec *mode;
256: PetscScalar *dots;
257: PetscInt dim, dimEmbed, n, m, b, d, i, j, off;
261: PetscObjectGetComm((PetscObject)dm,&comm);
262: DMGetDimension(dm, &dim);
263: DMGetCoordinateDim(dm, &dimEmbed);
264: DMGetSection(dm, §ion);
265: DMGetGlobalSection(dm, &globalSection);
266: PetscSectionGetConstrainedStorageSize(globalSection, &n);
267: m = nb * (dim*(dim+1))/2;
268: PetscMalloc2(m, &mode, m, &dots);
269: VecCreate(comm, &mode[0]);
270: VecSetSizes(mode[0], n, PETSC_DETERMINE);
271: VecSetUp(mode[0]);
272: for (i = 1; i < m; ++i) {VecDuplicate(mode[0], &mode[i]);}
273: for (b = 0, off = 0; b < nb; ++b) {
274: for (d = 0; d < m/nb; ++d) {
275: PetscInt ctx[2];
276: PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *) = DMPlexProjectRigidBody_Private;
277: void *voidctx = (void *) (&ctx[0]);
279: ctx[0] = dimEmbed;
280: ctx[1] = d;
281: DMProjectFunctionLabel(dm, 0.0, label, nids[b], &ids[off], 0, NULL, &func, &voidctx, INSERT_VALUES, mode[d]);
282: off += nids[b];
283: }
284: }
285: for (i = 0; i < dim; ++i) {VecNormalize(mode[i], NULL);}
286: /* Orthonormalize system */
287: for (i = 0; i < m; ++i) {
288: VecMDot(mode[i], i, mode, dots);
289: for (j = 0; j < i; ++j) dots[j] *= -1.0;
290: VecMAXPY(mode[i], i, dots, mode);
291: VecNormalize(mode[i], NULL);
292: }
293: MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);
294: for (i = 0; i< m; ++i) {VecDestroy(&mode[i]);}
295: PetscFree2(mode, dots);
296: return(0);
297: }
299: /*@
300: DMPlexSetMaxProjectionHeight - In DMPlexProjectXXXLocal() functions, the projected values of a basis function's dofs
301: are computed by associating the basis function with one of the mesh points in its transitively-closed support, and
302: evaluating the dual space basis of that point. A basis function is associated with the point in its
303: transitively-closed support whose mesh height is highest (w.r.t. DAG height), but not greater than the maximum
304: projection height, which is set with this function. By default, the maximum projection height is zero, which means
305: that only mesh cells are used to project basis functions. A height of one, for example, evaluates a cell-interior
306: basis functions using its cells dual space basis, but all other basis functions with the dual space basis of a face.
308: Input Parameters:
309: + dm - the DMPlex object
310: - height - the maximum projection height >= 0
312: Level: advanced
314: .seealso: DMPlexGetMaxProjectionHeight(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal()
315: @*/
316: PetscErrorCode DMPlexSetMaxProjectionHeight(DM dm, PetscInt height)
317: {
318: DM_Plex *plex = (DM_Plex *) dm->data;
322: plex->maxProjectionHeight = height;
323: return(0);
324: }
326: /*@
327: DMPlexGetMaxProjectionHeight - Get the maximum height (w.r.t. DAG) of mesh points used to evaluate dual bases in
328: DMPlexProjectXXXLocal() functions.
330: Input Parameters:
331: . dm - the DMPlex object
333: Output Parameters:
334: . height - the maximum projection height
336: Level: intermediate
338: .seealso: DMPlexSetMaxProjectionHeight(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal()
339: @*/
340: PetscErrorCode DMPlexGetMaxProjectionHeight(DM dm, PetscInt *height)
341: {
342: DM_Plex *plex = (DM_Plex *) dm->data;
346: *height = plex->maxProjectionHeight;
347: return(0);
348: }
350: /*@C
351: DMPlexInsertBoundaryValuesEssential - Insert boundary values into a local vector
353: Input Parameters:
354: + dm - The DM, with a PetscDS that matches the problem being constrained
355: . time - The time
356: . field - The field to constrain
357: . Nc - The number of constrained field components, or 0 for all components
358: . comps - An array of constrained component numbers, or NULL for all components
359: . label - The DMLabel defining constrained points
360: . numids - The number of DMLabel ids for constrained points
361: . ids - An array of ids for constrained points
362: . func - A pointwise function giving boundary values
363: - ctx - An optional user context for bcFunc
365: Output Parameter:
366: . locX - A local vector to receives the boundary values
368: Level: developer
370: .seealso: DMPlexInsertBoundaryValuesEssentialField(), DMAddBoundary()
371: @*/
372: 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)
373: {
374: PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
375: void **ctxs;
376: PetscInt numFields;
377: PetscErrorCode ierr;
380: DMGetNumFields(dm, &numFields);
381: PetscCalloc2(numFields,&funcs,numFields,&ctxs);
382: funcs[field] = func;
383: ctxs[field] = ctx;
384: DMProjectFunctionLabelLocal(dm, time, label, numids, ids, Nc, comps, funcs, ctxs, INSERT_BC_VALUES, locX);
385: PetscFree2(funcs,ctxs);
386: return(0);
387: }
389: /*@C
390: DMPlexInsertBoundaryValuesEssentialField - Insert boundary values into a local vector
392: Input Parameters:
393: + dm - The DM, with a PetscDS that matches the problem being constrained
394: . time - The time
395: . locU - A local vector with the input solution values
396: . field - The field to constrain
397: . Nc - The number of constrained field components, or 0 for all components
398: . comps - An array of constrained component numbers, or NULL for all components
399: . label - The DMLabel defining constrained points
400: . numids - The number of DMLabel ids for constrained points
401: . ids - An array of ids for constrained points
402: . func - A pointwise function giving boundary values
403: - ctx - An optional user context for bcFunc
405: Output Parameter:
406: . locX - A local vector to receives the boundary values
408: Level: developer
410: .seealso: DMPlexInsertBoundaryValuesEssential(), DMAddBoundary()
411: @*/
412: PetscErrorCode DMPlexInsertBoundaryValuesEssentialField(DM dm, PetscReal time, Vec locU, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[],
413: void (*func)(PetscInt, PetscInt, PetscInt,
414: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
415: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
416: PetscReal, const PetscReal[], PetscInt, const PetscScalar[],
417: PetscScalar[]),
418: void *ctx, Vec locX)
419: {
420: void (**funcs)(PetscInt, PetscInt, PetscInt,
421: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
422: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
423: PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]);
424: void **ctxs;
425: PetscInt numFields;
426: PetscErrorCode ierr;
429: DMGetNumFields(dm, &numFields);
430: PetscCalloc2(numFields,&funcs,numFields,&ctxs);
431: funcs[field] = func;
432: ctxs[field] = ctx;
433: DMProjectFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX);
434: PetscFree2(funcs,ctxs);
435: return(0);
436: }
438: /*@C
439: DMPlexInsertBoundaryValuesRiemann - Insert boundary values into a local vector
441: Input Parameters:
442: + dm - The DM, with a PetscDS that matches the problem being constrained
443: . time - The time
444: . faceGeometry - A vector with the FVM face geometry information
445: . cellGeometry - A vector with the FVM cell geometry information
446: . Grad - A vector with the FVM cell gradient information
447: . field - The field to constrain
448: . Nc - The number of constrained field components, or 0 for all components
449: . comps - An array of constrained component numbers, or NULL for all components
450: . label - The DMLabel defining constrained points
451: . numids - The number of DMLabel ids for constrained points
452: . ids - An array of ids for constrained points
453: . func - A pointwise function giving boundary values
454: - ctx - An optional user context for bcFunc
456: Output Parameter:
457: . locX - A local vector to receives the boundary values
459: Note: This implementation currently ignores the numcomps/comps argument from DMAddBoundary()
461: Level: developer
463: .seealso: DMPlexInsertBoundaryValuesEssential(), DMPlexInsertBoundaryValuesEssentialField(), DMAddBoundary()
464: @*/
465: 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[],
466: PetscErrorCode (*func)(PetscReal,const PetscReal*,const PetscReal*,const PetscScalar*,PetscScalar*,void*), void *ctx, Vec locX)
467: {
468: PetscDS prob;
469: PetscSF sf;
470: DM dmFace, dmCell, dmGrad;
471: const PetscScalar *facegeom, *cellgeom = NULL, *grad;
472: const PetscInt *leaves;
473: PetscScalar *x, *fx;
474: PetscInt dim, nleaves, loc, fStart, fEnd, pdim, i;
475: PetscErrorCode ierr, ierru = 0;
478: DMGetPointSF(dm, &sf);
479: PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL);
480: nleaves = PetscMax(0, nleaves);
481: DMGetDimension(dm, &dim);
482: DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
483: DMGetDS(dm, &prob);
484: VecGetDM(faceGeometry, &dmFace);
485: VecGetArrayRead(faceGeometry, &facegeom);
486: if (cellGeometry) {
487: VecGetDM(cellGeometry, &dmCell);
488: VecGetArrayRead(cellGeometry, &cellgeom);
489: }
490: if (Grad) {
491: PetscFV fv;
493: PetscDSGetDiscretization(prob, field, (PetscObject *) &fv);
494: VecGetDM(Grad, &dmGrad);
495: VecGetArrayRead(Grad, &grad);
496: PetscFVGetNumComponents(fv, &pdim);
497: DMGetWorkArray(dm, pdim, MPIU_SCALAR, &fx);
498: }
499: VecGetArray(locX, &x);
500: for (i = 0; i < numids; ++i) {
501: IS faceIS;
502: const PetscInt *faces;
503: PetscInt numFaces, f;
505: DMLabelGetStratumIS(label, ids[i], &faceIS);
506: if (!faceIS) continue; /* No points with that id on this process */
507: ISGetLocalSize(faceIS, &numFaces);
508: ISGetIndices(faceIS, &faces);
509: for (f = 0; f < numFaces; ++f) {
510: const PetscInt face = faces[f], *cells;
511: PetscFVFaceGeom *fg;
513: if ((face < fStart) || (face >= fEnd)) continue; /* Refinement adds non-faces to labels */
514: PetscFindInt(face, nleaves, (PetscInt *) leaves, &loc);
515: if (loc >= 0) continue;
516: DMPlexPointLocalRead(dmFace, face, facegeom, &fg);
517: DMPlexGetSupport(dm, face, &cells);
518: if (Grad) {
519: PetscFVCellGeom *cg;
520: PetscScalar *cx, *cgrad;
521: PetscScalar *xG;
522: PetscReal dx[3];
523: PetscInt d;
525: DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cg);
526: DMPlexPointLocalRead(dm, cells[0], x, &cx);
527: DMPlexPointLocalRead(dmGrad, cells[0], grad, &cgrad);
528: DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG);
529: DMPlex_WaxpyD_Internal(dim, -1, cg->centroid, fg->centroid, dx);
530: for (d = 0; d < pdim; ++d) fx[d] = cx[d] + DMPlex_DotD_Internal(dim, &cgrad[d*dim], dx);
531: ierru = (*func)(time, fg->centroid, fg->normal, fx, xG, ctx);
532: if (ierru) {
533: ISRestoreIndices(faceIS, &faces);
534: ISDestroy(&faceIS);
535: goto cleanup;
536: }
537: } else {
538: PetscScalar *xI;
539: PetscScalar *xG;
541: DMPlexPointLocalRead(dm, cells[0], x, &xI);
542: DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG);
543: ierru = (*func)(time, fg->centroid, fg->normal, xI, xG, ctx);
544: if (ierru) {
545: ISRestoreIndices(faceIS, &faces);
546: ISDestroy(&faceIS);
547: goto cleanup;
548: }
549: }
550: }
551: ISRestoreIndices(faceIS, &faces);
552: ISDestroy(&faceIS);
553: }
554: cleanup:
555: VecRestoreArray(locX, &x);
556: if (Grad) {
557: DMRestoreWorkArray(dm, pdim, MPIU_SCALAR, &fx);
558: VecRestoreArrayRead(Grad, &grad);
559: }
560: if (cellGeometry) {VecRestoreArrayRead(cellGeometry, &cellgeom);}
561: VecRestoreArrayRead(faceGeometry, &facegeom);
562: CHKERRQ(ierru);
563: return(0);
564: }
566: PetscErrorCode DMPlexInsertBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
567: {
568: PetscDS prob;
569: PetscInt numBd, b;
573: DMGetDS(dm, &prob);
574: PetscDSGetNumBoundary(prob, &numBd);
575: for (b = 0; b < numBd; ++b) {
576: DMBoundaryConditionType type;
577: const char *labelname;
578: DMLabel label;
579: PetscInt field, Nc;
580: const PetscInt *comps;
581: PetscObject obj;
582: PetscClassId id;
583: void (*func)(void);
584: PetscInt numids;
585: const PetscInt *ids;
586: void *ctx;
588: DMGetBoundary(dm, b, &type, NULL, &labelname, &field, &Nc, &comps, &func, &numids, &ids, &ctx);
589: if (insertEssential != (type & DM_BC_ESSENTIAL)) continue;
590: DMGetLabel(dm, labelname, &label);
591: DMGetField(dm, field, NULL, &obj);
592: PetscObjectGetClassId(obj, &id);
593: if (id == PETSCFE_CLASSID) {
594: switch (type) {
595: /* for FEM, there is no insertion to be done for non-essential boundary conditions */
596: case DM_BC_ESSENTIAL:
597: DMPlexLabelAddCells(dm,label);
598: DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, (PetscErrorCode (*)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *)) func, ctx, locX);
599: DMPlexLabelClearCells(dm,label);
600: break;
601: case DM_BC_ESSENTIAL_FIELD:
602: DMPlexLabelAddCells(dm,label);
603: DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids,
604: (void (*)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
605: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
606: PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[])) func, ctx, locX);
607: DMPlexLabelClearCells(dm,label);
608: break;
609: default: break;
610: }
611: } else if (id == PETSCFV_CLASSID) {
612: if (!faceGeomFVM) continue;
613: DMPlexInsertBoundaryValuesRiemann(dm, time, faceGeomFVM, cellGeomFVM, gradFVM, field, Nc, comps, label, numids, ids,
614: (PetscErrorCode (*)(PetscReal,const PetscReal*,const PetscReal*,const PetscScalar*,PetscScalar*,void*)) func, ctx, locX);
615: } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
616: }
617: return(0);
618: }
620: /*@
621: DMPlexInsertBoundaryValues - Puts coefficients which represent boundary values into the local solution vector
623: Input Parameters:
624: + dm - The DM
625: . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions
626: . time - The time
627: . faceGeomFVM - Face geometry data for FV discretizations
628: . cellGeomFVM - Cell geometry data for FV discretizations
629: - gradFVM - Gradient reconstruction data for FV discretizations
631: Output Parameters:
632: . locX - Solution updated with boundary values
634: Level: developer
636: .seealso: DMProjectFunctionLabelLocal()
637: @*/
638: PetscErrorCode DMPlexInsertBoundaryValues(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
639: {
648: PetscTryMethod(dm,"DMPlexInsertBoundaryValues_C",(DM,PetscBool,Vec,PetscReal,Vec,Vec,Vec),(dm,insertEssential,locX,time,faceGeomFVM,cellGeomFVM,gradFVM));
649: return(0);
650: }
652: PetscErrorCode DMComputeL2Diff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
653: {
654: Vec localX;
655: PetscErrorCode ierr;
658: DMGetLocalVector(dm, &localX);
659: DMPlexInsertBoundaryValues(dm, PETSC_TRUE, localX, time, NULL, NULL, NULL);
660: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
661: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
662: DMPlexComputeL2DiffLocal(dm, time, funcs, ctxs, localX, diff);
663: DMRestoreLocalVector(dm, &localX);
664: return(0);
665: }
667: /*@C
668: DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
670: Input Parameters:
671: + dm - The DM
672: . time - The time
673: . funcs - The functions to evaluate for each field component
674: . ctxs - Optional array of contexts to pass to each function, or NULL.
675: - localX - The coefficient vector u_h, a local vector
677: Output Parameter:
678: . diff - The diff ||u - u_h||_2
680: Level: developer
682: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
683: @*/
684: PetscErrorCode DMPlexComputeL2DiffLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec localX, PetscReal *diff)
685: {
686: const PetscInt debug = ((DM_Plex*)dm->data)->printL2;
687: PetscSection section;
688: PetscQuadrature quad;
689: PetscScalar *funcVal, *interpolant;
690: PetscReal *coords, *detJ, *J;
691: PetscReal localDiff = 0.0;
692: const PetscReal *quadWeights;
693: PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cellHeight, cStart, cEnd, cEndInterior, c, field, fieldOffset;
694: PetscErrorCode ierr;
697: DMGetDimension(dm, &dim);
698: DMGetCoordinateDim(dm, &coordDim);
699: DMGetSection(dm, §ion);
700: PetscSectionGetNumFields(section, &numFields);
701: for (field = 0; field < numFields; ++field) {
702: PetscObject obj;
703: PetscClassId id;
704: PetscInt Nc;
706: DMGetField(dm, field, NULL, &obj);
707: PetscObjectGetClassId(obj, &id);
708: if (id == PETSCFE_CLASSID) {
709: PetscFE fe = (PetscFE) obj;
711: PetscFEGetQuadrature(fe, &quad);
712: PetscFEGetNumComponents(fe, &Nc);
713: } else if (id == PETSCFV_CLASSID) {
714: PetscFV fv = (PetscFV) obj;
716: PetscFVGetQuadrature(fv, &quad);
717: PetscFVGetNumComponents(fv, &Nc);
718: } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
719: numComponents += Nc;
720: }
721: PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights);
722: if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents);
723: PetscMalloc5(numComponents,&funcVal,numComponents,&interpolant,coordDim*Nq,&coords,Nq,&detJ,coordDim*coordDim*Nq,&J);
724: DMPlexGetVTKCellHeight(dm, &cellHeight);
725: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
726: DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
727: cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
728: for (c = cStart; c < cEnd; ++c) {
729: PetscScalar *x = NULL;
730: PetscReal elemDiff = 0.0;
731: PetscInt qc = 0;
733: DMPlexComputeCellGeometryFEM(dm, c, quad, coords, J, NULL, detJ);
734: DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);
736: for (field = 0, fieldOffset = 0; field < numFields; ++field) {
737: PetscObject obj;
738: PetscClassId id;
739: void * const ctx = ctxs ? ctxs[field] : NULL;
740: PetscInt Nb, Nc, q, fc;
742: DMGetField(dm, field, NULL, &obj);
743: PetscObjectGetClassId(obj, &id);
744: if (id == PETSCFE_CLASSID) {PetscFEGetNumComponents((PetscFE) obj, &Nc);PetscFEGetDimension((PetscFE) obj, &Nb);}
745: else if (id == PETSCFV_CLASSID) {PetscFVGetNumComponents((PetscFV) obj, &Nc);Nb = 1;}
746: else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
747: if (debug) {
748: char title[1024];
749: PetscSNPrintf(title, 1023, "Solution for Field %d", field);
750: DMPrintCellVector(c, title, Nb, &x[fieldOffset]);
751: }
752: for (q = 0; q < Nq; ++q) {
753: if (detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, point %D", detJ[q], c, q);
754: (*funcs[field])(coordDim, time, &coords[coordDim * q], Nc, funcVal, ctx);
755: if (ierr) {
756: PetscErrorCode ierr2;
757: ierr2 = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr2);
758: ierr2 = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr2);
759: ierr2 = PetscFree5(funcVal,interpolant,coords,detJ,J);CHKERRQ(ierr2);
760:
761: }
762: if (id == PETSCFE_CLASSID) {PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], q, interpolant);}
763: else if (id == PETSCFV_CLASSID) {PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant);}
764: else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
765: for (fc = 0; fc < Nc; ++fc) {
766: const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)];
767: if (debug) {PetscPrintf(PETSC_COMM_SELF, " elem %d field %d diff %g\n", c, field, PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*detJ[q]);}
768: elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*detJ[q];
769: }
770: }
771: fieldOffset += Nb;
772: qc += Nc;
773: }
774: DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
775: if (debug) {PetscPrintf(PETSC_COMM_SELF, " elem %d diff %g\n", c, elemDiff);}
776: localDiff += elemDiff;
777: }
778: PetscFree5(funcVal,interpolant,coords,detJ,J);
779: MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));
780: *diff = PetscSqrtReal(*diff);
781: return(0);
782: }
784: 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)
785: {
786: const PetscInt debug = ((DM_Plex*)dm->data)->printL2;
787: PetscSection section;
788: PetscQuadrature quad;
789: Vec localX;
790: PetscScalar *funcVal, *interpolant;
791: const PetscReal *quadPoints, *quadWeights;
792: PetscReal *coords, *realSpaceDer, *J, *invJ, *detJ;
793: PetscReal localDiff = 0.0;
794: PetscInt dim, coordDim, qNc = 0, Nq = 0, numFields, numComponents = 0, cStart, cEnd, cEndInterior, c, field, fieldOffset;
795: PetscErrorCode ierr;
798: DMGetDimension(dm, &dim);
799: DMGetCoordinateDim(dm, &coordDim);
800: DMGetSection(dm, §ion);
801: PetscSectionGetNumFields(section, &numFields);
802: DMGetLocalVector(dm, &localX);
803: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
804: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
805: for (field = 0; field < numFields; ++field) {
806: PetscFE fe;
807: PetscInt Nc;
809: DMGetField(dm, field, NULL, (PetscObject *) &fe);
810: PetscFEGetQuadrature(fe, &quad);
811: PetscFEGetNumComponents(fe, &Nc);
812: numComponents += Nc;
813: }
814: PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);
815: if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents);
816: /* DMProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX); */
817: PetscMalloc7(numComponents,&funcVal,coordDim*Nq,&coords,coordDim*Nq,&realSpaceDer,coordDim*coordDim*Nq,&J,coordDim*coordDim*Nq,&invJ,numComponents,&interpolant,Nq,&detJ);
818: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
819: DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
820: cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
821: for (c = cStart; c < cEnd; ++c) {
822: PetscScalar *x = NULL;
823: PetscReal elemDiff = 0.0;
824: PetscInt qc = 0;
826: DMPlexComputeCellGeometryFEM(dm, c, quad, coords, J, invJ, detJ);
827: DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);
829: for (field = 0, fieldOffset = 0; field < numFields; ++field) {
830: PetscFE fe;
831: void * const ctx = ctxs ? ctxs[field] : NULL;
832: PetscReal *basisDer;
833: PetscInt Nb, Nc, q, fc;
835: DMGetField(dm, field, NULL, (PetscObject *) &fe);
836: PetscFEGetDimension(fe, &Nb);
837: PetscFEGetNumComponents(fe, &Nc);
838: PetscFEGetDefaultTabulation(fe, NULL, &basisDer, NULL);
839: if (debug) {
840: char title[1024];
841: PetscSNPrintf(title, 1023, "Solution for Field %d", field);
842: DMPrintCellVector(c, title, Nb, &x[fieldOffset]);
843: }
844: for (q = 0; q < Nq; ++q) {
845: if (detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, quadrature points %D", detJ[q], c, q);
846: (*funcs[field])(coordDim, time, &coords[q*coordDim], n, numFields, funcVal, ctx);
847: if (ierr) {
848: PetscErrorCode ierr2;
849: ierr2 = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr2);
850: ierr2 = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr2);
851: ierr2 = PetscFree7(funcVal,coords,realSpaceDer,J,invJ,interpolant,detJ);CHKERRQ(ierr2);
852:
853: }
854: PetscFEInterpolateGradient_Static(fe, &x[fieldOffset], coordDim, invJ, n, q, interpolant);
855: for (fc = 0; fc < Nc; ++fc) {
856: const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)];
857: if (debug) {PetscPrintf(PETSC_COMM_SELF, " elem %d fieldDer %d diff %g\n", c, field, PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*detJ[q]);}
858: elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*detJ[q];
859: }
860: }
861: fieldOffset += Nb;
862: qc += Nc;
863: }
864: DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
865: if (debug) {PetscPrintf(PETSC_COMM_SELF, " elem %d diff %g\n", c, elemDiff);}
866: localDiff += elemDiff;
867: }
868: PetscFree7(funcVal,coords,realSpaceDer,J,invJ,interpolant,detJ);
869: DMRestoreLocalVector(dm, &localX);
870: MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));
871: *diff = PetscSqrtReal(*diff);
872: return(0);
873: }
875: PetscErrorCode DMComputeL2FieldDiff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
876: {
877: const PetscInt debug = ((DM_Plex*)dm->data)->printL2;
878: PetscSection section;
879: PetscQuadrature quad;
880: Vec localX;
881: PetscScalar *funcVal, *interpolant;
882: PetscReal *coords, *detJ, *J;
883: PetscReal *localDiff;
884: const PetscReal *quadPoints, *quadWeights;
885: PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, cEndInterior, c, field, fieldOffset;
886: PetscErrorCode ierr;
889: DMGetDimension(dm, &dim);
890: DMGetCoordinateDim(dm, &coordDim);
891: DMGetSection(dm, §ion);
892: PetscSectionGetNumFields(section, &numFields);
893: DMGetLocalVector(dm, &localX);
894: DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX);
895: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
896: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
897: for (field = 0; field < numFields; ++field) {
898: PetscObject obj;
899: PetscClassId id;
900: PetscInt Nc;
902: DMGetField(dm, field, NULL, &obj);
903: PetscObjectGetClassId(obj, &id);
904: if (id == PETSCFE_CLASSID) {
905: PetscFE fe = (PetscFE) obj;
907: PetscFEGetQuadrature(fe, &quad);
908: PetscFEGetNumComponents(fe, &Nc);
909: } else if (id == PETSCFV_CLASSID) {
910: PetscFV fv = (PetscFV) obj;
912: PetscFVGetQuadrature(fv, &quad);
913: PetscFVGetNumComponents(fv, &Nc);
914: } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
915: numComponents += Nc;
916: }
917: PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);
918: if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents);
919: PetscCalloc6(numFields,&localDiff,numComponents,&funcVal,numComponents,&interpolant,coordDim*Nq,&coords,Nq,&detJ,coordDim*coordDim*Nq,&J);
920: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
921: DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
922: cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
923: for (c = cStart; c < cEnd; ++c) {
924: PetscScalar *x = NULL;
925: PetscInt qc = 0;
927: DMPlexComputeCellGeometryFEM(dm, c, quad, coords, J, NULL, detJ);
928: DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);
930: for (field = 0, fieldOffset = 0; field < numFields; ++field) {
931: PetscObject obj;
932: PetscClassId id;
933: void * const ctx = ctxs ? ctxs[field] : NULL;
934: PetscInt Nb, Nc, q, fc;
936: PetscReal elemDiff = 0.0;
938: DMGetField(dm, field, NULL, &obj);
939: PetscObjectGetClassId(obj, &id);
940: if (id == PETSCFE_CLASSID) {PetscFEGetNumComponents((PetscFE) obj, &Nc);PetscFEGetDimension((PetscFE) obj, &Nb);}
941: else if (id == PETSCFV_CLASSID) {PetscFVGetNumComponents((PetscFV) obj, &Nc);Nb = 1;}
942: else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
943: if (debug) {
944: char title[1024];
945: PetscSNPrintf(title, 1023, "Solution for Field %d", field);
946: DMPrintCellVector(c, title, Nb*Nc, &x[fieldOffset]);
947: }
948: for (q = 0; q < Nq; ++q) {
949: if (detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, quadrature point %D", detJ, c, q);
950: (*funcs[field])(coordDim, time, &coords[coordDim*q], numFields, funcVal, ctx);
951: if (ierr) {
952: PetscErrorCode ierr2;
953: ierr2 = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr2);
954: ierr2 = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr2);
955: ierr2 = PetscFree6(localDiff,funcVal,interpolant,coords,detJ,J);CHKERRQ(ierr2);
956:
957: }
958: if (id == PETSCFE_CLASSID) {PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], q, interpolant);}
959: else if (id == PETSCFV_CLASSID) {PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant);}
960: else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
961: for (fc = 0; fc < Nc; ++fc) {
962: const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)];
963: if (debug) {PetscPrintf(PETSC_COMM_SELF, " elem %d field %d point %g %g %g diff %g\n", c, field, coordDim > 0 ? coords[0] : 0., coordDim > 1 ? coords[1] : 0., coordDim > 2 ? coords[2] : 0., PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*detJ[q]);}
964: elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*detJ[q];
965: }
966: }
967: fieldOffset += Nb;
968: qc += Nc;
969: localDiff[field] += elemDiff;
970: }
971: DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
972: }
973: DMRestoreLocalVector(dm, &localX);
974: MPIU_Allreduce(localDiff, diff, numFields, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));
975: for (field = 0; field < numFields; ++field) diff[field] = PetscSqrtReal(diff[field]);
976: PetscFree6(localDiff,funcVal,interpolant,coords,detJ,J);
977: return(0);
978: }
980: /*@C
981: 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.
983: Input Parameters:
984: + dm - The DM
985: . time - The time
986: . funcs - The functions to evaluate for each field component: NULL means that component does not contribute to error calculation
987: . ctxs - Optional array of contexts to pass to each function, or NULL.
988: - X - The coefficient vector u_h
990: Output Parameter:
991: . D - A Vec which holds the difference ||u - u_h||_2 for each cell
993: Level: developer
995: .seealso: DMProjectFunction(), DMComputeL2Diff(), DMPlexComputeL2FieldDiff(), DMComputeL2GradientDiff()
996: @*/
997: PetscErrorCode DMPlexComputeL2DiffVec(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, Vec D)
998: {
999: PetscSection section;
1000: PetscQuadrature quad;
1001: Vec localX;
1002: PetscScalar *funcVal, *interpolant;
1003: PetscReal *coords, *detJ, *J;
1004: const PetscReal *quadPoints, *quadWeights;
1005: PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, cEndInterior, c, field, fieldOffset;
1006: PetscErrorCode ierr;
1009: VecSet(D, 0.0);
1010: DMGetDimension(dm, &dim);
1011: DMGetCoordinateDim(dm, &coordDim);
1012: DMGetSection(dm, §ion);
1013: PetscSectionGetNumFields(section, &numFields);
1014: DMGetLocalVector(dm, &localX);
1015: DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX);
1016: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
1017: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
1018: for (field = 0; field < numFields; ++field) {
1019: PetscObject obj;
1020: PetscClassId id;
1021: PetscInt Nc;
1023: DMGetField(dm, field, NULL, &obj);
1024: PetscObjectGetClassId(obj, &id);
1025: if (id == PETSCFE_CLASSID) {
1026: PetscFE fe = (PetscFE) obj;
1028: PetscFEGetQuadrature(fe, &quad);
1029: PetscFEGetNumComponents(fe, &Nc);
1030: } else if (id == PETSCFV_CLASSID) {
1031: PetscFV fv = (PetscFV) obj;
1033: PetscFVGetQuadrature(fv, &quad);
1034: PetscFVGetNumComponents(fv, &Nc);
1035: } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1036: numComponents += Nc;
1037: }
1038: PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);
1039: if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents);
1040: PetscMalloc5(numComponents,&funcVal,numComponents,&interpolant,coordDim*Nq,&coords,Nq,&detJ,coordDim*coordDim*Nq,&J);
1041: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
1042: DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
1043: cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
1044: for (c = cStart; c < cEnd; ++c) {
1045: PetscScalar *x = NULL;
1046: PetscScalar elemDiff = 0.0;
1047: PetscInt qc = 0;
1049: DMPlexComputeCellGeometryFEM(dm, c, quad, coords, J, NULL, detJ);
1050: DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);
1052: for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1053: PetscObject obj;
1054: PetscClassId id;
1055: void * const ctx = ctxs ? ctxs[field] : NULL;
1056: PetscInt Nb, Nc, q, fc;
1058: DMGetField(dm, field, NULL, &obj);
1059: PetscObjectGetClassId(obj, &id);
1060: if (id == PETSCFE_CLASSID) {PetscFEGetNumComponents((PetscFE) obj, &Nc);PetscFEGetDimension((PetscFE) obj, &Nb);}
1061: else if (id == PETSCFV_CLASSID) {PetscFVGetNumComponents((PetscFV) obj, &Nc);Nb = 1;}
1062: else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1063: if (funcs[field]) {
1064: for (q = 0; q < Nq; ++q) {
1065: if (detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, quadrature points %D", (double)detJ[q], c, q);
1066: (*funcs[field])(coordDim, time, &coords[q*coordDim], Nc, funcVal, ctx);
1067: if (ierr) {
1068: PetscErrorCode ierr2;
1069: ierr2 = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr2);
1070: ierr2 = PetscFree5(funcVal,interpolant,coords,detJ,J);CHKERRQ(ierr2);
1071: ierr2 = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr2);
1072:
1073: }
1074: if (id == PETSCFE_CLASSID) {PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], q, interpolant);}
1075: else if (id == PETSCFV_CLASSID) {PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant);}
1076: else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1077: for (fc = 0; fc < Nc; ++fc) {
1078: const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)];
1079: elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*detJ[q];
1080: }
1081: }
1082: }
1083: fieldOffset += Nb;
1084: qc += Nc;
1085: }
1086: DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
1087: VecSetValue(D, c - cStart, elemDiff, INSERT_VALUES);
1088: }
1089: PetscFree5(funcVal,interpolant,coords,detJ,J);
1090: DMRestoreLocalVector(dm, &localX);
1091: VecSqrtAbs(D);
1092: return(0);
1093: }
1095: /*@C
1096: DMPlexComputeGradientClementInterpolant - This function computes the L2 projection of the cellwise gradient of a function u onto P1, and stores it in a Vec.
1098: Input Parameters:
1099: + dm - The DM
1100: - LocX - The coefficient vector u_h
1102: Output Parameter:
1103: . locC - A Vec which holds the Clement interpolant of the gradient
1105: Notes:
1106: Add citation to (Clement, 1975) and definition of the interpolant
1107: \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
1109: Level: developer
1111: .seealso: DMProjectFunction(), DMComputeL2Diff(), DMPlexComputeL2FieldDiff(), DMComputeL2GradientDiff()
1112: @*/
1113: PetscErrorCode DMPlexComputeGradientClementInterpolant(DM dm, Vec locX, Vec locC)
1114: {
1115: DM_Plex *mesh = (DM_Plex *) dm->data;
1116: PetscInt debug = mesh->printFEM;
1117: DM dmC;
1118: PetscSection section;
1119: PetscQuadrature quad;
1120: PetscScalar *interpolant, *gradsum;
1121: PetscReal *coords, *detJ, *J, *invJ;
1122: const PetscReal *quadPoints, *quadWeights;
1123: PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, cEndInterior, vStart, vEnd, v, field, fieldOffset;
1124: PetscErrorCode ierr;
1127: VecGetDM(locC, &dmC);
1128: VecSet(locC, 0.0);
1129: DMGetDimension(dm, &dim);
1130: DMGetCoordinateDim(dm, &coordDim);
1131: DMGetSection(dm, §ion);
1132: PetscSectionGetNumFields(section, &numFields);
1133: for (field = 0; field < numFields; ++field) {
1134: PetscObject obj;
1135: PetscClassId id;
1136: PetscInt Nc;
1138: DMGetField(dm, field, NULL, &obj);
1139: PetscObjectGetClassId(obj, &id);
1140: if (id == PETSCFE_CLASSID) {
1141: PetscFE fe = (PetscFE) obj;
1143: PetscFEGetQuadrature(fe, &quad);
1144: PetscFEGetNumComponents(fe, &Nc);
1145: } else if (id == PETSCFV_CLASSID) {
1146: PetscFV fv = (PetscFV) obj;
1148: PetscFVGetQuadrature(fv, &quad);
1149: PetscFVGetNumComponents(fv, &Nc);
1150: } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1151: numComponents += Nc;
1152: }
1153: PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);
1154: if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents);
1155: PetscMalloc6(coordDim*numComponents*2,&gradsum,coordDim*numComponents,&interpolant,coordDim*Nq,&coords,Nq,&detJ,coordDim*coordDim*Nq,&J,coordDim*coordDim*Nq,&invJ);
1156: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1157: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
1158: DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
1159: cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
1160: for (v = vStart; v < vEnd; ++v) {
1161: PetscScalar volsum = 0.0;
1162: PetscInt *star = NULL;
1163: PetscInt starSize, st, d, fc;
1165: PetscMemzero(gradsum, coordDim*numComponents * sizeof(PetscScalar));
1166: DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star);
1167: for (st = 0; st < starSize*2; st += 2) {
1168: const PetscInt cell = star[st];
1169: PetscScalar *grad = &gradsum[coordDim*numComponents];
1170: PetscScalar *x = NULL;
1171: PetscReal vol = 0.0;
1173: if ((cell < cStart) || (cell >= cEnd)) continue;
1174: DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, J, invJ, detJ);
1175: DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x);
1176: for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1177: PetscObject obj;
1178: PetscClassId id;
1179: PetscInt Nb, Nc, q, qc = 0;
1181: PetscMemzero(grad, coordDim*numComponents * sizeof(PetscScalar));
1182: DMGetField(dm, field, NULL, &obj);
1183: PetscObjectGetClassId(obj, &id);
1184: if (id == PETSCFE_CLASSID) {PetscFEGetNumComponents((PetscFE) obj, &Nc);PetscFEGetDimension((PetscFE) obj, &Nb);}
1185: else if (id == PETSCFV_CLASSID) {PetscFVGetNumComponents((PetscFV) obj, &Nc);Nb = 1;}
1186: else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1187: for (q = 0; q < Nq; ++q) {
1188: if (detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, quadrature points %D", (double)detJ[q], cell, q);
1189: if (ierr) {
1190: PetscErrorCode ierr2;
1191: ierr2 = DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x);CHKERRQ(ierr2);
1192: ierr2 = DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr2);
1193: ierr2 = PetscFree4(interpolant,coords,detJ,J);CHKERRQ(ierr2);
1194:
1195: }
1196: if (id == PETSCFE_CLASSID) {PetscFEInterpolateGradient_Static((PetscFE) obj, &x[fieldOffset], coordDim, invJ, NULL, q, interpolant);}
1197: else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1198: for (fc = 0; fc < Nc; ++fc) {
1199: const PetscReal wt = quadWeights[q*qNc+qc+fc];
1201: for (d = 0; d < coordDim; ++d) grad[fc*coordDim+d] += interpolant[fc*dim+d]*wt*detJ[q];
1202: }
1203: vol += quadWeights[q*qNc]*detJ[q];
1204: }
1205: fieldOffset += Nb;
1206: qc += Nc;
1207: }
1208: DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x);
1209: for (fc = 0; fc < numComponents; ++fc) {
1210: for (d = 0; d < coordDim; ++d) {
1211: gradsum[fc*coordDim+d] += grad[fc*coordDim+d];
1212: }
1213: }
1214: volsum += vol;
1215: if (debug) {
1216: PetscPrintf(PETSC_COMM_SELF, "Cell %D gradient: [", cell);
1217: for (fc = 0; fc < numComponents; ++fc) {
1218: for (d = 0; d < coordDim; ++d) {
1219: if (fc || d > 0) {PetscPrintf(PETSC_COMM_SELF, ", ");}
1220: PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(grad[fc*coordDim+d]));
1221: }
1222: }
1223: PetscPrintf(PETSC_COMM_SELF, "]\n");
1224: }
1225: }
1226: for (fc = 0; fc < numComponents; ++fc) {
1227: for (d = 0; d < coordDim; ++d) gradsum[fc*coordDim+d] /= volsum;
1228: }
1229: DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star);
1230: DMPlexVecSetClosure(dmC, NULL, locC, v, gradsum, INSERT_VALUES);
1231: }
1232: PetscFree6(gradsum,interpolant,coords,detJ,J,invJ);
1233: return(0);
1234: }
1236: static PetscErrorCode DMPlexComputeIntegral_Internal(DM dm, Vec X, PetscInt cStart, PetscInt cEnd, PetscScalar *cintegral, void *user)
1237: {
1238: DM dmAux = NULL;
1239: PetscDS prob, probAux = NULL;
1240: PetscSection section, sectionAux;
1241: Vec locX, locA;
1242: PetscInt dim, numCells = cEnd - cStart, c, f;
1243: PetscBool useFVM = PETSC_FALSE;
1244: /* DS */
1245: PetscInt Nf, totDim, *uOff, *uOff_x, numConstants;
1246: PetscInt NfAux, totDimAux, *aOff;
1247: PetscScalar *u, *a;
1248: const PetscScalar *constants;
1249: /* Geometry */
1250: PetscFEGeom *cgeomFEM;
1251: DM dmGrad;
1252: PetscQuadrature affineQuad = NULL;
1253: Vec cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL;
1254: PetscFVCellGeom *cgeomFVM;
1255: const PetscScalar *lgrad;
1256: PetscInt maxDegree;
1257: DMField coordField;
1258: IS cellIS;
1259: PetscErrorCode ierr;
1262: DMGetDS(dm, &prob);
1263: DMGetDimension(dm, &dim);
1264: DMGetSection(dm, §ion);
1265: PetscSectionGetNumFields(section, &Nf);
1266: /* Determine which discretizations we have */
1267: for (f = 0; f < Nf; ++f) {
1268: PetscObject obj;
1269: PetscClassId id;
1271: PetscDSGetDiscretization(prob, f, &obj);
1272: PetscObjectGetClassId(obj, &id);
1273: if (id == PETSCFV_CLASSID) useFVM = PETSC_TRUE;
1274: }
1275: /* Get local solution with boundary values */
1276: DMGetLocalVector(dm, &locX);
1277: DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL);
1278: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX);
1279: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX);
1280: /* Read DS information */
1281: PetscDSGetTotalDimension(prob, &totDim);
1282: PetscDSGetComponentOffsets(prob, &uOff);
1283: PetscDSGetComponentDerivativeOffsets(prob, &uOff_x);
1284: ISCreateStride(PETSC_COMM_SELF,numCells,cStart,1,&cellIS);
1285: PetscDSGetConstants(prob, &numConstants, &constants);
1286: /* Read Auxiliary DS information */
1287: PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
1288: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
1289: if (dmAux) {
1290: DMGetDS(dmAux, &probAux);
1291: PetscDSGetNumFields(probAux, &NfAux);
1292: DMGetSection(dmAux, §ionAux);
1293: PetscDSGetTotalDimension(probAux, &totDimAux);
1294: PetscDSGetComponentOffsets(probAux, &aOff);
1295: }
1296: /* Allocate data arrays */
1297: PetscCalloc1(numCells*totDim, &u);
1298: if (dmAux) {PetscMalloc1(numCells*totDimAux, &a);}
1299: /* Read out geometry */
1300: DMGetCoordinateField(dm,&coordField);
1301: DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);
1302: if (maxDegree <= 1) {
1303: DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad);
1304: if (affineQuad) {
1305: DMFieldCreateFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&cgeomFEM);
1306: }
1307: }
1308: if (useFVM) {
1309: PetscFV fv = NULL;
1310: Vec grad;
1311: PetscInt fStart, fEnd;
1312: PetscBool compGrad;
1314: for (f = 0; f < Nf; ++f) {
1315: PetscObject obj;
1316: PetscClassId id;
1318: PetscDSGetDiscretization(prob, f, &obj);
1319: PetscObjectGetClassId(obj, &id);
1320: if (id == PETSCFV_CLASSID) {fv = (PetscFV) obj; break;}
1321: }
1322: PetscFVGetComputeGradients(fv, &compGrad);
1323: PetscFVSetComputeGradients(fv, PETSC_TRUE);
1324: DMPlexComputeGeometryFVM(dm, &cellGeometryFVM, &faceGeometryFVM);
1325: DMPlexComputeGradientFVM(dm, fv, faceGeometryFVM, cellGeometryFVM, &dmGrad);
1326: PetscFVSetComputeGradients(fv, compGrad);
1327: VecGetArrayRead(cellGeometryFVM, (const PetscScalar **) &cgeomFVM);
1328: /* Reconstruct and limit cell gradients */
1329: DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
1330: DMGetGlobalVector(dmGrad, &grad);
1331: DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad);
1332: /* Communicate gradient values */
1333: DMGetLocalVector(dmGrad, &locGrad);
1334: DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad);
1335: DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad);
1336: DMRestoreGlobalVector(dmGrad, &grad);
1337: /* Handle non-essential (e.g. outflow) boundary values */
1338: DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, 0.0, faceGeometryFVM, cellGeometryFVM, locGrad);
1339: VecGetArrayRead(locGrad, &lgrad);
1340: }
1341: /* Read out data from inputs */
1342: for (c = cStart; c < cEnd; ++c) {
1343: PetscScalar *x = NULL;
1344: PetscInt i;
1346: DMPlexVecGetClosure(dm, section, locX, c, NULL, &x);
1347: for (i = 0; i < totDim; ++i) u[c*totDim+i] = x[i];
1348: DMPlexVecRestoreClosure(dm, section, locX, c, NULL, &x);
1349: if (dmAux) {
1350: DMPlexVecGetClosure(dmAux, sectionAux, locA, c, NULL, &x);
1351: for (i = 0; i < totDimAux; ++i) a[c*totDimAux+i] = x[i];
1352: DMPlexVecRestoreClosure(dmAux, sectionAux, locA, c, NULL, &x);
1353: }
1354: }
1355: /* Do integration for each field */
1356: for (f = 0; f < Nf; ++f) {
1357: PetscObject obj;
1358: PetscClassId id;
1359: PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
1361: PetscDSGetDiscretization(prob, f, &obj);
1362: PetscObjectGetClassId(obj, &id);
1363: if (id == PETSCFE_CLASSID) {
1364: PetscFE fe = (PetscFE) obj;
1365: PetscQuadrature q;
1366: PetscFEGeom *chunkGeom = NULL;
1367: PetscInt Nq, Nb;
1369: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
1370: PetscFEGetQuadrature(fe, &q);
1371: PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL);
1372: PetscFEGetDimension(fe, &Nb);
1373: blockSize = Nb*Nq;
1374: batchSize = numBlocks * blockSize;
1375: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
1376: numChunks = numCells / (numBatches*batchSize);
1377: Ne = numChunks*numBatches*batchSize;
1378: Nr = numCells % (numBatches*batchSize);
1379: offset = numCells - Nr;
1380: if (!affineQuad) {
1381: DMFieldCreateFEGeom(coordField,cellIS,q,PETSC_FALSE,&cgeomFEM);
1382: }
1383: PetscFEGeomGetChunk(cgeomFEM,0,offset,&chunkGeom);
1384: PetscFEIntegrate(fe, prob, f, Ne, chunkGeom, u, probAux, a, cintegral);
1385: PetscFEGeomGetChunk(cgeomFEM,offset,numCells,&chunkGeom);
1386: PetscFEIntegrate(fe, prob, f, Nr, chunkGeom, &u[offset*totDim], probAux, &a[offset*totDimAux], &cintegral[offset*Nf]);
1387: PetscFEGeomRestoreChunk(cgeomFEM,offset,numCells,&chunkGeom);
1388: if (!affineQuad) {
1389: PetscFEGeomDestroy(&cgeomFEM);
1390: }
1391: } else if (id == PETSCFV_CLASSID) {
1392: PetscInt foff;
1393: PetscPointFunc obj_func;
1394: PetscScalar lint;
1396: PetscDSGetObjective(prob, f, &obj_func);
1397: PetscDSGetFieldOffset(prob, f, &foff);
1398: if (obj_func) {
1399: for (c = 0; c < numCells; ++c) {
1400: PetscScalar *u_x;
1402: DMPlexPointLocalRead(dmGrad, c, lgrad, &u_x);
1403: 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);
1404: cintegral[c*Nf+f] += PetscRealPart(lint)*cgeomFVM[c].volume;
1405: }
1406: }
1407: } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
1408: }
1409: /* Cleanup data arrays */
1410: if (useFVM) {
1411: VecRestoreArrayRead(locGrad, &lgrad);
1412: VecRestoreArrayRead(cellGeometryFVM, (const PetscScalar **) &cgeomFVM);
1413: DMRestoreLocalVector(dmGrad, &locGrad);
1414: VecDestroy(&faceGeometryFVM);
1415: VecDestroy(&cellGeometryFVM);
1416: DMDestroy(&dmGrad);
1417: }
1418: if (dmAux) {PetscFree(a);}
1419: PetscFree(u);
1420: /* Cleanup */
1421: if (affineQuad) {
1422: PetscFEGeomDestroy(&cgeomFEM);
1423: }
1424: PetscQuadratureDestroy(&affineQuad);
1425: ISDestroy(&cellIS);
1426: DMRestoreLocalVector(dm, &locX);
1427: return(0);
1428: }
1430: /*@
1431: DMPlexComputeIntegralFEM - Form the integral over the domain from the global input X using pointwise functions specified by the user
1433: Input Parameters:
1434: + dm - The mesh
1435: . X - Global input vector
1436: - user - The user context
1438: Output Parameter:
1439: . integral - Integral for each field
1441: Level: developer
1443: .seealso: DMPlexComputeResidualFEM()
1444: @*/
1445: PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscScalar *integral, void *user)
1446: {
1447: DM_Plex *mesh = (DM_Plex *) dm->data;
1448: PetscScalar *cintegral, *lintegral;
1449: PetscInt Nf, f, cellHeight, cStart, cEnd, cEndInterior[4], cell;
1456: PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0);
1457: DMGetNumFields(dm, &Nf);
1458: DMPlexGetVTKCellHeight(dm, &cellHeight);
1459: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
1460: DMPlexGetHybridBounds(dm, &cEndInterior[0], &cEndInterior[1], &cEndInterior[2], &cEndInterior[3]);
1461: cEnd = cEndInterior[cellHeight] < 0 ? cEnd : cEndInterior[cellHeight];
1462: /* TODO Introduce a loop over large chunks (right now this is a single chunk) */
1463: PetscCalloc2(Nf, &lintegral, (cEnd-cStart)*Nf, &cintegral);
1464: DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user);
1465: /* Sum up values */
1466: for (cell = cStart; cell < cEnd; ++cell) {
1467: const PetscInt c = cell - cStart;
1469: if (mesh->printFEM > 1) {DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c*Nf]);}
1470: for (f = 0; f < Nf; ++f) lintegral[f] += cintegral[c*Nf+f];
1471: }
1472: MPIU_Allreduce(lintegral, integral, Nf, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject) dm));
1473: if (mesh->printFEM) {
1474: PetscPrintf(PetscObjectComm((PetscObject) dm), "Integral:");
1475: for (f = 0; f < Nf; ++f) {PetscPrintf(PetscObjectComm((PetscObject) dm), " %g", (double) PetscRealPart(integral[f]));}
1476: PetscPrintf(PetscObjectComm((PetscObject) dm), "\n");
1477: }
1478: PetscFree2(lintegral, cintegral);
1479: PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0);
1480: return(0);
1481: }
1483: /*@
1484: DMPlexComputeCellwiseIntegralFEM - Form the vector of cellwise integrals F from the global input X using pointwise functions specified by the user
1486: Input Parameters:
1487: + dm - The mesh
1488: . X - Global input vector
1489: - user - The user context
1491: Output Parameter:
1492: . integral - Cellwise integrals for each field
1494: Level: developer
1496: .seealso: DMPlexComputeResidualFEM()
1497: @*/
1498: PetscErrorCode DMPlexComputeCellwiseIntegralFEM(DM dm, Vec X, Vec F, void *user)
1499: {
1500: DM_Plex *mesh = (DM_Plex *) dm->data;
1501: DM dmF;
1502: PetscSection sectionF;
1503: PetscScalar *cintegral, *af;
1504: PetscInt Nf, f, cellHeight, cStart, cEnd, cEndInterior[4], cell;
1511: PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0);
1512: DMGetNumFields(dm, &Nf);
1513: DMPlexGetVTKCellHeight(dm, &cellHeight);
1514: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
1515: DMPlexGetHybridBounds(dm, &cEndInterior[0], &cEndInterior[1], &cEndInterior[2], &cEndInterior[3]);
1516: cEnd = cEndInterior[cellHeight] < 0 ? cEnd : cEndInterior[cellHeight];
1517: /* TODO Introduce a loop over large chunks (right now this is a single chunk) */
1518: PetscCalloc1((cEnd-cStart)*Nf, &cintegral);
1519: DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user);
1520: /* Put values in F*/
1521: VecGetDM(F, &dmF);
1522: DMGetSection(dmF, §ionF);
1523: VecGetArray(F, &af);
1524: for (cell = cStart; cell < cEnd; ++cell) {
1525: const PetscInt c = cell - cStart;
1526: PetscInt dof, off;
1528: if (mesh->printFEM > 1) {DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c*Nf]);}
1529: PetscSectionGetDof(sectionF, cell, &dof);
1530: PetscSectionGetOffset(sectionF, cell, &off);
1531: if (dof != Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cell dofs %D != %D", dof, Nf);
1532: for (f = 0; f < Nf; ++f) af[off+f] = cintegral[c*Nf+f];
1533: }
1534: VecRestoreArray(F, &af);
1535: PetscFree(cintegral);
1536: PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0);
1537: return(0);
1538: }
1540: static PetscErrorCode DMPlexComputeBdIntegral_Internal(DM dm, Vec locX, IS pointIS,
1541: void (*func)(PetscInt, PetscInt, PetscInt,
1542: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
1543: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
1544: PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
1545: PetscScalar *fintegral, void *user)
1546: {
1547: DM plex = NULL, plexA = NULL;
1548: PetscDS prob, probAux = NULL;
1549: PetscSection section, sectionAux = NULL;
1550: Vec locA = NULL;
1551: DMField coordField;
1552: PetscInt Nf, totDim, *uOff, *uOff_x;
1553: PetscInt NfAux = 0, totDimAux = 0, *aOff = NULL;
1554: PetscScalar *u, *a = NULL;
1555: const PetscScalar *constants;
1556: PetscInt numConstants, f;
1557: PetscErrorCode ierr;
1560: DMGetCoordinateField(dm, &coordField);
1561: DMConvert(dm, DMPLEX, &plex);
1562: DMGetDS(dm, &prob);
1563: DMGetDefaultSection(dm, §ion);
1564: PetscSectionGetNumFields(section, &Nf);
1565: /* Determine which discretizations we have */
1566: for (f = 0; f < Nf; ++f) {
1567: PetscObject obj;
1568: PetscClassId id;
1570: PetscDSGetDiscretization(prob, f, &obj);
1571: PetscObjectGetClassId(obj, &id);
1572: if (id == PETSCFV_CLASSID) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Not supported for FVM (field %D)", f);
1573: }
1574: /* Read DS information */
1575: PetscDSGetTotalDimension(prob, &totDim);
1576: PetscDSGetComponentOffsets(prob, &uOff);
1577: PetscDSGetComponentDerivativeOffsets(prob, &uOff_x);
1578: PetscDSGetConstants(prob, &numConstants, &constants);
1579: /* Read Auxiliary DS information */
1580: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
1581: if (locA) {
1582: DM dmAux;
1584: VecGetDM(locA, &dmAux);
1585: DMConvert(dmAux, DMPLEX, &plexA);
1586: DMGetDS(dmAux, &probAux);
1587: PetscDSGetNumFields(probAux, &NfAux);
1588: DMGetDefaultSection(dmAux, §ionAux);
1589: PetscDSGetTotalDimension(probAux, &totDimAux);
1590: PetscDSGetComponentOffsets(probAux, &aOff);
1591: }
1592: /* Integrate over points */
1593: {
1594: PetscFEGeom *fgeom, *chunkGeom = NULL;
1595: PetscInt maxDegree;
1596: PetscQuadrature qGeom = NULL;
1597: const PetscInt *points;
1598: PetscInt numFaces, face, Nq, field;
1599: PetscInt numChunks, chunkSize, chunk, Nr, offset;
1601: ISGetLocalSize(pointIS, &numFaces);
1602: ISGetIndices(pointIS, &points);
1603: PetscCalloc2(numFaces*totDim, &u, locA ? numFaces*totDimAux : 0, &a);
1604: DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree);
1605: for (field = 0; field < Nf; ++field) {
1606: PetscFE fe;
1608: PetscDSGetDiscretization(prob, field, (PetscObject *) &fe);
1609: if (maxDegree <= 1) {DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom);}
1610: if (!qGeom) {
1611: PetscFEGetFaceQuadrature(fe, &qGeom);
1612: PetscObjectReference((PetscObject) qGeom);
1613: }
1614: PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
1615: DMPlexGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom);
1616: for (face = 0; face < numFaces; ++face) {
1617: const PetscInt point = points[face], *support, *cone;
1618: PetscScalar *x = NULL;
1619: PetscInt i, coneSize, faceLoc;
1621: DMPlexGetSupport(dm, point, &support);
1622: DMPlexGetConeSize(dm, support[0], &coneSize);
1623: DMPlexGetCone(dm, support[0], &cone);
1624: for (faceLoc = 0; faceLoc < coneSize; ++faceLoc) if (cone[faceLoc] == point) break;
1625: if (faceLoc == coneSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of support[0] %D", face, support[0]);
1626: fgeom->face[face][0] = faceLoc;
1627: DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);
1628: for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i];
1629: DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);
1630: if (locA) {
1631: PetscInt subp;
1632: DMPlexGetSubpoint(plexA, support[0], &subp);
1633: DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);
1634: for (i = 0; i < totDimAux; ++i) a[f*totDimAux+i] = x[i];
1635: DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);
1636: }
1637: }
1638: /* Get blocking */
1639: {
1640: PetscQuadrature q;
1641: PetscInt numBatches, batchSize, numBlocks, blockSize;
1642: PetscInt Nq, Nb;
1644: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
1645: PetscFEGetQuadrature(fe, &q);
1646: PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL);
1647: PetscFEGetDimension(fe, &Nb);
1648: blockSize = Nb*Nq;
1649: batchSize = numBlocks * blockSize;
1650: chunkSize = numBatches*batchSize;
1651: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
1652: numChunks = numFaces / chunkSize;
1653: Nr = numFaces % chunkSize;
1654: offset = numFaces - Nr;
1655: }
1656: /* Do integration for each field */
1657: for (chunk = 0; chunk < numChunks; ++chunk) {
1658: PetscFEGeomGetChunk(fgeom, chunk*chunkSize, (chunk+1)*chunkSize, &chunkGeom);
1659: PetscFEIntegrateBd(fe, prob, field, func, chunkSize, chunkGeom, u, probAux, a, fintegral);
1660: PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom);
1661: }
1662: PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom);
1663: PetscFEIntegrateBd(fe, prob, field, func, Nr, chunkGeom, &u[offset*totDim], probAux, a ? &a[offset*totDimAux] : NULL, &fintegral[offset*Nf]);
1664: PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom);
1665: /* Cleanup data arrays */
1666: DMPlexRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom);
1667: PetscQuadratureDestroy(&qGeom);
1668: PetscFree2(u, a);
1669: ISRestoreIndices(pointIS, &points);
1670: }
1671: }
1672: if (plex) {DMDestroy(&plex);}
1673: if (plexA) {DMDestroy(&plexA);}
1674: return(0);
1675: }
1677: /*@
1678: DMPlexComputeBdIntegral - Form the integral over the specified boundary from the global input X using pointwise functions specified by the user
1680: Input Parameters:
1681: + dm - The mesh
1682: . X - Global input vector
1683: . label - The boundary DMLabel
1684: . numVals - The number of label values to use, or PETSC_DETERMINE for all values
1685: . vals - The label values to use, or PETSC_NULL for all values
1686: . func = The function to integrate along the boundary
1687: - user - The user context
1689: Output Parameter:
1690: . integral - Integral for each field
1692: Level: developer
1694: .seealso: DMPlexComputeIntegralFEM(), DMPlexComputeBdResidualFEM()
1695: @*/
1696: PetscErrorCode DMPlexComputeBdIntegral(DM dm, Vec X, DMLabel label, PetscInt numVals, const PetscInt vals[],
1697: void (*func)(PetscInt, PetscInt, PetscInt,
1698: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
1699: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
1700: PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
1701: PetscScalar *integral, void *user)
1702: {
1703: Vec locX;
1704: PetscSection section;
1705: DMLabel depthLabel;
1706: IS facetIS;
1707: PetscInt dim, Nf, f, v;
1716: PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0);
1717: DMPlexGetDepthLabel(dm, &depthLabel);
1718: DMGetDimension(dm, &dim);
1719: DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);
1720: DMGetDefaultSection(dm, §ion);
1721: PetscSectionGetNumFields(section, &Nf);
1722: /* Get local solution with boundary values */
1723: DMGetLocalVector(dm, &locX);
1724: DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL);
1725: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX);
1726: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX);
1727: /* Loop over label values */
1728: PetscMemzero(integral, Nf * sizeof(PetscScalar));
1729: for (v = 0; v < numVals; ++v) {
1730: IS pointIS;
1731: PetscInt numFaces, face;
1732: PetscScalar *fintegral;
1734: DMLabelGetStratumIS(label, vals[v], &pointIS);
1735: if (!pointIS) continue; /* No points with that id on this process */
1736: {
1737: IS isectIS;
1739: /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */
1740: ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS);
1741: ISDestroy(&pointIS);
1742: pointIS = isectIS;
1743: }
1744: ISGetLocalSize(pointIS, &numFaces);
1745: PetscCalloc1(numFaces*Nf, &fintegral);
1746: DMPlexComputeBdIntegral_Internal(dm, locX, pointIS, func, fintegral, user);
1747: /* Sum point contributions into integral */
1748: for (f = 0; f < Nf; ++f) for (face = 0; face < numFaces; ++face) integral[f] += fintegral[face*Nf+f];
1749: PetscFree(fintegral);
1750: ISDestroy(&pointIS);
1751: }
1752: DMRestoreLocalVector(dm, &locX);
1753: ISDestroy(&facetIS);
1754: PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0);
1755: return(0);
1756: }
1758: /*@
1759: DMPlexComputeInterpolatorNested - Form the local portion of the interpolation matrix I from the coarse DM to the uniformly refined DM.
1761: Input Parameters:
1762: + dmf - The fine mesh
1763: . dmc - The coarse mesh
1764: - user - The user context
1766: Output Parameter:
1767: . In - The interpolation matrix
1769: Level: developer
1771: .seealso: DMPlexComputeInterpolatorGeneral(), DMPlexComputeJacobianFEM()
1772: @*/
1773: PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, Mat In, void *user)
1774: {
1775: DM_Plex *mesh = (DM_Plex *) dmc->data;
1776: const char *name = "Interpolator";
1777: PetscDS prob;
1778: PetscFE *feRef;
1779: PetscFV *fvRef;
1780: PetscSection fsection, fglobalSection;
1781: PetscSection csection, cglobalSection;
1782: PetscScalar *elemMat;
1783: PetscInt dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, cEndInterior, c;
1784: PetscInt cTotDim, rTotDim = 0;
1785: PetscErrorCode ierr;
1788: PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
1789: DMGetDimension(dmf, &dim);
1790: DMGetSection(dmf, &fsection);
1791: DMGetGlobalSection(dmf, &fglobalSection);
1792: DMGetSection(dmc, &csection);
1793: DMGetGlobalSection(dmc, &cglobalSection);
1794: PetscSectionGetNumFields(fsection, &Nf);
1795: DMPlexGetHeightStratum(dmc, 0, &cStart, &cEnd);
1796: DMPlexGetHybridBounds(dmc, &cEndInterior, NULL, NULL, NULL);
1797: cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
1798: DMGetDS(dmf, &prob);
1799: PetscCalloc2(Nf,&feRef,Nf,&fvRef);
1800: for (f = 0; f < Nf; ++f) {
1801: PetscObject obj;
1802: PetscClassId id;
1803: PetscInt rNb = 0, Nc = 0;
1805: PetscDSGetDiscretization(prob, f, &obj);
1806: PetscObjectGetClassId(obj, &id);
1807: if (id == PETSCFE_CLASSID) {
1808: PetscFE fe = (PetscFE) obj;
1810: PetscFERefine(fe, &feRef[f]);
1811: PetscFEGetDimension(feRef[f], &rNb);
1812: PetscFEGetNumComponents(fe, &Nc);
1813: } else if (id == PETSCFV_CLASSID) {
1814: PetscFV fv = (PetscFV) obj;
1815: PetscDualSpace Q;
1817: PetscFVRefine(fv, &fvRef[f]);
1818: PetscFVGetDualSpace(fvRef[f], &Q);
1819: PetscDualSpaceGetDimension(Q, &rNb);
1820: PetscFVGetNumComponents(fv, &Nc);
1821: }
1822: rTotDim += rNb;
1823: }
1824: PetscDSGetTotalDimension(prob, &cTotDim);
1825: PetscMalloc1(rTotDim*cTotDim,&elemMat);
1826: PetscMemzero(elemMat, rTotDim*cTotDim * sizeof(PetscScalar));
1827: for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) {
1828: PetscDualSpace Qref;
1829: PetscQuadrature f;
1830: const PetscReal *qpoints, *qweights;
1831: PetscReal *points;
1832: PetscInt npoints = 0, Nc, Np, fpdim, i, k, p, d;
1834: /* Compose points from all dual basis functionals */
1835: if (feRef[fieldI]) {
1836: PetscFEGetDualSpace(feRef[fieldI], &Qref);
1837: PetscFEGetNumComponents(feRef[fieldI], &Nc);
1838: } else {
1839: PetscFVGetDualSpace(fvRef[fieldI], &Qref);
1840: PetscFVGetNumComponents(fvRef[fieldI], &Nc);
1841: }
1842: PetscDualSpaceGetDimension(Qref, &fpdim);
1843: for (i = 0; i < fpdim; ++i) {
1844: PetscDualSpaceGetFunctional(Qref, i, &f);
1845: PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL);
1846: npoints += Np;
1847: }
1848: PetscMalloc1(npoints*dim,&points);
1849: for (i = 0, k = 0; i < fpdim; ++i) {
1850: PetscDualSpaceGetFunctional(Qref, i, &f);
1851: PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL);
1852: for (p = 0; p < Np; ++p, ++k) for (d = 0; d < dim; ++d) points[k*dim+d] = qpoints[p*dim+d];
1853: }
1855: for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) {
1856: PetscObject obj;
1857: PetscClassId id;
1858: PetscReal *B;
1859: PetscInt NcJ = 0, cpdim = 0, j, qNc;
1861: PetscDSGetDiscretization(prob, fieldJ, &obj);
1862: PetscObjectGetClassId(obj, &id);
1863: if (id == PETSCFE_CLASSID) {
1864: PetscFE fe = (PetscFE) obj;
1866: /* Evaluate basis at points */
1867: PetscFEGetNumComponents(fe, &NcJ);
1868: PetscFEGetDimension(fe, &cpdim);
1869: /* For now, fields only interpolate themselves */
1870: if (fieldI == fieldJ) {
1871: if (Nc != NcJ) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %D does not match coarse field %D", Nc, NcJ);
1872: PetscFEGetTabulation(fe, npoints, points, &B, NULL, NULL);
1873: for (i = 0, k = 0; i < fpdim; ++i) {
1874: PetscDualSpaceGetFunctional(Qref, i, &f);
1875: PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights);
1876: if (qNc != NcJ) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %D does not match coarse field %D", qNc, NcJ);
1877: for (p = 0; p < Np; ++p, ++k) {
1878: for (j = 0; j < cpdim; ++j) {
1879: /*
1880: cTotDim: Total columns in element interpolation matrix, sum of number of dual basis functionals in each field
1881: offsetI, offsetJ: Offsets into the larger element interpolation matrix for different fields
1882: fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals
1883: qNC, Nc, Ncj, c: Number of components in this field
1884: Np, p: Number of quad points in the fine grid functional i
1885: k: i*Np + p, overall point number for the interpolation
1886: */
1887: for (c = 0; c < Nc; ++c) elemMat[(offsetI + i)*cTotDim + offsetJ + j] += B[k*cpdim*NcJ+j*Nc+c]*qweights[p*qNc+c];
1888: }
1889: }
1890: }
1891: PetscFERestoreTabulation(fe, npoints, points, &B, NULL, NULL);
1892: }
1893: } else if (id == PETSCFV_CLASSID) {
1894: PetscFV fv = (PetscFV) obj;
1896: /* Evaluate constant function at points */
1897: PetscFVGetNumComponents(fv, &NcJ);
1898: cpdim = 1;
1899: /* For now, fields only interpolate themselves */
1900: if (fieldI == fieldJ) {
1901: if (Nc != NcJ) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %d does not match coarse field %d", Nc, NcJ);
1902: for (i = 0, k = 0; i < fpdim; ++i) {
1903: PetscDualSpaceGetFunctional(Qref, i, &f);
1904: PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights);
1905: if (qNc != NcJ) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %D does not match coarse field %D", qNc, NcJ);
1906: for (p = 0; p < Np; ++p, ++k) {
1907: for (j = 0; j < cpdim; ++j) {
1908: for (c = 0; c < Nc; ++c) elemMat[(offsetI + i)*cTotDim + offsetJ + j] += 1.0*qweights[p*qNc+c];
1909: }
1910: }
1911: }
1912: }
1913: }
1914: offsetJ += cpdim;
1915: }
1916: offsetI += fpdim;
1917: PetscFree(points);
1918: }
1919: if (mesh->printFEM > 1) {DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat);}
1920: /* Preallocate matrix */
1921: {
1922: Mat preallocator;
1923: PetscScalar *vals;
1924: PetscInt *cellCIndices, *cellFIndices;
1925: PetscInt locRows, locCols, cell;
1927: MatGetLocalSize(In, &locRows, &locCols);
1928: MatCreate(PetscObjectComm((PetscObject) In), &preallocator);
1929: MatSetType(preallocator, MATPREALLOCATOR);
1930: MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE);
1931: MatSetUp(preallocator);
1932: PetscCalloc3(rTotDim*cTotDim, &vals,cTotDim,&cellCIndices,rTotDim,&cellFIndices);
1933: for (cell = cStart; cell < cEnd; ++cell) {
1934: DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices);
1935: MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES);
1936: }
1937: PetscFree3(vals,cellCIndices,cellFIndices);
1938: MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY);
1939: MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY);
1940: MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In);
1941: MatDestroy(&preallocator);
1942: }
1943: /* Fill matrix */
1944: MatZeroEntries(In);
1945: for (c = cStart; c < cEnd; ++c) {
1946: DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES);
1947: }
1948: for (f = 0; f < Nf; ++f) {PetscFEDestroy(&feRef[f]);}
1949: PetscFree2(feRef,fvRef);
1950: PetscFree(elemMat);
1951: MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);
1952: MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);
1953: if (mesh->printFEM) {
1954: PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name);
1955: MatChop(In, 1.0e-10);
1956: MatView(In, NULL);
1957: }
1958: PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
1959: return(0);
1960: }
1962: PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user)
1963: {
1964: SETERRQ(PetscObjectComm((PetscObject) dmc), PETSC_ERR_SUP, "Laziness");
1965: }
1967: /*@
1968: DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix I from the coarse DM to a non-nested fine DM.
1970: Input Parameters:
1971: + dmf - The fine mesh
1972: . dmc - The coarse mesh
1973: - user - The user context
1975: Output Parameter:
1976: . In - The interpolation matrix
1978: Level: developer
1980: .seealso: DMPlexComputeInterpolatorNested(), DMPlexComputeJacobianFEM()
1981: @*/
1982: PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user)
1983: {
1984: DM_Plex *mesh = (DM_Plex *) dmf->data;
1985: const char *name = "Interpolator";
1986: PetscDS prob;
1987: PetscSection fsection, csection, globalFSection, globalCSection;
1988: PetscHSetIJ ht;
1989: PetscLayout rLayout;
1990: PetscInt *dnz, *onz;
1991: PetscInt locRows, rStart, rEnd;
1992: PetscReal *x, *v0, *J, *invJ, detJ;
1993: PetscReal *v0c, *Jc, *invJc, detJc;
1994: PetscScalar *elemMat;
1995: PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell;
1999: PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
2000: DMGetCoordinateDim(dmc, &dim);
2001: DMGetDS(dmc, &prob);
2002: PetscDSGetRefCoordArrays(prob, &x, NULL);
2003: PetscDSGetNumFields(prob, &Nf);
2004: PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);
2005: PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc);
2006: DMGetSection(dmf, &fsection);
2007: DMGetGlobalSection(dmf, &globalFSection);
2008: DMGetSection(dmc, &csection);
2009: DMGetGlobalSection(dmc, &globalCSection);
2010: DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);
2011: PetscDSGetTotalDimension(prob, &totDim);
2012: PetscMalloc1(totDim, &elemMat);
2014: MatGetLocalSize(In, &locRows, NULL);
2015: PetscLayoutCreate(PetscObjectComm((PetscObject) In), &rLayout);
2016: PetscLayoutSetLocalSize(rLayout, locRows);
2017: PetscLayoutSetBlockSize(rLayout, 1);
2018: PetscLayoutSetUp(rLayout);
2019: PetscLayoutGetRange(rLayout, &rStart, &rEnd);
2020: PetscLayoutDestroy(&rLayout);
2021: PetscCalloc2(locRows,&dnz,locRows,&onz);
2022: PetscHSetIJCreate(&ht);
2023: for (field = 0; field < Nf; ++field) {
2024: PetscObject obj;
2025: PetscClassId id;
2026: PetscDualSpace Q = NULL;
2027: PetscQuadrature f;
2028: const PetscReal *qpoints;
2029: PetscInt Nc, Np, fpdim, i, d;
2031: PetscDSGetDiscretization(prob, field, &obj);
2032: PetscObjectGetClassId(obj, &id);
2033: if (id == PETSCFE_CLASSID) {
2034: PetscFE fe = (PetscFE) obj;
2036: PetscFEGetDualSpace(fe, &Q);
2037: PetscFEGetNumComponents(fe, &Nc);
2038: } else if (id == PETSCFV_CLASSID) {
2039: PetscFV fv = (PetscFV) obj;
2041: PetscFVGetDualSpace(fv, &Q);
2042: Nc = 1;
2043: }
2044: PetscDualSpaceGetDimension(Q, &fpdim);
2045: /* For each fine grid cell */
2046: for (cell = cStart; cell < cEnd; ++cell) {
2047: PetscInt *findices, *cindices;
2048: PetscInt numFIndices, numCIndices;
2050: DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);
2051: DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
2052: if (numFIndices != fpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %d != %d dual basis vecs", numFIndices, fpdim);
2053: for (i = 0; i < fpdim; ++i) {
2054: Vec pointVec;
2055: PetscScalar *pV;
2056: PetscSF coarseCellSF = NULL;
2057: const PetscSFNode *coarseCells;
2058: PetscInt numCoarseCells, q, c;
2060: /* Get points from the dual basis functional quadrature */
2061: PetscDualSpaceGetFunctional(Q, i, &f);
2062: PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL);
2063: VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec);
2064: VecSetBlockSize(pointVec, dim);
2065: VecGetArray(pointVec, &pV);
2066: for (q = 0; q < Np; ++q) {
2067: const PetscReal xi0[3] = {-1., -1., -1.};
2069: /* Transform point to real space */
2070: CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x);
2071: for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
2072: }
2073: VecRestoreArray(pointVec, &pV);
2074: /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
2075: /* OPT: Pack all quad points from fine cell */
2076: DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
2077: PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view");
2078: /* Update preallocation info */
2079: PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
2080: if (numCoarseCells != Np) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located");
2081: {
2082: PetscHashIJKey key;
2083: PetscBool missing;
2085: key.i = findices[i];
2086: if (key.i >= 0) {
2087: /* Get indices for coarse elements */
2088: for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2089: DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);
2090: for (c = 0; c < numCIndices; ++c) {
2091: key.j = cindices[c];
2092: if (key.j < 0) continue;
2093: PetscHSetIJQueryAdd(ht, key, &missing);
2094: if (missing) {
2095: if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i-rStart];
2096: else ++onz[key.i-rStart];
2097: }
2098: }
2099: DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);
2100: }
2101: }
2102: }
2103: PetscSFDestroy(&coarseCellSF);
2104: VecDestroy(&pointVec);
2105: }
2106: DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);
2107: }
2108: }
2109: PetscHSetIJDestroy(&ht);
2110: MatXAIJSetPreallocation(In, 1, dnz, onz, NULL, NULL);
2111: MatSetOption(In, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);
2112: PetscFree2(dnz,onz);
2113: for (field = 0; field < Nf; ++field) {
2114: PetscObject obj;
2115: PetscClassId id;
2116: PetscDualSpace Q = NULL;
2117: PetscQuadrature f;
2118: const PetscReal *qpoints, *qweights;
2119: PetscInt Nc, qNc, Np, fpdim, i, d;
2121: PetscDSGetDiscretization(prob, field, &obj);
2122: PetscObjectGetClassId(obj, &id);
2123: if (id == PETSCFE_CLASSID) {
2124: PetscFE fe = (PetscFE) obj;
2126: PetscFEGetDualSpace(fe, &Q);
2127: PetscFEGetNumComponents(fe, &Nc);
2128: } else if (id == PETSCFV_CLASSID) {
2129: PetscFV fv = (PetscFV) obj;
2131: PetscFVGetDualSpace(fv, &Q);
2132: Nc = 1;
2133: } else SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_ARG_WRONG,"Unknown discretization type for field %d",field);
2134: PetscDualSpaceGetDimension(Q, &fpdim);
2135: /* For each fine grid cell */
2136: for (cell = cStart; cell < cEnd; ++cell) {
2137: PetscInt *findices, *cindices;
2138: PetscInt numFIndices, numCIndices;
2140: DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);
2141: DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
2142: if (numFIndices != fpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %d != %d dual basis vecs", numFIndices, fpdim);
2143: for (i = 0; i < fpdim; ++i) {
2144: Vec pointVec;
2145: PetscScalar *pV;
2146: PetscSF coarseCellSF = NULL;
2147: const PetscSFNode *coarseCells;
2148: PetscInt numCoarseCells, cpdim, q, c, j;
2150: /* Get points from the dual basis functional quadrature */
2151: PetscDualSpaceGetFunctional(Q, i, &f);
2152: PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights);
2153: if (qNc != Nc) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %D does not match coarse field %D", qNc, Nc);
2154: VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec);
2155: VecSetBlockSize(pointVec, dim);
2156: VecGetArray(pointVec, &pV);
2157: for (q = 0; q < Np; ++q) {
2158: const PetscReal xi0[3] = {-1., -1., -1.};
2160: /* Transform point to real space */
2161: CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x);
2162: for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
2163: }
2164: VecRestoreArray(pointVec, &pV);
2165: /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
2166: /* OPT: Read this out from preallocation information */
2167: DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
2168: /* Update preallocation info */
2169: PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
2170: if (numCoarseCells != Np) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located");
2171: VecGetArray(pointVec, &pV);
2172: for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2173: PetscReal pVReal[3];
2174: const PetscReal xi0[3] = {-1., -1., -1.};
2176: DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);
2177: /* Transform points from real space to coarse reference space */
2178: DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc);
2179: for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell*dim+d]);
2180: CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x);
2182: if (id == PETSCFE_CLASSID) {
2183: PetscFE fe = (PetscFE) obj;
2184: PetscReal *B;
2186: /* Evaluate coarse basis on contained point */
2187: PetscFEGetDimension(fe, &cpdim);
2188: PetscFEGetTabulation(fe, 1, x, &B, NULL, NULL);
2189: PetscMemzero(elemMat, cpdim * sizeof(PetscScalar));
2190: /* Get elemMat entries by multiplying by weight */
2191: for (j = 0; j < cpdim; ++j) {
2192: for (c = 0; c < Nc; ++c) elemMat[j] += B[j*Nc + c]*qweights[ccell*qNc + c];
2193: }
2194: PetscFERestoreTabulation(fe, 1, x, &B, NULL, NULL);
2195: } else {
2196: cpdim = 1;
2197: for (j = 0; j < cpdim; ++j) {
2198: for (c = 0; c < Nc; ++c) elemMat[j] += 1.0*qweights[ccell*qNc + c];
2199: }
2200: }
2201: /* Update interpolator */
2202: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);}
2203: if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim);
2204: MatSetValues(In, 1, &findices[i], numCIndices, cindices, elemMat, INSERT_VALUES);
2205: DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);
2206: }
2207: VecRestoreArray(pointVec, &pV);
2208: PetscSFDestroy(&coarseCellSF);
2209: VecDestroy(&pointVec);
2210: }
2211: DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);
2212: }
2213: }
2214: PetscFree3(v0,J,invJ);
2215: PetscFree3(v0c,Jc,invJc);
2216: PetscFree(elemMat);
2217: MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);
2218: MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);
2219: PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
2220: return(0);
2221: }
2223: /*@
2224: DMPlexComputeMassMatrixGeneral - Form the local portion of the mass matrix M from the coarse DM to a non-nested fine DM.
2226: Input Parameters:
2227: + dmf - The fine mesh
2228: . dmc - The coarse mesh
2229: - user - The user context
2231: Output Parameter:
2232: . mass - The mass matrix
2234: Level: developer
2236: .seealso: DMPlexComputeMassMatrixNested(), DMPlexComputeInterpolatorNested(), DMPlexComputeInterpolatorGeneral(), DMPlexComputeJacobianFEM()
2237: @*/
2238: PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, void *user)
2239: {
2240: DM_Plex *mesh = (DM_Plex *) dmf->data;
2241: const char *name = "Mass Matrix";
2242: PetscDS prob;
2243: PetscSection fsection, csection, globalFSection, globalCSection;
2244: PetscHSetIJ ht;
2245: PetscLayout rLayout;
2246: PetscInt *dnz, *onz;
2247: PetscInt locRows, rStart, rEnd;
2248: PetscReal *x, *v0, *J, *invJ, detJ;
2249: PetscReal *v0c, *Jc, *invJc, detJc;
2250: PetscScalar *elemMat;
2251: PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell;
2255: DMGetCoordinateDim(dmc, &dim);
2256: DMGetDS(dmc, &prob);
2257: PetscDSGetRefCoordArrays(prob, &x, NULL);
2258: PetscDSGetNumFields(prob, &Nf);
2259: PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);
2260: PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc);
2261: DMGetSection(dmf, &fsection);
2262: DMGetGlobalSection(dmf, &globalFSection);
2263: DMGetSection(dmc, &csection);
2264: DMGetGlobalSection(dmc, &globalCSection);
2265: DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);
2266: PetscDSGetTotalDimension(prob, &totDim);
2267: PetscMalloc1(totDim, &elemMat);
2269: MatGetLocalSize(mass, &locRows, NULL);
2270: PetscLayoutCreate(PetscObjectComm((PetscObject) mass), &rLayout);
2271: PetscLayoutSetLocalSize(rLayout, locRows);
2272: PetscLayoutSetBlockSize(rLayout, 1);
2273: PetscLayoutSetUp(rLayout);
2274: PetscLayoutGetRange(rLayout, &rStart, &rEnd);
2275: PetscLayoutDestroy(&rLayout);
2276: PetscCalloc2(locRows,&dnz,locRows,&onz);
2277: PetscHSetIJCreate(&ht);
2278: for (field = 0; field < Nf; ++field) {
2279: PetscObject obj;
2280: PetscClassId id;
2281: PetscQuadrature quad;
2282: const PetscReal *qpoints;
2283: PetscInt Nq, Nc, i, d;
2285: PetscDSGetDiscretization(prob, field, &obj);
2286: PetscObjectGetClassId(obj, &id);
2287: if (id == PETSCFE_CLASSID) {PetscFEGetQuadrature((PetscFE) obj, &quad);}
2288: else {PetscFVGetQuadrature((PetscFV) obj, &quad);}
2289: PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL);
2290: /* For each fine grid cell */
2291: for (cell = cStart; cell < cEnd; ++cell) {
2292: Vec pointVec;
2293: PetscScalar *pV;
2294: PetscSF coarseCellSF = NULL;
2295: const PetscSFNode *coarseCells;
2296: PetscInt numCoarseCells, q, c;
2297: PetscInt *findices, *cindices;
2298: PetscInt numFIndices, numCIndices;
2300: DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);
2301: DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
2302: /* Get points from the quadrature */
2303: VecCreateSeq(PETSC_COMM_SELF, Nq*dim, &pointVec);
2304: VecSetBlockSize(pointVec, dim);
2305: VecGetArray(pointVec, &pV);
2306: for (q = 0; q < Nq; ++q) {
2307: const PetscReal xi0[3] = {-1., -1., -1.};
2309: /* Transform point to real space */
2310: CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x);
2311: for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
2312: }
2313: VecRestoreArray(pointVec, &pV);
2314: /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
2315: DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
2316: PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view");
2317: /* Update preallocation info */
2318: PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
2319: if (numCoarseCells != Nq) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located");
2320: {
2321: PetscHashIJKey key;
2322: PetscBool missing;
2324: for (i = 0; i < numFIndices; ++i) {
2325: key.i = findices[i];
2326: if (key.i >= 0) {
2327: /* Get indices for coarse elements */
2328: for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2329: DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);
2330: for (c = 0; c < numCIndices; ++c) {
2331: key.j = cindices[c];
2332: if (key.j < 0) continue;
2333: PetscHSetIJQueryAdd(ht, key, &missing);
2334: if (missing) {
2335: if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i-rStart];
2336: else ++onz[key.i-rStart];
2337: }
2338: }
2339: DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);
2340: }
2341: }
2342: }
2343: }
2344: PetscSFDestroy(&coarseCellSF);
2345: VecDestroy(&pointVec);
2346: DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);
2347: }
2348: }
2349: PetscHSetIJDestroy(&ht);
2350: MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL);
2351: MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);
2352: PetscFree2(dnz,onz);
2353: for (field = 0; field < Nf; ++field) {
2354: PetscObject obj;
2355: PetscClassId id;
2356: PetscQuadrature quad;
2357: PetscReal *Bfine;
2358: const PetscReal *qpoints, *qweights;
2359: PetscInt Nq, Nc, i, d;
2361: PetscDSGetDiscretization(prob, field, &obj);
2362: PetscObjectGetClassId(obj, &id);
2363: if (id == PETSCFE_CLASSID) {PetscFEGetQuadrature((PetscFE) obj, &quad);PetscFEGetDefaultTabulation((PetscFE) obj, &Bfine, NULL, NULL);}
2364: else {PetscFVGetQuadrature((PetscFV) obj, &quad);}
2365: PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights);
2366: /* For each fine grid cell */
2367: for (cell = cStart; cell < cEnd; ++cell) {
2368: Vec pointVec;
2369: PetscScalar *pV;
2370: PetscSF coarseCellSF = NULL;
2371: const PetscSFNode *coarseCells;
2372: PetscInt numCoarseCells, cpdim, q, c, j;
2373: PetscInt *findices, *cindices;
2374: PetscInt numFIndices, numCIndices;
2376: DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);
2377: DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
2378: /* Get points from the quadrature */
2379: VecCreateSeq(PETSC_COMM_SELF, Nq*dim, &pointVec);
2380: VecSetBlockSize(pointVec, dim);
2381: VecGetArray(pointVec, &pV);
2382: for (q = 0; q < Nq; ++q) {
2383: const PetscReal xi0[3] = {-1., -1., -1.};
2385: /* Transform point to real space */
2386: CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x);
2387: for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
2388: }
2389: VecRestoreArray(pointVec, &pV);
2390: /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
2391: DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
2392: /* Update matrix */
2393: PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
2394: if (numCoarseCells != Nq) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located");
2395: VecGetArray(pointVec, &pV);
2396: for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2397: PetscReal pVReal[3];
2398: const PetscReal xi0[3] = {-1., -1., -1.};
2401: DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);
2402: /* Transform points from real space to coarse reference space */
2403: DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc);
2404: for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell*dim+d]);
2405: CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x);
2407: if (id == PETSCFE_CLASSID) {
2408: PetscFE fe = (PetscFE) obj;
2409: PetscReal *B;
2411: /* Evaluate coarse basis on contained point */
2412: PetscFEGetDimension(fe, &cpdim);
2413: PetscFEGetTabulation(fe, 1, x, &B, NULL, NULL);
2414: /* Get elemMat entries by multiplying by weight */
2415: for (i = 0; i < numFIndices; ++i) {
2416: PetscMemzero(elemMat, cpdim * sizeof(PetscScalar));
2417: for (j = 0; j < cpdim; ++j) {
2418: for (c = 0; c < Nc; ++c) elemMat[j] += B[j*Nc + c]*Bfine[(ccell*numFIndices + i)*Nc + c]*qweights[ccell*Nc + c]*detJ;
2419: }
2420: /* Update interpolator */
2421: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);}
2422: if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim);
2423: MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES);
2424: }
2425: PetscFERestoreTabulation(fe, 1, x, &B, NULL, NULL);
2426: } else {
2427: cpdim = 1;
2428: for (i = 0; i < numFIndices; ++i) {
2429: PetscMemzero(elemMat, cpdim * sizeof(PetscScalar));
2430: for (j = 0; j < cpdim; ++j) {
2431: for (c = 0; c < Nc; ++c) elemMat[j] += 1.0*1.0*qweights[ccell*Nc + c]*detJ;
2432: }
2433: /* Update interpolator */
2434: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);}
2435: PetscPrintf(PETSC_COMM_SELF, "Nq: %d %d Nf: %d %d Nc: %d %d\n", ccell, Nq, i, numFIndices, j, numCIndices);
2436: if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim);
2437: MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES);
2438: }
2439: }
2440: DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);
2441: }
2442: VecRestoreArray(pointVec, &pV);
2443: PetscSFDestroy(&coarseCellSF);
2444: VecDestroy(&pointVec);
2445: DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);
2446: }
2447: }
2448: PetscFree3(v0,J,invJ);
2449: PetscFree3(v0c,Jc,invJc);
2450: PetscFree(elemMat);
2451: MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY);
2452: MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY);
2453: return(0);
2454: }
2456: /*@
2457: DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns
2459: Input Parameters:
2460: + dmc - The coarse mesh
2461: - dmf - The fine mesh
2462: - user - The user context
2464: Output Parameter:
2465: . sc - The mapping
2467: Level: developer
2469: .seealso: DMPlexComputeInterpolatorNested(), DMPlexComputeJacobianFEM()
2470: @*/
2471: PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user)
2472: {
2473: PetscDS prob;
2474: PetscFE *feRef;
2475: PetscFV *fvRef;
2476: Vec fv, cv;
2477: IS fis, cis;
2478: PetscSection fsection, fglobalSection, csection, cglobalSection;
2479: PetscInt *cmap, *cellCIndices, *cellFIndices, *cindices, *findices;
2480: PetscInt cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, cEndInterior, c, dim, d, startC, endC, offsetC, offsetF, m;
2481: PetscBool *needAvg;
2485: PetscLogEventBegin(DMPLEX_InjectorFEM,dmc,dmf,0,0);
2486: DMGetDimension(dmf, &dim);
2487: DMGetSection(dmf, &fsection);
2488: DMGetGlobalSection(dmf, &fglobalSection);
2489: DMGetSection(dmc, &csection);
2490: DMGetGlobalSection(dmc, &cglobalSection);
2491: PetscSectionGetNumFields(fsection, &Nf);
2492: DMPlexGetHeightStratum(dmc, 0, &cStart, &cEnd);
2493: DMPlexGetHybridBounds(dmc, &cEndInterior, NULL, NULL, NULL);
2494: cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
2495: DMGetDS(dmc, &prob);
2496: PetscCalloc3(Nf,&feRef,Nf,&fvRef,Nf,&needAvg);
2497: for (f = 0; f < Nf; ++f) {
2498: PetscObject obj;
2499: PetscClassId id;
2500: PetscInt fNb = 0, Nc = 0;
2502: PetscDSGetDiscretization(prob, f, &obj);
2503: PetscObjectGetClassId(obj, &id);
2504: if (id == PETSCFE_CLASSID) {
2505: PetscFE fe = (PetscFE) obj;
2506: PetscSpace sp;
2507: PetscInt maxDegree;
2509: PetscFERefine(fe, &feRef[f]);
2510: PetscFEGetDimension(feRef[f], &fNb);
2511: PetscFEGetNumComponents(fe, &Nc);
2512: PetscFEGetBasisSpace(fe, &sp);
2513: PetscSpaceGetDegree(sp, NULL, &maxDegree);
2514: if (!maxDegree) needAvg[f] = PETSC_TRUE;
2515: } else if (id == PETSCFV_CLASSID) {
2516: PetscFV fv = (PetscFV) obj;
2517: PetscDualSpace Q;
2519: PetscFVRefine(fv, &fvRef[f]);
2520: PetscFVGetDualSpace(fvRef[f], &Q);
2521: PetscDualSpaceGetDimension(Q, &fNb);
2522: PetscFVGetNumComponents(fv, &Nc);
2523: needAvg[f] = PETSC_TRUE;
2524: }
2525: fTotDim += fNb;
2526: }
2527: PetscDSGetTotalDimension(prob, &cTotDim);
2528: PetscMalloc1(cTotDim,&cmap);
2529: for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) {
2530: PetscFE feC;
2531: PetscFV fvC;
2532: PetscDualSpace QF, QC;
2533: PetscInt order = -1, NcF, NcC, fpdim, cpdim;
2535: if (feRef[field]) {
2536: PetscDSGetDiscretization(prob, field, (PetscObject *) &feC);
2537: PetscFEGetNumComponents(feC, &NcC);
2538: PetscFEGetNumComponents(feRef[field], &NcF);
2539: PetscFEGetDualSpace(feRef[field], &QF);
2540: PetscDualSpaceGetOrder(QF, &order);
2541: PetscDualSpaceGetDimension(QF, &fpdim);
2542: PetscFEGetDualSpace(feC, &QC);
2543: PetscDualSpaceGetDimension(QC, &cpdim);
2544: } else {
2545: PetscDSGetDiscretization(prob, field, (PetscObject *) &fvC);
2546: PetscFVGetNumComponents(fvC, &NcC);
2547: PetscFVGetNumComponents(fvRef[field], &NcF);
2548: PetscFVGetDualSpace(fvRef[field], &QF);
2549: PetscDualSpaceGetDimension(QF, &fpdim);
2550: PetscFVGetDualSpace(fvC, &QC);
2551: PetscDualSpaceGetDimension(QC, &cpdim);
2552: }
2553: if (NcF != NcC) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %d does not match coarse field %d", NcF, NcC);
2554: for (c = 0; c < cpdim; ++c) {
2555: PetscQuadrature cfunc;
2556: const PetscReal *cqpoints, *cqweights;
2557: PetscInt NqcC, NpC;
2558: PetscBool found = PETSC_FALSE;
2560: PetscDualSpaceGetFunctional(QC, c, &cfunc);
2561: PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights);
2562: if (NqcC != NcC) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of quadrature components %D must match number of field components", NqcC, NcC);
2563: if (NpC != 1 && feRef[field]) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments");
2564: for (f = 0; f < fpdim; ++f) {
2565: PetscQuadrature ffunc;
2566: const PetscReal *fqpoints, *fqweights;
2567: PetscReal sum = 0.0;
2568: PetscInt NqcF, NpF;
2570: PetscDualSpaceGetFunctional(QF, f, &ffunc);
2571: PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights);
2572: if (NqcF != NcF) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of quadrature components %D must match number of field components", NqcF, NcF);
2573: if (NpC != NpF) continue;
2574: for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]);
2575: if (sum > 1.0e-9) continue;
2576: for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d]*fqweights[d]);
2577: if (sum < 1.0e-9) continue;
2578: cmap[offsetC+c] = offsetF+f;
2579: found = PETSC_TRUE;
2580: break;
2581: }
2582: if (!found) {
2583: /* TODO We really want the average here, but some asshole put VecScatter in the interface */
2584: if (fvRef[field] || (feRef[field] && order == 0)) {
2585: cmap[offsetC+c] = offsetF+0;
2586: } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection");
2587: }
2588: }
2589: offsetC += cpdim;
2590: offsetF += fpdim;
2591: }
2592: for (f = 0; f < Nf; ++f) {PetscFEDestroy(&feRef[f]);PetscFVDestroy(&fvRef[f]);}
2593: PetscFree3(feRef,fvRef,needAvg);
2595: DMGetGlobalVector(dmf, &fv);
2596: DMGetGlobalVector(dmc, &cv);
2597: VecGetOwnershipRange(cv, &startC, &endC);
2598: PetscSectionGetConstrainedStorageSize(cglobalSection, &m);
2599: PetscMalloc2(cTotDim,&cellCIndices,fTotDim,&cellFIndices);
2600: PetscMalloc1(m,&cindices);
2601: PetscMalloc1(m,&findices);
2602: for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1;
2603: for (c = cStart; c < cEnd; ++c) {
2604: DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices);
2605: for (d = 0; d < cTotDim; ++d) {
2606: if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue;
2607: if ((findices[cellCIndices[d]-startC] >= 0) && (findices[cellCIndices[d]-startC] != cellFIndices[cmap[d]])) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Coarse dof %d maps to both %d and %d", cindices[cellCIndices[d]-startC], findices[cellCIndices[d]-startC], cellFIndices[cmap[d]]);
2608: cindices[cellCIndices[d]-startC] = cellCIndices[d];
2609: findices[cellCIndices[d]-startC] = cellFIndices[cmap[d]];
2610: }
2611: }
2612: PetscFree(cmap);
2613: PetscFree2(cellCIndices,cellFIndices);
2615: ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis);
2616: ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis);
2617: VecScatterCreate(cv, cis, fv, fis, sc);
2618: ISDestroy(&cis);
2619: ISDestroy(&fis);
2620: DMRestoreGlobalVector(dmf, &fv);
2621: DMRestoreGlobalVector(dmc, &cv);
2622: PetscLogEventEnd(DMPLEX_InjectorFEM,dmc,dmf,0,0);
2623: return(0);
2624: }
2626: /*@C
2627: DMPlexGetCellFields - Retrieve the field values values for a chunk of cells
2629: Input Parameters:
2630: + dm - The DM
2631: . cellIS - The cells to include
2632: . locX - A local vector with the solution fields
2633: . locX_t - A local vector with solution field time derivatives, or NULL
2634: - locA - A local vector with auxiliary fields, or NULL
2636: Output Parameters:
2637: + u - The field coefficients
2638: . u_t - The fields derivative coefficients
2639: - a - The auxiliary field coefficients
2641: Level: developer
2643: .seealso: DMPlexGetFaceFields()
2644: @*/
2645: PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a)
2646: {
2647: DM plex, plexA = NULL;
2648: PetscSection section, sectionAux;
2649: PetscDS prob;
2650: const PetscInt *cells;
2651: PetscInt cStart, cEnd, numCells, totDim, totDimAux, c;
2652: PetscErrorCode ierr;
2662: DMPlexConvertPlex(dm, &plex, PETSC_FALSE);
2663: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
2664: DMGetSection(dm, §ion);
2665: DMGetCellDS(dm, cStart, &prob);
2666: PetscDSGetTotalDimension(prob, &totDim);
2667: if (locA) {
2668: DM dmAux;
2669: PetscDS probAux;
2671: VecGetDM(locA, &dmAux);
2672: DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE);
2673: DMGetSection(dmAux, §ionAux);
2674: DMGetDS(dmAux, &probAux);
2675: PetscDSGetTotalDimension(probAux, &totDimAux);
2676: }
2677: numCells = cEnd - cStart;
2678: DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, u);
2679: if (locX_t) {DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, u_t);} else {*u_t = NULL;}
2680: if (locA) {DMGetWorkArray(dm, numCells*totDimAux, MPIU_SCALAR, a);} else {*a = NULL;}
2681: for (c = cStart; c < cEnd; ++c) {
2682: const PetscInt cell = cells ? cells[c] : c;
2683: const PetscInt cind = c - cStart;
2684: PetscScalar *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a;
2685: PetscInt i;
2687: DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x);
2688: for (i = 0; i < totDim; ++i) ul[cind*totDim+i] = x[i];
2689: DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x);
2690: if (locX_t) {
2691: DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t);
2692: for (i = 0; i < totDim; ++i) ul_t[cind*totDim+i] = x_t[i];
2693: DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t);
2694: }
2695: if (locA) {
2696: PetscInt subcell;
2697: DMPlexGetAuxiliaryPoint(plex, plexA, cell, &subcell);
2698: DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x);
2699: for (i = 0; i < totDimAux; ++i) al[cind*totDimAux+i] = x[i];
2700: DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x);
2701: }
2702: }
2703: DMDestroy(&plex);
2704: if (locA) {DMDestroy(&plexA);}
2705: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
2706: return(0);
2707: }
2709: /*@C
2710: DMPlexRestoreCellFields - Restore the field values values for a chunk of cells
2712: Input Parameters:
2713: + dm - The DM
2714: . cellIS - The cells to include
2715: . locX - A local vector with the solution fields
2716: . locX_t - A local vector with solution field time derivatives, or NULL
2717: - locA - A local vector with auxiliary fields, or NULL
2719: Output Parameters:
2720: + u - The field coefficients
2721: . u_t - The fields derivative coefficients
2722: - a - The auxiliary field coefficients
2724: Level: developer
2726: .seealso: DMPlexGetFaceFields()
2727: @*/
2728: PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a)
2729: {
2733: DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u);
2734: if (locX_t) {DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t);}
2735: if (locA) {DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a);}
2736: return(0);
2737: }
2739: /*@C
2740: DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces
2742: Input Parameters:
2743: + dm - The DM
2744: . fStart - The first face to include
2745: . fEnd - The first face to exclude
2746: . locX - A local vector with the solution fields
2747: . locX_t - A local vector with solution field time derivatives, or NULL
2748: . faceGeometry - A local vector with face geometry
2749: . cellGeometry - A local vector with cell geometry
2750: - locaGrad - A local vector with field gradients, or NULL
2752: Output Parameters:
2753: + Nface - The number of faces with field values
2754: . uL - The field values at the left side of the face
2755: - uR - The field values at the right side of the face
2757: Level: developer
2759: .seealso: DMPlexGetCellFields()
2760: @*/
2761: 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)
2762: {
2763: DM dmFace, dmCell, dmGrad = NULL;
2764: PetscSection section;
2765: PetscDS prob;
2766: DMLabel ghostLabel;
2767: const PetscScalar *facegeom, *cellgeom, *x, *lgrad;
2768: PetscBool *isFE;
2769: PetscInt dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face;
2770: PetscErrorCode ierr;
2781: DMGetDimension(dm, &dim);
2782: DMGetDS(dm, &prob);
2783: DMGetSection(dm, §ion);
2784: PetscDSGetNumFields(prob, &Nf);
2785: PetscDSGetTotalComponents(prob, &Nc);
2786: PetscMalloc1(Nf, &isFE);
2787: for (f = 0; f < Nf; ++f) {
2788: PetscObject obj;
2789: PetscClassId id;
2791: PetscDSGetDiscretization(prob, f, &obj);
2792: PetscObjectGetClassId(obj, &id);
2793: if (id == PETSCFE_CLASSID) {isFE[f] = PETSC_TRUE;}
2794: else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
2795: else {isFE[f] = PETSC_FALSE;}
2796: }
2797: DMGetLabel(dm, "ghost", &ghostLabel);
2798: VecGetArrayRead(locX, &x);
2799: VecGetDM(faceGeometry, &dmFace);
2800: VecGetArrayRead(faceGeometry, &facegeom);
2801: VecGetDM(cellGeometry, &dmCell);
2802: VecGetArrayRead(cellGeometry, &cellgeom);
2803: if (locGrad) {
2804: VecGetDM(locGrad, &dmGrad);
2805: VecGetArrayRead(locGrad, &lgrad);
2806: }
2807: DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uL);
2808: DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uR);
2809: /* Right now just eat the extra work for FE (could make a cell loop) */
2810: for (face = fStart, iface = 0; face < fEnd; ++face) {
2811: const PetscInt *cells;
2812: PetscFVFaceGeom *fg;
2813: PetscFVCellGeom *cgL, *cgR;
2814: PetscScalar *xL, *xR, *gL, *gR;
2815: PetscScalar *uLl = *uL, *uRl = *uR;
2816: PetscInt ghost, nsupp, nchild;
2818: DMLabelGetValue(ghostLabel, face, &ghost);
2819: DMPlexGetSupportSize(dm, face, &nsupp);
2820: DMPlexGetTreeChildren(dm, face, &nchild, NULL);
2821: if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
2822: DMPlexPointLocalRead(dmFace, face, facegeom, &fg);
2823: DMPlexGetSupport(dm, face, &cells);
2824: DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL);
2825: DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR);
2826: for (f = 0; f < Nf; ++f) {
2827: PetscInt off;
2829: PetscDSGetComponentOffset(prob, f, &off);
2830: if (isFE[f]) {
2831: const PetscInt *cone;
2832: PetscInt comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d;
2834: xL = xR = NULL;
2835: PetscSectionGetFieldComponents(section, f, &comp);
2836: DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL);
2837: DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR);
2838: DMPlexGetCone(dm, cells[0], &cone);
2839: DMPlexGetConeSize(dm, cells[0], &coneSizeL);
2840: for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL) if (cone[faceLocL] == face) break;
2841: DMPlexGetCone(dm, cells[1], &cone);
2842: DMPlexGetConeSize(dm, cells[1], &coneSizeR);
2843: for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR) if (cone[faceLocR] == face) break;
2844: if (faceLocL == coneSizeL && faceLocR == coneSizeR) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d or cell %d", face, cells[0], cells[1]);
2845: /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */
2846: /* TODO: this is a hack that might not be right for nonconforming */
2847: if (faceLocL < coneSizeL) {
2848: EvaluateFaceFields(prob, f, faceLocL, xL, &uLl[iface*Nc+off]);
2849: if (rdof == ldof && faceLocR < coneSizeR) {EvaluateFaceFields(prob, f, faceLocR, xR, &uRl[iface*Nc+off]);}
2850: else {for(d = 0; d < comp; ++d) uRl[iface*Nc+off+d] = uLl[iface*Nc+off+d];}
2851: }
2852: else {
2853: EvaluateFaceFields(prob, f, faceLocR, xR, &uRl[iface*Nc+off]);
2854: PetscSectionGetFieldComponents(section, f, &comp);
2855: for(d = 0; d < comp; ++d) uLl[iface*Nc+off+d] = uRl[iface*Nc+off+d];
2856: }
2857: DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL);
2858: DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR);
2859: } else {
2860: PetscFV fv;
2861: PetscInt numComp, c;
2863: PetscDSGetDiscretization(prob, f, (PetscObject *) &fv);
2864: PetscFVGetNumComponents(fv, &numComp);
2865: DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL);
2866: DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR);
2867: if (dmGrad) {
2868: PetscReal dxL[3], dxR[3];
2870: DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL);
2871: DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR);
2872: DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL);
2873: DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR);
2874: for (c = 0; c < numComp; ++c) {
2875: uLl[iface*Nc+off+c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c*dim], dxL);
2876: uRl[iface*Nc+off+c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c*dim], dxR);
2877: }
2878: } else {
2879: for (c = 0; c < numComp; ++c) {
2880: uLl[iface*Nc+off+c] = xL[c];
2881: uRl[iface*Nc+off+c] = xR[c];
2882: }
2883: }
2884: }
2885: }
2886: ++iface;
2887: }
2888: *Nface = iface;
2889: VecRestoreArrayRead(locX, &x);
2890: VecRestoreArrayRead(faceGeometry, &facegeom);
2891: VecRestoreArrayRead(cellGeometry, &cellgeom);
2892: if (locGrad) {
2893: VecRestoreArrayRead(locGrad, &lgrad);
2894: }
2895: PetscFree(isFE);
2896: return(0);
2897: }
2899: /*@C
2900: DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces
2902: Input Parameters:
2903: + dm - The DM
2904: . fStart - The first face to include
2905: . fEnd - The first face to exclude
2906: . locX - A local vector with the solution fields
2907: . locX_t - A local vector with solution field time derivatives, or NULL
2908: . faceGeometry - A local vector with face geometry
2909: . cellGeometry - A local vector with cell geometry
2910: - locaGrad - A local vector with field gradients, or NULL
2912: Output Parameters:
2913: + Nface - The number of faces with field values
2914: . uL - The field values at the left side of the face
2915: - uR - The field values at the right side of the face
2917: Level: developer
2919: .seealso: DMPlexGetFaceFields()
2920: @*/
2921: 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)
2922: {
2926: DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL);
2927: DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR);
2928: return(0);
2929: }
2931: /*@C
2932: DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces
2934: Input Parameters:
2935: + dm - The DM
2936: . fStart - The first face to include
2937: . fEnd - The first face to exclude
2938: . faceGeometry - A local vector with face geometry
2939: - cellGeometry - A local vector with cell geometry
2941: Output Parameters:
2942: + Nface - The number of faces with field values
2943: . fgeom - The extract the face centroid and normal
2944: - vol - The cell volume
2946: Level: developer
2948: .seealso: DMPlexGetCellFields()
2949: @*/
2950: PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol)
2951: {
2952: DM dmFace, dmCell;
2953: DMLabel ghostLabel;
2954: const PetscScalar *facegeom, *cellgeom;
2955: PetscInt dim, numFaces = fEnd - fStart, iface, face;
2956: PetscErrorCode ierr;
2964: DMGetDimension(dm, &dim);
2965: DMGetLabel(dm, "ghost", &ghostLabel);
2966: VecGetDM(faceGeometry, &dmFace);
2967: VecGetArrayRead(faceGeometry, &facegeom);
2968: VecGetDM(cellGeometry, &dmCell);
2969: VecGetArrayRead(cellGeometry, &cellgeom);
2970: PetscMalloc1(numFaces, fgeom);
2971: DMGetWorkArray(dm, numFaces*2, MPIU_SCALAR, vol);
2972: for (face = fStart, iface = 0; face < fEnd; ++face) {
2973: const PetscInt *cells;
2974: PetscFVFaceGeom *fg;
2975: PetscFVCellGeom *cgL, *cgR;
2976: PetscFVFaceGeom *fgeoml = *fgeom;
2977: PetscReal *voll = *vol;
2978: PetscInt ghost, d, nchild, nsupp;
2980: DMLabelGetValue(ghostLabel, face, &ghost);
2981: DMPlexGetSupportSize(dm, face, &nsupp);
2982: DMPlexGetTreeChildren(dm, face, &nchild, NULL);
2983: if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
2984: DMPlexPointLocalRead(dmFace, face, facegeom, &fg);
2985: DMPlexGetSupport(dm, face, &cells);
2986: DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL);
2987: DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR);
2988: for (d = 0; d < dim; ++d) {
2989: fgeoml[iface].centroid[d] = fg->centroid[d];
2990: fgeoml[iface].normal[d] = fg->normal[d];
2991: }
2992: voll[iface*2+0] = cgL->volume;
2993: voll[iface*2+1] = cgR->volume;
2994: ++iface;
2995: }
2996: *Nface = iface;
2997: VecRestoreArrayRead(faceGeometry, &facegeom);
2998: VecRestoreArrayRead(cellGeometry, &cellgeom);
2999: return(0);
3000: }
3002: /*@C
3003: DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces
3005: Input Parameters:
3006: + dm - The DM
3007: . fStart - The first face to include
3008: . fEnd - The first face to exclude
3009: . faceGeometry - A local vector with face geometry
3010: - cellGeometry - A local vector with cell geometry
3012: Output Parameters:
3013: + Nface - The number of faces with field values
3014: . fgeom - The extract the face centroid and normal
3015: - vol - The cell volume
3017: Level: developer
3019: .seealso: DMPlexGetFaceFields()
3020: @*/
3021: PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol)
3022: {
3026: PetscFree(*fgeom);
3027: DMRestoreWorkArray(dm, 0, MPIU_REAL, vol);
3028: return(0);
3029: }
3031: PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
3032: {
3033: char composeStr[33] = {0};
3034: PetscObjectId id;
3035: PetscContainer container;
3036: PetscErrorCode ierr;
3039: PetscObjectGetId((PetscObject)quad,&id);
3040: PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%x\n", id);
3041: PetscObjectQuery((PetscObject) pointIS, composeStr, (PetscObject *) &container);
3042: if (container) {
3043: PetscContainerGetPointer(container, (void **) geom);
3044: } else {
3045: DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom);
3046: PetscContainerCreate(PETSC_COMM_SELF,&container);
3047: PetscContainerSetPointer(container, (void *) *geom);
3048: PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom);
3049: PetscObjectCompose((PetscObject) pointIS, composeStr, (PetscObject) container);
3050: PetscContainerDestroy(&container);
3051: }
3052: return(0);
3053: }
3055: PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
3056: {
3058: *geom = NULL;
3059: return(0);
3060: }
3062: PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user)
3063: {
3064: DM_Plex *mesh = (DM_Plex *) dm->data;
3065: const char *name = "Residual";
3066: DM dmAux = NULL;
3067: DMLabel ghostLabel = NULL;
3068: PetscDS prob = NULL;
3069: PetscDS probAux = NULL;
3070: PetscBool useFEM = PETSC_FALSE;
3071: PetscBool isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE;
3072: DMField coordField = NULL;
3073: Vec locA;
3074: PetscScalar *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL;
3075: IS chunkIS;
3076: const PetscInt *cells;
3077: PetscInt cStart, cEnd, numCells;
3078: PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd;
3079: PetscInt maxDegree = PETSC_MAX_INT;
3080: PetscQuadrature affineQuad = NULL, *quads = NULL;
3081: PetscFEGeom *affineGeom = NULL, **geoms = NULL;
3082: PetscErrorCode ierr;
3085: PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);
3086: /* FEM+FVM */
3087: /* 1: Get sizes from dm and dmAux */
3088: DMGetLabel(dm, "ghost", &ghostLabel);
3089: DMGetDS(dm, &prob);
3090: PetscDSGetNumFields(prob, &Nf);
3091: PetscDSGetTotalDimension(prob, &totDim);
3092: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
3093: if (locA) {
3094: VecGetDM(locA, &dmAux);
3095: DMGetDS(dmAux, &probAux);
3096: PetscDSGetTotalDimension(probAux, &totDimAux);
3097: }
3098: /* 2: Get geometric data */
3099: for (f = 0; f < Nf; ++f) {
3100: PetscObject obj;
3101: PetscClassId id;
3102: PetscBool fimp;
3104: PetscDSGetImplicit(prob, f, &fimp);
3105: if (isImplicit != fimp) continue;
3106: PetscDSGetDiscretization(prob, f, &obj);
3107: PetscObjectGetClassId(obj, &id);
3108: if (id == PETSCFE_CLASSID) {useFEM = PETSC_TRUE;}
3109: if (id == PETSCFV_CLASSID) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Use of FVM with PCPATCH not yet implemented");
3110: }
3111: if (useFEM) {
3112: DMGetCoordinateField(dm, &coordField);
3113: DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);
3114: if (maxDegree <= 1) {
3115: DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad);
3116: if (affineQuad) {
3117: DMSNESGetFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
3118: }
3119: } else {
3120: PetscCalloc2(Nf,&quads,Nf,&geoms);
3121: for (f = 0; f < Nf; ++f) {
3122: PetscObject obj;
3123: PetscClassId id;
3124: PetscBool fimp;
3126: PetscDSGetImplicit(prob, f, &fimp);
3127: if (isImplicit != fimp) continue;
3128: PetscDSGetDiscretization(prob, f, &obj);
3129: PetscObjectGetClassId(obj, &id);
3130: if (id == PETSCFE_CLASSID) {
3131: PetscFE fe = (PetscFE) obj;
3133: PetscFEGetQuadrature(fe, &quads[f]);
3134: PetscObjectReference((PetscObject)quads[f]);
3135: DMSNESGetFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
3136: }
3137: }
3138: }
3139: }
3140: /* Loop over chunks */
3141: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
3142: DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
3143: if (useFEM) {ISCreate(PETSC_COMM_SELF, &chunkIS);}
3144: numCells = cEnd - cStart;
3145: numChunks = 1;
3146: cellChunkSize = numCells/numChunks;
3147: numChunks = PetscMin(1,numCells);
3148: for (chunk = 0; chunk < numChunks; ++chunk) {
3149: PetscScalar *elemVec, *fluxL = NULL, *fluxR = NULL;
3150: PetscReal *vol = NULL;
3151: PetscFVFaceGeom *fgeom = NULL;
3152: PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c;
3153: PetscInt numFaces = 0;
3155: /* Extract field coefficients */
3156: if (useFEM) {
3157: ISGetPointSubrange(chunkIS, cS, cE, cells);
3158: DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
3159: DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
3160: PetscMemzero(elemVec, numCells*totDim * sizeof(PetscScalar));
3161: }
3162: /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */
3163: /* Loop over fields */
3164: for (f = 0; f < Nf; ++f) {
3165: PetscObject obj;
3166: PetscClassId id;
3167: PetscBool fimp;
3168: PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
3170: PetscDSGetImplicit(prob, f, &fimp);
3171: if (isImplicit != fimp) continue;
3172: PetscDSGetDiscretization(prob, f, &obj);
3173: PetscObjectGetClassId(obj, &id);
3174: if (id == PETSCFE_CLASSID) {
3175: PetscFE fe = (PetscFE) obj;
3176: PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f];
3177: PetscFEGeom *chunkGeom = NULL;
3178: PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
3179: PetscInt Nq, Nb;
3181: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
3182: PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
3183: PetscFEGetDimension(fe, &Nb);
3184: blockSize = Nb;
3185: batchSize = numBlocks * blockSize;
3186: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
3187: numChunks = numCells / (numBatches*batchSize);
3188: Ne = numChunks*numBatches*batchSize;
3189: Nr = numCells % (numBatches*batchSize);
3190: offset = numCells - Nr;
3191: /* Integrate FE residual to get elemVec (need fields at quadrature points) */
3192: /* 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) */
3193: PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
3194: PetscFEIntegrateResidual(fe, prob, f, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);
3195: PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);
3196: PetscFEIntegrateResidual(fe, prob, f, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, &elemVec[offset*totDim]);
3197: PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);
3198: } else if (id == PETSCFV_CLASSID) {
3199: PetscFV fv = (PetscFV) obj;
3201: Ne = numFaces;
3202: /* Riemann solve over faces (need fields at face centroids) */
3203: /* We need to evaluate FE fields at those coordinates */
3204: PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR);
3205: } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
3206: }
3207: /* Loop over domain */
3208: if (useFEM) {
3209: /* Add elemVec to locX */
3210: for (c = cS; c < cE; ++c) {
3211: const PetscInt cell = cells ? cells[c] : c;
3212: const PetscInt cind = c - cStart;
3214: if (mesh->printFEM > 1) {DMPrintCellVector(cell, name, totDim, &elemVec[cind*totDim]);}
3215: if (ghostLabel) {
3216: PetscInt ghostVal;
3218: DMLabelGetValue(ghostLabel,cell,&ghostVal);
3219: if (ghostVal > 0) continue;
3220: }
3221: DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);
3222: }
3223: }
3224: /* Handle time derivative */
3225: if (locX_t) {
3226: PetscScalar *x_t, *fa;
3228: VecGetArray(locF, &fa);
3229: VecGetArray(locX_t, &x_t);
3230: for (f = 0; f < Nf; ++f) {
3231: PetscFV fv;
3232: PetscObject obj;
3233: PetscClassId id;
3234: PetscInt pdim, d;
3236: PetscDSGetDiscretization(prob, f, &obj);
3237: PetscObjectGetClassId(obj, &id);
3238: if (id != PETSCFV_CLASSID) continue;
3239: fv = (PetscFV) obj;
3240: PetscFVGetNumComponents(fv, &pdim);
3241: for (c = cS; c < cE; ++c) {
3242: const PetscInt cell = cells ? cells[c] : c;
3243: PetscScalar *u_t, *r;
3245: if (ghostLabel) {
3246: PetscInt ghostVal;
3248: DMLabelGetValue(ghostLabel, cell, &ghostVal);
3249: if (ghostVal > 0) continue;
3250: }
3251: DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t);
3252: DMPlexPointLocalFieldRef(dm, cell, f, fa, &r);
3253: for (d = 0; d < pdim; ++d) r[d] += u_t[d];
3254: }
3255: }
3256: VecRestoreArray(locX_t, &x_t);
3257: VecRestoreArray(locF, &fa);
3258: }
3259: if (useFEM) {
3260: DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
3261: DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
3262: }
3263: }
3264: if (useFEM) {ISDestroy(&chunkIS);}
3265: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
3266: /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */
3267: if (useFEM) {
3268: if (maxDegree <= 1) {
3269: DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
3270: PetscQuadratureDestroy(&affineQuad);
3271: } else {
3272: for (f = 0; f < Nf; ++f) {
3273: DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
3274: PetscQuadratureDestroy(&quads[f]);
3275: }
3276: PetscFree2(quads,geoms);
3277: }
3278: }
3279: PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);
3280: return(0);
3281: }
3283: /*
3284: 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
3286: X - The local solution vector
3287: X_t - The local solution time derviative vector, or NULL
3288: */
3289: PetscErrorCode DMPlexComputeJacobian_Patch_Internal(DM dm, PetscSection section, PetscSection globalSection, IS cellIS,
3290: PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP, void *ctx)
3291: {
3292: DM_Plex *mesh = (DM_Plex *) dm->data;
3293: const char *name = "Jacobian", *nameP = "JacobianPre";
3294: DM dmAux = NULL;
3295: PetscDS prob, probAux = NULL;
3296: PetscSection sectionAux = NULL;
3297: Vec A;
3298: DMField coordField;
3299: PetscFEGeom *cgeomFEM;
3300: PetscQuadrature qGeom = NULL;
3301: Mat J = Jac, JP = JacP;
3302: PetscScalar *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL;
3303: PetscBool hasJac, hasPrec, hasDyn, assembleJac, isMatIS, isMatISP, *isFE, hasFV = PETSC_FALSE;
3304: const PetscInt *cells;
3305: PetscInt Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0;
3306: PetscErrorCode ierr;
3309: CHKMEMQ;
3310: ISGetLocalSize(cellIS, &numCells);
3311: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
3312: PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);
3313: DMGetDS(dm, &prob);
3314: PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
3315: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);
3316: if (dmAux) {
3317: DMGetDefaultSection(dmAux, §ionAux);
3318: DMGetDS(dmAux, &probAux);
3319: }
3320: /* Get flags */
3321: PetscDSGetNumFields(prob, &Nf);
3322: DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE);
3323: for (fieldI = 0; fieldI < Nf; ++fieldI) {
3324: PetscObject disc;
3325: PetscClassId id;
3326: PetscDSGetDiscretization(prob, fieldI, &disc);
3327: PetscObjectGetClassId(disc, &id);
3328: if (id == PETSCFE_CLASSID) {isFE[fieldI] = PETSC_TRUE;}
3329: else if (id == PETSCFV_CLASSID) {hasFV = PETSC_TRUE; isFE[fieldI] = PETSC_FALSE;}
3330: }
3331: PetscDSHasJacobian(prob, &hasJac);
3332: PetscDSHasJacobianPreconditioner(prob, &hasPrec);
3333: PetscDSHasDynamicJacobian(prob, &hasDyn);
3334: assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE;
3335: hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
3336: PetscObjectTypeCompare((PetscObject) Jac, MATIS, &isMatIS);
3337: PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);
3338: /* Setup input data and temp arrays (should be DMGetWorkArray) */
3339: if (isMatISP || isMatISP) {DMPlexGetSubdomainSection(dm, &globalSection);}
3340: if (isMatIS) {MatISGetLocalMat(Jac, &J);}
3341: if (isMatISP) {MatISGetLocalMat(JacP, &JP);}
3342: if (hasFV) {MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE);} /* No allocated space for FV stuff, so ignore the zero entries */
3343: PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
3344: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);
3345: PetscDSGetTotalDimension(prob, &totDim);
3346: if (probAux) {PetscDSGetTotalDimension(probAux, &totDimAux);}
3347: CHKMEMQ;
3348: /* Compute batch sizes */
3349: if (isFE[0]) {
3350: PetscFE fe;
3351: PetscQuadrature q;
3352: PetscInt numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb;
3354: PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe);
3355: PetscFEGetQuadrature(fe, &q);
3356: PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL);
3357: PetscFEGetDimension(fe, &Nb);
3358: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
3359: blockSize = Nb*numQuadPoints;
3360: batchSize = numBlocks * blockSize;
3361: chunkSize = numBatches * batchSize;
3362: numChunks = numCells / chunkSize + numCells % chunkSize;
3363: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
3364: } else {
3365: chunkSize = numCells;
3366: numChunks = 1;
3367: }
3368: /* Get work space */
3369: wsz = (((X?1:0) + (X_t?1:0) + (dmAux?1:0))*totDim + ((hasJac?1:0) + (hasPrec?1:0) + (hasDyn?1:0))*totDim*totDim)*chunkSize;
3370: DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work);
3371: PetscMemzero(work, wsz * sizeof(PetscScalar));
3372: off = 0;
3373: u = X ? (sz = chunkSize*totDim, off += sz, work+off-sz) : NULL;
3374: u_t = X_t ? (sz = chunkSize*totDim, off += sz, work+off-sz) : NULL;
3375: a = dmAux ? (sz = chunkSize*totDimAux, off += sz, work+off-sz) : NULL;
3376: elemMat = hasJac ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL;
3377: elemMatP = hasPrec ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL;
3378: elemMatD = hasDyn ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL;
3379: if (off != wsz) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %D should be %D", off, wsz);
3380: /* Setup geometry */
3381: DMGetCoordinateField(dm, &coordField);
3382: DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
3383: if (maxDegree <= 1) {DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom);}
3384: if (!qGeom) {
3385: PetscFE fe;
3387: PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe);
3388: PetscFEGetQuadrature(fe, &qGeom);
3389: PetscObjectReference((PetscObject) qGeom);
3390: }
3391: DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);
3392: /* Compute volume integrals */
3393: if (assembleJac) {MatZeroEntries(J);}
3394: MatZeroEntries(JP);
3395: for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) {
3396: const PetscInt Ncell = PetscMin(chunkSize, numCells - offCell);
3397: PetscInt c;
3399: /* Extract values */
3400: for (c = 0; c < Ncell; ++c) {
3401: const PetscInt cell = cells ? cells[c+offCell] : c+offCell;
3402: PetscScalar *x = NULL, *x_t = NULL;
3403: PetscInt i;
3405: if (X) {
3406: DMPlexVecGetClosure(dm, section, X, cell, NULL, &x);
3407: for (i = 0; i < totDim; ++i) u[c*totDim+i] = x[i];
3408: DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x);
3409: }
3410: if (X_t) {
3411: DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t);
3412: for (i = 0; i < totDim; ++i) u_t[c*totDim+i] = x_t[i];
3413: DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t);
3414: }
3415: if (dmAux) {
3416: DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x);
3417: for (i = 0; i < totDimAux; ++i) a[c*totDimAux+i] = x[i];
3418: DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x);
3419: }
3420: }
3421: CHKMEMQ;
3422: for (fieldI = 0; fieldI < Nf; ++fieldI) {
3423: PetscFE fe;
3424: PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
3425: for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
3426: if (hasJac) {PetscFEIntegrateJacobian(fe, prob, PETSCFE_JACOBIAN, fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat);}
3427: if (hasPrec) {PetscFEIntegrateJacobian(fe, prob, PETSCFE_JACOBIAN_PRE, fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP);}
3428: if (hasDyn) {PetscFEIntegrateJacobian(fe, prob, PETSCFE_JACOBIAN_DYN, fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD);}
3429: }
3430: /* For finite volume, add the identity */
3431: if (!isFE[fieldI]) {
3432: PetscFV fv;
3433: PetscInt eOffset = 0, Nc, fc, foff;
3435: PetscDSGetFieldOffset(prob, fieldI, &foff);
3436: PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fv);
3437: PetscFVGetNumComponents(fv, &Nc);
3438: for (c = 0; c < chunkSize; ++c, eOffset += totDim*totDim) {
3439: for (fc = 0; fc < Nc; ++fc) {
3440: const PetscInt i = foff + fc;
3441: if (hasJac) {elemMat [eOffset+i*totDim+i] = 1.0;}
3442: if (hasPrec) {elemMatP[eOffset+i*totDim+i] = 1.0;}
3443: }
3444: }
3445: }
3446: }
3447: CHKMEMQ;
3448: /* Add contribution from X_t */
3449: if (hasDyn) {for (c = 0; c < chunkSize*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c];}
3450: /* Insert values into matrix */
3451: for (c = 0; c < Ncell; ++c) {
3452: const PetscInt cell = cells ? cells[c+offCell] : c+offCell;
3453: if (mesh->printFEM > 1) {
3454: if (hasJac) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[(c-cStart)*totDim*totDim]);}
3455: if (hasPrec) {DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c-cStart)*totDim*totDim]);}
3456: }
3457: if (assembleJac) {DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES);}
3458: DMPlexMatSetClosure(dm, section, globalSection, JP, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES);
3459: }
3460: CHKMEMQ;
3461: }
3462: /* Cleanup */
3463: DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);
3464: PetscQuadratureDestroy(&qGeom);
3465: if (hasFV) {MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE);}
3466: DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE);
3467: 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);
3468: /* Compute boundary integrals */
3469: /* DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx); */
3470: /* Assemble matrix */
3471: if (assembleJac) {MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);}
3472: MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);
3473: PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);
3474: CHKMEMQ;
3475: return(0);
3476: }