xref: /petsc/src/dm/impls/swarm/tests/ex7.c (revision 3c61180074fb218d306db6efca283cdc905c977f)
1*3c611800SMark Adams static char help[] = "Example program demonstrating projection between particle and finite element spaces using OpenMP in 2D cylindrical coordinates\n";
2*3c611800SMark Adams 
3*3c611800SMark Adams #include "petscdmplex.h"
4*3c611800SMark Adams #include "petscds.h"
5*3c611800SMark Adams #include "petscdmswarm.h"
6*3c611800SMark Adams #include "petscksp.h"
7*3c611800SMark Adams #include <petsc/private/petscimpl.h>
8*3c611800SMark Adams #if defined(PETSC_HAVE_OPENMP) && defined(PETSC_HAVE_THREADSAFETY)
9*3c611800SMark Adams #include <omp.h>
10*3c611800SMark Adams #endif
11*3c611800SMark Adams 
12*3c611800SMark Adams typedef struct {
13*3c611800SMark Adams   Mat MpTrans;
14*3c611800SMark Adams   Mat Mp;
15*3c611800SMark Adams   Vec ff;
16*3c611800SMark Adams   Vec uu;
17*3c611800SMark Adams } MatShellCtx;
18*3c611800SMark Adams 
19*3c611800SMark Adams PetscErrorCode MatMultMtM_SeqAIJ(Mat MtM,Vec xx,Vec yy)
20*3c611800SMark Adams {
21*3c611800SMark Adams   MatShellCtx    *matshellctx;
22*3c611800SMark Adams   PetscErrorCode ierr;
23*3c611800SMark Adams 
24*3c611800SMark Adams   PetscFunctionBeginUser;
25*3c611800SMark Adams   ierr = MatShellGetContext(MtM,&matshellctx);CHKERRQ(ierr);
26*3c611800SMark Adams   if (!matshellctx) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "No context");
27*3c611800SMark Adams   ierr = MatMult(matshellctx->Mp, xx, matshellctx->ff);CHKERRQ(ierr);
28*3c611800SMark Adams   ierr = MatMult(matshellctx->MpTrans, matshellctx->ff, yy);CHKERRQ(ierr);
29*3c611800SMark Adams   PetscFunctionReturn(0);
30*3c611800SMark Adams }
31*3c611800SMark Adams 
32*3c611800SMark Adams PetscErrorCode MatMultAddMtM_SeqAIJ(Mat MtM,Vec xx, Vec yy, Vec zz)
33*3c611800SMark Adams {
34*3c611800SMark Adams   MatShellCtx    *matshellctx;
35*3c611800SMark Adams   PetscErrorCode ierr;
36*3c611800SMark Adams 
37*3c611800SMark Adams   PetscFunctionBeginUser;
38*3c611800SMark Adams   ierr = MatShellGetContext(MtM,&matshellctx);CHKERRQ(ierr);
39*3c611800SMark Adams   if (!matshellctx) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "No context");
40*3c611800SMark Adams   ierr = MatMult(matshellctx->Mp, xx, matshellctx->ff);CHKERRQ(ierr);
41*3c611800SMark Adams   ierr = MatMultAdd(matshellctx->MpTrans, matshellctx->ff, yy, zz);CHKERRQ(ierr);
42*3c611800SMark Adams   PetscFunctionReturn(0);
43*3c611800SMark Adams }
44*3c611800SMark Adams 
45*3c611800SMark Adams PetscErrorCode createSwarm(const DM dm, DM *sw)
46*3c611800SMark Adams {
47*3c611800SMark Adams   PetscErrorCode ierr;
48*3c611800SMark Adams   PetscInt       Nc = 1, dim = 2;
49*3c611800SMark Adams 
50*3c611800SMark Adams   PetscFunctionBeginUser;
51*3c611800SMark Adams   ierr = DMCreate(PETSC_COMM_SELF, sw);CHKERRQ(ierr);
52*3c611800SMark Adams   ierr = DMSetType(*sw, DMSWARM);CHKERRQ(ierr);
53*3c611800SMark Adams   ierr = DMSetDimension(*sw, dim);CHKERRQ(ierr);
54*3c611800SMark Adams   ierr = DMSwarmSetType(*sw, DMSWARM_PIC);CHKERRQ(ierr);
55*3c611800SMark Adams   ierr = DMSwarmSetCellDM(*sw, dm);CHKERRQ(ierr);
56*3c611800SMark Adams   ierr = DMSwarmRegisterPetscDatatypeField(*sw, "w_q", Nc, PETSC_SCALAR);CHKERRQ(ierr);
57*3c611800SMark Adams   ierr = DMSwarmFinalizeFieldRegister(*sw);CHKERRQ(ierr);
58*3c611800SMark Adams   ierr = DMSetFromOptions(*sw);CHKERRQ(ierr);
59*3c611800SMark Adams   PetscFunctionReturn(0);
60*3c611800SMark Adams }
61*3c611800SMark Adams 
62*3c611800SMark Adams PetscErrorCode gridToParticles(const DM dm, DM sw, PetscReal *moments, Vec rhs, Mat M_p)
63*3c611800SMark Adams {
64*3c611800SMark Adams   PetscBool      is_lsqr;
65*3c611800SMark Adams   KSP            ksp;
66*3c611800SMark Adams   Mat            PM_p=NULL,MtM,D;
67*3c611800SMark Adams   Vec            ff;
68*3c611800SMark Adams   PetscErrorCode ierr;
69*3c611800SMark Adams   PetscInt       Np, timestep = 0, bs, N, M, nzl;
70*3c611800SMark Adams   PetscReal      time = 0.0;
71*3c611800SMark Adams   PetscDataType  dtype;
72*3c611800SMark Adams   MatShellCtx    *matshellctx;
73*3c611800SMark Adams 
74*3c611800SMark Adams   PetscFunctionBeginUser;
75*3c611800SMark Adams   ierr = KSPCreate(PETSC_COMM_SELF, &ksp);CHKERRQ(ierr);
76*3c611800SMark Adams   ierr = KSPSetOptionsPrefix(ksp, "ftop_");CHKERRQ(ierr);
77*3c611800SMark Adams   ierr = KSPSetFromOptions(ksp);CHKERRQ(ierr);
78*3c611800SMark Adams   ierr = PetscObjectTypeCompare((PetscObject)ksp,KSPLSQR,&is_lsqr);
79*3c611800SMark Adams   if (!is_lsqr) {
80*3c611800SMark Adams     ierr = MatGetLocalSize(M_p, &M, &N);CHKERRQ(ierr);
81*3c611800SMark Adams     if (N>M) {
82*3c611800SMark Adams       PC        pc;
83*3c611800SMark Adams       ierr = PetscInfo2(ksp, " M (%D) < M (%D) -- skip revert to lsqr\n",M,N);CHKERRQ(ierr);
84*3c611800SMark Adams       is_lsqr = PETSC_TRUE;
85*3c611800SMark Adams       ierr = KSPSetType(ksp,KSPLSQR);CHKERRQ(ierr);
86*3c611800SMark Adams       ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr);
87*3c611800SMark Adams       ierr = PCSetType(pc,PCNONE);CHKERRQ(ierr); // could put in better solver -ftop_pc_type bjacobi -ftop_sub_pc_type lu -ftop_sub_pc_factor_shift_type nonzero
88*3c611800SMark Adams     } else {
89*3c611800SMark Adams       ierr = PetscNew(&matshellctx);CHKERRQ(ierr);
90*3c611800SMark Adams       ierr = MatCreateShell(PetscObjectComm((PetscObject)dm),N,N,PETSC_DECIDE,PETSC_DECIDE,matshellctx,&MtM);CHKERRQ(ierr);
91*3c611800SMark Adams       ierr = MatTranspose(M_p,MAT_INITIAL_MATRIX,&matshellctx->MpTrans);CHKERRQ(ierr);
92*3c611800SMark Adams       matshellctx->Mp = M_p;
93*3c611800SMark Adams       ierr = MatShellSetOperation(MtM, MATOP_MULT, (void (*)(void))MatMultMtM_SeqAIJ);CHKERRQ(ierr);
94*3c611800SMark Adams       ierr = MatShellSetOperation(MtM, MATOP_MULT_ADD, (void (*)(void))MatMultAddMtM_SeqAIJ);CHKERRQ(ierr);
95*3c611800SMark Adams       ierr = MatCreateVecs(M_p,&matshellctx->uu,&matshellctx->ff);CHKERRQ(ierr);
96*3c611800SMark Adams       ierr = MatCreateSeqAIJ(PETSC_COMM_SELF,N,N,1,NULL,&D);CHKERRQ(ierr);
97*3c611800SMark Adams       for (int i=0 ; i<N ; i++) {
98*3c611800SMark Adams         const PetscScalar *vals;
99*3c611800SMark Adams         const PetscInt    *cols;
100*3c611800SMark Adams         PetscScalar dot = 0;
101*3c611800SMark Adams         ierr = MatGetRow(matshellctx->MpTrans,i,&nzl,&cols,&vals);CHKERRQ(ierr);
102*3c611800SMark Adams         for (int ii=0 ; ii<nzl ; ii++) dot += PetscSqr(vals[ii]);
103*3c611800SMark Adams         if (dot==0.0) SETERRQ1(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Row %D is empty", i);
104*3c611800SMark Adams         ierr = MatSetValue(D,i,i,dot,INSERT_VALUES);
105*3c611800SMark Adams       }
106*3c611800SMark Adams       ierr = MatAssemblyBegin(D, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
107*3c611800SMark Adams       ierr = MatAssemblyEnd(D, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
108*3c611800SMark Adams       PetscInfo2(M_p,"createMtMKSP Have %D eqs, nzl = %D\n",N,nzl);
109*3c611800SMark Adams       ierr = KSPSetOperators(ksp, MtM, D);CHKERRQ(ierr);
110*3c611800SMark Adams       ierr = MatViewFromOptions(D,NULL,"-ftop2_D_mat_view");CHKERRQ(ierr);
111*3c611800SMark Adams       ierr = MatViewFromOptions(M_p,NULL,"-ftop2_Mp_mat_view");CHKERRQ(ierr);
112*3c611800SMark Adams       ierr = MatViewFromOptions(matshellctx->MpTrans,NULL,"-ftop2_MpTranspose_mat_view");CHKERRQ(ierr);
113*3c611800SMark Adams     }
114*3c611800SMark Adams   }
115*3c611800SMark Adams   if (is_lsqr) {
116*3c611800SMark Adams     PC        pc;
117*3c611800SMark Adams     PetscBool is_bjac;
118*3c611800SMark Adams     ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr);
119*3c611800SMark Adams     ierr = PetscObjectTypeCompare((PetscObject)pc,PCBJACOBI,&is_bjac);
120*3c611800SMark Adams     if (is_bjac) {
121*3c611800SMark Adams       ierr = DMSwarmCreateMassMatrixSquare(sw, dm, &PM_p);CHKERRQ(ierr);
122*3c611800SMark Adams       ierr = KSPSetOperators(ksp, M_p, PM_p);CHKERRQ(ierr);
123*3c611800SMark Adams     } else {
124*3c611800SMark Adams       ierr = KSPSetOperators(ksp, M_p, M_p);CHKERRQ(ierr);
125*3c611800SMark Adams     }
126*3c611800SMark Adams   }
127*3c611800SMark Adams   ierr = DMSwarmCreateGlobalVectorFromField(sw, "w_q", &ff);CHKERRQ(ierr); // this grabs access !!!!!
128*3c611800SMark Adams   if (!is_lsqr) {
129*3c611800SMark Adams     ierr = KSPSolve(ksp, rhs, matshellctx->uu);CHKERRQ(ierr);
130*3c611800SMark Adams     ierr = MatMult(M_p, matshellctx->uu, ff);CHKERRQ(ierr);
131*3c611800SMark Adams     ierr = MatDestroy(&matshellctx->MpTrans);CHKERRQ(ierr);
132*3c611800SMark Adams     ierr = VecDestroy(&matshellctx->ff);CHKERRQ(ierr);
133*3c611800SMark Adams     ierr = VecDestroy(&matshellctx->uu);CHKERRQ(ierr);
134*3c611800SMark Adams     ierr = MatDestroy(&D);CHKERRQ(ierr);
135*3c611800SMark Adams     ierr = MatDestroy(&MtM);CHKERRQ(ierr);
136*3c611800SMark Adams     ierr = PetscFree(matshellctx);CHKERRQ(ierr);
137*3c611800SMark Adams   } else {
138*3c611800SMark Adams     ierr = KSPSolveTranspose(ksp, rhs, ff);CHKERRQ(ierr);
139*3c611800SMark Adams   }
140*3c611800SMark Adams   ierr = KSPDestroy(&ksp);CHKERRQ(ierr);
141*3c611800SMark Adams   /* Visualize particle field */
142*3c611800SMark Adams   ierr = DMSetOutputSequenceNumber(sw, timestep, time);CHKERRQ(ierr);
143*3c611800SMark Adams   ierr = VecViewFromOptions(ff, NULL, "-weights_view");CHKERRQ(ierr);
144*3c611800SMark Adams   ierr = DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &ff);CHKERRQ(ierr);
145*3c611800SMark Adams 
146*3c611800SMark Adams   /* compute energy */
147*3c611800SMark Adams   if (moments) {
148*3c611800SMark Adams     PetscReal *wq, *coords;
149*3c611800SMark Adams     ierr = DMSwarmGetLocalSize(sw,&Np);CHKERRQ(ierr);
150*3c611800SMark Adams     ierr = DMSwarmGetField(sw, "w_q", &bs, &dtype, (void**)&wq);CHKERRQ(ierr);
151*3c611800SMark Adams     ierr = DMSwarmGetField(sw, "DMSwarmPIC_coor", &bs, &dtype, (void**)&coords);CHKERRQ(ierr);
152*3c611800SMark Adams     moments[0] = moments[1] = moments[2] = 0;
153*3c611800SMark Adams     for (int p=0;p<Np;p++) {
154*3c611800SMark Adams       moments[0] += wq[p];
155*3c611800SMark Adams       moments[1] += wq[p] * coords[p*2+0]; // x-momentum
156*3c611800SMark Adams       moments[2] += wq[p] * (PetscSqr(coords[p*2+0])+PetscSqr(coords[p*2+1]));
157*3c611800SMark Adams     }
158*3c611800SMark Adams     ierr = DMSwarmRestoreField(sw, "DMSwarmPIC_coor", &bs, &dtype, (void**)&coords);CHKERRQ(ierr);
159*3c611800SMark Adams     ierr = DMSwarmRestoreField(sw, "w_q", &bs, &dtype, (void**)&wq);CHKERRQ(ierr);
160*3c611800SMark Adams   }
161*3c611800SMark Adams   ierr = MatDestroy(&PM_p);
162*3c611800SMark Adams 
163*3c611800SMark Adams   PetscFunctionReturn(0);
164*3c611800SMark Adams }
165*3c611800SMark Adams 
166*3c611800SMark Adams PetscErrorCode particlesToGrid(const DM dm, DM sw, const PetscInt Np, const PetscInt a_tid, const PetscInt dim, const PetscInt target,
167*3c611800SMark Adams                                const PetscReal xx[], const PetscReal yy[], const PetscReal a_wp[], Vec rho, Mat *Mp_out)
168*3c611800SMark Adams {
169*3c611800SMark Adams 
170*3c611800SMark Adams   PetscBool      removePoints = PETSC_TRUE;
171*3c611800SMark Adams   PetscReal      *wq, *coords;
172*3c611800SMark Adams   PetscDataType  dtype;
173*3c611800SMark Adams   Mat            M_p;
174*3c611800SMark Adams   Vec            ff;
175*3c611800SMark Adams   PetscErrorCode ierr;
176*3c611800SMark Adams   PetscInt       bs,p,zero=0;
177*3c611800SMark Adams 
178*3c611800SMark Adams   PetscFunctionBeginUser;
179*3c611800SMark Adams   ierr = DMSwarmSetLocalSizes(sw, Np, zero);CHKERRQ(ierr);
180*3c611800SMark Adams   ierr = DMSwarmGetField(sw, "w_q", &bs, &dtype, (void**)&wq);CHKERRQ(ierr);
181*3c611800SMark Adams   ierr = DMSwarmGetField(sw, "DMSwarmPIC_coor", &bs, &dtype, (void**)&coords);CHKERRQ(ierr);
182*3c611800SMark Adams   for (p=0;p<Np;p++) {
183*3c611800SMark Adams     coords[p*2+0]  = xx[p];
184*3c611800SMark Adams     coords[p*2+1]  = yy[p];
185*3c611800SMark Adams     wq[p]          = a_wp[p];
186*3c611800SMark Adams   }
187*3c611800SMark Adams   ierr = DMSwarmRestoreField(sw, "DMSwarmPIC_coor", &bs, &dtype, (void**)&coords);CHKERRQ(ierr);
188*3c611800SMark Adams   ierr = DMSwarmRestoreField(sw, "w_q", &bs, &dtype, (void**)&wq);CHKERRQ(ierr);
189*3c611800SMark Adams   ierr = DMSwarmMigrate(sw, removePoints);CHKERRQ(ierr);
190*3c611800SMark Adams   ierr = PetscObjectSetName((PetscObject)sw, "Particle Grid");CHKERRQ(ierr);
191*3c611800SMark Adams   if (a_tid==target) {ierr = DMViewFromOptions(sw, NULL, "-swarm_view");CHKERRQ(ierr);}
192*3c611800SMark Adams 
193*3c611800SMark Adams   /* Project particles to field */
194*3c611800SMark Adams   /* This gives M f = \int_\Omega \phi f, which looks like a rhs for a PDE */
195*3c611800SMark Adams   ierr = DMCreateMassMatrix(sw, dm, &M_p);CHKERRQ(ierr);
196*3c611800SMark Adams   ierr = PetscObjectSetName((PetscObject)rho, "rho");CHKERRQ(ierr);
197*3c611800SMark Adams 
198*3c611800SMark Adams   ierr = DMSwarmCreateGlobalVectorFromField(sw, "w_q", &ff);CHKERRQ(ierr); // this grabs access !!!!!
199*3c611800SMark Adams   ierr = PetscObjectSetName((PetscObject)ff, "weights");CHKERRQ(ierr);
200*3c611800SMark Adams   ierr = MatMultTranspose(M_p, ff, rho);CHKERRQ(ierr);
201*3c611800SMark Adams   ierr = DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &ff);CHKERRQ(ierr);
202*3c611800SMark Adams 
203*3c611800SMark Adams   /* Visualize mesh field */
204*3c611800SMark Adams   if (a_tid==target) {ierr = VecViewFromOptions(rho, NULL, "-rho_view");CHKERRQ(ierr);}
205*3c611800SMark Adams   // output
206*3c611800SMark Adams   *Mp_out = M_p;
207*3c611800SMark Adams 
208*3c611800SMark Adams   PetscFunctionReturn(0);
209*3c611800SMark Adams }
210*3c611800SMark Adams static PetscErrorCode maxwellian(PetscInt dim, const PetscReal x[], PetscReal kt_m, PetscReal n, PetscScalar *u)
211*3c611800SMark Adams {
212*3c611800SMark Adams   PetscInt      i;
213*3c611800SMark Adams   PetscReal     v2 = 0, theta = 2*kt_m; /* theta = 2kT/mc^2 */
214*3c611800SMark Adams 
215*3c611800SMark Adams   PetscFunctionBegin;
216*3c611800SMark Adams   /* compute the exponents, v^2 */
217*3c611800SMark Adams   for (i = 0; i < dim; ++i) v2 += x[i]*x[i];
218*3c611800SMark Adams   /* evaluate the Maxwellian */
219*3c611800SMark Adams   u[0] = n*PetscPowReal(PETSC_PI*theta,-1.5)*(PetscExpReal(-v2/theta)) * 2.*PETSC_PI*x[1]; // radial term for 2D axi-sym.
220*3c611800SMark Adams   PetscFunctionReturn(0);
221*3c611800SMark Adams }
222*3c611800SMark Adams #define NUM_SOLVE_LOOPS 100
223*3c611800SMark Adams #define MAX_NUM_THRDS 12
224*3c611800SMark Adams PetscErrorCode go()
225*3c611800SMark Adams {
226*3c611800SMark Adams   DM              dm_t[MAX_NUM_THRDS], sw_t[MAX_NUM_THRDS];
227*3c611800SMark Adams   PetscFE         fe;
228*3c611800SMark Adams   PetscInt        dim = 2, Nc = 1, timestep = 0, i, faces[3];
229*3c611800SMark Adams   PetscInt        Np[2] = {10,10}, Np2[2], field = 0, target = 0, Np_t[MAX_NUM_THRDS];
230*3c611800SMark Adams   PetscReal       time = 0.0, moments_0[3], moments_1[3], vol;
231*3c611800SMark Adams   PetscReal       lo[3] = {-5,0,-5}, hi[3] = {5,5,5}, h[3], hp[3], *xx_t[MAX_NUM_THRDS], *yy_t[MAX_NUM_THRDS], *wp_t[MAX_NUM_THRDS], solve_time = 0;
232*3c611800SMark Adams   Vec             rho_t[MAX_NUM_THRDS], rhs_t[MAX_NUM_THRDS];
233*3c611800SMark Adams   Mat             M_p_t[MAX_NUM_THRDS];
234*3c611800SMark Adams   PetscErrorCode  ierr;
235*3c611800SMark Adams #if defined PETSC_USE_LOG
236*3c611800SMark Adams   PetscLogStage   stage;
237*3c611800SMark Adams   PetscLogEvent   swarm_create_ev, solve_ev, solve_loop_ev;
238*3c611800SMark Adams #endif
239*3c611800SMark Adams #if defined(PETSC_HAVE_OPENMP) && defined(PETSC_HAVE_THREADSAFETY)
240*3c611800SMark Adams   PetscInt        numthreads = PetscNumOMPThreads;
241*3c611800SMark Adams   double          starttime, endtime;
242*3c611800SMark Adams #else
243*3c611800SMark Adams   PetscInt        numthreads = 1;
244*3c611800SMark Adams #endif
245*3c611800SMark Adams 
246*3c611800SMark Adams   PetscFunctionBeginUser;
247*3c611800SMark Adams #if defined(PETSC_HAVE_OPENMP) && defined(PETSC_HAVE_THREADSAFETY)
248*3c611800SMark Adams   if (numthreads>MAX_NUM_THRDS) SETERRQ2(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Too many threads %D > %D", numthreads, MAX_NUM_THRDS);
249*3c611800SMark Adams   if (numthreads<=0) SETERRQ2(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "No threads %D > %D ", numthreads,  MAX_NUM_THRDS);
250*3c611800SMark Adams #endif
251*3c611800SMark Adams   if (target >= numthreads) target = numthreads-1;
252*3c611800SMark Adams   ierr = PetscLogEventRegister("Create Swarm", DM_CLASSID, &swarm_create_ev);CHKERRQ(ierr);
253*3c611800SMark Adams   ierr = PetscLogEventRegister("Single solve", DM_CLASSID, &solve_ev);CHKERRQ(ierr);
254*3c611800SMark Adams   ierr = PetscLogEventRegister("Solve loop", DM_CLASSID, &solve_loop_ev);CHKERRQ(ierr);
255*3c611800SMark Adams   ierr = PetscLogStageRegister("Solve", &stage);CHKERRQ(ierr);
256*3c611800SMark Adams   i    = dim;
257*3c611800SMark Adams   ierr = PetscOptionsGetIntArray(NULL, NULL, "-dm_plex_box_faces", faces, &i, NULL);CHKERRQ(ierr);
258*3c611800SMark Adams   i    = dim;
259*3c611800SMark Adams   ierr = PetscOptionsGetIntArray(NULL, NULL, "-np", Np,  &i, NULL);CHKERRQ(ierr);
260*3c611800SMark Adams   /* Create thread meshes */
261*3c611800SMark Adams   for (int tid=0; tid<numthreads; tid++) {
262*3c611800SMark Adams     // setup mesh dm_t, could use PETSc's Landau create velocity space mesh here to get dm_t[tid]
263*3c611800SMark Adams     ierr = DMCreate(PETSC_COMM_SELF, &dm_t[tid]);CHKERRQ(ierr);
264*3c611800SMark Adams     ierr = DMSetType(dm_t[tid], DMPLEX);CHKERRQ(ierr);
265*3c611800SMark Adams     ierr = DMSetFromOptions(dm_t[tid]);CHKERRQ(ierr);
266*3c611800SMark Adams     ierr = PetscFECreateDefault(PETSC_COMM_SELF, dim, Nc, PETSC_FALSE, "", PETSC_DECIDE, &fe);CHKERRQ(ierr);
267*3c611800SMark Adams     ierr = PetscFESetFromOptions(fe);CHKERRQ(ierr);
268*3c611800SMark Adams     ierr = PetscObjectSetName((PetscObject)fe, "fe");CHKERRQ(ierr);
269*3c611800SMark Adams     ierr = DMSetField(dm_t[tid], field, NULL, (PetscObject)fe);CHKERRQ(ierr);
270*3c611800SMark Adams     ierr = DMCreateDS(dm_t[tid]);CHKERRQ(ierr);
271*3c611800SMark Adams     ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
272*3c611800SMark Adams     // helper vectors
273*3c611800SMark Adams     ierr = DMSetOutputSequenceNumber(dm_t[tid], timestep, time);CHKERRQ(ierr); // not used
274*3c611800SMark Adams     ierr = DMCreateGlobalVector(dm_t[tid], &rho_t[tid]);CHKERRQ(ierr);
275*3c611800SMark Adams     ierr = DMCreateGlobalVector(dm_t[tid], &rhs_t[tid]);CHKERRQ(ierr);
276*3c611800SMark Adams     // this mimics application code
277*3c611800SMark Adams     ierr = DMGetBoundingBox(dm_t[tid], lo, hi);CHKERRQ(ierr);
278*3c611800SMark Adams     if (tid==target) {
279*3c611800SMark Adams       ierr = DMViewFromOptions(dm_t[tid], NULL, "-dm_view");CHKERRQ(ierr);
280*3c611800SMark Adams       for (i=0,vol=1;i<dim;i++) {
281*3c611800SMark Adams         h[i] = (hi[i] - lo[i])/faces[i];
282*3c611800SMark Adams         hp[i] = (hi[i] - lo[i])/Np[i];
283*3c611800SMark Adams         vol *= (hi[i] - lo[i]);
284*3c611800SMark Adams         ierr = PetscInfo5(dm_t[tid]," lo = %g hi = %g n = %D h = %g hp = %g\n",lo[i],hi[i],faces[i],h[i],hp[i]);CHKERRQ(ierr);
285*3c611800SMark Adams       }
286*3c611800SMark Adams     }
287*3c611800SMark Adams   }
288*3c611800SMark Adams   // prepare particle data for problems. This mimics application code
289*3c611800SMark Adams   ierr = PetscLogEventBegin(swarm_create_ev,0,0,0,0);CHKERRQ(ierr);
290*3c611800SMark Adams   Np2[0] = Np[0]; Np2[1] = Np[1];
291*3c611800SMark Adams   for (int tid=0; tid<numthreads; tid++) { // change size of particle list a little
292*3c611800SMark Adams     Np_t[tid] = Np2[0]*Np2[1];
293*3c611800SMark Adams     ierr = PetscMalloc3(Np_t[tid],&xx_t[tid],Np_t[tid],&yy_t[tid],Np_t[tid],&wp_t[tid]);CHKERRQ(ierr);
294*3c611800SMark Adams     if (tid==target) {moments_0[0] = moments_0[1] = moments_0[2] = 0;}
295*3c611800SMark Adams     for (int pi=0, pp=0;pi<Np2[0];pi++) {
296*3c611800SMark Adams       for (int pj=0;pj<Np2[1];pj++,pp++) {
297*3c611800SMark Adams         xx_t[tid][pp] = lo[0] + hp[0]/2. + pi*hp[0];
298*3c611800SMark Adams         yy_t[tid][pp] = lo[1] + hp[1]/2. + pj*hp[1];
299*3c611800SMark Adams         {
300*3c611800SMark Adams           PetscReal x[] = {xx_t[tid][pp],yy_t[tid][pp]};
301*3c611800SMark Adams           ierr = maxwellian(2, x, 1.0, vol/(PetscReal)Np_t[tid], &wp_t[tid][pp]);
302*3c611800SMark Adams         }
303*3c611800SMark Adams         if (tid==target) { //energy_0 += wp_t[tid][pp]*(PetscSqr(xx_t[tid][pp])+PetscSqr(yy_t[tid][pp]));
304*3c611800SMark Adams           moments_0[0] += wp_t[tid][pp];
305*3c611800SMark Adams           moments_0[1] += wp_t[tid][pp] * xx_t[tid][pp]; // x-momentum
306*3c611800SMark Adams           moments_0[2] += wp_t[tid][pp] * (PetscSqr(xx_t[tid][pp]) + PetscSqr(yy_t[tid][pp]));
307*3c611800SMark Adams         }
308*3c611800SMark Adams       }
309*3c611800SMark Adams     }
310*3c611800SMark Adams     Np2[0]++; Np2[1]++;
311*3c611800SMark Adams   }
312*3c611800SMark Adams   ierr = PetscLogEventEnd(swarm_create_ev,0,0,0,0);CHKERRQ(ierr);
313*3c611800SMark Adams   ierr = PetscLogEventBegin(solve_ev,0,0,0,0);CHKERRQ(ierr);
314*3c611800SMark Adams   /* Create particle swarm */
315*3c611800SMark Adams   PetscPragmaOMP(parallel for)
316*3c611800SMark Adams   for (int tid=0; tid<numthreads; tid++) {
317*3c611800SMark Adams     PetscErrorCode  ierr_t;
318*3c611800SMark Adams     ierr_t = createSwarm(dm_t[tid], &sw_t[tid]);
319*3c611800SMark Adams     if (ierr_t) ierr = ierr_t;
320*3c611800SMark Adams   }
321*3c611800SMark Adams   CHKERRQ(ierr);
322*3c611800SMark Adams   PetscPragmaOMP(parallel for)
323*3c611800SMark Adams   for (int tid=0; tid<numthreads; tid++) {
324*3c611800SMark Adams     PetscErrorCode  ierr_t;
325*3c611800SMark Adams     ierr_t = particlesToGrid(dm_t[tid], sw_t[tid], Np_t[tid], tid, dim, target, xx_t[tid], yy_t[tid], wp_t[tid], rho_t[tid], &M_p_t[tid]);
326*3c611800SMark Adams     if (ierr_t) ierr = ierr_t;
327*3c611800SMark Adams   }
328*3c611800SMark Adams   CHKERRQ(ierr);
329*3c611800SMark Adams   /* Project field to particles */
330*3c611800SMark Adams   /*   This gives f_p = M_p^+ M f */
331*3c611800SMark Adams   PetscPragmaOMP(parallel for)
332*3c611800SMark Adams   for (int tid=0; tid<numthreads; tid++) {
333*3c611800SMark Adams     PetscErrorCode  ierr_t;
334*3c611800SMark Adams     ierr_t = VecCopy(rho_t[tid], rhs_t[tid]); /* Identity: M^1 M rho */
335*3c611800SMark Adams     if (ierr_t) ierr = ierr_t;
336*3c611800SMark Adams   }
337*3c611800SMark Adams   CHKERRQ(ierr);
338*3c611800SMark Adams   PetscPragmaOMP(parallel for)
339*3c611800SMark Adams   for (int tid=0; tid<numthreads; tid++) {
340*3c611800SMark Adams     PetscErrorCode  ierr_t;
341*3c611800SMark Adams     ierr_t = gridToParticles(dm_t[tid], sw_t[tid], (tid==target) ?  moments_1 : NULL, rhs_t[tid], M_p_t[tid]);
342*3c611800SMark Adams     if (ierr_t) ierr = ierr_t;
343*3c611800SMark Adams   }
344*3c611800SMark Adams   CHKERRQ(ierr);
345*3c611800SMark Adams   /* Cleanup */
346*3c611800SMark Adams   for (int tid=0; tid<numthreads; tid++) {
347*3c611800SMark Adams     ierr = MatDestroy(&M_p_t[tid]);CHKERRQ(ierr);
348*3c611800SMark Adams     ierr = DMDestroy(&sw_t[tid]);CHKERRQ(ierr);
349*3c611800SMark Adams   }
350*3c611800SMark Adams   ierr = PetscLogEventEnd(solve_ev,0,0,0,0);CHKERRQ(ierr);
351*3c611800SMark Adams   /* for timing */
352*3c611800SMark Adams   ierr = PetscOptionsClearValue(NULL,"-ftop_ksp_converged_reason");CHKERRQ(ierr);
353*3c611800SMark Adams   ierr = PetscOptionsClearValue(NULL,"-ftop_ksp_monitor");CHKERRQ(ierr);
354*3c611800SMark Adams   ierr = PetscOptionsClearValue(NULL,"-ftop_ksp_view");CHKERRQ(ierr);
355*3c611800SMark Adams   ierr = PetscOptionsClearValue(NULL,"-info");CHKERRQ(ierr);
356*3c611800SMark Adams   // repeat solve many times to get warmed up data
357*3c611800SMark Adams   ierr = PetscLogStagePush(stage);CHKERRQ(ierr);
358*3c611800SMark Adams #if defined(PETSC_HAVE_OPENMP) && defined(PETSC_HAVE_THREADSAFETY)
359*3c611800SMark Adams   starttime = MPI_Wtime();
360*3c611800SMark Adams #endif
361*3c611800SMark Adams   ierr = PetscLogEventBegin(solve_loop_ev,0,0,0,0);CHKERRQ(ierr);
362*3c611800SMark Adams   for (int d=0; d<NUM_SOLVE_LOOPS; d++) {
363*3c611800SMark Adams   /* Create particle swarm */
364*3c611800SMark Adams     PetscPragmaOMP(parallel for)
365*3c611800SMark Adams     for (int tid=0; tid<numthreads; tid++) {
366*3c611800SMark Adams       PetscErrorCode  ierr_t;
367*3c611800SMark Adams       ierr_t = createSwarm(dm_t[tid], &sw_t[tid]);
368*3c611800SMark Adams       if (ierr_t) ierr = ierr_t;
369*3c611800SMark Adams     }
370*3c611800SMark Adams     CHKERRQ(ierr);
371*3c611800SMark Adams     PetscPragmaOMP(parallel for)
372*3c611800SMark Adams     for (int tid=0; tid<numthreads; tid++) {
373*3c611800SMark Adams       PetscErrorCode  ierr_t;
374*3c611800SMark Adams       ierr_t = particlesToGrid(dm_t[tid], sw_t[tid], Np_t[tid], tid, dim, target, xx_t[tid], yy_t[tid], wp_t[tid], rho_t[tid], &M_p_t[tid]);
375*3c611800SMark Adams       if (ierr_t) ierr = ierr_t;
376*3c611800SMark Adams     }
377*3c611800SMark Adams     CHKERRQ(ierr);
378*3c611800SMark Adams     PetscPragmaOMP(parallel for)
379*3c611800SMark Adams     for (int tid=0; tid<numthreads; tid++) {
380*3c611800SMark Adams       PetscErrorCode  ierr_t;
381*3c611800SMark Adams       ierr_t = VecCopy(rho_t[tid], rhs_t[tid]); /* Identity: M^1 M rho */
382*3c611800SMark Adams       if (ierr_t) ierr = ierr_t;
383*3c611800SMark Adams     }
384*3c611800SMark Adams     CHKERRQ(ierr);
385*3c611800SMark Adams     PetscPragmaOMP(parallel for)
386*3c611800SMark Adams     for (int tid=0; tid<numthreads; tid++) {
387*3c611800SMark Adams       PetscErrorCode  ierr_t;
388*3c611800SMark Adams       ierr_t = gridToParticles(dm_t[tid], sw_t[tid], NULL, rhs_t[tid], M_p_t[tid]);
389*3c611800SMark Adams       if (ierr_t) ierr = ierr_t;
390*3c611800SMark Adams     }
391*3c611800SMark Adams     CHKERRQ(ierr);
392*3c611800SMark Adams     /* Cleanup */
393*3c611800SMark Adams     for (int tid=0; tid<numthreads; tid++) {
394*3c611800SMark Adams       ierr = MatDestroy(&M_p_t[tid]);CHKERRQ(ierr);
395*3c611800SMark Adams       ierr = DMDestroy(&sw_t[tid]);CHKERRQ(ierr);
396*3c611800SMark Adams     }
397*3c611800SMark Adams   }
398*3c611800SMark Adams   ierr = PetscLogEventEnd(solve_loop_ev,0,0,0,0);CHKERRQ(ierr);
399*3c611800SMark Adams #if defined(PETSC_HAVE_OPENMP) && defined(PETSC_HAVE_THREADSAFETY)
400*3c611800SMark Adams   endtime = MPI_Wtime();
401*3c611800SMark Adams   solve_time += (endtime - starttime);
402*3c611800SMark Adams #endif
403*3c611800SMark Adams   ierr = PetscLogStagePop();CHKERRQ(ierr);
404*3c611800SMark Adams   //
405*3c611800SMark Adams   ierr = PetscPrintf(PETSC_COMM_SELF,"Total number density: %20.12e (%20.12e); x-momentum = %g (%g); energy = %g error = %e, %D particles. Use %D threads, Solve time: %g\n", moments_1[0], moments_0[0], moments_1[1], moments_0[1], moments_1[2], (moments_1[2]-moments_0[2])/moments_0[2],Np[0]*Np[1],numthreads,solve_time);CHKERRQ(ierr);
406*3c611800SMark Adams   /* Cleanup */
407*3c611800SMark Adams   for (int tid=0; tid<numthreads; tid++) {
408*3c611800SMark Adams     ierr = VecDestroy(&rho_t[tid]);CHKERRQ(ierr);
409*3c611800SMark Adams     ierr = VecDestroy(&rhs_t[tid]);CHKERRQ(ierr);
410*3c611800SMark Adams     ierr = DMDestroy(&dm_t[tid]);CHKERRQ(ierr);
411*3c611800SMark Adams     ierr = PetscFree3(xx_t[tid],yy_t[tid],wp_t[tid]);CHKERRQ(ierr);
412*3c611800SMark Adams   }
413*3c611800SMark Adams 
414*3c611800SMark Adams   PetscFunctionReturn(0);
415*3c611800SMark Adams }
416*3c611800SMark Adams 
417*3c611800SMark Adams int main(int argc, char **argv)
418*3c611800SMark Adams {
419*3c611800SMark Adams   PetscErrorCode  ierr;
420*3c611800SMark Adams   ierr = PetscInitialize(&argc, &argv, NULL,help);if (ierr) return ierr;
421*3c611800SMark Adams   ierr = go();CHKERRQ(ierr);
422*3c611800SMark Adams   ierr = PetscFinalize();
423*3c611800SMark Adams   return ierr;
424*3c611800SMark Adams }
425*3c611800SMark Adams 
426*3c611800SMark Adams /*TEST
427*3c611800SMark Adams 
428*3c611800SMark Adams   build:
429*3c611800SMark Adams     requires: !complex
430*3c611800SMark Adams 
431*3c611800SMark Adams   test:
432*3c611800SMark Adams     suffix: 0
433*3c611800SMark Adams     requires: double triangle
434*3c611800SMark Adams     args: -dm_plex_simplex 0 -dm_plex_box_faces 4,2 -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 -ftop_ksp_converged_reason -ftop_ksp_rtol 1.e-14
435*3c611800SMark Adams     filter: grep -v DM_ | grep -v atomic
436*3c611800SMark Adams 
437*3c611800SMark Adams   test:
438*3c611800SMark Adams     suffix: 1
439*3c611800SMark Adams     requires: double triangle
440*3c611800SMark Adams     args: -dm_plex_simplex 0 -dm_plex_box_faces 4,2 -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 -ftop_ksp_converged_reason -ftop_ksp_rtol 1.e-14
441*3c611800SMark Adams     filter: grep -v DM_ | grep -v atomic
442*3c611800SMark Adams 
443*3c611800SMark Adams   test:
444*3c611800SMark Adams     suffix: 2
445*3c611800SMark Adams     requires: double triangle
446*3c611800SMark Adams     args: -dm_plex_simplex 0 -dm_plex_box_faces 4,2 -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 cg -ftop_pc_type jacobi -dm_view -ftop_ksp_converged_reason -ftop_ksp_rtol 1.e-14
447*3c611800SMark Adams     filter: grep -v DM_ | grep -v atomic
448*3c611800SMark Adams 
449*3c611800SMark Adams TEST*/
450