SpM Handbook 1.2.4
Loading...
Searching...
No Matches
example_mdof1.c
Go to the documentation of this file.
1/**
2 *
3 * @file example_mdof1.c
4 *
5 * Example to show how to use the SPM library with a variadic 0-based multi-dof
6 * sparse matrix allocated through the library but initialized by the user.
7 *
8 * @copyright 2020-2024 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
9 * Univ. Bordeaux. All rights reserved.
10 *
11 * @version 1.2.4
12 * @author Mathieu Faverge
13 * @author Tony Delarue
14 * @date 2024-06-26
15 *
16 * @ingroup examples_c
17 * @code
18 **/
19#include <spm.h>
20
21/**
22 * @brief Create an IJV symmetric laplacian structure matrix for a regular cube of
23 * dimensions (dim1 x dim2 x dim3) and with 1-based values as in Fortran arrays.
24 */
25static inline void
26spm_example_fill_ijv_struct( spmatrix_t *spm,
27 spm_int_t dim1,
28 spm_int_t dim2,
29 spm_int_t dim3 )
30{
31 spm_int_t i, j, k, d, n, nnz;
32 spm_int_t mdim1, mdim2, mdim3;
33
34 mdim1 = dim1 - 1;
35 mdim2 = dim2 - 1;
36 mdim3 = dim3 - 1;
37 n = 0;
38 nnz = 0;
39 d = 0;
40 for( i = 0; i < dim1; i++ )
41 {
42 for( j = 0; j < dim2; j++ )
43 {
44 for( k = 0; k < dim3; k++ )
45 {
46 /*
47 * Start with the diagonal element connected with its two
48 * neigbours in the three directions
49 */
50 spm->rowptr[nnz] = i + dim1 * j + dim1 * dim2 * k;
51 spm->colptr[nnz] = i + dim1 * j + dim1 * dim2 * k;
52 nnz++;
53
54 spm->dofs[n] = d;
55 n++;
56
57 /* Number of degrees of freedom of the current element */
58 d += (( i + j + k ) % 3) + 1;
59
60 /* Add connexions */
61 if ( i < mdim1 ) {
62 spm->rowptr[nnz] = (i+1) + dim1 * j + dim1 * dim2 * k;
63 spm->colptr[nnz] = i + dim1 * j + dim1 * dim2 * k;
64 nnz++;
65 }
66
67 if ( j < mdim2 ) {
68 spm->rowptr[nnz] = i + dim1 * (j+1) + dim1 * dim2 * k;
69 spm->colptr[nnz] = i + dim1 * j + dim1 * dim2 * k;
70 nnz++;
71 }
72
73 if ( k < mdim3 ) {
74 spm->rowptr[nnz] = i + dim1 * j + dim1 * dim2 * (k+1);
75 spm->colptr[nnz] = i + dim1 * j + dim1 * dim2 * k;
76 nnz++;
77 }
78 }
79 }
80 }
81 /* Final value */
82 spm->dofs[n] = d;
83
84 assert( nnz == ((2*(dim1)-1) * dim2 * dim3 + (dim2-1)*dim1*dim3 + dim2*dim1*(dim3-1)) );
85}
86
87/**
88 * @brief Fill-in the values array of a variadic dof IJV sparse matrix.
89 */
90static inline void
91spm_example_fill_ijv_values( spmatrix_t *spm,
92 spm_int_t dim1,
93 spm_int_t dim2,
94 spm_int_t dim3 )
95{
96 spm_int_t v, l, i, j, k, m, n;
97 spm_int_t mdim1, mdim2, mdim3;
98 spm_int_t row, col, dofrow, dofcol;
99 double *values = spm->values;
100 double alpha = 8.;
101 double beta = 0.5;
102 double value;
103
104 mdim1 = dim1 - 1;
105 mdim2 = dim2 - 1;
106 mdim3 = dim3 - 1;
107 v = 0;
108 for( l=0; l<spm->nnz; l++ )
109 {
110 /* Get indices in the mesh */
111 k = l / ( dim1 * dim2 );
112 j = (l % ( dim1 * dim2 )) / dim1;
113 i = l % dim1;
114
115 col = spm->colptr[l];
116 row = spm->rowptr[l];
117 dofcol = spm->dofs[ col+1 ] - spm->dofs[ col ];
118 dofrow = spm->dofs[ row+1 ] - spm->dofs[ row ];
119
120 /* diagonal element */
121 if ( col == row ) {
122 value = 6.;
123
124 /*
125 * Handle limit cases
126 */
127 if ( i == 0 ) { value -= 1.; }
128 if ( i == mdim1 ) { value -= 1.; }
129 if ( j == 0 ) { value -= 1.; }
130 if ( j == mdim2 ) { value -= 1.; }
131 if ( k == 0 ) { value -= 1.; }
132 if ( k == mdim3 ) { value -= 1.; }
133
134 value *= alpha;
135 }
136 else {
137 value = - beta;
138 }
139
140 /* Fill the element matrix */
141 for ( n=0; n<dofcol; n++ ) {
142 for ( m=0; m<dofrow; m++ ) {
143 values[v] = value;
144 v++;
145 }
146 }
147 }
148
149 assert( v == spm->nnzexp );
150}
151
152/**
153 * @brief Create a laplacian manually
154 */
155void
156spm_example_create_laplacian( spmatrix_t *spm )
157{
158 spm_int_t dim1, dim2, dim3;
159 dim1 = 6;
160 dim2 = 6;
161 dim3 = 6;
162
163 /*
164 * Initialize all non computed fields.
165 */
166 spmInit( spm );
167
168 /*
169 * Set the fields according to what we want to generate.
170 * All non computed fields must be set.
171 */
172 spm->baseval = 0;
173 spm->mtxtype = SpmSymmetric;
174 spm->flttype = SpmPattern;
175 spm->fmttype = SpmIJV;
176 spm->n = dim1 * dim2 * dim3;
177 spm->nnz = dim1 * dim2 * dim3; /* Diagonal elements */
178 spm->nnz += (dim1 - 1) * dim2 * dim3; /* Connexions along first axe */
179 spm->nnz += dim1 * (dim2 - 1) * dim3; /* Connexions along second axe */
180 spm->nnz += dim1 * dim2 * (dim3 - 1); /* Connexions along third axe */
181
182 /* The full matrix is replicated on all nodes */
183 spm->replicated = 1;
184
185 /* Force gN to allocate dof array in spmAlloc() */
186 spm->gN = spm->n;
187 spm->dof = -1;
188
189 /*
190 * Let's allocate first only the structure arrays
191 * That is why we set flttype to SpmPattern
192 */
193 spmAlloc( spm );
194
195 /*
196 * Fill the structure arrays with the generator.
197 */
198 spm_example_fill_ijv_struct( spm, dim1, dim2, dim3 );
199
200 /*
201 * Update the computed fields now that the dofs arrays is initialized.
202 */
204
205 /*
206 * Switch to the arithmetic type of interest and allocate the value array
207 */
208 spm->layout = SpmColMajor; /* Storage of the element matrices */
209 spm->flttype = SpmDouble;
210 spmAlloc( spm );
211
212 /*
213 * Fill the value array with the generator.
214 */
215 spm_example_fill_ijv_values( spm, dim1, dim2, dim3 );
216}
217
218int main( int argc, char **argv )
219{
220 spmatrix_t spm;
221 spm_int_t nrhs = 10;
222 double alpha = 2.;
223 spm_int_t size, ldb, ldx;
224 double epsilon, norm;
225 void *x, *b;
226 int rc = 0;
227
228 /*
229 * MPI need to be initialize before any call to spm library if it has been
230 * compiled wth MPI support.
231 */
232#if defined(SPM_WITH_MPI)
233 MPI_Init( &argc, &argv );
234#endif
235
236 /*
237 * Create a user made sparse matrix.
238 */
239 spm_example_create_laplacian( &spm );
240
241 /*
242 * Print basic information about the sparse matrix
243 */
244 spmPrintInfo( &spm, stdout );
245
246 /*
247 * Possibly convert the SPM into another format (CSC may be needed for a few routines)
248 */
249 spmConvert( SpmCSC, &spm );
250
251 /*
252 * Compute the frobenius norm of the spm
253 */
254 norm = spmNorm( SpmFrobeniusNorm, &spm );
255 fprintf( stdout, " || A ||_f: %e\n", norm );
256
257 /*
258 * Scale the sparse matrix.
259 */
260 if ( norm > 0. ) {
261 spmScal( 1. / norm, &spm );
262 }
263
264 /*
265 * Create a random matrix x to test products (multiple right hand side).
266 * Note that you can get the size to allocate with spm_size_of() that
267 * returns the size of each value.
268 */
269 ldb = spm.nexp > 1 ? spm.nexp : 1;
270 ldx = spm.nexp > 1 ? spm.nexp : 1;
271 size = spm_size_of( spm.flttype ) * spm.nexp * nrhs;
272 x = malloc( size );
273 rc = spmGenMat( SpmRhsRndX, nrhs, &spm, &alpha, 24356, x, ldx );
274 if ( rc != SPM_SUCCESS ) {
275 free( x );
276 spmExit( &spm );
277 return rc;
278 }
279
280 /*
281 * Compute b = A * x
282 */
283 b = malloc( size );
284 spmMatMat( SpmNoTrans, nrhs, 1., &spm, x, ldx, 0., b, ldb );
285
286 /*
287 * The following routines helps to check results obtained out of solvers by
288 * computing b = b - A * x with a given precision.
289 */
290 if ( (spm.flttype == SpmDouble ) ||
291 (spm.flttype == SpmComplex64) )
292 {
293 epsilon = 1e-15;
294 }
295 else {
296 epsilon = 1e-7;
297 }
298 epsilon = epsilon * spm.nnzexp / spm.gN;
299 rc = spmCheckAxb( epsilon, nrhs, &spm, NULL, 1, b, ldb, x, ldx );
300
301 free( x );
302 free( b );
303 spmExit( &spm );
304
305#if defined(SPM_WITH_MPI)
306 MPI_Finalize();
307#endif
308
309 (void)argc;
310 (void)argv;
311 return rc;
312}
313/**
314 * @endcode
315 */
static size_t spm_size_of(spm_coeftype_t type)
Double datatype that is not converted through precision generator functions.
Definition datatypes.h:209
@ SPM_SUCCESS
Definition const.h:82
@ SpmNoTrans
Definition const.h:155
@ SpmColMajor
Definition const.h:148
@ SpmComplex64
Definition const.h:66
@ SpmDouble
Definition const.h:64
@ SpmPattern
Definition const.h:62
@ SpmSymmetric
Definition const.h:166
@ SpmCSC
Definition const.h:73
@ SpmIJV
Definition const.h:75
@ SpmFrobeniusNorm
Definition const.h:200
spm_coeftype_t flttype
Definition spm.h:67
spm_int_t * dofs
Definition spm.h:85
spm_int_t nexp
Definition spm.h:78
void * values
Definition spm.h:92
spm_int_t nnz
Definition spm.h:75
spm_int_t nnzexp
Definition spm.h:80
spm_int_t * rowptr
Definition spm.h:90
spm_fmttype_t fmttype
Definition spm.h:69
spm_int_t dof
Definition spm.h:82
spm_int_t n
Definition spm.h:73
spm_mtxtype_t mtxtype
Definition spm.h:65
spm_layout_t layout
Definition spm.h:87
spm_int_t baseval
Definition spm.h:71
spm_int_t * colptr
Definition spm.h:89
spm_int_t gN
Definition spm.h:72
int replicated
Definition spm.h:98
void spmAlloc(spmatrix_t *spm)
Allocate the arrays of an spm structure.
Definition spm.c:175
void spmExit(spmatrix_t *spm)
Cleanup the spm structure but do not free the spm pointer.
Definition spm.c:224
void spmUpdateComputedFields(spmatrix_t *spm)
Update all the computed fields based on the static values stored.
int spm_int_t
The main integer datatype used in spm arrays.
Definition datatypes.h:70
int spmCheckAxb(double eps, spm_int_t nrhs, const spmatrix_t *spm, void *opt_X0, spm_int_t opt_ldx0, void *B, spm_int_t ldb, const void *X, spm_int_t ldx)
Check the backward error, and the forward error if x0 is provided.
Definition spm.c:1423
int spmConvert(int ofmttype, spmatrix_t *ospm)
Convert the storage format of the spm.
Definition spm.c:418
int spmMatMat(spm_trans_t trans, spm_int_t n, double alpha, const spmatrix_t *A, const void *B, spm_int_t ldb, double beta, void *C, spm_int_t ldc)
Compute a matrix-matrix product.
Definition spm.c:1327
void spmScal(double alpha, spmatrix_t *spm)
Scale the spm.
Definition spm.c:1481
double spmNorm(spm_normtype_t ntype, const spmatrix_t *spm)
Compute the norm of the spm.
Definition spm.c:514
void spmInit(spmatrix_t *spm)
Init the spm structure.
Definition spm.c:152
int spmGenMat(spm_rhstype_t type, spm_int_t nrhs, const spmatrix_t *spm, void *alpha, unsigned long long int seed, void *A, spm_int_t lda)
Generate a set of vectors associated to a given matrix.
Definition spm.c:1732
void spmPrintInfo(const spmatrix_t *spm, FILE *f)
Print basic informations about the spm matrix into a given stream.
Definition spm.c:1026
The sparse matrix data structure.
Definition spm.h:64