xref: /petsc/src/dm/impls/swarm/tutorials/ex1.c (revision 4dfa11a44d5adf2389f1d3acbc8f3c1116dc6c3a)
1 static char help[] = "Example program demonstrating projection between particle and finite element spaces\n\n";
2 
3 #include "petscdmplex.h"
4 #include "petscds.h"
5 #include "petscdmswarm.h"
6 #include "petscksp.h"
7 
8 int main(int argc, char **argv) {
9   DM            dm, sw;
10   PetscFE       fe;
11   KSP           ksp;
12   PC            pc;
13   Mat           M_p, PM_p = NULL;
14   Vec           f, rho, rhs;
15   PetscInt      dim, Nc = 1, timestep = 0, i, faces[3];
16   PetscInt      Np = 10, p, field = 0, zero = 0, bs;
17   PetscReal     time = 0.0, norm, energy_0, energy_1;
18   PetscReal     lo[3], hi[3], h[3];
19   PetscBool     removePoints = PETSC_TRUE;
20   PetscReal    *wq, *coords;
21   PetscDataType dtype;
22   PetscBool     is_bjac;
23 
24   PetscFunctionBeginUser;
25   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
26   /* Create a mesh */
27   PetscCall(DMCreate(PETSC_COMM_WORLD, &dm));
28   PetscCall(DMSetType(dm, DMPLEX));
29   PetscCall(DMSetFromOptions(dm));
30   PetscCall(DMViewFromOptions(dm, NULL, "-dm_view"));
31 
32   PetscCall(DMGetDimension(dm, &dim));
33   i = dim;
34   PetscCall(PetscOptionsGetIntArray(NULL, NULL, "-dm_plex_box_faces", faces, &i, NULL));
35   PetscCall(PetscOptionsGetInt(NULL, NULL, "-np", &Np, NULL));
36   PetscCall(DMGetBoundingBox(dm, lo, hi));
37   for (i = 0; i < dim; i++) {
38     h[i] = (hi[i] - lo[i]) / faces[i];
39     PetscCall(PetscPrintf(PETSC_COMM_SELF, " lo = %g hi = %g n = %" PetscInt_FMT " h = %g\n", (double)lo[i], (double)hi[i], faces[i], (double)h[i]));
40   }
41 
42   PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, Nc, PETSC_FALSE, "", PETSC_DECIDE, &fe));
43   PetscCall(PetscFESetFromOptions(fe));
44   PetscCall(PetscObjectSetName((PetscObject)fe, "fe"));
45   PetscCall(DMSetField(dm, field, NULL, (PetscObject)fe));
46   PetscCall(DMCreateDS(dm));
47   PetscCall(PetscFEDestroy(&fe));
48   /* Create particle swarm */
49   PetscCall(DMCreate(PETSC_COMM_SELF, &sw));
50   PetscCall(DMSetType(sw, DMSWARM));
51   PetscCall(DMSetDimension(sw, dim));
52   PetscCall(DMSwarmSetType(sw, DMSWARM_PIC));
53   PetscCall(DMSwarmSetCellDM(sw, dm));
54   PetscCall(DMSwarmRegisterPetscDatatypeField(sw, "w_q", Nc, PETSC_SCALAR));
55   PetscCall(DMSwarmFinalizeFieldRegister(sw));
56   PetscCall(DMSwarmSetLocalSizes(sw, Np, zero));
57   PetscCall(DMSetFromOptions(sw));
58   PetscCall(DMSwarmGetField(sw, "w_q", &bs, &dtype, (void **)&wq));
59   PetscCall(DMSwarmGetField(sw, "DMSwarmPIC_coor", &bs, &dtype, (void **)&coords));
60   for (p = 0, energy_0 = 0; p < Np; p++) {
61     coords[p * 2 + 0] = -PetscCosReal((PetscReal)(p + 1) / (PetscReal)(Np + 1) * PETSC_PI);
62     coords[p * 2 + 1] = PetscSinReal((PetscReal)(p + 1) / (PetscReal)(Np + 1) * PETSC_PI);
63     wq[p]             = 1.0;
64     energy_0 += wq[p] * (PetscSqr(coords[p * 2 + 0]) + PetscSqr(coords[p * 2 + 1]));
65   }
66   PetscCall(DMSwarmRestoreField(sw, "DMSwarmPIC_coor", &bs, &dtype, (void **)&coords));
67   PetscCall(DMSwarmRestoreField(sw, "w_q", &bs, &dtype, (void **)&wq));
68   PetscCall(DMSwarmMigrate(sw, removePoints));
69   PetscCall(PetscObjectSetName((PetscObject)sw, "Particle Grid"));
70   PetscCall(DMViewFromOptions(sw, NULL, "-swarm_view"));
71 
72   /* Project particles to field */
73   /* This gives M f = \int_\Omega \phi f, which looks like a rhs for a PDE */
74   PetscCall(DMCreateMassMatrix(sw, dm, &M_p));
75   PetscCall(DMCreateGlobalVector(dm, &rho));
76   PetscCall(PetscObjectSetName((PetscObject)rho, "rho"));
77 
78   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f));
79   PetscCall(PetscObjectSetName((PetscObject)f, "weights"));
80   PetscCall(MatMultTranspose(M_p, f, rho));
81 
82   /* Visualize mesh field */
83   PetscCall(DMSetOutputSequenceNumber(dm, timestep, time));
84   PetscCall(VecViewFromOptions(rho, NULL, "-rho_view"));
85 
86   /* Project field to particles */
87   /*   This gives f_p = M_p^+ M f */
88   PetscCall(DMCreateGlobalVector(dm, &rhs));
89   PetscCall(VecCopy(rho, rhs)); /* Identity: M^1 M rho */
90 
91   PetscCall(KSPCreate(PETSC_COMM_WORLD, &ksp));
92   PetscCall(KSPSetOptionsPrefix(ksp, "ftop_"));
93   PetscCall(KSPSetFromOptions(ksp));
94   PetscCall(KSPGetPC(ksp, &pc));
95   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCBJACOBI, &is_bjac));
96   if (is_bjac) {
97     PetscCall(DMSwarmCreateMassMatrixSquare(sw, dm, &PM_p));
98     PetscCall(KSPSetOperators(ksp, M_p, PM_p));
99   } else {
100     PetscCall(KSPSetOperators(ksp, M_p, M_p));
101   }
102   PetscCall(KSPSolveTranspose(ksp, rhs, f));
103   PetscCall(KSPDestroy(&ksp));
104   PetscCall(VecDestroy(&rhs));
105 
106   /* Visualize particle field */
107   PetscCall(DMSetOutputSequenceNumber(sw, timestep, time));
108   PetscCall(VecViewFromOptions(f, NULL, "-weights_view"));
109   PetscCall(VecNorm(f, NORM_1, &norm));
110   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f));
111 
112   /* compute energy */
113   PetscCall(DMSwarmGetField(sw, "w_q", &bs, &dtype, (void **)&wq));
114   PetscCall(DMSwarmGetField(sw, "DMSwarmPIC_coor", &bs, &dtype, (void **)&coords));
115   for (p = 0, energy_1 = 0; p < Np; p++) energy_1 += wq[p] * (PetscSqr(coords[p * 2 + 0]) + PetscSqr(coords[p * 2 + 1]));
116   PetscCall(DMSwarmRestoreField(sw, "DMSwarmPIC_coor", &bs, &dtype, (void **)&coords));
117   PetscCall(DMSwarmRestoreField(sw, "w_q", &bs, &dtype, (void **)&wq));
118   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Total number = %20.12e. energy = %20.12e error = %20.12e\n", (double)norm, (double)energy_0, (double)((energy_1 - energy_0) / energy_0)));
119   /* Cleanup */
120   PetscCall(MatDestroy(&M_p));
121   PetscCall(MatDestroy(&PM_p));
122   PetscCall(VecDestroy(&rho));
123   PetscCall(DMDestroy(&sw));
124   PetscCall(DMDestroy(&dm));
125   PetscCall(PetscFinalize());
126   return 0;
127 }
128 
129 /*TEST
130 
131   build:
132     requires: !complex
133 
134   test:
135     suffix: 0
136     requires: double triangle
137     args: -dm_plex_simplex 0 -dm_plex_box_faces 4,2 -np 50 -dm_plex_box_lower -2.0,0.0 -dm_plex_box_upper 2.0,2.0 -petscspace_degree 2 -ftop_ksp_type lsqr -ftop_pc_type none -dm_view -swarm_view -ftop_ksp_rtol 1.e-14
138     filter: grep -v DM_ | grep -v atomic
139 
140   test:
141     suffix: bjacobi
142     requires: double triangle
143     args: -dm_plex_simplex 0 -dm_plex_box_faces 4,2 -np 50 -dm_plex_box_lower -2.0,0.0 -dm_plex_box_upper 2.0,2.0 -petscspace_degree 2 -dm_plex_hash_location -ftop_ksp_type lsqr -ftop_pc_type bjacobi -ftop_sub_pc_type lu -ftop_sub_pc_factor_shift_type nonzero -dm_view -swarm_view -ftop_ksp_rtol 1.e-14
144     filter: grep -v DM_ | grep -v atomic
145 
146 TEST*/
147