SpM Handbook 1.2.4
Loading...
Searching...
No Matches
spm_scatter.c
Go to the documentation of this file.
1/**
2 *
3 * @file spm_scatter.c
4 *
5 * SParse Matrix scatter routine.
6 *
7 * @copyright 2020-2024 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
8 * Univ. Bordeaux. All rights reserved.
9 *
10 * @version 1.2.4
11 * @author Tony Delarue
12 * @author Mathieu Faverge
13 * @author Alycia Lisito
14 * @date 2024-07-02
15 *
16 * @ingroup spm_dev_mpi
17 * @{
18 *
19 **/
20#include "common.h"
21
22/*
23 * Structure of the functions in this file
24 *
25 * spmScatter (user level)
26 * - spm_scatter_init Initialize the new spm structure
27 * - spm_scatter_create_loc2glob Create basic loc2glob if needed
28 * - spm_scatter_getn
29 * - spm_scatter_[csx|ijv]_get_locals Compute the local values
30 * - spmUpdateComputedFields
31 * - Scatter according to format
32 * - spm_scatter_csx
33 * - Scatter from all nodes
34 * - spm_scatter_csx_local_continuous Continuous loc2glob
35 * - spm_scatter_csx_local_generic Generic loc2glob
36 * - Scatter from one node
37 * - spm_scatter_csx_send Send function
38 * - spm_scatter_csx_send_continuous Send for Continuous loc2glob
39 * - spm_scatter_csx_send_generic Send for Generic loc2glob
40 * - spm_scatter_csx_recv Recv function
41 * - spm_scatter_ijv
42 * - spm_scatter_ijv_local Scatter from all nodes
43 * - Scatter from a single node
44 * - spm_scatter_ijv_send Sender function
45 * - spm_scatter_ijv_remote Equivalent to _local function to init remote spm
46 * - spm_scatter_ijv_recv Receiver function
47 */
48#if !defined(SPM_WITH_MPI)
49#error "This file should not be compiled if MPI support is not enabled (SPM_WITH_MPI)"
50#endif
51
52/**
53 *******************************************************************************
54 *
55 * @brief Gather the n values from all nodes
56 *
57 *******************************************************************************
58 *
59 * @param[in] spm
60 * The newspm that will be generated with the n field correctly set.
61 *
62 * @param[inout] allcounts
63 * On entry, the array must be allocated.
64 * On exit, stores the {n, nnz, nnzexp} information for all nodes.
65 *
66 * @param[in] root
67 * The root process of the scatter operation. -1 if everyone hold a
68 * copy of the oldspm.
69 *
70 *******************************************************************************/
71static inline void
73 spm_int_t *allcounts,
74 int root )
75{
76 /* Collect the number of elements per node */
77 if ( root == -1 ) {
78 MPI_Allgather( &(spm->n), 1, SPM_MPI_INT,
79 allcounts, 1, SPM_MPI_INT, spm->comm );
80 }
81 else {
82 MPI_Gather( &(spm->n), 1, SPM_MPI_INT,
83 allcounts, 1, SPM_MPI_INT, root, spm->comm );
84 }
85
86 if ( allcounts ) {
87 int c;
88 for ( c=spm->clustnbr-1; c>0; c-- ) {
89 allcounts[ 3 * c ] = allcounts[c];
90 allcounts[ c ] = 0;
91 }
92 }
93 return;
94}
95
96/**
97 *******************************************************************************
98 *
99 * @brief Compute the allcounts array with CSC/CSR formats
100 *
101 *******************************************************************************
102 *
103 * @param[in] oldspm
104 * The input sparse matrix to scatter in the CSC or CSR format.
105 *
106 * @param[inout] newspm
107 * The allocated and spmInit() spm in which to store the local information.
108 * On entry, n and loc2glob must be specified.
109 * On exit, nnz and nnzexp fields are updated.
110 *
111 * @param[inout] allcounts
112 * On entry, the array must be allocated.
113 * On exit, stores the {n, nnz, nnzexp} information for all nodes.
114 *
115 * @param[in] root
116 * The root process of the scatter operation. -1 if everyone hold a
117 * copy of the oldspm.
118 *
119 *******************************************************************************/
120static inline void
122 spmatrix_t *newspm,
123 spm_int_t *allcounts,
124 int root )
125{
126 spm_int_t c, ig, jg, kg, nnz, nnzexp;
127 spm_int_t dofj;
128 const spm_int_t *oldcol;
129 const spm_int_t *oldrow;
130 const spm_int_t *glob2loc;
131 const spm_int_t *dofs;
132 spm_int_t baseval = newspm->baseval;
133
134 /*
135 * Make sure the gN field is set before calling glob2loc to avoid possible
136 * issue with spmUpdateComputedFields()
137 */
138 assert( newspm->gN > 0 );
139
140 /*
141 * Initialize glob2loc collaborately before non involved processes return from the function.
142 * The pointer is shifted to avoid extra baseval computations
143 */
144 glob2loc = spm_getandset_glob2loc( newspm );
145 glob2loc -= baseval;
146
147 if ( !allcounts ) {
148 spm_int_t counters[3];
149
150 assert( root != -1 );
151 MPI_Scatter( NULL, 3, SPM_MPI_INT,
152 counters, 3, SPM_MPI_INT,
153 root, newspm->comm );
154
155 assert( newspm->n == counters[0] );
156 newspm->nnz = counters[1];
157 newspm->nnzexp = counters[2];
158 return;
159 }
160
161 assert( oldspm );
162 dofs = oldspm->dofs - baseval;
163 oldcol = (oldspm->fmttype == SpmCSC) ? oldspm->colptr : oldspm->rowptr;
164 oldrow = (oldspm->fmttype == SpmCSC) ? oldspm->rowptr : oldspm->colptr;
165
166 for ( jg=baseval; jg<oldspm->n+baseval; jg++, oldcol++ )
167 {
168 /* Get the owner */
169 c = - glob2loc[jg];
170 if ( c <= 0 ) {
171 c = newspm->clustnum;
172 }
173 else {
174 c--;
175 }
176
177 /* Get the dof of column jg */
178 if ( newspm->dof > 0 ) {
179 dofj = newspm->dof;
180 }
181 else {
182 dofj = dofs[ jg+1 ] - dofs[ jg ];
183 }
184
185 nnz = 0;
186 nnzexp = 0;
187 for( kg = oldcol[0]; kg<oldcol[1]; kg++, oldrow++ )
188 {
189 ig = *oldrow;
190
191 /* Compute the number of non-zeroes compressed and expanded per column */
192 nnz++;
193 if ( newspm->dof <= 0 ) {
194 nnzexp += dofs[ ig+1 ] - dofs[ ig ];
195 }
196 else {
197 nnzexp += newspm->dof;
198 }
199 }
200
201 /* Count nnz and nnzexp */
202 allcounts[ c * 3 + 1 ] += nnz;
203 allcounts[ c * 3 + 2 ] += nnzexp * dofj;
204 }
205
206 /* Send the information to nodes who do not own the oldspm */
207 if ( root == newspm->clustnum ) {
208 spm_int_t counters[3];
209
210 MPI_Scatter( allcounts, 3, SPM_MPI_INT,
211 counters, 3, SPM_MPI_INT,
212 root, newspm->comm );
213 }
214
215 /* Store the local information */
216 newspm->nnz = allcounts[ newspm->clustnum * 3 + 1 ];
217 newspm->nnzexp = allcounts[ newspm->clustnum * 3 + 2 ];
218
219 return;
220}
221
222/**
223 *******************************************************************************
224 *
225 * @brief Compute the allcounts array with IJV format
226 *
227 *******************************************************************************
228 *
229 * @param[in] oldspm
230 * The input sparse matrix to scatter in the CSC or CSR format.
231 *
232 * @param[inout] newspm
233 * The allocated and spmInit() spm in which to store the local information.
234 * On entry, n and loc2glob must be specified.
235 * On exit, nnz and nnzexp fields are updated.
236 *
237 * @param[in] distByColumn
238 * Boolean to decide if the matrix is distributed by rows or columns.
239 * If false, distribution by rows. If true, distribution by columns.
240 *
241 * @param[inout] allcounts
242 * On entry, the array must be allocated.
243 * On exit, stores the {n, nnz, nnzexp} information for all nodes.
244 *
245 * @param[in] root
246 * The root process of the scatter operation. -1 if everyone hold a
247 * copy of the oldspm.
248 *
249 *******************************************************************************/
250static inline void
252 spmatrix_t *newspm,
253 int distByColumn,
254 spm_int_t *allcounts,
255 int root )
256{
257 spm_int_t c, ig, jg, kg, nnz;
258 spm_int_t dof2, dofi, dofj;
259 const spm_int_t *oldcol;
260 const spm_int_t *oldrow;
261 const spm_int_t *glob2loc = spm_getandset_glob2loc( newspm );
262 const spm_int_t *dofs;
263 spm_int_t baseval = newspm->baseval;
264
265 /* Shift the pointer to avoid extra baseval computations */
266 glob2loc -= baseval;
267
268 if ( !allcounts ) {
269 spm_int_t counters[3];
270
271 assert( root != -1 );
272 MPI_Scatter( NULL, 3, SPM_MPI_INT,
273 counters, 3, SPM_MPI_INT,
274 root, newspm->comm );
275
276 assert( newspm->n == counters[0] );
277 newspm->nnz = counters[1];
278 newspm->nnzexp = counters[2];
279 return;
280 }
281
282 assert( oldspm );
283 dofs = oldspm->dofs - baseval;
284 oldcol = distByColumn ? oldspm->colptr : oldspm->rowptr;
285 oldrow = distByColumn ? oldspm->rowptr : oldspm->colptr;
286
287 dof2 = newspm->dof * newspm->dof;
288
289 for ( kg=0; kg<oldspm->nnz; kg++, oldcol++, oldrow++ )
290 {
291 ig = *oldrow;
292 jg = *oldcol;
293 c = glob2loc[jg];
294
295 if ( c >= 0 ) {
296 c = newspm->clustnum;
297 }
298 else {
299 c = (-c - 1);
300 }
301
302 if ( newspm->dof > 0 ) {
303 nnz = dof2;
304 }
305 else {
306 dofi = dofs[ ig+1 ] - dofs[ ig ];
307 dofj = dofs[ jg+1 ] - dofs[ jg ];
308 nnz = dofi * dofj;
309 }
310
311 /* Count nnz and nnzexp */
312 allcounts[ c * 3 + 1 ]++;
313 allcounts[ c * 3 + 2 ] += nnz;
314 }
315
316 /* Send the information to nodes who do not own the oldspm */
317 if ( root == newspm->clustnum ) {
318 spm_int_t counters[3];
319
320 MPI_Scatter( allcounts, 3, SPM_MPI_INT,
321 counters, 3, SPM_MPI_INT,
322 root, newspm->comm );
323 }
324
325 /* Store the local information */
326 newspm->nnz = allcounts[ newspm->clustnum * 3 + 1 ];
327 newspm->nnzexp = allcounts[ newspm->clustnum * 3 + 2 ];
328
329 return;
330}
331
332/**
333 *******************************************************************************
334 *
335 * @brief Generic function to initialize a scattered spm on each node.
336 *
337 *******************************************************************************
338 *
339 * @param[inout] newspm
340 * On entry, an allocated spm structure. Must be provided by all
341 * participants.
342 * On exit, contains the local part of the scattered spm.
343 *
344 * @param[in] oldspm
345 * The input sparse matrix to scatter in the CSC or CSR format.
346 *
347 * @param[in] n
348 * The local loc2glob size if provided. Unused if spm->replicated
349 *
350 * @param[in] loc2glob
351 * The indices of the local unknowns in the scattered spm. Must be of
352 * size n if provided. If NULL, the spm is scattered with equal chunks
353 * of unknowns.
354 *
355 * @param[in] distByColumn
356 * Boolean to decide if the matrix is distributed by rows or columns.
357 * If false, distribution by rows. If true, distribution by columns.
358 *
359 * @param[out] allcounts
360 * Pointer to an array of triplet {n, nnz, nnzexp} per node allocated
361 * by this call.
362 *
363 * @param[in] root
364 * The root process of the scatter operation. -1 if everyone hold a
365 * copy of the oldspm.
366 *
367 * @param[in] clustnum
368 * Local MPI procnum index in the communicator comm.
369 *
370 * @param[in] comm
371 * The MPI communicator on which to distribute the SPM.
372 *
373 *******************************************************************************/
374static inline void
376 const spmatrix_t *oldspm,
377 int n,
378 const spm_int_t *loc2glob,
379 int distByColumn,
380 spm_int_t **allcounts,
381 int root,
382 int clustnum,
383 SPM_Comm comm )
384{
385 spm_int_t baseval;
386 int clustnbr;
387 int alloc = (root == -1) || (root == clustnum);
388
389 MPI_Comm_size( comm, &clustnbr );
390
391 spmInit( newspm );
392
393 /* Copy what can be copied from the global spm, and init baseval */
394 if ( root == -1 ) {
395 memcpy( newspm, oldspm, sizeof(spmatrix_t) );
396 baseval = oldspm->baseval;
397 }
398 else {
399 if ( root == clustnum ) {
400 memcpy( newspm, oldspm, sizeof(spmatrix_t) );
401 baseval = oldspm->baseval;
402 }
403 MPI_Bcast( newspm, sizeof(spmatrix_t), MPI_BYTE, root, comm );
404 MPI_Bcast( &baseval, 1, SPM_MPI_INT, root, comm );
405 }
406
407 /* Reset pointers */
408 newspm->baseval = baseval;
409 newspm->dofs = NULL;
410 newspm->colptr = NULL;
411 newspm->rowptr = NULL;
412 newspm->loc2glob = NULL;
413 newspm->values = NULL;
414
415 /* Set local ditribution informations */
416 newspm->comm = comm;
417 newspm->clustnum = clustnum;
418 newspm->clustnbr = clustnbr;
419
420 /* Initialize the loc2glob array */
421 if( loc2glob != NULL ) {
422 newspm->loc2glob = (spm_int_t*)malloc( n * sizeof(spm_int_t) );
423 memcpy( newspm->loc2glob, loc2glob, n * sizeof(spm_int_t) );
424 }
425 else {
426 n = spm_create_loc2glob_continuous( newspm, &(newspm->loc2glob) );
427 }
428 newspm->replicated = 0;
429
430 /* Set local values */
431 if ( alloc ) {
432 *allcounts = calloc( 3 * newspm->clustnbr, sizeof(spm_int_t) );
433 }
434 else {
435 *allcounts = NULL;
436 }
437
438 /* Collect the triplets (n, nnz, nnzexp) from all nodes on root(s) */
439 newspm->n = n;
440 newspm->nnz = 0;
441 newspm->nnzexp = 0;
442 spm_scatter_getn( newspm, *allcounts, root );
443
444 if ( newspm->fmttype == SpmIJV ) {
445 spm_scatter_ijv_get_locals( oldspm, newspm, distByColumn,
446 *allcounts, root );
447 }
448 else {
449 spm_scatter_csx_get_locals( oldspm, newspm,
450 *allcounts, root );
451 }
452
453 /* Perform an initial allocation with given datas */
454 spmAlloc( newspm );
455
456 /* Take care of the dof array */
457 if ( newspm->dof < 1 ) {
458 if ( root == -1 ) {
459 memcpy( newspm->dofs, oldspm->dofs, (newspm->gN + 1) * sizeof(spm_int_t) );
460 }
461 else {
462 if ( root == newspm->clustnum ) {
463 memcpy( newspm->dofs, oldspm->dofs, (newspm->gN + 1) * sizeof(spm_int_t) );
464 }
465 MPI_Bcast( newspm->dofs, newspm->gN+1, SPM_MPI_INT, root, newspm->comm );
466 }
467 }
468
469 /* The spm is now ready to receive local information */
470 return;
471}
472
473/**
474 *******************************************************************************
475 *
476 * @brief Local copy of a scattered SPM in CSC or CSR format when everyone holds
477 * the original (Generic loc2glob).
478 *
479 *******************************************************************************
480 *
481 * @param[in] oldspm
482 * The input sparse matrix to scatter in the CSC or CSR format.
483 *
484 * @param[in] newspm
485 * The new scattered sparse matrix structure to access the clustnbr and
486 * communicator.
487 *
488 *******************************************************************************/
489static inline void
491 spmatrix_t *newspm )
492{
493 const spm_int_t *oldcol = (oldspm->fmttype == SpmCSC) ? oldspm->colptr : oldspm->rowptr;
494 const spm_int_t *oldrow = (oldspm->fmttype == SpmCSC) ? oldspm->rowptr : oldspm->colptr;
495 const char *oldval = oldspm->values;
496 spm_int_t *newcol = (newspm->fmttype == SpmCSC) ? newspm->colptr : newspm->rowptr;
497 spm_int_t *newrow = (newspm->fmttype == SpmCSC) ? newspm->rowptr : newspm->colptr;
498 char *newval = newspm->values;
499 const spm_int_t *loc2glob = newspm->loc2glob;
500 const spm_int_t *dofs = newspm->dofs;
501 spm_int_t baseval = newspm->baseval;
502 spm_int_t dofi, dofj, dof;
503 spm_int_t *dofshift = spm_get_value_idx_by_elt( oldspm );
504 spm_int_t row;
505 size_t typesize;
506
507 spm_int_t i, il, ig, jl, jg, nnz, nnzexp;
508 size_t vl, vg;
509
510 typesize = ( newspm->flttype != SpmPattern ) ? spm_size_of(newspm->flttype) : 1;
511
512 jl = 0;
513 vl = 0;
514 dof = newspm->dof;
515 for ( il=0; il<newspm->n; il++, loc2glob++, newcol++)
516 {
517 /* Init the col info */
518 *newcol = jl + baseval;
519
520 ig = *loc2glob - baseval;
521 jg = oldcol[ ig ] - baseval;
522 nnz = oldcol[ ig+1 ] - oldcol[ ig ];
523
524 /* Get the amount of values to copy */
525 dofj = (dof > 0) ? dof : dofs[ig+1] - dofs[ig];
526 dofi = 0;
527 for ( i=0; i < nnz; i++ )
528 {
529 row = oldrow[jg + i] - baseval;
530 dofi += (dof > 0) ? dof : dofs[row + 1] - dofs[row];
531 }
532
533 /* Copy the row infos */
534 memcpy( newrow, oldrow + jg, nnz * sizeof(spm_int_t) );
535 jl += nnz;
536 newrow += nnz;
537
538 /* Copy the values infos */
539 vg = dofshift[jg];
540 nnzexp = dofi * dofj;
541 if ( newspm->flttype != SpmPattern ) {
542 memcpy( newval, oldval + vg * typesize, nnzexp * typesize );
543 }
544
545 vl += nnzexp;
546 newval += nnzexp * typesize;
547 }
548 *newcol = jl + baseval;
549
550 assert( jl == newspm->nnz );
551 assert( vl == (size_t)(newspm->nnzexp) );
552 free( dofshift );
553 (void) vl;
554}
555
556/**
557 *******************************************************************************
558 *
559 * @brief Local copy of a scattered SPM in CSC or CSR format when everyone holds
560 * the original (Contiuous loc2glob).
561 *
562 *******************************************************************************
563 *
564 * @param[in] oldspm
565 * The input sparse matrix to scatter in the CSC or CSR format.
566 *
567 * @param[in] newspm
568 * The new scattered sparse matrix structure to access the clustnbr and
569 * communicator.
570 *
571 * @param[in] allcounts
572 * Internal array that stores the triplets {n, nnz, nnzexp} for each
573 * node.
574 *
575 *******************************************************************************/
576static inline void
578 spmatrix_t *newspm,
579 const spm_int_t *allcounts )
580{
581 const spm_int_t *oldcol = (oldspm->fmttype == SpmCSC) ? oldspm->colptr : oldspm->rowptr;
582 const spm_int_t *oldrow = (oldspm->fmttype == SpmCSC) ? oldspm->rowptr : oldspm->colptr;
583 const char *oldval = oldspm->values;
584 spm_int_t *newcol = (newspm->fmttype == SpmCSC) ? newspm->colptr : newspm->rowptr;
585 spm_int_t *newrow = (newspm->fmttype == SpmCSC) ? newspm->rowptr : newspm->colptr;
586 char *newval = newspm->values;
587 size_t typesize = (newspm->flttype != SpmPattern) ? spm_size_of(newspm->flttype) : 1;
588
589 spm_int_t c, ig, jg;
590 size_t vg;
591
592 ig = 0;
593 jg = 0;
594 vg = 0;
595 for( c=0; c<newspm->clustnum; c++ ) {
596 ig += allcounts[3 * c];
597 jg += allcounts[3 * c + 1];
598 vg += allcounts[3 * c + 2];
599 }
600
601 assert( ig == (newspm->loc2glob[0] - newspm->baseval) );
602 assert( jg == (oldcol[ig] - newspm->baseval) );
603
604 /* Copy the col infos */
605 memcpy( newcol, oldcol + ig, (newspm->n + 1) * sizeof(spm_int_t) );
606 for( c=0; c<=newspm->n; c++ ) {
607 newcol[c] -= jg;
608 }
609
610 /* Copy the row infos */
611 memcpy( newrow, oldrow + jg, newspm->nnz * sizeof(spm_int_t) );
612
613 /* Copy the values infos */
614 if ( newspm->flttype != SpmPattern ) {
615 memcpy( newval, oldval + vg * typesize, newspm->nnzexp * typesize );
616 }
617}
618
619/**
620 *******************************************************************************
621 *
622 * @brief Send function to scatter an SPM in CSC or CSR format from a single
623 * node when the loc2glob array is generic.
624 *
625 *******************************************************************************
626 *
627 * @param[in] oldspm
628 * The input sparse matrix to scatter in the CSC or CSR format.
629 *
630 * @param[in] newspm
631 * The new scattered sparse matrix structure to access the clustnbr and
632 * communicator.
633 *
634 * @param[in] allcounts
635 * Internal array that stores the triplets {n, nnz, nnzexp} for each
636 * node.
637 *
638 * @param[in] root
639 * The root process of the scatter operation. -1 if everyone hold a
640 * copy of the oldspm.
641 *
642 *******************************************************************************/
643static inline void
645 const spmatrix_t *newspm,
646 const spm_int_t *allcounts,
647 int root )
648{
649 spmatrix_t dstspm;
650 spm_int_t *newcol, *newrow, *loc2glob;
651 const spm_int_t *counts;
652 char *newval = NULL;
653 MPI_Datatype valtype = spm_get_datatype( oldspm );
654 size_t typesize = (newspm->flttype != SpmPattern) ? spm_size_of(newspm->flttype) : 1;
655 MPI_Status status;
656 spm_int_t n, nnz, nnzexp;
657 spm_int_t maxn, maxnnz, maxnnzexp;
658 spm_int_t dst;
659
660 /* First loop to compute max size */
661 maxn = 0;
662 maxnnz = 0;
663 maxnnzexp = 0;
664 counts = allcounts;
665 for( dst=0; dst<newspm->clustnbr; dst++, counts+=3 ) {
666 n = counts[0];
667 nnz = counts[1];
668 nnzexp = counts[2];
669
670 if ( dst == root ) {
671 continue;
672 }
673
674 maxn = spm_imax( maxn, n );
675 maxnnz = spm_imax( maxnnz, nnz );
676 maxnnzexp = spm_imax( maxnnzexp, nnzexp );
677 }
678
679 /*
680 * Initialize the copy of the remote spm
681 */
682 memcpy( &dstspm, newspm, sizeof(spmatrix_t) );
683 newcol = malloc( (maxn+1) * sizeof(spm_int_t) );
684 newrow = malloc( maxnnz * sizeof(spm_int_t) );
685 loc2glob = malloc( maxn * sizeof(spm_int_t) );
686 if ( dstspm.flttype != SpmPattern ) {
687 newval = malloc( maxnnzexp * typesize );
688 }
689
690 if ( oldspm->fmttype == SpmCSC ) {
691 dstspm.colptr = newcol;
692 dstspm.rowptr = newrow;
693 }
694 else {
695 dstspm.colptr = newrow;
696 dstspm.rowptr = newcol;
697 }
698 dstspm.loc2glob = loc2glob;
699 dstspm.values = newval;
700
701 counts = allcounts;
702 for( dst=0; dst<newspm->clustnbr; dst++, counts+=3 ) {
703 n = counts[0];
704 nnz = counts[1];
705 nnzexp = counts[2];
706
707 if ( dst == root ) {
708 continue;
709 }
710
711 /*
712 * Initialize the local information of the remote spm
713 */
714 dstspm.n = n;
715 dstspm.nexp = -1; /* Not used and set to -1 to break things */
716 dstspm.nnz = nnz;
717 dstspm.nnzexp = nnzexp;
718 dstspm.clustnum = dst;
719
720 if ( dstspm.n == 0 ) {
721 continue;
722 }
723
724 /* Receive the loc2glob */
725 MPI_Recv( dstspm.loc2glob, n, SPM_MPI_INT, dst, 4, newspm->comm, &status );
726
727 /* Extract the remote information */
728 spm_scatter_csx_local_generic( oldspm, &dstspm );
729
730 /* Send the col infos */
731 MPI_Send( newcol, n+1, SPM_MPI_INT, dst, 0, newspm->comm );
732
733 /* Send the row infos */
734 MPI_Send( newrow, nnz, SPM_MPI_INT, dst, 1, newspm->comm );
735
736 /* Send the values infos */
737 if ( dstspm.flttype != SpmPattern ) {
738 MPI_Send( newval, nnzexp, valtype, dst, 2, newspm->comm );
739 }
740 }
741
742 free( newcol );
743 free( newrow );
744 free( loc2glob );
745 free( newval );
746}
747
748/**
749 *******************************************************************************
750 *
751 * @brief Send function to scatter an SPM in CSC or CSR format from a single
752 * node when the loc2glob array is split in continuous sets.
753 *
754 *******************************************************************************
755 *
756 * @param[in] oldspm
757 * The input sparse matrix to scatter in the CSC or CSR format.
758 *
759 * @param[in] newspm
760 * The new scattered sparse matrix structure to access the clustnbr and
761 * communicator.
762 *
763 * @param[in] allcounts
764 * Internal array that stores the triplets {n, nnz, nnzexp} for each
765 * node.
766 *
767 * @param[in] root
768 * The root process of the scatter operation. -1 if everyone hold a
769 * copy of the oldspm.
770 *
771 *******************************************************************************
772 *
773 * @return The pointer to the communication request.
774 *
775 *******************************************************************************/
776static inline MPI_Request *
778 const spmatrix_t *newspm,
779 const spm_int_t *allcounts,
780 int root )
781{
782 MPI_Request *allreqs = malloc( (newspm->clustnbr-1) * 3 * sizeof(MPI_Request) );
783 MPI_Request *requests;
784 const spm_int_t *oldcol = (oldspm->fmttype == SpmCSC) ? oldspm->colptr : oldspm->rowptr;
785 const spm_int_t *oldrow = (oldspm->fmttype == SpmCSC) ? oldspm->rowptr : oldspm->colptr;
786 const char *oldval = oldspm->values;
787 MPI_Datatype valtype = spm_get_datatype( oldspm );
788 size_t typesize = (oldspm->flttype != SpmPattern) ? spm_size_of(oldspm->flttype) : 1;
789 spm_int_t n, nnz, nnzexp;
790 spm_int_t dst, ig, jg;
791 size_t vg;
792
793 ig = 0;
794 jg = 0;
795 vg = 0;
796 requests = allreqs;
797 for( dst=0; dst<newspm->clustnbr; dst++, allcounts+=3 ) {
798 n = allcounts[0];
799 nnz = allcounts[1];
800 nnzexp = allcounts[2];
801
802 if ( dst == root ) {
803 goto end;
804 }
805
806 if ( n == 0 ) {
807 requests[0] = MPI_REQUEST_NULL;
808 requests[1] = MPI_REQUEST_NULL;
809 requests[2] = MPI_REQUEST_NULL;
810 requests += 3;
811 continue;
812 }
813
814 /* Send the col infos */
815 MPI_Isend( oldcol + ig, n+1, SPM_MPI_INT, dst, 0, newspm->comm, requests );
816
817 /* Send the row infos */
818 MPI_Isend( oldrow + jg, nnz, SPM_MPI_INT, dst, 1, newspm->comm, requests + 1 );
819
820 /* Send the values infos */
821 assert( oldspm->flttype == newspm->flttype );
822 if ( oldspm->flttype != SpmPattern ) {
823 MPI_Isend( oldval + vg * typesize, nnzexp, valtype, dst, 2, newspm->comm, requests + 2 );
824 }
825 else {
826 requests[2] = MPI_REQUEST_NULL;
827 }
828 requests += 3;
829
830 end:
831 ig += n;
832 jg += nnz;
833 vg += nnzexp;
834 }
835
836 return allreqs;
837}
838
839/**
840 *******************************************************************************
841 *
842 * @brief Send wrapper function to scatter an SPM in CSC or CSR format from a
843 * single node
844 *
845 *******************************************************************************
846 *
847 * @param[in] oldspm
848 * The input sparse matrix to scatter in the CSC or CSR format.
849 *
850 * @param[inout] newspm
851 * The structure to hold the local new scattered sparse matrix.
852 * It must have been allocated first, and non array fields must have
853 * been initialized, as well as dof and loc2glob.
854 *
855 * @param[in] allcounts
856 * Internal array that stores the triplets {n, nnz, nnzexp} for each
857 * node.
858 *
859 * @param[in] continuous
860 * Boolean to specify if the distribution is made by regular continuous
861 * sets or not.
862 *
863 * @param[in] root
864 * The root process of the scatter operation. -1 if everyone hold a
865 * copy of the oldspm.
866 *
867 *******************************************************************************/
868static inline void
870 spmatrix_t *newspm,
871 const spm_int_t *allcounts,
872 int continuous,
873 int root )
874{
875 if ( continuous ) {
876 MPI_Request *allreqs;
877 MPI_Status *allstatus = malloc( (newspm->clustnbr-1) * 3 * sizeof(MPI_Status) );
878
879 allreqs = spm_scatter_csx_send_continuous( oldspm, newspm, allcounts, root );
880 /* Don't forget the local one */
881 if ( newspm->n ) {
882 spm_scatter_csx_local_continuous( oldspm, newspm, allcounts );
883 }
884
885 MPI_Waitall( (newspm->clustnbr-1) * 3, allreqs, allstatus );
886
887 free( allreqs );
888 free( allstatus );
889 }
890 else {
891 spm_scatter_csx_send_generic( oldspm, newspm, allcounts, root );
892
893 /* Don't forget the local one */
894 if ( newspm->n ) {
895 spm_scatter_csx_local_generic( oldspm, newspm );
896 }
897 }
898}
899
900/**
901 *******************************************************************************
902 *
903 * @brief Reception of a scattered SPM in the CSC/CSR formats
904 *
905 *******************************************************************************
906 *
907 * @param[inout] newspm
908 * The structure to hold the new scattered sparse matrix.
909 * It must have been allocated first, and non array fields must have
910 * been initialized, as well as dof and loc2glob.
911 *
912 * @param[in] continuous
913 * Boolean to specify if the distribution is made by regular continuous
914 * sets or not.
915 *
916 * @param[in] root
917 * The root process of the scatter operation. -1 if everyone hold a
918 * copy of the oldspm.
919 *
920 *******************************************************************************/
921static inline void
923 int continuous,
924 int root )
925{
926 MPI_Request allrequests[3] = { MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL };
927 MPI_Status allstatuses[3];
928 spm_int_t *newcol = (newspm->fmttype == SpmCSC) ? newspm->colptr : newspm->rowptr;
929 spm_int_t *newrow = (newspm->fmttype == SpmCSC) ? newspm->rowptr : newspm->colptr;
930 char *newval = newspm->values;
931 MPI_Datatype valtype = spm_get_datatype( newspm );
932
933 if ( newspm->n == 0 ) {
934 return;
935 }
936
937 if ( !continuous ) {
938 MPI_Send( newspm->loc2glob, newspm->n, SPM_MPI_INT, root, 4, newspm->comm );
939 }
940
941 /* Recv the col infos */
942 MPI_Irecv( newcol, newspm->n+1, SPM_MPI_INT, root, 0, newspm->comm, allrequests );
943
944 /* Recv the row infos */
945 MPI_Irecv( newrow, newspm->nnz, SPM_MPI_INT, root, 1, newspm->comm, allrequests + 1 );
946
947 /* Recv the values infos */
948 if ( newspm->flttype != SpmPattern ) {
949 MPI_Irecv( newval, newspm->nnzexp, valtype, root, 2, newspm->comm, allrequests + 2 );
950 }
951
952 MPI_Waitall( 3, allrequests, allstatuses );
953
954 /* Need to update the colptr array */
955 if ( continuous && (newspm->n > 0) ) {
956 spm_int_t baseval = newspm->baseval;
957 spm_int_t shift = newcol[0] - baseval;
958 spm_int_t i;
959 for( i=0; i<=newspm->n; i++, newcol++ ) {
960 *newcol -= shift;
961 }
962 }
963}
964
965/**
966 *******************************************************************************
967 *
968 * @brief Scatter the SPM in the CSC/CSR formats
969 *
970 *******************************************************************************
971 *
972 * @param[in] oldspm
973 * The input sparse matrix to scatter in the CSC or CSR format.
974 *
975 * @param[inout] newspm
976 * The structure to hold the new scattered sparse matrix.
977 * It must have been allocated first, and non array fields must have
978 * been initialized, as well as dof and loc2glob.
979 *
980 * @param[in] allcounts
981 * Internal array that stores the triplets {n, nnz, nnzexp} for each
982 * node.
983 *
984 * @param[in] continuous
985 * Boolean to specify if the distribution is made by regular continuous
986 * sets or not.
987 *
988 * @param[in] root
989 * The root process of the scatter operation. -1 if everyone hold a
990 * copy of the oldspm.
991 *
992 *******************************************************************************/
993static inline void
995 spmatrix_t *newspm,
996 const spm_int_t *allcounts,
997 int continuous,
998 int root )
999{
1000 if ( root == -1 ) {
1001 if ( newspm->n == 0 ) {
1002 return;
1003 }
1004 if ( continuous ) {
1005 spm_scatter_csx_local_continuous( oldspm, newspm, allcounts );
1006 }
1007 else {
1008 spm_scatter_csx_local_generic( oldspm, newspm );
1009 }
1010 }
1011 else {
1012 if ( root == newspm->clustnum ) {
1013 spm_scatter_csx_send( oldspm, newspm, allcounts,
1014 continuous, root );
1015 }
1016 else {
1017 spm_scatter_csx_recv( newspm, continuous, root );
1018 }
1019 }
1020}
1021
1022/**
1023 *******************************************************************************
1024 *
1025 * @brief Initialize a local spm in IJV format
1026 *
1027 *******************************************************************************
1028 *
1029 * @param[in] oldspm
1030 * The input sparse matrix to scatter in the IJV format.
1031 *
1032 * @param[inout] newspm
1033 * The structure to hold the local new scattered sparse matrix.
1034 * It must have been allocated first, and non array fields must have
1035 * been initialized, as well as dof and loc2glob.
1036 *
1037 * @param[in] distByColumn
1038 * Boolean to decide if the matrix is distributed by rows or columns.
1039 * If false, distribution by rows. If true, distribution by columns.
1040 *
1041 *******************************************************************************/
1042static inline void
1044 spmatrix_t *newspm,
1045 int distByColumn )
1046{
1047 const spm_int_t *oldcol = distByColumn ? oldspm->colptr : oldspm->rowptr;
1048 const spm_int_t *oldrow = distByColumn ? oldspm->rowptr : oldspm->colptr;
1049 const char *oldval = oldspm->values;
1050 spm_int_t *newcol = distByColumn ? newspm->colptr : newspm->rowptr;
1051 spm_int_t *newrow = distByColumn ? newspm->rowptr : newspm->colptr;
1052 char *newval = newspm->values;
1053 size_t typesize = (newspm->flttype != SpmPattern) ? spm_size_of(newspm->flttype) : 1;
1054 const spm_int_t *dofs = newspm->dofs;
1055 const spm_int_t *glob2loc = newspm->glob2loc; /* It has normally already been initialized */
1056 spm_int_t baseval = newspm->baseval;
1057
1058 spm_int_t kl, kg, ig, jg, nnz;
1059 spm_int_t vl, dof2, dofi, dofj;
1060
1061 assert( newspm->glob2loc );
1062
1063 /* Shift the pointers to avoid extra baseval computations */
1064 glob2loc -= baseval;
1065 dofs -= baseval;
1066
1067 dof2 = newspm->dof * newspm->dof;
1068 vl = 0;
1069 kl = 0;
1070 for ( kg=0; kg<oldspm->nnz; kg++, oldcol++, oldrow++ )
1071 {
1072 ig = *oldrow;
1073 jg = *oldcol;
1074
1075 if ( newspm->dof > 0 ) {
1076 nnz = dof2;
1077 }
1078 else {
1079 dofi = dofs[ ig+1 ] - dofs[ ig ];
1080 dofj = dofs[ jg+1 ] - dofs[ jg ];
1081 nnz = dofi * dofj;
1082 }
1083
1084 if ( glob2loc[ jg ] < 0 ) {
1085 oldval += typesize * nnz;
1086 continue;
1087 }
1088
1089 /* Init the col info */
1090 *newrow = ig;
1091 *newcol = jg;
1092
1093 kl++;
1094 newrow++;
1095 newcol++;
1096
1097 /* Copy the values infos */
1098 if ( newspm->flttype != SpmPattern ) {
1099 memcpy( newval, oldval, nnz * typesize );
1100 newval += nnz * typesize;
1101 oldval += nnz * typesize;
1102 }
1103 vl += nnz;
1104 }
1105
1106 assert( kl == newspm->nnz );
1107 assert( vl == newspm->nnzexp );
1108 (void) kl;
1109 (void) vl;
1110}
1111
1112/**
1113 *******************************************************************************
1114 *
1115 * @brief Initialize a temporary remote spm in IJV format to send it
1116 *
1117 *******************************************************************************
1118 *
1119 * @param[in] oldspm
1120 * The input sparse matrix to scatter in the IJV format.
1121 *
1122 * @param[inout] newspm
1123 * The structure to hold the local new scattered sparse matrix.
1124 * It must have been allocated first, and non array fields must have
1125 * been initialized, as well as dof and loc2glob.
1126 *
1127 * @param[in] distByColumn
1128 * Boolean to decide if the matrix is distributed by rows or columns.
1129 * If false, distribution by rows. If true, distribution by columns.
1130 *
1131 *******************************************************************************/
1132static inline void
1134 spmatrix_t *newspm,
1135 int distByColumn )
1136{
1137 const spm_int_t *oldcol = distByColumn ? oldspm->colptr : oldspm->rowptr;
1138 const spm_int_t *oldrow = distByColumn ? oldspm->rowptr : oldspm->colptr;
1139 const char *oldval = oldspm->values;
1140 spm_int_t *newcol = distByColumn ? newspm->colptr : newspm->rowptr;
1141 spm_int_t *newrow = distByColumn ? newspm->rowptr : newspm->colptr;
1142 char *newval = newspm->values;
1143 size_t typesize = (newspm->flttype != SpmPattern) ? spm_size_of(newspm->flttype) : 1;
1144 const spm_int_t *dofs = newspm->dofs;
1145 const spm_int_t *glob2loc = newspm->glob2loc; /* Must be already initialized */
1146 spm_int_t baseval = newspm->baseval;
1147
1148 spm_int_t kl, kg, ig, jg, nnz;
1149 spm_int_t vl, dof2, dofi, dofj;
1150
1151 assert( newspm->glob2loc );
1152 /* Shift the pointers to avoid extra baseval computations */
1153 glob2loc -= baseval;
1154 dofs -= baseval;
1155
1156 dof2 = newspm->dof * newspm->dof;
1157 vl = 0;
1158 kl = 0;
1159 for ( kg=0; kg<oldspm->nnz; kg++, oldcol++, oldrow++ )
1160 {
1161 ig = *oldrow;
1162 jg = *oldcol;
1163
1164 if ( newspm->dof > 0 ) {
1165 nnz = dof2;
1166 }
1167 else {
1168 dofi = dofs[ ig+1 ] - dofs[ ig ];
1169 dofj = dofs[ jg+1 ] - dofs[ jg ];
1170 nnz = dofi * dofj;
1171 }
1172
1173 if ( glob2loc[ jg ] != (-newspm->clustnum-1) ) {
1174 oldval += typesize * nnz;
1175 continue;
1176 }
1177
1178 /* Init the col info */
1179 *newrow = ig;
1180 *newcol = jg;
1181
1182 kl++;
1183 newrow++;
1184 newcol++;
1185
1186 /* Copy the values infos */
1187 if ( newspm->flttype != SpmPattern ) {
1188 memcpy( newval, oldval, nnz * typesize );
1189 newval += nnz * typesize;
1190 oldval += nnz * typesize;
1191 }
1192 vl += nnz;
1193 }
1194
1195 assert( kl == newspm->nnz );
1196 assert( vl == newspm->nnzexp );
1197 (void) kl;
1198 (void) vl;
1199}
1200
1201/**
1202 *******************************************************************************
1203 *
1204 * @brief Send function to scatter an IJV SPM from a single node
1205 *
1206 *******************************************************************************
1207 *
1208 * @param[in] oldspm
1209 * The input sparse matrix to scatter in the IJV format.
1210 *
1211 * @param[inout] newspm
1212 * The structure to hold the local new scattered sparse matrix.
1213 * It must have been allocated first, and non array fields must have
1214 * been initialized, as well as dof and loc2glob.
1215 *
1216 * @param[in] allcounts
1217 * Internal array that stores the triplets {n, nnz, nnzexp} for each
1218 * node.
1219 *
1220 * @param[in] distByColumn
1221 * Boolean to decide if the matrix is distributed by rows or columns.
1222 * If false, distribution by rows. If true, distribution by columns.
1223 *
1224 * @param[in] root
1225 * The root process of the scatter operation. -1 if everyone hold a
1226 * copy of the oldspm.
1227 *
1228 *******************************************************************************/
1229static inline void
1231 spmatrix_t *newspm,
1232 const spm_int_t *allcounts,
1233 int distByColumn,
1234 int root )
1235{
1236 spmatrix_t dstspm;
1237 spm_int_t *newcol, *newrow;
1238 const spm_int_t *counts;
1239 char *newval = NULL;
1240 MPI_Datatype valtype = spm_get_datatype( oldspm );
1241 size_t typesize = (oldspm->flttype != SpmPattern) ? spm_size_of(oldspm->flttype) : 1;
1242 spm_int_t n, nnz, nnzexp;
1243 spm_int_t maxnnz, maxnnzexp;
1244 spm_int_t dst;
1245
1246 /* First loop to compute max size */
1247 maxnnz = 0;
1248 maxnnzexp = 0;
1249 counts = allcounts;
1250 for( dst=0; dst<newspm->clustnbr; dst++, counts+=3 ) {
1251 nnz = counts[1];
1252 nnzexp = counts[2];
1253
1254 if ( dst == root ) {
1255 continue;
1256 }
1257
1258 maxnnz = spm_imax( maxnnz, nnz );
1259 maxnnzexp = spm_imax( maxnnzexp, nnzexp );
1260 }
1261
1262 /*
1263 * Initialize the copy of the remote spm
1264 */
1265 memcpy( &dstspm, newspm, sizeof(spmatrix_t) );
1266 newcol = malloc( maxnnz * sizeof(spm_int_t) );
1267 newrow = malloc( maxnnz * sizeof(spm_int_t) );
1268 if ( dstspm.flttype != SpmPattern ) {
1269 newval = malloc( maxnnzexp * typesize );
1270 }
1271
1272 dstspm.colptr = newcol;
1273 dstspm.rowptr = newrow;
1274 dstspm.loc2glob = NULL;
1275 dstspm.values = newval;
1276
1277 counts = allcounts;
1278 for( dst=0; dst<newspm->clustnbr; dst++, counts+=3 ) {
1279 n = counts[0];
1280 nnz = counts[1];
1281 nnzexp = counts[2];
1282
1283 if ( dst == root ) {
1284 continue;
1285 }
1286
1287 /*
1288 * Initialize the local information of the remote spm
1289 */
1290 dstspm.n = n;
1291 dstspm.nexp = -1; /* Not used and set to -1 to break things */
1292 dstspm.nnz = nnz;
1293 dstspm.nnzexp = nnzexp;
1294 dstspm.clustnum = dst;
1295
1296 /* Extract the remote information */
1297 spm_scatter_ijv_remote( oldspm, &dstspm, distByColumn );
1298
1299 /* Send the col infos */
1300 MPI_Send( dstspm.colptr, nnz, SPM_MPI_INT, dst, 0, newspm->comm );
1301
1302 /* Send the row infos */
1303 MPI_Send( dstspm.rowptr, nnz, SPM_MPI_INT, dst, 1, newspm->comm );
1304
1305 /* Send the values infos */
1306 if ( dstspm.flttype != SpmPattern ) {
1307 MPI_Send( newval, nnzexp, valtype, dst, 2, newspm->comm );
1308 }
1309 }
1310
1311 free( newcol );
1312 free( newrow );
1313 free( newval );
1314
1315 /* Don't forget the local spm */
1316 spm_scatter_ijv_local( oldspm, newspm, distByColumn );
1317}
1318
1319/**
1320 *******************************************************************************
1321 *
1322 * @brief Reception of a scattered SPM in the IJV format
1323 *
1324 *******************************************************************************
1325 *
1326 * @param[inout] newspm
1327 * The structure to hold the new scattered sparse matrix.
1328 * It must have been allocated first, and non array fields must have
1329 * been initialized, as well as dof and loc2glob.
1330 *
1331 * @param[in] root
1332 * The root process sending the information.
1333 *
1334 *******************************************************************************/
1335static inline void
1337 int root )
1338{
1339 MPI_Request allrequests[3] = { MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL };
1340 MPI_Status allstatuses[3];
1341 spm_int_t *newcol = newspm->colptr;
1342 spm_int_t *newrow = newspm->rowptr;
1343 char *newval = newspm->values;
1344 MPI_Datatype valtype = spm_get_datatype( newspm );
1345
1346 /* Recv the col infos */
1347 MPI_Irecv( newcol, newspm->nnz, SPM_MPI_INT, root, 0, newspm->comm, allrequests );
1348
1349 /* Recv the row infos */
1350 MPI_Irecv( newrow, newspm->nnz, SPM_MPI_INT, root, 1, newspm->comm, allrequests + 1 );
1351
1352 /* Recv the values infos */
1353 if ( newspm->flttype != SpmPattern ) {
1354 MPI_Irecv( newval, newspm->nnzexp, valtype, root, 2, newspm->comm, allrequests + 2 );
1355 }
1356
1357 MPI_Waitall( 3, allrequests, allstatuses );
1358}
1359
1360/**
1361 *******************************************************************************
1362 *
1363 * @brief Scatter the SPM in the IJV format
1364 *
1365 *******************************************************************************
1366 *
1367 * @param[in] oldspm
1368 * The input sparse matrix to scatter in the IJV format.
1369 *
1370 * @param[inout] newspm
1371 * The structure to hold the new scattered sparse matrix.
1372 * It must have been allocated first, and non array fields must have
1373 * been initialized, as well as dof and loc2glob.
1374 *
1375 * @param[in] allcounts
1376 * Internal array that stores the triplets {n, nnz, nnzexp} for each
1377 * node.
1378 *
1379 * @param[in] distByColumn
1380 * Boolean to decide if the matrix is distributed by rows or columns.
1381 * If false, distribution by rows. If true, distribution by columns.
1382 *
1383 * @param[in] root
1384 * The root process of the scatter operation. -1 if everyone hold a
1385 * copy of the oldspm.
1386 *
1387 *******************************************************************************/
1388static inline void
1390 spmatrix_t *newspm,
1391 const spm_int_t *allcounts,
1392 int distByColumn,
1393 int root )
1394{
1395 if ( root == -1 ) {
1396 spm_scatter_ijv_local( oldspm, newspm, distByColumn );
1397 }
1398 else {
1399 if ( root == newspm->clustnum ) {
1400 spm_scatter_ijv_send( oldspm, newspm, allcounts,
1401 distByColumn, root );
1402 }
1403 else {
1404 spm_scatter_ijv_recv( newspm, root );
1405 }
1406 }
1407}
1408
1409/**
1410 * @}
1411 */
1412
1413/**
1414 *******************************************************************************
1415 *
1416 * @ingroup spm
1417 *
1418 * @brief Scatter the SPM thanks to loc2glob
1419 *
1420 *******************************************************************************
1421 *
1422 * @param[inout] newspm
1423 * The pre-allocated spm filled by the scattered spm.
1424 *
1425 * @param[in] root
1426 * The root process of the scatter operation. -1 if everyone hold a
1427 * copy of the oldspm.
1428 *
1429 * @param[in] oldspm
1430 * The old sparse matrix to scatter.
1431 * If spm is a CSC matrix, distribution by row is not possible.
1432 * If spm is a CSR matrix, distribution by column is not possible.
1433 * Referenced only on root node(s).
1434 *
1435 * @param[in] n
1436 * Size of the loc2glob array if provided. Unused otherwise.
1437 *
1438 * @param[in] loc2glob
1439 * Distribution array of the matrix. Will be copied.
1440 * If NULL, the columns/rows are evenly distributed among the processes.
1441 *
1442 * @param[in] distByColumn
1443 * Boolean to decide if the matrix is distributed by rows or columns.
1444 * If false, distribution by rows.
1445 * If true, distribution by columns.
1446 *
1447 * @param[in] comm
1448 * MPI communicator.
1449 *
1450 *******************************************************************************
1451 *
1452 * @retval SPM_SUCCESS on success,
1453 * @retval SPM_ERR_BADPARAMETER otherwise.
1454 *
1455 *******************************************************************************/
1456int
1458 int root,
1459 const spmatrix_t *oldspm,
1460 spm_int_t n,
1461 const spm_int_t *loc2glob,
1462 int distByColumn,
1463 SPM_Comm comm )
1464{
1465 spm_int_t gN = 0;
1466 spm_int_t *allcounts = NULL;
1467 int clustnum, clustnbr;
1468 int local, rc = 0;
1469
1470 MPI_Comm_rank( comm, &clustnum );
1471 local = ( ( root == -1 ) || (root == clustnum) );
1472
1473 /* Check the initial conditions */
1474 if ( local ) {
1475 if ( loc2glob ) {
1476 assert( n >= 0 );
1477 MPI_Allreduce( &n, &gN, 1, SPM_MPI_INT,
1478 MPI_SUM, comm );
1479 }
1480
1481 if ( oldspm == NULL ) {
1482 spm_print_warning( "[%02d] spmScatter: Missing input matrix\n", clustnum );
1483 rc = 1;
1484 goto reduce;
1485 }
1486
1487 assert( oldspm->replicated != -1 );
1488 if ( oldspm->replicated == 0 ) {
1489 spm_print_warning( "[%02d] spmScatter: The spm is already distributed\n", clustnum );
1490 rc = 1;
1491 goto reduce;
1492 }
1493
1494 if ( loc2glob && (gN != oldspm->gN) ) {
1495 spm_print_warning( "[%02d] spmScatter: Incorrect n sum (%ld != %ld)\n",
1496 clustnum, (long)(oldspm->gN), (long)gN );
1497 rc = 1;
1498 goto reduce;
1499 }
1500
1501 if ( ( distByColumn && (oldspm->fmttype == SpmCSR) ) ||
1502 ((!distByColumn) && (oldspm->fmttype == SpmCSC) ) )
1503 {
1504 spm_print_warning( "[%02d] spmScatter: Does not support to scatter along the non compressed array in CSC/CSR formats\n",
1505 clustnum );
1506 rc = 1;
1507 goto reduce;
1508 }
1509 reduce:
1510 MPI_Allreduce( MPI_IN_PLACE, &rc, 1, MPI_INT,
1511 MPI_SUM, comm );
1512 if ( rc != 0 ) {
1513 return SPM_ERR_BADPARAMETER;
1514 }
1515 }
1516 else {
1517 if ( loc2glob ) {
1518 MPI_Allreduce( &n, &gN, 1, SPM_MPI_INT,
1519 MPI_SUM, comm );
1520 }
1521 MPI_Allreduce( MPI_IN_PLACE, &rc, 1, MPI_INT,
1522 MPI_SUM, comm );
1523 if ( rc != 0 ) {
1524 return SPM_ERR_BADPARAMETER;
1525 }
1526 }
1527
1528 /* If only one node involve, let's just copy and update the communicator */
1529 MPI_Comm_size( comm, &clustnbr );
1530 if ( clustnbr == 1 ) {
1531 spmCopy( oldspm, newspm );
1532 newspm->comm = comm;
1533 newspm->clustnum = 0;
1534 newspm->clustnbr = 1;
1535 return SPM_SUCCESS;
1536 }
1537
1538 /* Create the local spm */
1539 spm_scatter_init( newspm, oldspm,
1540 n, loc2glob, distByColumn,
1541 &allcounts,
1542 root, clustnum, comm );
1543
1544 /* Scatter the information */
1545 switch(newspm->fmttype){
1546 case SpmCSC:
1547 case SpmCSR:
1548 spm_scatter_csx( oldspm, newspm,
1549 allcounts, (loc2glob == NULL), root );
1550 break;
1551 case SpmIJV:
1552 spm_scatter_ijv( oldspm, newspm,
1553 allcounts, distByColumn, root );
1554 break;
1555 default:
1556 fprintf( stderr, "spmScatter (Unexpected error)\n" );
1557 exit(0);
1558 }
1559
1560 /*
1561 * Now that we have loc2glob and dof, we can update the computed fields and
1562 * adjust values array if needed
1563 */
1564 spmUpdateComputedFields( newspm );
1565
1566 assert( (allcounts == NULL) || (allcounts[ newspm->clustnum * 3 + 0 ] == newspm->n ) );
1567 assert( (allcounts == NULL) || (allcounts[ newspm->clustnum * 3 + 1 ] == newspm->nnz ) );
1568 assert( (allcounts == NULL) || (allcounts[ newspm->clustnum * 3 + 2 ] == newspm->nnzexp) );
1569
1570 if ( allcounts != NULL ) {
1571 free( allcounts );
1572 }
1573 return SPM_SUCCESS;
1574}
static size_t spm_size_of(spm_coeftype_t type)
Double datatype that is not converted through precision generator functions.
Definition datatypes.h:209
static spm_int_t spm_imax(spm_int_t a, spm_int_t b)
Internal function to compute max(a,b)
Definition datatypes.h:119
@ SPM_ERR_BADPARAMETER
Definition const.h:89
@ SPM_SUCCESS
Definition const.h:82
@ SpmPattern
Definition const.h:62
@ SpmCSC
Definition const.h:73
@ SpmCSR
Definition const.h:74
@ SpmIJV
Definition const.h:75
spm_int_t * spm_get_value_idx_by_elt(const spmatrix_t *spm)
Create an array that represents the shift for each sub-element of the original multidof value array.
Definition spm.c:2211
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
int clustnbr
Definition spm.h:96
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_int_t * loc2glob
Definition spm.h:91
SPM_Comm comm
Definition spm.h:97
spm_int_t baseval
Definition spm.h:71
spm_int_t * glob2loc
Definition spm.h:94
spm_int_t * colptr
Definition spm.h:89
int clustnum
Definition spm.h:95
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
#define SPM_MPI_INT
The MPI type associated to spm_int_t.
Definition datatypes.h:72
void spmUpdateComputedFields(spmatrix_t *spm)
Update all the computed fields based on the static values stored.
int spmScatter(spmatrix_t *spm_scattered, int root, const spmatrix_t *opt_spm_gathered, spm_int_t opt_n, const spm_int_t *opt_loc2glob, int opt_distByColumn, SPM_Comm opt_comm)
Scatter the SPM thanks to loc2glob.
int spm_int_t
The main integer datatype used in spm arrays.
Definition datatypes.h:70
void spmCopy(const spmatrix_t *spm_in, spmatrix_t *spm_out)
Create a copy of the spm.
Definition spm.c:969
void spmInit(spmatrix_t *spm)
Init the spm structure.
Definition spm.c:152
The sparse matrix data structure.
Definition spm.h:64
spm_int_t * spm_getandset_glob2loc(spmatrix_t *spm)
Computes the glob2loc array if needed, and returns it.
Definition spm.c:2007
spm_int_t spm_create_loc2glob_continuous(const spmatrix_t *spm, spm_int_t **l2g_ptr)
Generate a continuous loc2glob array on each node.
Definition spm.c:1841
static void spm_scatter_ijv_remote(const spmatrix_t *oldspm, spmatrix_t *newspm, int distByColumn)
Initialize a temporary remote spm in IJV format to send it.
static void spm_scatter_csx_send_generic(const spmatrix_t *oldspm, const spmatrix_t *newspm, const spm_int_t *allcounts, int root)
Send function to scatter an SPM in CSC or CSR format from a single node when the loc2glob array is ge...
static void spm_scatter_ijv(const spmatrix_t *oldspm, spmatrix_t *newspm, const spm_int_t *allcounts, int distByColumn, int root)
Scatter the SPM in the IJV format.
static void spm_scatter_csx_local_generic(const spmatrix_t *oldspm, spmatrix_t *newspm)
Local copy of a scattered SPM in CSC or CSR format when everyone holds the original (Generic loc2glob...
static MPI_Request * spm_scatter_csx_send_continuous(const spmatrix_t *oldspm, const spmatrix_t *newspm, const spm_int_t *allcounts, int root)
Send function to scatter an SPM in CSC or CSR format from a single node when the loc2glob array is sp...
static void spm_scatter_csx(const spmatrix_t *oldspm, spmatrix_t *newspm, const spm_int_t *allcounts, int continuous, int root)
Scatter the SPM in the CSC/CSR formats.
static void spm_scatter_ijv_get_locals(const spmatrix_t *oldspm, spmatrix_t *newspm, int distByColumn, spm_int_t *allcounts, int root)
Compute the allcounts array with IJV format.
static void spm_scatter_init(spmatrix_t *newspm, const spmatrix_t *oldspm, int n, const spm_int_t *loc2glob, int distByColumn, spm_int_t **allcounts, int root, int clustnum, SPM_Comm comm)
Generic function to initialize a scattered spm on each node.
static void spm_scatter_csx_local_continuous(const spmatrix_t *oldspm, spmatrix_t *newspm, const spm_int_t *allcounts)
Local copy of a scattered SPM in CSC or CSR format when everyone holds the original (Contiuous loc2gl...
static void spm_scatter_getn(const spmatrix_t *spm, spm_int_t *allcounts, int root)
Gather the n values from all nodes.
Definition spm_scatter.c:72
static void spm_scatter_csx_recv(const spmatrix_t *newspm, int continuous, int root)
Reception of a scattered SPM in the CSC/CSR formats.
static void spm_scatter_csx_send(const spmatrix_t *oldspm, spmatrix_t *newspm, const spm_int_t *allcounts, int continuous, int root)
Send wrapper function to scatter an SPM in CSC or CSR format from a single node.
static void spm_scatter_ijv_local(const spmatrix_t *oldspm, spmatrix_t *newspm, int distByColumn)
Initialize a local spm in IJV format.
static void spm_scatter_ijv_send(const spmatrix_t *oldspm, spmatrix_t *newspm, const spm_int_t *allcounts, int distByColumn, int root)
Send function to scatter an IJV SPM from a single node.
static void spm_scatter_csx_get_locals(const spmatrix_t *oldspm, spmatrix_t *newspm, spm_int_t *allcounts, int root)
Compute the allcounts array with CSC/CSR formats.
static void spm_scatter_ijv_recv(const spmatrix_t *newspm, int root)
Reception of a scattered SPM in the IJV format.