xref: /petsc/src/snes/tutorials/ex7.c (revision de19e7feca70f9e5591b63d32a40fba1b76f2b32)
17b197a28SMatthew G. Knepley static char help[] = "Fermions on a hypercubic lattice.\n\n";
27b197a28SMatthew G. Knepley 
37b197a28SMatthew G. Knepley #include <petscdmplex.h>
47b197a28SMatthew G. Knepley #include <petscsnes.h>
57b197a28SMatthew G. Knepley 
67b197a28SMatthew G. Knepley /* Common operations:
77b197a28SMatthew G. Knepley 
87b197a28SMatthew G. Knepley  - View the input \psi as ASCII in lexicographic order: -psi_view
97b197a28SMatthew G. Knepley */
107b197a28SMatthew G. Knepley 
117b197a28SMatthew G. Knepley const PetscReal M = 1.0;
127b197a28SMatthew G. Knepley 
137b197a28SMatthew G. Knepley typedef struct {
147b197a28SMatthew G. Knepley   PetscBool usePV; /* Use Pauli-Villars preconditioning */
157b197a28SMatthew G. Knepley } AppCtx;
167b197a28SMatthew G. Knepley 
177b197a28SMatthew G. Knepley PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
187b197a28SMatthew G. Knepley {
197b197a28SMatthew G. Knepley   PetscFunctionBegin;
207b197a28SMatthew G. Knepley   options->usePV = PETSC_TRUE;
217b197a28SMatthew G. Knepley 
227b197a28SMatthew G. Knepley   PetscOptionsBegin(comm, "", "Meshing Problem Options", "DMPLEX");
237b197a28SMatthew G. Knepley   PetscCall(PetscOptionsBool("-use_pv", "Use Pauli-Villars preconditioning", "ex1.c", options->usePV, &options->usePV, NULL));
247b197a28SMatthew G. Knepley   PetscOptionsEnd();
257b197a28SMatthew G. Knepley   PetscFunctionReturn(0);
267b197a28SMatthew G. Knepley }
277b197a28SMatthew G. Knepley 
287b197a28SMatthew G. Knepley PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
297b197a28SMatthew G. Knepley {
307b197a28SMatthew G. Knepley   PetscFunctionBegin;
317b197a28SMatthew G. Knepley   PetscCall(DMCreate(comm, dm));
327b197a28SMatthew G. Knepley   PetscCall(DMSetType(*dm, DMPLEX));
337b197a28SMatthew G. Knepley   PetscCall(DMSetFromOptions(*dm));
347b197a28SMatthew G. Knepley   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
357b197a28SMatthew G. Knepley   PetscFunctionReturn(0);
367b197a28SMatthew G. Knepley }
377b197a28SMatthew G. Knepley 
387b197a28SMatthew G. Knepley static PetscErrorCode SetupDiscretization(DM dm, AppCtx *ctx)
397b197a28SMatthew G. Knepley {
407b197a28SMatthew G. Knepley   PetscSection s;
417b197a28SMatthew G. Knepley   PetscInt     vStart, vEnd, v;
427b197a28SMatthew G. Knepley 
437b197a28SMatthew G. Knepley   PetscFunctionBegin;
447b197a28SMatthew G. Knepley   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s));
457b197a28SMatthew G. Knepley   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
467b197a28SMatthew G. Knepley   PetscCall(PetscSectionSetChart(s, vStart, vEnd));
477b197a28SMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
487b197a28SMatthew G. Knepley     PetscCall(PetscSectionSetDof(s, v, 12));
497b197a28SMatthew G. Knepley     /* TODO Divide the values into fields/components */
507b197a28SMatthew G. Knepley   }
517b197a28SMatthew G. Knepley   PetscCall(PetscSectionSetUp(s));
527b197a28SMatthew G. Knepley   PetscCall(DMSetLocalSection(dm, s));
537b197a28SMatthew G. Knepley   PetscCall(PetscSectionDestroy(&s));
547b197a28SMatthew G. Knepley   PetscFunctionReturn(0);
557b197a28SMatthew G. Knepley }
567b197a28SMatthew G. Knepley 
577b197a28SMatthew G. Knepley static PetscErrorCode SetupAuxDiscretization(DM dm, AppCtx *user)
587b197a28SMatthew G. Knepley {
597b197a28SMatthew G. Knepley   DM           dmAux, coordDM;
607b197a28SMatthew G. Knepley   PetscSection s;
617b197a28SMatthew G. Knepley   Vec          gauge;
627b197a28SMatthew G. Knepley   PetscInt     eStart, eEnd, e;
637b197a28SMatthew G. Knepley 
647b197a28SMatthew G. Knepley   PetscFunctionBegin;
657b197a28SMatthew G. Knepley   /* MUST call DMGetCoordinateDM() in order to get p4est setup if present */
667b197a28SMatthew G. Knepley   PetscCall(DMGetCoordinateDM(dm, &coordDM));
677b197a28SMatthew G. Knepley   PetscCall(DMClone(dm, &dmAux));
687b197a28SMatthew G. Knepley   PetscCall(DMSetCoordinateDM(dmAux, coordDM));
697b197a28SMatthew G. Knepley   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s));
707b197a28SMatthew G. Knepley   PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
717b197a28SMatthew G. Knepley   PetscCall(PetscSectionSetChart(s, eStart, eEnd));
727b197a28SMatthew G. Knepley   for (e = eStart; e < eEnd; ++e) {
737b197a28SMatthew G. Knepley     /* TODO Should we store the whole SU(3) matrix, or the symmetric part? */
747b197a28SMatthew G. Knepley     PetscCall(PetscSectionSetDof(s, e, 9));
757b197a28SMatthew G. Knepley   }
767b197a28SMatthew G. Knepley   PetscCall(PetscSectionSetUp(s));
777b197a28SMatthew G. Knepley   PetscCall(DMSetLocalSection(dmAux, s));
787b197a28SMatthew G. Knepley   PetscCall(PetscSectionDestroy(&s));
797b197a28SMatthew G. Knepley   PetscCall(DMCreateLocalVector(dmAux, &gauge));
807b197a28SMatthew G. Knepley   PetscCall(DMDestroy(&dmAux));
817b197a28SMatthew G. Knepley   PetscCall(DMSetAuxiliaryVec(dm, NULL, 0, 0, gauge));
827b197a28SMatthew G. Knepley   PetscCall(VecDestroy(&gauge));
837b197a28SMatthew G. Knepley   PetscFunctionReturn(0);
847b197a28SMatthew G. Knepley }
857b197a28SMatthew G. Knepley 
867b197a28SMatthew G. Knepley static PetscErrorCode PrintVertex(DM dm, PetscInt v)
877b197a28SMatthew G. Knepley {
887b197a28SMatthew G. Knepley   MPI_Comm       comm;
897b197a28SMatthew G. Knepley   PetscContainer c;
907b197a28SMatthew G. Knepley   PetscInt      *extent;
917b197a28SMatthew G. Knepley   PetscInt       dim, cStart, cEnd, sum;
927b197a28SMatthew G. Knepley 
937b197a28SMatthew G. Knepley   PetscFunctionBeginUser;
947b197a28SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
957b197a28SMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
967b197a28SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
977b197a28SMatthew G. Knepley   PetscCall(PetscObjectQuery((PetscObject)dm, "_extent", (PetscObject *)&c));
987b197a28SMatthew G. Knepley   PetscCall(PetscContainerGetPointer(c, (void **)&extent));
997b197a28SMatthew G. Knepley   sum = 1;
1007b197a28SMatthew G. Knepley   PetscCall(PetscPrintf(comm, "Vertex %" PetscInt_FMT ":", v));
1017b197a28SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) {
1027b197a28SMatthew G. Knepley     PetscCall(PetscPrintf(comm, " %" PetscInt_FMT, (v / sum) % extent[d]));
1037b197a28SMatthew G. Knepley     if (d < dim) sum *= extent[d];
1047b197a28SMatthew G. Knepley   }
1057b197a28SMatthew G. Knepley   PetscFunctionReturn(0);
1067b197a28SMatthew G. Knepley }
1077b197a28SMatthew G. Knepley 
1087b197a28SMatthew G. Knepley // Apply \gamma_\mu
1097b197a28SMatthew G. Knepley static PetscErrorCode ComputeGamma(PetscInt d, PetscInt ldx, PetscScalar f[])
1107b197a28SMatthew G. Knepley {
1117b197a28SMatthew G. Knepley   const PetscScalar fin[4] = {f[0 * ldx], f[1 * ldx], f[2 * ldx], f[3 * ldx]};
1127b197a28SMatthew G. Knepley 
1137b197a28SMatthew G. Knepley   PetscFunctionBeginHot;
1147b197a28SMatthew G. Knepley   switch (d) {
1157b197a28SMatthew G. Knepley   case 0:
1167b197a28SMatthew G. Knepley     f[0 * ldx] = PETSC_i * fin[3];
1177b197a28SMatthew G. Knepley     f[1 * ldx] = PETSC_i * fin[2];
1187b197a28SMatthew G. Knepley     f[2 * ldx] = -PETSC_i * fin[1];
1197b197a28SMatthew G. Knepley     f[3 * ldx] = -PETSC_i * fin[0];
1207b197a28SMatthew G. Knepley     break;
1217b197a28SMatthew G. Knepley   case 1:
1227b197a28SMatthew G. Knepley     f[0 * ldx] = -fin[3];
1237b197a28SMatthew G. Knepley     f[1 * ldx] = fin[2];
1247b197a28SMatthew G. Knepley     f[2 * ldx] = fin[1];
1257b197a28SMatthew G. Knepley     f[3 * ldx] = -fin[0];
1267b197a28SMatthew G. Knepley     break;
1277b197a28SMatthew G. Knepley   case 2:
1287b197a28SMatthew G. Knepley     f[0 * ldx] = PETSC_i * fin[2];
1297b197a28SMatthew G. Knepley     f[1 * ldx] = -PETSC_i * fin[3];
1307b197a28SMatthew G. Knepley     f[2 * ldx] = -PETSC_i * fin[0];
1317b197a28SMatthew G. Knepley     f[3 * ldx] = PETSC_i * fin[1];
1327b197a28SMatthew G. Knepley     break;
1337b197a28SMatthew G. Knepley   case 3:
1347b197a28SMatthew G. Knepley     f[0 * ldx] = fin[2];
1357b197a28SMatthew G. Knepley     f[1 * ldx] = fin[3];
1367b197a28SMatthew G. Knepley     f[2 * ldx] = fin[0];
1377b197a28SMatthew G. Knepley     f[3 * ldx] = fin[1];
1387b197a28SMatthew G. Knepley     break;
1397b197a28SMatthew G. Knepley   default:
1407b197a28SMatthew G. Knepley     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Direction for gamma %" PetscInt_FMT " not in [0, 4)", d);
1417b197a28SMatthew G. Knepley   }
1427b197a28SMatthew G. Knepley   PetscFunctionReturn(0);
1437b197a28SMatthew G. Knepley }
1447b197a28SMatthew G. Knepley 
1457b197a28SMatthew G. Knepley // Apply (1 \pm \gamma_\mu)/2
1467b197a28SMatthew G. Knepley static PetscErrorCode ComputeGammaFactor(PetscInt d, PetscBool forward, PetscInt ldx, PetscScalar f[])
1477b197a28SMatthew G. Knepley {
1487b197a28SMatthew G. Knepley   const PetscReal   sign   = forward ? -1. : 1.;
1497b197a28SMatthew G. Knepley   const PetscScalar fin[4] = {f[0 * ldx], f[1 * ldx], f[2 * ldx], f[3 * ldx]};
1507b197a28SMatthew G. Knepley 
1517b197a28SMatthew G. Knepley   PetscFunctionBeginHot;
1527b197a28SMatthew G. Knepley   switch (d) {
1537b197a28SMatthew G. Knepley   case 0:
1547b197a28SMatthew G. Knepley     f[0 * ldx] += sign * PETSC_i * fin[3];
1557b197a28SMatthew G. Knepley     f[1 * ldx] += sign * PETSC_i * fin[2];
1567b197a28SMatthew G. Knepley     f[2 * ldx] += sign * -PETSC_i * fin[1];
1577b197a28SMatthew G. Knepley     f[3 * ldx] += sign * -PETSC_i * fin[0];
1587b197a28SMatthew G. Knepley     break;
1597b197a28SMatthew G. Knepley   case 1:
1607b197a28SMatthew G. Knepley     f[0 * ldx] += -sign * fin[3];
1617b197a28SMatthew G. Knepley     f[1 * ldx] += sign * fin[2];
1627b197a28SMatthew G. Knepley     f[2 * ldx] += sign * fin[1];
1637b197a28SMatthew G. Knepley     f[3 * ldx] += -sign * fin[0];
1647b197a28SMatthew G. Knepley     break;
1657b197a28SMatthew G. Knepley   case 2:
1667b197a28SMatthew G. Knepley     f[0 * ldx] += sign * PETSC_i * fin[2];
1677b197a28SMatthew G. Knepley     f[1 * ldx] += sign * -PETSC_i * fin[3];
1687b197a28SMatthew G. Knepley     f[2 * ldx] += sign * -PETSC_i * fin[0];
1697b197a28SMatthew G. Knepley     f[3 * ldx] += sign * PETSC_i * fin[1];
1707b197a28SMatthew G. Knepley     break;
1717b197a28SMatthew G. Knepley   case 3:
1727b197a28SMatthew G. Knepley     f[0 * ldx] += sign * fin[2];
1737b197a28SMatthew G. Knepley     f[1 * ldx] += sign * fin[3];
1747b197a28SMatthew G. Knepley     f[2 * ldx] += sign * fin[0];
1757b197a28SMatthew G. Knepley     f[3 * ldx] += sign * fin[1];
1767b197a28SMatthew G. Knepley     break;
1777b197a28SMatthew G. Knepley   default:
1787b197a28SMatthew G. Knepley     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Direction for gamma %" PetscInt_FMT " not in [0, 4)", d);
1797b197a28SMatthew G. Knepley   }
1807b197a28SMatthew G. Knepley   f[0 * ldx] *= 0.5;
1817b197a28SMatthew G. Knepley   f[1 * ldx] *= 0.5;
1827b197a28SMatthew G. Knepley   f[2 * ldx] *= 0.5;
1837b197a28SMatthew G. Knepley   f[3 * ldx] *= 0.5;
1847b197a28SMatthew G. Knepley   PetscFunctionReturn(0);
1857b197a28SMatthew G. Knepley }
1867b197a28SMatthew G. Knepley 
1877b197a28SMatthew G. Knepley #include <petsc/private/dmpleximpl.h>
1887b197a28SMatthew G. Knepley 
1897b197a28SMatthew G. Knepley // ComputeAction() sums the action of 1/2 (1 \pm \gamma_\mu) U \psi into f
1907b197a28SMatthew G. Knepley static PetscErrorCode ComputeAction(PetscInt d, PetscBool forward, const PetscScalar U[], const PetscScalar psi[], PetscScalar f[])
1917b197a28SMatthew G. Knepley {
1927b197a28SMatthew G. Knepley   PetscScalar tmp[12];
1937b197a28SMatthew G. Knepley 
1947b197a28SMatthew G. Knepley   PetscFunctionBeginHot;
1957b197a28SMatthew G. Knepley   // Apply U
1967b197a28SMatthew G. Knepley   for (PetscInt beta = 0; beta < 4; ++beta) {
1977b197a28SMatthew G. Knepley     if (forward) DMPlex_Mult3D_Internal(U, 1, &psi[beta * 3], &tmp[beta * 3]);
1987b197a28SMatthew G. Knepley     else DMPlex_MultTranspose3D_Internal(U, 1, &psi[beta * 3], &tmp[beta * 3]);
1997b197a28SMatthew G. Knepley   }
2007b197a28SMatthew G. Knepley   // Apply (1 \pm \gamma_\mu)/2 to each color
2017b197a28SMatthew G. Knepley   for (PetscInt c = 0; c < 3; ++c) PetscCall(ComputeGammaFactor(d, forward, 3, &tmp[c]));
2027b197a28SMatthew G. Knepley   // Note that we are subtracting this contribution
2037b197a28SMatthew G. Knepley   for (PetscInt i = 0; i < 12; ++i) f[i] -= tmp[i];
2047b197a28SMatthew G. Knepley   PetscFunctionReturn(0);
2057b197a28SMatthew G. Knepley }
2067b197a28SMatthew G. Knepley 
2077b197a28SMatthew G. Knepley /*
2087b197a28SMatthew G. Knepley   The assembly loop runs over vertices. Each vertex has 2d edges in its support. The edges are ordered first by the dimension along which they run, and second from smaller to larger index, expect for edges which loop periodically. The vertices on edges are also ordered from smaller to larger index except for periodic edges.
2097b197a28SMatthew G. Knepley */
2107b197a28SMatthew G. Knepley static PetscErrorCode ComputeResidual(DM dm, Vec u, Vec f)
2117b197a28SMatthew G. Knepley {
212*de19e7feSJoseph Pusztay   DM                 dmAux;
213*de19e7feSJoseph Pusztay   Vec                gauge;
214*de19e7feSJoseph Pusztay   PetscSection       s, sGauge;
2157b197a28SMatthew G. Knepley   const PetscScalar *ua;
216*de19e7feSJoseph Pusztay   PetscScalar       *fa, *link;
2177b197a28SMatthew G. Knepley   PetscInt           dim, vStart, vEnd;
2187b197a28SMatthew G. Knepley 
2197b197a28SMatthew G. Knepley   PetscFunctionBeginUser;
2207b197a28SMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
2217b197a28SMatthew G. Knepley   PetscCall(DMGetLocalSection(dm, &s));
2227b197a28SMatthew G. Knepley   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
2237b197a28SMatthew G. Knepley   PetscCall(VecGetArrayRead(u, &ua));
2247b197a28SMatthew G. Knepley   PetscCall(VecGetArray(f, &fa));
225*de19e7feSJoseph Pusztay 
226*de19e7feSJoseph Pusztay   PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &gauge));
227*de19e7feSJoseph Pusztay   PetscCall(VecGetDM(gauge, &dmAux));
228*de19e7feSJoseph Pusztay   PetscCall(DMGetLocalSection(dmAux, &sGauge));
229*de19e7feSJoseph Pusztay   PetscCall(VecGetArray(gauge, &link));
2307b197a28SMatthew G. Knepley   // Loop over y
2317b197a28SMatthew G. Knepley   for (PetscInt v = vStart; v < vEnd; ++v) {
2327b197a28SMatthew G. Knepley     const PetscInt *supp;
2337b197a28SMatthew G. Knepley     PetscInt        xdof, xoff;
2347b197a28SMatthew G. Knepley 
2357b197a28SMatthew G. Knepley     PetscCall(DMPlexGetSupport(dm, v, &supp));
2367b197a28SMatthew G. Knepley     PetscCall(PetscSectionGetDof(s, v, &xdof));
2377b197a28SMatthew G. Knepley     PetscCall(PetscSectionGetOffset(s, v, &xoff));
2387b197a28SMatthew G. Knepley     // Diagonal
2397b197a28SMatthew G. Knepley     for (PetscInt i = 0; i < xdof; ++i) fa[xoff + i] += (M + 4) * ua[xoff + i];
2407b197a28SMatthew G. Knepley     // Loop over mu
2417b197a28SMatthew G. Knepley     for (PetscInt d = 0; d < dim; ++d) {
2427b197a28SMatthew G. Knepley       const PetscInt *cone;
243*de19e7feSJoseph Pusztay       PetscInt        yoff, goff;
2447b197a28SMatthew G. Knepley 
2457b197a28SMatthew G. Knepley       // Left action -(1 + \gamma_\mu)/2 \otimes U^\dagger_\mu(y) \delta_{x - \mu,y} \psi(y)
2467b197a28SMatthew G. Knepley       PetscCall(DMPlexGetCone(dm, supp[2 * d + 0], &cone));
2477b197a28SMatthew G. Knepley       PetscCall(PetscSectionGetOffset(s, cone[0], &yoff));
248*de19e7feSJoseph Pusztay       PetscCall(PetscSectionGetOffset(sGauge, supp[2 * d + 0], &goff));
249*de19e7feSJoseph Pusztay       PetscCall(ComputeAction(d, PETSC_FALSE, &link[goff], &ua[yoff], &fa[xoff]));
2507b197a28SMatthew G. Knepley       // Right edge -(1 - \gamma_\mu)/2 \otimes U_\mu(x) \delta_{x + \mu,y} \psi(y)
2517b197a28SMatthew G. Knepley       PetscCall(DMPlexGetCone(dm, supp[2 * d + 1], &cone));
2527b197a28SMatthew G. Knepley       PetscCall(PetscSectionGetOffset(s, cone[1], &yoff));
253*de19e7feSJoseph Pusztay       PetscCall(PetscSectionGetOffset(sGauge, supp[2 * d + 1], &goff));
254*de19e7feSJoseph Pusztay       PetscCall(ComputeAction(d, PETSC_TRUE, &link[goff], &ua[yoff], &fa[xoff]));
2557b197a28SMatthew G. Knepley     }
2567b197a28SMatthew G. Knepley   }
2577b197a28SMatthew G. Knepley   PetscCall(VecRestoreArray(f, &fa));
258*de19e7feSJoseph Pusztay   PetscCall(VecRestoreArray(gauge, &link));
2597b197a28SMatthew G. Knepley   PetscCall(VecRestoreArrayRead(u, &ua));
2607b197a28SMatthew G. Knepley   PetscFunctionReturn(0);
2617b197a28SMatthew G. Knepley }
2627b197a28SMatthew G. Knepley 
2637b197a28SMatthew G. Knepley static PetscErrorCode CreateJacobian(DM dm, Mat *J)
2647b197a28SMatthew G. Knepley {
2657b197a28SMatthew G. Knepley   PetscFunctionBegin;
2667b197a28SMatthew G. Knepley   PetscFunctionReturn(0);
2677b197a28SMatthew G. Knepley }
2687b197a28SMatthew G. Knepley 
2697b197a28SMatthew G. Knepley static PetscErrorCode ComputeJacobian(DM dm, Vec u, Mat J)
2707b197a28SMatthew G. Knepley {
2717b197a28SMatthew G. Knepley   PetscFunctionBegin;
2727b197a28SMatthew G. Knepley   PetscFunctionReturn(0);
2737b197a28SMatthew G. Knepley }
2747b197a28SMatthew G. Knepley 
2757b197a28SMatthew G. Knepley static PetscErrorCode PrintTraversal(DM dm)
2767b197a28SMatthew G. Knepley {
2777b197a28SMatthew G. Knepley   MPI_Comm comm;
2787b197a28SMatthew G. Knepley   PetscInt vStart, vEnd;
2797b197a28SMatthew G. Knepley 
2807b197a28SMatthew G. Knepley   PetscFunctionBeginUser;
2817b197a28SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
2827b197a28SMatthew G. Knepley   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
2837b197a28SMatthew G. Knepley   for (PetscInt v = vStart; v < vEnd; ++v) {
2847b197a28SMatthew G. Knepley     const PetscInt *supp;
2857b197a28SMatthew G. Knepley     PetscInt        Ns;
2867b197a28SMatthew G. Knepley 
2877b197a28SMatthew G. Knepley     PetscCall(DMPlexGetSupportSize(dm, v, &Ns));
2887b197a28SMatthew G. Knepley     PetscCall(DMPlexGetSupport(dm, v, &supp));
2897b197a28SMatthew G. Knepley     PetscCall(PrintVertex(dm, v));
2907b197a28SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "\n"));
2917b197a28SMatthew G. Knepley     for (PetscInt s = 0; s < Ns; ++s) {
2927b197a28SMatthew G. Knepley       const PetscInt *cone;
2937b197a28SMatthew G. Knepley 
2947b197a28SMatthew G. Knepley       PetscCall(DMPlexGetCone(dm, supp[s], &cone));
2957b197a28SMatthew G. Knepley       PetscCall(PetscPrintf(comm, "  Edge %" PetscInt_FMT ": ", supp[s]));
2967b197a28SMatthew G. Knepley       PetscCall(PrintVertex(dm, cone[0]));
2977b197a28SMatthew G. Knepley       PetscCall(PetscPrintf(comm, " -- "));
2987b197a28SMatthew G. Knepley       PetscCall(PrintVertex(dm, cone[1]));
2997b197a28SMatthew G. Knepley       PetscCall(PetscPrintf(comm, "\n"));
3007b197a28SMatthew G. Knepley     }
3017b197a28SMatthew G. Knepley   }
3027b197a28SMatthew G. Knepley   PetscFunctionReturn(0);
3037b197a28SMatthew G. Knepley }
3047b197a28SMatthew G. Knepley 
3057b197a28SMatthew G. Knepley static PetscErrorCode ComputeFFT(Mat FT, PetscInt Nc, Vec x, Vec p)
3067b197a28SMatthew G. Knepley {
3077b197a28SMatthew G. Knepley   Vec     *xComp, *pComp;
3087b197a28SMatthew G. Knepley   PetscInt n, N;
3097b197a28SMatthew G. Knepley 
3107b197a28SMatthew G. Knepley   PetscFunctionBeginUser;
3117b197a28SMatthew G. Knepley   PetscCall(PetscMalloc2(Nc, &xComp, Nc, &pComp));
3127b197a28SMatthew G. Knepley   PetscCall(VecGetLocalSize(x, &n));
3137b197a28SMatthew G. Knepley   PetscCall(VecGetSize(x, &N));
3147b197a28SMatthew G. Knepley   for (PetscInt i = 0; i < Nc; ++i) {
3157b197a28SMatthew G. Knepley     const char *vtype;
3167b197a28SMatthew G. Knepley 
3177b197a28SMatthew G. Knepley     // HACK: Make these from another DM up front
3187b197a28SMatthew G. Knepley     PetscCall(VecCreate(PetscObjectComm((PetscObject)x), &xComp[i]));
3197b197a28SMatthew G. Knepley     PetscCall(VecGetType(x, &vtype));
3207b197a28SMatthew G. Knepley     PetscCall(VecSetType(xComp[i], vtype));
3217b197a28SMatthew G. Knepley     PetscCall(VecSetSizes(xComp[i], n / Nc, N / Nc));
3227b197a28SMatthew G. Knepley     PetscCall(VecDuplicate(xComp[i], &pComp[i]));
3237b197a28SMatthew G. Knepley   }
3247b197a28SMatthew G. Knepley   PetscCall(VecStrideGatherAll(x, xComp, INSERT_VALUES));
3257b197a28SMatthew G. Knepley   for (PetscInt i = 0; i < Nc; ++i) PetscCall(MatMult(FT, xComp[i], pComp[i]));
3267b197a28SMatthew G. Knepley   PetscCall(VecStrideScatterAll(pComp, p, INSERT_VALUES));
3277b197a28SMatthew G. Knepley   for (PetscInt i = 0; i < Nc; ++i) {
3287b197a28SMatthew G. Knepley     PetscCall(VecDestroy(&xComp[i]));
3297b197a28SMatthew G. Knepley     PetscCall(VecDestroy(&pComp[i]));
3307b197a28SMatthew G. Knepley   }
3317b197a28SMatthew G. Knepley   PetscCall(PetscFree2(xComp, pComp));
3327b197a28SMatthew G. Knepley   PetscFunctionReturn(0);
3337b197a28SMatthew G. Knepley }
3347b197a28SMatthew G. Knepley 
335*de19e7feSJoseph Pusztay // Sets each link to be the identity for the free field test
336*de19e7feSJoseph Pusztay static PetscErrorCode SetGauge_Identity(DM dm)
337*de19e7feSJoseph Pusztay {
338*de19e7feSJoseph Pusztay   DM           auxDM;
339*de19e7feSJoseph Pusztay   Vec          auxVec;
340*de19e7feSJoseph Pusztay   PetscSection s;
341*de19e7feSJoseph Pusztay   PetscScalar  id[9] = {1., 0., 0., 0., 1., 0., 0., 0., 1.};
342*de19e7feSJoseph Pusztay   PetscInt     eStart, eEnd;
343*de19e7feSJoseph Pusztay 
344*de19e7feSJoseph Pusztay   PetscFunctionBegin;
345*de19e7feSJoseph Pusztay   PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &auxVec));
346*de19e7feSJoseph Pusztay   PetscCall(VecGetDM(auxVec, &auxDM));
347*de19e7feSJoseph Pusztay   PetscCall(DMGetLocalSection(auxDM, &s));
348*de19e7feSJoseph Pusztay   PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
349*de19e7feSJoseph Pusztay   for (PetscInt i = eStart; i < eEnd; ++i) { PetscCall(VecSetValuesSection(auxVec, s, i, id, INSERT_VALUES)); }
350*de19e7feSJoseph Pusztay   PetscCall(VecViewFromOptions(auxVec, NULL, "-gauge_view"));
351*de19e7feSJoseph Pusztay   PetscFunctionReturn(0);
352*de19e7feSJoseph Pusztay }
353*de19e7feSJoseph Pusztay 
3547b197a28SMatthew G. Knepley /*
3557b197a28SMatthew G. Knepley   Test the action of the Wilson operator in the free field case U = I,
3567b197a28SMatthew G. Knepley 
3577b197a28SMatthew G. Knepley     \eta(x) = D_W(x - y) \psi(y)
3587b197a28SMatthew G. Knepley 
3597b197a28SMatthew G. Knepley   The Wilson operator is a convolution for the free field, so we can check that by the convolution theorem
3607b197a28SMatthew G. Knepley 
3617b197a28SMatthew G. Knepley     \hat\eta(x) = \mathcal{F}(D_W(x - y) \psi(y))
3627b197a28SMatthew G. Knepley                 = \hat D_W(p) \mathcal{F}\psi(p)
3637b197a28SMatthew G. Knepley 
3647b197a28SMatthew G. Knepley   The Fourier series for the Wilson operator is
3657b197a28SMatthew G. Knepley 
3667b197a28SMatthew G. Knepley     M + \sum_\mu 2 \sin^2(p_\mu / 2) + i \gamma_\mu \sin(p_\mu)
3677b197a28SMatthew G. Knepley */
3687b197a28SMatthew G. Knepley static PetscErrorCode TestFreeField(DM dm)
3697b197a28SMatthew G. Knepley {
3707b197a28SMatthew G. Knepley   PetscSection       s;
3717b197a28SMatthew G. Knepley   Mat                FT;
3727b197a28SMatthew G. Knepley   Vec                psi, psiHat;
3737b197a28SMatthew G. Knepley   Vec                eta, etaHat;
3747b197a28SMatthew G. Knepley   Vec                DHat; // The product \hat D_w \hat psi
3757b197a28SMatthew G. Knepley   PetscRandom        r;
3767b197a28SMatthew G. Knepley   const PetscScalar *psih;
3777b197a28SMatthew G. Knepley   PetscScalar       *dh;
3787b197a28SMatthew G. Knepley   PetscReal         *coef, nrm;
3797b197a28SMatthew G. Knepley   const PetscInt    *extent, Nc = 12;
3807b197a28SMatthew G. Knepley   PetscInt           dim, V     = 1, vStart, vEnd;
3817b197a28SMatthew G. Knepley   PetscContainer     c;
3827b197a28SMatthew G. Knepley   PetscBool          constRhs = PETSC_FALSE;
3837b197a28SMatthew G. Knepley 
3847b197a28SMatthew G. Knepley   PetscFunctionBeginUser;
3857b197a28SMatthew G. Knepley   PetscCall(PetscOptionsGetBool(NULL, NULL, "-const_rhs", &constRhs, NULL));
3867b197a28SMatthew G. Knepley 
387*de19e7feSJoseph Pusztay   PetscCall(SetGauge_Identity(dm));
3887b197a28SMatthew G. Knepley   PetscCall(DMGetLocalSection(dm, &s));
3897b197a28SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &psi));
3907b197a28SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)psi, "psi"));
3917b197a28SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &psiHat));
3927b197a28SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)psiHat, "psihat"));
3937b197a28SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &eta));
3947b197a28SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)eta, "eta"));
3957b197a28SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &etaHat));
3967b197a28SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)etaHat, "etahat"));
3977b197a28SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &DHat));
3987b197a28SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)DHat, "Dhat"));
3997b197a28SMatthew G. Knepley   PetscCall(PetscRandomCreate(PETSC_COMM_SELF, &r));
4007b197a28SMatthew G. Knepley   PetscCall(PetscRandomSetType(r, PETSCRAND48));
4017b197a28SMatthew G. Knepley   if (constRhs) PetscCall(VecSet(psi, 1.));
4027b197a28SMatthew G. Knepley   else PetscCall(VecSetRandom(psi, r));
4037b197a28SMatthew G. Knepley   PetscCall(PetscRandomDestroy(&r));
4047b197a28SMatthew G. Knepley 
4057b197a28SMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
4067b197a28SMatthew G. Knepley   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
4077b197a28SMatthew G. Knepley   PetscCall(PetscObjectQuery((PetscObject)dm, "_extent", (PetscObject *)&c));
4087b197a28SMatthew G. Knepley   PetscCall(PetscContainerGetPointer(c, (void **)&extent));
4097b197a28SMatthew G. Knepley   PetscCall(MatCreateFFT(PetscObjectComm((PetscObject)dm), dim, extent, MATFFTW, &FT));
4107b197a28SMatthew G. Knepley 
4117b197a28SMatthew G. Knepley   PetscCall(PetscMalloc1(dim, &coef));
4127b197a28SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) {
4137b197a28SMatthew G. Knepley     coef[d] = 2. * PETSC_PI / extent[d];
4147b197a28SMatthew G. Knepley     V *= extent[d];
4157b197a28SMatthew G. Knepley   }
4167b197a28SMatthew G. Knepley   PetscCall(ComputeResidual(dm, psi, eta));
4177b197a28SMatthew G. Knepley   PetscCall(VecViewFromOptions(eta, NULL, "-psi_view"));
4187b197a28SMatthew G. Knepley   PetscCall(VecViewFromOptions(eta, NULL, "-eta_view"));
4197b197a28SMatthew G. Knepley   PetscCall(ComputeFFT(FT, Nc, psi, psiHat));
4207b197a28SMatthew G. Knepley   PetscCall(VecScale(psiHat, 1. / V));
4217b197a28SMatthew G. Knepley   PetscCall(ComputeFFT(FT, Nc, eta, etaHat));
4227b197a28SMatthew G. Knepley   PetscCall(VecScale(etaHat, 1. / V));
4237b197a28SMatthew G. Knepley   PetscCall(VecGetArrayRead(psiHat, &psih));
4247b197a28SMatthew G. Knepley   PetscCall(VecGetArray(DHat, &dh));
4257b197a28SMatthew G. Knepley   for (PetscInt v = vStart; v < vEnd; ++v) {
4267b197a28SMatthew G. Knepley     PetscScalar tmp[12], tmp1 = 0.;
4277b197a28SMatthew G. Knepley     PetscInt    dof, off;
4287b197a28SMatthew G. Knepley 
4297b197a28SMatthew G. Knepley     PetscCall(PetscSectionGetDof(s, v, &dof));
4307b197a28SMatthew G. Knepley     PetscCall(PetscSectionGetOffset(s, v, &off));
4317b197a28SMatthew G. Knepley     for (PetscInt d = 0, prod = 1; d < dim; prod *= extent[d], ++d) {
4327b197a28SMatthew G. Knepley       const PetscInt idx = (v / prod) % extent[d];
4337b197a28SMatthew G. Knepley 
4347b197a28SMatthew G. Knepley       tmp1 += 2. * PetscSqr(PetscSinReal(0.5 * coef[d] * idx));
4357b197a28SMatthew G. Knepley       for (PetscInt i = 0; i < dof; ++i) tmp[i] = PETSC_i * PetscSinReal(coef[d] * idx) * psih[off + i];
4367b197a28SMatthew G. Knepley       for (PetscInt c = 0; c < 3; ++c) ComputeGamma(d, 3, &tmp[c]);
4377b197a28SMatthew G. Knepley       for (PetscInt i = 0; i < dof; ++i) dh[off + i] += tmp[i];
4387b197a28SMatthew G. Knepley     }
4397b197a28SMatthew G. Knepley     for (PetscInt i = 0; i < dof; ++i) dh[off + i] += (M + tmp1) * psih[off + i];
4407b197a28SMatthew G. Knepley   }
4417b197a28SMatthew G. Knepley   PetscCall(VecRestoreArrayRead(psiHat, &psih));
4427b197a28SMatthew G. Knepley   PetscCall(VecRestoreArray(DHat, &dh));
4437b197a28SMatthew G. Knepley 
4447b197a28SMatthew G. Knepley   {
4457b197a28SMatthew G. Knepley     Vec     *etaComp, *DComp;
4467b197a28SMatthew G. Knepley     PetscInt n, N;
4477b197a28SMatthew G. Knepley 
4487b197a28SMatthew G. Knepley     PetscCall(PetscMalloc2(Nc, &etaComp, Nc, &DComp));
4497b197a28SMatthew G. Knepley     PetscCall(VecGetLocalSize(etaHat, &n));
4507b197a28SMatthew G. Knepley     PetscCall(VecGetSize(etaHat, &N));
4517b197a28SMatthew G. Knepley     for (PetscInt i = 0; i < Nc; ++i) {
4527b197a28SMatthew G. Knepley       const char *vtype;
4537b197a28SMatthew G. Knepley 
4547b197a28SMatthew G. Knepley       // HACK: Make these from another DM up front
4557b197a28SMatthew G. Knepley       PetscCall(VecCreate(PetscObjectComm((PetscObject)etaHat), &etaComp[i]));
4567b197a28SMatthew G. Knepley       PetscCall(VecGetType(etaHat, &vtype));
4577b197a28SMatthew G. Knepley       PetscCall(VecSetType(etaComp[i], vtype));
4587b197a28SMatthew G. Knepley       PetscCall(VecSetSizes(etaComp[i], n / Nc, N / Nc));
4597b197a28SMatthew G. Knepley       PetscCall(VecDuplicate(etaComp[i], &DComp[i]));
4607b197a28SMatthew G. Knepley     }
4617b197a28SMatthew G. Knepley     PetscCall(VecStrideGatherAll(etaHat, etaComp, INSERT_VALUES));
4627b197a28SMatthew G. Knepley     PetscCall(VecStrideGatherAll(DHat, DComp, INSERT_VALUES));
4637b197a28SMatthew G. Knepley     for (PetscInt i = 0; i < Nc; ++i) {
4647b197a28SMatthew G. Knepley       if (!i) {
4657b197a28SMatthew G. Knepley         PetscCall(VecViewFromOptions(etaComp[i], NULL, "-etahat_view"));
4667b197a28SMatthew G. Knepley         PetscCall(VecViewFromOptions(DComp[i], NULL, "-dhat_view"));
4677b197a28SMatthew G. Knepley       }
4687b197a28SMatthew G. Knepley       PetscCall(VecAXPY(etaComp[i], -1., DComp[i]));
4697b197a28SMatthew G. Knepley       PetscCall(VecNorm(etaComp[i], NORM_INFINITY, &nrm));
4707b197a28SMatthew G. Knepley       PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Slice %" PetscInt_FMT ": %g\n", i, (double)nrm));
4717b197a28SMatthew G. Knepley     }
4727b197a28SMatthew G. Knepley     PetscCall(VecStrideScatterAll(etaComp, etaHat, INSERT_VALUES));
4737b197a28SMatthew G. Knepley     for (PetscInt i = 0; i < Nc; ++i) {
4747b197a28SMatthew G. Knepley       PetscCall(VecDestroy(&etaComp[i]));
4757b197a28SMatthew G. Knepley       PetscCall(VecDestroy(&DComp[i]));
4767b197a28SMatthew G. Knepley     }
4777b197a28SMatthew G. Knepley     PetscCall(PetscFree2(etaComp, DComp));
4787b197a28SMatthew G. Knepley     PetscCall(VecNorm(etaHat, NORM_INFINITY, &nrm));
4797b197a28SMatthew G. Knepley     PetscCheck(nrm < PETSC_SMALL, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Free field test failed: %g", (double)nrm);
4807b197a28SMatthew G. Knepley   }
4817b197a28SMatthew G. Knepley 
4827b197a28SMatthew G. Knepley   PetscCall(PetscFree(coef));
4837b197a28SMatthew G. Knepley   PetscCall(MatDestroy(&FT));
4847b197a28SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &psi));
4857b197a28SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &psiHat));
4867b197a28SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &eta));
4877b197a28SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &etaHat));
4887b197a28SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &DHat));
4897b197a28SMatthew G. Knepley   PetscFunctionReturn(0);
4907b197a28SMatthew G. Knepley }
4917b197a28SMatthew G. Knepley 
4927b197a28SMatthew G. Knepley int main(int argc, char **argv)
4937b197a28SMatthew G. Knepley {
4947b197a28SMatthew G. Knepley   DM     dm;
4957b197a28SMatthew G. Knepley   Vec    u, f;
4967b197a28SMatthew G. Knepley   Mat    J;
4977b197a28SMatthew G. Knepley   AppCtx user;
4987b197a28SMatthew G. Knepley 
4997b197a28SMatthew G. Knepley   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
5007b197a28SMatthew G. Knepley   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user));
5017b197a28SMatthew G. Knepley   PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm));
5027b197a28SMatthew G. Knepley   PetscCall(SetupDiscretization(dm, &user));
5037b197a28SMatthew G. Knepley   PetscCall(SetupAuxDiscretization(dm, &user));
5047b197a28SMatthew G. Knepley   PetscCall(DMCreateGlobalVector(dm, &u));
5057b197a28SMatthew G. Knepley   PetscCall(DMCreateGlobalVector(dm, &f));
5067b197a28SMatthew G. Knepley   PetscCall(PrintTraversal(dm));
5077b197a28SMatthew G. Knepley   PetscCall(ComputeResidual(dm, u, f));
5087b197a28SMatthew G. Knepley   PetscCall(VecViewFromOptions(f, NULL, "-res_view"));
5097b197a28SMatthew G. Knepley   PetscCall(CreateJacobian(dm, &J));
5107b197a28SMatthew G. Knepley   PetscCall(ComputeJacobian(dm, u, J));
5117b197a28SMatthew G. Knepley   PetscCall(VecViewFromOptions(u, NULL, "-sol_view"));
5127b197a28SMatthew G. Knepley   PetscCall(TestFreeField(dm));
5137b197a28SMatthew G. Knepley   PetscCall(VecDestroy(&f));
5147b197a28SMatthew G. Knepley   PetscCall(VecDestroy(&u));
5157b197a28SMatthew G. Knepley   PetscCall(DMDestroy(&dm));
5167b197a28SMatthew G. Knepley   PetscCall(PetscFinalize());
5177b197a28SMatthew G. Knepley   return 0;
5187b197a28SMatthew G. Knepley }
5197b197a28SMatthew G. Knepley 
5207b197a28SMatthew G. Knepley /*TEST
5217b197a28SMatthew G. Knepley 
5227b197a28SMatthew G. Knepley   build:
5237b197a28SMatthew G. Knepley     requires: complex
5247b197a28SMatthew G. Knepley 
5257b197a28SMatthew G. Knepley   test:
5267b197a28SMatthew G. Knepley     requires: fftw
5277b197a28SMatthew G. Knepley     suffix: dirac_free_field
5287b197a28SMatthew G. Knepley     args: -dm_plex_dim 4 -dm_plex_shape hypercubic -dm_plex_box_faces 3,3,3,3 -dm_view -sol_view \
5297b197a28SMatthew G. Knepley           -dm_plex_check_symmetry -dm_plex_check_skeleton -dm_plex_check_faces -dm_plex_check_pointsf
5307b197a28SMatthew G. Knepley 
5317b197a28SMatthew G. Knepley TEST*/
532