BELFEM 0.9.0
Berkeley Lab Finite Element Framework
Loading...
Searching...
No Matches
cl_SolverDistMatrix.hpp
Go to the documentation of this file.
1/*
2 * BELFEM -- The Berkeley Lab Finite Element Framework
3 * Copyright (c) 2026, The Regents of the University of California, through
4 * Lawrence Berkeley National Laboratory (subject to receipt of any required
5 * approvals from the U.S. Dept. of Energy). All rights reserved.
6 *
7 * Developers: Christian Messe, Gregory Giard
8 *
9 * See the top-level LICENSE file for the complete license and disclaimer.
10 */
11
12#ifndef BELFEM_CL_SOLVERDISTMATRIX_HPP
13#define BELFEM_CL_SOLVERDISTMATRIX_HPP
14
15#include <set> // for std::set (garray unique collection)
16
17#include "typedefs.hpp"
18#include "commtools.hpp"
19#include "cl_Cell.hpp"
20#include "cl_Vector.hpp"
21#include "cl_SpMatrix.hpp"
22#include "cl_OrderedMap.hpp"
24
25namespace belfem
26{
27 namespace sparse
28 {
30 {
31 protected:
32
35 const bool mPermutationSwitch ;
36
40
41 SpMatrix * mMatrix = nullptr ;
42
46
50
55
58
59 public:
60
61 DistMatrix( const SolverParameters * aParams, SpMatrix * aMatrix = nullptr ) ;
62
63 virtual ~DistMatrix();
64
65 virtual void
66 distribute_values( SpMatrix * aMatrix ) = 0 ;
67
68 const int_t *
69 dist() const
70 {
71 return mDist.data();
72 }
73
74 const real *
75 rhs() const
76 {
77 return mMyRhs.data();
78 }
79
80 real *
82 {
83 return mMyLhs.data();
84 }
85
87 size() const
88 {
89 return mNumRows;
90 }
91
94 {
95 return mMyLhs;
96 }
97
100 {
101 return mMyRhs;
102 }
103
104 void
105 distribute_rhs( const Vector< real > & aRhs ) ;
106
107 // as initial guess
108 void
109 distribute_lhs( const Vector< real > & aLhs ) ;
110
111 void
112 collect_lhs( Vector< real > & aLhs ) ;
113
114 protected:
115
116 void
118
119 virtual void
121
122 private:
123
124 bool
125 set_permutation_switch( const SolverParameters * aParams );
126
128 set_reordering_method( const SolverParameters * aParams );
129
130 void
131 create_matrix( SpMatrix * aMatrix );
132
136 void
137 order_graph( Graph & aGraph );
138
139 void
140 compute_index_permutation( const SpMatrix * aMatrix );
141
142
143 };
144
145 template< typename T >
147 {
148 Cell< Vector< T > > mAllPointers ;
149 Cell< Vector< T > > mAllIndices ;
150
151 Vector< T > mMyPointers ;
152 Vector< T > mMyIndices ;
153 Vector< real > mMyValues ;
154
155 // rank 0 only: points into the (permuted) matrix data set by
156 // distribute_values(); the solver copies on set/update, so the
157 // pointer only has to outlive that call
158 const real * mMyValuesData = nullptr ;
159
160 public:
161
162 DistMatrixCSR( const SolverParameters * aParams, SpMatrix * aMatrix ) :
163 DistMatrix( aParams, aMatrix )
164 {
166 }
167
168 void
169 distribute_values( SpMatrix * aMatrix ) override
170 {
171 if ( mCommRank == 0 )
172 {
174
175 real * tData = mPermutationSwitch ? mMatrix->data() : aMatrix->data();
176
177 // reorganize data
178 if ( mPermutationSwitch )
179 {
180 real * tValues = aMatrix->data();
181
182 index_t tCount = 0 ;
183 for ( index_t k : mIndexPermutation )
184 {
185 tData[ tCount++ ] = tValues[ k ] ;
186 }
187 }
188
189 // per-rank value slices are contiguous ranges
190 // [ ptr[dist(p)], ptr[dist(p+1)] ) = mOffsets ranges,
191 // so we scatter straight from the matrix data
192 mMyValuesData = tData ;
193
194 comm_barrier();
195 distribute( tData, mOffsets );
196 comm_barrier();
197 }
198 else
199 {
200 comm_barrier();
201 receive( mMyValues );
202 comm_barrier();
203 }
204 }
205
206 const T *
207 pointers() const
208 {
209 return mMyPointers.data();
210 }
211
212 const T *
213 indices() const
214 {
215 return mMyIndices.data();
216 }
217
218 const T
219 n_rows() const
220 {
221 return mMyNumRows;
222 }
223
224 const real *
225 values() const
226 {
227 if ( mCommRank == 0 )
228 {
229 BELFEM_ASSERT( mMyValuesData != nullptr,
230 "values() called before distribute_values()" );
231
232 // rank 0 owns rows [ 0, dist(1) ), so its slice starts
233 // at the beginning of the matrix data
234 return mMyValuesData ;
235 }
236 else
237 {
238 return mMyValues.data();
239 }
240 }
241
242 protected:
243
244 void
246 {
247 if ( mCommRank == 0 )
248 {
249 const int_t * tPtrs = mMatrix->pointers();
250 const int_t * tIdx = mMatrix->indices();
251
252 mAllPointers.set_size( mCommSize, {} );
253 mAllIndices.set_size( mCommSize, {} );
254
255 for ( proc_t p = 0; p < mCommSize; ++p )
256 {
257 Vector< T > & tPointers = mAllPointers( p );
258 Vector< T > & tIndices = mAllIndices( p );
259
260 int_t a = mDist( p );
261 int_t b = mDist( p+1 );
262 int_t n = b - a;
263
264 // Count total nnz
265 int_t nnz = tPtrs[b] - tPtrs[a];
266
267 tPointers.set_size( n + 1, 0 );
268 tIndices.set_size( nnz );
269
270 // local index
271 int_t k = 0 ;
272 for ( int_t i = a; i < b; ++i )
273 {
274 // local row
275 int_t r = i - a ;
276
277 // nnz per row
278 nnz = tPtrs[i+1] - tPtrs[i];
279
280 tPointers( r+1 ) = tPointers( r ) + nnz;
281
282 for ( int_t j = tPtrs[i]; j < tPtrs[i+1]; ++j )
283 {
284 tIndices( k++ ) = tIdx[j];
285 }
286 }
287 }
288
289 comm_barrier();
290
291 share( mDist );
292
293 mMyPointers = std::move( mAllPointers( mCommRank ) );
294 mMyIndices = std::move( mAllIndices( mCommRank ) );
295 mMyNumRows = mMyPointers.length() - 1;
296
297 distribute( mAllPointers );
298 distribute( mAllIndices );
299 comm_barrier() ;
300
301 mAllPointers.clear();
302 mAllIndices.clear();
303
304 }
305 else
306 {
307 comm_barrier();
308 receive( mDist );
309 receive( mMyPointers );
310 receive( mMyIndices );
311 comm_barrier() ;
312
313 mMyNumRows = mMyPointers.length() - 1;
314 mMyValues.set_size( mMyIndices.length(), 0 );
315 mMyLhs.set_size( mMyNumRows, 0.0 );
316 mMyRhs.set_size( mMyNumRows, 0.0 );
317 }
318 }
319
320 };
321
322 template< typename T >
324 {
325 Cell< Vector< T > > mAllDiagonalPointers ;
326 Cell< Vector< T > > mAllOffDiagonalPointers ;
327 Cell< Vector< T > > mAllDiagonalIndices ;
328 Cell< Vector< T > > mAllOffDiagonalIndices ;
329 Cell< Vector< T > > mAllGarrays ;
330
331 Cell< Vector< real > > mAllDiagonalValues ;
332 Cell< Vector< real > > mAllOffDiagonalValues ;
333
334 Vector< T > mMyDiagonalPointers ;
335 Vector< T > mMyOffDiagonalPointers ;
336 Vector< T > mMyDiagonalIndices ;
337 Vector< T > mMyOffDiagonalIndices ;
338 Vector< T > mMyGarray ;
339
340 Vector< real > mMyDiagonalValues ;
341 Vector< real > mMyOffDiagonalValues ;
342
343 const bool mUseLocalIndices ;
344 public:
345
346 DistMatrixAIJ( const SolverParameters * aParams, SpMatrix * aMatrix ) :
347 DistMatrix( aParams, aMatrix ),
348 mUseLocalIndices( aParams->type() == SolverType::STRUMPACK )
349 {
351 }
352
353 void
354 distribute_values( SpMatrix * aMatrix ) override
355 {
356 if ( mCommRank == 0 )
357 {
358 const int_t * tPtrs = mPermutationSwitch ? mMatrix->pointers() : aMatrix->pointers();
359 const int_t * tIdx = mPermutationSwitch ? mMatrix->indices() : aMatrix->indices();
360 real * tData = mPermutationSwitch ? mMatrix->data() : aMatrix->data();
361
362 // reorganize data
363 if ( mPermutationSwitch )
364 {
365 real * tValues = aMatrix->data();
366
367 index_t tCount = 0 ;
368 for ( index_t k : mIndexPermutation )
369 {
370 tData[ tCount++ ] = tValues[ k ] ;
371 }
372 }
373
374 index_t tCount = 0 ;
375 for ( proc_t p=0; p<mCommSize; ++p )
376 {
377 Vector< real > & tDiagValues = mAllDiagonalValues( p );
378 Vector< real > & tOffDiagValues = mAllOffDiagonalValues( p );
379 int_t a = mDist( p );
380 int_t b = mDist( p+1 );
381
382 index_t d = 0 ;
383 index_t o = 0 ;
384
385 for ( int_t i=a; i<b; ++i )
386 {
387 int_t n = tPtrs[i+1] - tPtrs[i];
388
389 for ( int_t j=0; j<n; ++j )
390 {
391 int_t k = tIdx[ tPtrs[i] + j ];
392
393 if ( k < a || k >= b )
394 {
395 tOffDiagValues( o++ ) = tData[ tCount++ ];
396 }
397 else
398 {
399 tDiagValues( d++ ) = tData[ tCount++ ];
400 }
401 }
402 }
403 }
404
405 comm_barrier() ;
406 distribute( mAllDiagonalValues );
407 distribute( mAllOffDiagonalValues );
408 comm_barrier() ;
409 }
410 else
411 {
412 comm_barrier();
413 receive( mMyDiagonalValues );
414 receive( mMyOffDiagonalValues );
415 comm_barrier() ;
416 }
417 }
418
419 T *
421 {
422 return mMyDiagonalPointers.data();
423 }
424
425 T *
427 {
428 return mMyOffDiagonalPointers.data();
429 }
430
431 T *
433 {
434 return mMyDiagonalIndices.data();
435 }
436
437 T *
439 {
440 return mMyOffDiagonalIndices.data();
441 }
442
443
444 T *
446 {
447 return mMyGarray.data();
448 }
449
450 T
452 {
453 return mMyGarray.length();
454 }
455
456 T
457 n_rows() const
458 {
459 return mMyNumRows;
460 }
461
462 real *
464 {
465 if ( mCommRank == 0 )
466 {
467 return mAllDiagonalValues( 0 ).data();
468 }
469 else
470 {
471 return mMyDiagonalValues.data();
472 }
473 }
474
475 real *
477 {
478 if ( mCommRank == 0 )
479 {
480 return mAllOffDiagonalValues( 0 ).data();
481 }
482 else
483 {
484 return mMyOffDiagonalValues.data();
485 }
486 }
487
488 protected:
489
490 void
492 {
493 if ( mCommRank == 0 )
494 {
495 mAllDiagonalPointers.set_size( mCommSize, {} );
496 mAllOffDiagonalPointers.set_size( mCommSize, {} );
497 mAllDiagonalIndices.set_size( mCommSize, {} );
498 mAllOffDiagonalIndices.set_size( mCommSize, {} );
499 mAllDiagonalValues.set_size( mCommSize, {} );
500 mAllOffDiagonalValues.set_size( mCommSize, {} );
501 mAllGarrays.set_size( mCommSize, {} );
502
503 const int_t * tPtrs = mMatrix->pointers() ;
504
505 const int_t * tIdx = mMatrix->indices() ;
506
507 for ( proc_t p = 0; p < mCommSize; ++p )
508 {
509 int_t a = mDist( p );
510 int_t b = mDist( p+1 );
511 int_t n = b - a;
512
513 // STEP 1: Collect unique off-diagonal columns for this rank
514 // Use std::set for automatic sorting and uniqueness
515 std::set< int_t > tUniqueOffDiagCols;
516
517 // Count total nnz and diagonal/off-diagonal entries
518 //int_t nnz = tPtrs[b] - tPtrs[a];
519 int_t nd = 0 ;
520 int_t no = 0 ;
521
522 // Count total nnz and diagonal/off-diagonal entries
523 for ( int_t i = a; i < b; ++i )
524 {
525 for ( int_t j=tPtrs[i]; j<tPtrs[i+1]; ++j )
526 {
527 int_t k = tIdx[j];
528 if ( a <=k && k < b )
529 {
530 ++nd;
531 }
532 else
533 {
534 ++no;
535 tUniqueOffDiagCols.insert( k );
536 }
537 }
538 }
539
540 // STEP 2: Build garray from unique off-diagonal columns
541 // std::set is already sorted, so we can copy directly
542 Vector< int_t > & tGarray = mAllGarrays( p );
543 tGarray.set_size( tUniqueOffDiagCols.size() );
544 int_t garrayIdx = 0;
545 OrderedMap< int_t, int_t > tGlobalToLocal; // Map global col -> local garray index
546 for ( int_t globalCol : tUniqueOffDiagCols )
547 {
548 tGarray( garrayIdx ) = globalCol;
549 tGlobalToLocal[ globalCol ] = garrayIdx++ ;
550 }
551
552 // STEP 3: Allocate MPIAIJ format (for set_MPIAIJ_matrix)
553
554 Vector< T > & tDiagPointers = mAllDiagonalPointers( p );
555 Vector< T > & tOffDiagPointers = mAllOffDiagonalPointers( p );
556 Vector< T > & tDiagIndices = mAllDiagonalIndices( p );
557 Vector< T > & tOffDiagIndices = mAllOffDiagonalIndices( p );
558 Vector< real > & tDiagValues = mAllDiagonalValues( p );
559 Vector< real > & tOffDiagValues = mAllOffDiagonalValues( p );
560
561 tDiagPointers.set_size( n + 1, 0 );
562 tOffDiagPointers.set_size( n + 1, 0 );
563 tDiagIndices.set_size( nd );
564 tOffDiagIndices.set_size( no );
565 tDiagValues.set_size( nd, 0.0 );
566 tOffDiagValues.set_size( no, 0.0 );
567
568 // STEP4: Build the format
569 int_t d = 0 ;
570 int_t o = 0 ;
571 for ( int_t i=a; i<b; ++i )
572 {
573 // local row index
574 int_t r = i - a ;
575
576 nd = 0 ;
577 no = 0 ;
578
579 // loop over the columns
580 for ( int_t j=tPtrs[i]; j<tPtrs[i+1]; ++j )
581 {
582 int_t k = tIdx[j];
583 if ( a <=k && k < b )
584 {
585 tDiagIndices( d++ ) = k - a ;
586 ++nd ;
587 }
588 else
589 {
590 // Off-diagonal block: convention depends on solver
591 if ( mUseLocalIndices )
592 {
593 // STRUMPACK: use local garray index
594 auto it = tGlobalToLocal.find( k );
595 BELFEM_ASSERT( it != tGlobalToLocal.end(),
596 "Failed to find global column %lu in garray map for rank %lu",
597 (long unsigned int) k, (long unsigned int) p );
598 tOffDiagIndices( o++ ) = it->second;
599 }
600 else
601 {
602 // PETSc: use global column index
603 tOffDiagIndices( o++ ) = k;
604 }
605 ++no ;
606 }
607 }
608
609 tDiagPointers( r+1 ) = tDiagPointers( r ) + nd;
610 tOffDiagPointers( r+1 ) = tOffDiagPointers( r ) + no;
611 }
612 }
613
614 comm_barrier();
615 share( mDist );
616
617 mMyDiagonalPointers = std::move( mAllDiagonalPointers( mCommRank ) );
618 mMyOffDiagonalPointers = std::move( mAllOffDiagonalPointers( mCommRank ) );
619 mMyDiagonalIndices = std::move( mAllDiagonalIndices( mCommRank ) );
620 mMyOffDiagonalIndices = std::move( mAllOffDiagonalIndices( mCommRank ) );
621 mMyGarray = std::move( mAllGarrays( mCommRank ) );
622
623 distribute( mAllDiagonalPointers );
624 distribute( mAllOffDiagonalPointers );
625 distribute( mAllDiagonalIndices );
626 distribute( mAllOffDiagonalIndices );
627 distribute( mAllGarrays );
628
629 comm_barrier();
630
631 mAllDiagonalPointers.clear();
632 mAllOffDiagonalPointers.clear();
633 mAllDiagonalIndices.clear();
634 mAllOffDiagonalIndices.clear();
635 mAllGarrays.clear();
636 }
637 else
638 {
639 comm_barrier();
640 receive( mDist );
641 receive( mMyDiagonalPointers );
642 receive( mMyOffDiagonalPointers );
643 receive( mMyDiagonalIndices );
644 receive( mMyOffDiagonalIndices );
645 receive( mMyGarray );
646 comm_barrier();
647
648 mMyDiagonalValues.set_size( mMyDiagonalIndices.length(), 0 );
649 mMyOffDiagonalValues.set_size( mMyOffDiagonalIndices.length(), 0 );
650 mMyNumRows = mMyDiagonalPointers.length() - 1;
651 mMyLhs.set_size( mMyNumRows, 0.0 );
652 mMyRhs.set_size( mMyNumRows, 0.0 );
653
654 }
655 }
656 };
657
658 }
659}
660#endif //BELFEM_CL_SOLVERDISTMATRIX_HPP
#define BELFEM_ASSERT(aCheck,...)
Definition assert.hpp:244
Sorted map (ordered key-value).
Definition cl_OrderedMap.hpp:32
auto find(const Key &tKey) const -> decltype(mMap.find(tKey))
Definition cl_OrderedMap.hpp:139
auto end() const -> decltype(mMap.end())
Definition cl_OrderedMap.hpp:133
Configuration for a Solver.
Definition cl_SolverParameters.hpp:27
Sparse matrix in CSR or CSC format.
Definition cl_SpMatrix.hpp:52
void set_indexing_base(const enum SpMatrixIndexingBase &aBasis)
change the indexing base
Definition cl_SpMatrix.cpp:814
int_t * indices()
expose the index array
Definition cl_SpMatrix.hpp:701
real * data()
expose the data container
Definition cl_SpMatrix.hpp:787
int_t * pointers()
expose the pointers
Definition cl_SpMatrix.hpp:771
T * data()
expose the underlying raw pointer ( writable version )
Definition cl_AR_Vector.hpp:182
void set_size(const size_t aNumRows)
change the size of the vector
Definition cl_AR_Vector.hpp:237
T * diagonal_pointers()
Definition cl_SolverDistMatrix.hpp:420
T * garray()
Definition cl_SolverDistMatrix.hpp:445
void distribute_sparsity_pattern() override
Definition cl_SolverDistMatrix.hpp:491
T garray_size() const
Definition cl_SolverDistMatrix.hpp:451
T * diagonal_indices()
Definition cl_SolverDistMatrix.hpp:432
T * offdiagonal_pointers()
Definition cl_SolverDistMatrix.hpp:426
real * offdiagonal_values()
Definition cl_SolverDistMatrix.hpp:476
DistMatrixAIJ(const SolverParameters *aParams, SpMatrix *aMatrix)
Definition cl_SolverDistMatrix.hpp:346
real * diagonal_values()
Definition cl_SolverDistMatrix.hpp:463
T n_rows() const
Definition cl_SolverDistMatrix.hpp:457
void distribute_values(SpMatrix *aMatrix) override
Definition cl_SolverDistMatrix.hpp:354
T * offdiagonal_indices()
Definition cl_SolverDistMatrix.hpp:438
void distribute_sparsity_pattern() override
Definition cl_SolverDistMatrix.hpp:245
const T * indices() const
Definition cl_SolverDistMatrix.hpp:213
void distribute_values(SpMatrix *aMatrix) override
Definition cl_SolverDistMatrix.hpp:169
const T n_rows() const
Definition cl_SolverDistMatrix.hpp:219
const real * values() const
Definition cl_SolverDistMatrix.hpp:225
DistMatrixCSR(const SolverParameters *aParams, SpMatrix *aMatrix)
Definition cl_SolverDistMatrix.hpp:162
const T * pointers() const
Definition cl_SolverDistMatrix.hpp:207
const ReorderingMethod mReorderingMethod
Definition cl_SolverDistMatrix.hpp:39
virtual void distribute_sparsity_pattern()=0
Vector< real > & lhs_vector()
Definition cl_SolverDistMatrix.hpp:93
const int_t * dist() const
Definition cl_SolverDistMatrix.hpp:69
Cell< index_t > mIndexPermutation
Definition cl_SolverDistMatrix.hpp:45
Vector< int_t > mDist
Definition cl_SolverDistMatrix.hpp:48
void determine_sizes_and_offsets()
Definition cl_SolverDistMatrix.cpp:232
const bool mPermutationSwitch
Definition cl_SolverDistMatrix.hpp:35
const real * rhs() const
Definition cl_SolverDistMatrix.hpp:75
Vector< real > mMyRhs
Definition cl_SolverDistMatrix.hpp:52
Cell< index_t > mForwardPermutation
Definition cl_SolverDistMatrix.hpp:43
void distribute_lhs(const Vector< real > &aLhs)
Definition cl_SolverDistMatrix.cpp:333
index_t mNumRows
Definition cl_SolverDistMatrix.hpp:56
Vector< int_t > mOffsets
Definition cl_SolverDistMatrix.hpp:49
const proc_t mCommSize
Definition cl_SolverDistMatrix.hpp:34
void distribute_rhs(const Vector< real > &aRhs)
Definition cl_SolverDistMatrix.cpp:289
real * lhs()
Definition cl_SolverDistMatrix.hpp:81
index_t size() const
Definition cl_SolverDistMatrix.hpp:87
virtual void distribute_values(SpMatrix *aMatrix)=0
Vector< real > mRhs
Definition cl_SolverDistMatrix.hpp:51
index_t mMyNumRows
Definition cl_SolverDistMatrix.hpp:57
Vector< real > mMyLhs
Definition cl_SolverDistMatrix.hpp:54
SpMatrix * mMatrix
Definition cl_SolverDistMatrix.hpp:41
const proc_t mCommRank
Definition cl_SolverDistMatrix.hpp:33
Vector< int_t > mSizes
Definition cl_SolverDistMatrix.hpp:47
Cell< index_t > mBackwardPermutation
Definition cl_SolverDistMatrix.hpp:44
void collect_lhs(Vector< real > &aLhs)
Definition cl_SolverDistMatrix.cpp:377
Vector< real > mLhs
Definition cl_SolverDistMatrix.hpp:53
DistMatrix(const SolverParameters *aParams, SpMatrix *aMatrix=nullptr)
Definition cl_SolverDistMatrix.cpp:23
Vector< real > & rhs_vector()
Definition cl_SolverDistMatrix.hpp:99
Definition cl_SolverDistMatrix.cpp:21
USER GUIDES:
Definition cl_Capacitor.cpp:16
void receive(string &aMessage, const proc_t aSource)
Definition commtools.cpp:348
void share(Vector< T > &aData)
Definition commtools.hpp:1671
Cell< graph::Vertex * > Graph
Definition cl_Graph_Vertex.hpp:329
@ Cpp
Definition cl_SpMatrix.hpp:39
void comm_barrier()
Synchronizes all processes in the communicator.
Definition commtools.cpp:57
int proc_t
Definition commtypes.hpp:29
SolverType
Definition en_SolverEnums.hpp:23
@ STRUMPACK
Definition en_SolverEnums.hpp:27
void distribute(Cell< T > &aData)
Distributes elements of a cell to other processes.
Definition commtools.hpp:804
ReorderingMethod
Definition en_SolverEnums.hpp:116
uint32_t index_t
Definition typedefs.hpp:52
double real
Definition typedefs.hpp:36
int32_t int_t
Definition typedefs.hpp:51