xref: /petsc/src/mat/tutorials/ex18.c (revision 8cc725e69398de546bdc828d7b714aa2223f5218)
1 static char help[] = "Demonstrates the use of the COO interface to PETSc matrices for finite element computations\n\n";
2 
3 /*
4      The COO interface for PETSc matrices provides a convenient way to provide finite element element stiffness matrices to PETSc matrix that should work
5    well on both CPUs and GPUs. It is an alternative to using MatSetValues()
6 
7      This example is intended for people who are NOT using DMPLEX or libCEED or any other higher-level infrastructure for finite elements;
8    it is only to demonstrate the concepts in a simple way for those people who are interested and for those people who are using PETSc for
9    linear algebra solvers but are managing their own finite element process.
10 
11      Please do NOT use this example as a starting point to writing your own finite element code from scratch!
12 
13      Each element in this example has three vertices; hence the the usage below needs to be adjusted for elements of a different number of vertices.
14 */
15 
16 #include <petscmat.h>
17 #include "ex18.h"
18 
19 static PetscErrorCode CreateFEStruct(FEStruct *fe)
20 {
21   PetscFunctionBeginUser;
22   fe->Nv = 5;
23   fe->Ne = 3;
24   PetscCall(PetscMalloc1(3*fe->Ne,&fe->vertices));
25   /* the three vertices associated with each element in order of element */
26   fe->vertices[0 + 0] = 0;
27   fe->vertices[0 + 1] = 1;
28   fe->vertices[0 + 2] = 2;
29   fe->vertices[3 + 0] = 2;
30   fe->vertices[3 + 1] = 1;
31   fe->vertices[3 + 2] = 3;
32   fe->vertices[6 + 0] = 2;
33   fe->vertices[6 + 1] = 4;
34   fe->vertices[6 + 2] = 3;
35   fe->n  = 5;
36   PetscFunctionReturn(0);
37 }
38 
39 static PetscErrorCode DestroyFEStruct(FEStruct *fe)
40 {
41   PetscFunctionBeginUser;
42   PetscCall(PetscFree(fe->vertices));
43   PetscCall(PetscFree(fe->coo));
44   PetscFunctionReturn(0);
45 }
46 
47 static PetscErrorCode CreateMatrix(FEStruct *fe,Mat *A)
48 {
49   PetscInt *oor,*ooc,cnt = 0;
50 
51   PetscFunctionBeginUser;
52   PetscCall(MatCreate(PETSC_COMM_WORLD,A));
53   PetscCall(MatSetSizes(*A,fe->n,fe->n,PETSC_DECIDE,PETSC_DECIDE));
54   PetscCall(MatSetFromOptions(*A));
55 
56   /* determine for each entry in each element stiffness matrix the global row and colum */
57   /* since the element is triangular with piecewise linear basis functions there are three degrees of freedom per element, one for each vertex */
58   PetscCall(PetscMalloc2(3*3*fe->Ne,&oor,3*3*fe->Ne,&ooc));
59   for (PetscInt e=0; e<fe->Ne; e++) {
60     for (PetscInt vi=0; vi<3; vi++) {
61       for (PetscInt vj=0; vj<3; vj++) {
62         oor[cnt]   = fe->vertices[3*e+vi];
63         ooc[cnt++] = fe->vertices[3*e+vj];
64       }
65     }
66   }
67   PetscCall(MatSetPreallocationCOO(*A,3*3*fe->Ne,oor,ooc));
68   PetscCall(PetscFree2(oor,ooc));
69 
70   /* determine the offset into the COO value array the offset of each element stiffness; there are 9 = 3*3 entries for each element stiffness */
71   /* for lists of elements with different numbers of degrees of freedom assocated with each element the offsets will not be uniform */
72   PetscCall(PetscMalloc1(fe->Ne,&fe->coo));
73   fe->coo[0] = 0;
74   for (PetscInt e=1; e<fe->Ne; e++) {
75     fe->coo[e] = fe->coo[e-1] + 3*3;
76   }
77   PetscFunctionReturn(0);
78 }
79 
80 static PetscErrorCode FillMatrixCPU(FEStruct *fe,Mat A)
81 {
82   PetscScalar s[9];
83 
84   PetscFunctionBeginUser;
85   /* simulation of traditional PETSc CPU based finite assembly process */
86   for (PetscInt e=0; e<fe->Ne; e++) {
87     for (PetscInt vi=0; vi<3; vi++) {
88       for (PetscInt vj=0; vj<3; vj++) {
89         s[3*vi+vj] = vi+2*vj;
90       }
91     }
92     PetscCall(MatSetValues(A,3,fe->vertices + 3*e,3, fe->vertices + 3*e,s,ADD_VALUES));
93   }
94   PetscCall(MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY));
95   PetscCall(MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY));
96   PetscFunctionReturn(0);
97 }
98 
99 /*
100    Shows an example of tracking element offsets explicitly, which allows for
101    mixed-topology meshes and combining both volume and surface parts into the weak form.
102 */
103 static PetscErrorCode FillMatrixCPUCOO(FEStruct *fe,Mat A)
104 {
105   PetscScalar *v,*s;
106 
107   PetscFunctionBeginUser;
108   /* simulation of CPU based finite assembly process with COO */
109   PetscCall(PetscMalloc1(3*3*fe->Ne,&v));
110   for (PetscInt e=0; e<fe->Ne; e++) {
111     s = v + fe->coo[e]; /* point to location in COO of current element stiffness */
112     for (PetscInt vi=0; vi<3; vi++) {
113       for (PetscInt vj=0; vj<3; vj++) {
114         s[3*vi+vj] = vi+2*vj;
115       }
116     }
117   }
118   PetscCall(MatSetValuesCOO(A,v,ADD_VALUES));
119   PetscCall(PetscFree(v));
120   PetscFunctionReturn(0);
121 }
122 
123 /*
124   Uses a multi-dimensional indexing technique that works for homogeneous meshes
125   such as single-topology with volume integral only.
126 */
127 static PetscErrorCode FillMatrixCPUCOO3d(FEStruct *fe,Mat A)
128 {
129   PetscScalar (*s)[3][3];
130 
131   PetscFunctionBeginUser;
132   /* simulation of CPU based finite assembly process with COO */
133   PetscCall(PetscMalloc1(fe->Ne,&s));
134   for (PetscInt e=0; e<fe->Ne; e++) {
135     for (PetscInt vi=0; vi<3; vi++) {
136       for (PetscInt vj=0; vj<3; vj++) {
137         s[e][vi][vj] = vi+2*vj;
138       }
139     }
140   }
141   PetscCall(MatSetValuesCOO(A,(PetscScalar*)s,INSERT_VALUES));
142   PetscCall(PetscFree(s));
143   PetscFunctionReturn(0);
144 }
145 
146 int main(int argc, char **args)
147 {
148   Mat             A;
149   FEStruct        fe;
150   PetscMPIInt     size;
151   PetscBool       is_kokkos,is_cuda;
152 
153   PetscCall(PetscInitialize(&argc,&args,(char*)0,help));
154   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD,&size));
155   PetscCheck(size <= 1,PETSC_COMM_WORLD,PETSC_ERR_WRONG_MPI_SIZE,"Demonstration is only for sequential runs");
156 
157   PetscCall(CreateFEStruct(&fe));
158   PetscCall(CreateMatrix(&fe,&A));
159 
160   PetscCall(FillMatrixCPU(&fe,A));
161   PetscCall(MatView(A,PETSC_VIEWER_STDOUT_WORLD));
162 
163   PetscCall(MatZeroEntries(A));
164   PetscCall(FillMatrixCPUCOO(&fe,A));
165   PetscCall(MatView(A,PETSC_VIEWER_STDOUT_WORLD));
166 
167   PetscCall(MatZeroEntries(A));
168   PetscCall(FillMatrixCPUCOO3d(&fe,A));
169   PetscCall(MatView(A,PETSC_VIEWER_STDOUT_WORLD));
170 
171   PetscCall(MatZeroEntries(A));
172   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A,MATSEQAIJKOKKOS,&is_kokkos));
173   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A,MATSEQAIJCUSPARSE,&is_cuda));
174  #if defined(PETSC_HAVE_KOKKOS)
175   if (is_kokkos) PetscCall(FillMatrixKokkosCOO(&fe,A));
176  #endif
177  #if defined(PETSC_HAVE_CUDA)
178   if (is_cuda) PetscCall(FillMatrixCUDACOO(&fe,A));
179  #endif
180   PetscCall(MatView(A,PETSC_VIEWER_STDOUT_WORLD));
181 
182   PetscCall(MatDestroy(&A));
183   PetscCall(DestroyFEStruct(&fe));
184   PetscCall(PetscFinalize());
185   return 0;
186 }
187 
188 /*TEST
189   build:
190     requires: cuda kokkos_kernels
191     depends: ex18cu.cu ex18kok.kokkos.cxx
192 
193   testset:
194     filter: grep -v "type"
195     output_file: output/ex18_1.out
196 
197     test:
198       suffix: kok
199       requires: kokkos_kernels
200       args: -mat_type aijkokkos
201 
202     test:
203       suffix: cuda
204       requires: cuda
205       args: -mat_type aijcusparse
206 
207 TEST*/
208