Alien  1.3.0
Developer documentation
Loading...
Searching...
No Matches
StreamMatrixBuilderT.h
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7
8
9#pragma once
10
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
15#include <alien/kernels/simple_csr/CSRStructInfo.h>
16#include <alien/kernels/simple_csr/SimpleCSRInternal.h>
17#include <alien/kernels/simple_csr/SimpleCSRMatrix.h>
18
19/*---------------------------------------------------------------------------*/
20
21#define USE_VMAP
22
23#ifdef USE_VMAP
24#include <alien/utils/VMap.h>
25#undef KEY_OF
26#undef VALUE_OF
27#undef NVALUE_OF
28#define KEY_OF(i) (i).key()
29//#define VALUE_OF(i) (i).value().first
30#define VALUE_OF(i) (i).value().first
31#define NVALUE_OF(i) (i).value().second
32#else /* USE_VMAP */
33#include <algorithm>
34#include <cstdlib>
35#include <iostream>
36#include <map>
37#include <utility>
38#include <vector>
39
40#undef KEY_OF
41#undef VALUE_OF
42#define KEY_OF(i) (i)->first
43#define VALUE_OF(i) (i)->second.m_build_position
44#endif /* USE_VMAP */
45
46/*---------------------------------------------------------------------------*/
47
48namespace Alien
49{
50
51/*---------------------------------------------------------------------------*/
52
53template <typename ValueT>
54StreamMatrixBuilderT<ValueT>::StreamMatrixBuilderT(Matrix& matrix, bool init_and_start)
55: m_matrix(matrix)
56, m_col_ordering(eUndef)
57, m_state(eNone)
58{
59 if (init_and_start) {
60 init();
61 start();
62 }
63}
64
65/*---------------------------------------------------------------------------*/
66
67template <typename ValueT>
69BlockMatrix& matrix, bool init_and_start)
70: m_matrix(matrix)
71, m_col_ordering(eUndef)
72, m_state(eNone)
73{
74 if (init_and_start) {
75 init();
76 start();
77 }
78}
79
80/*---------------------------------------------------------------------------*/
81
82template <typename ValueT>
84: m_matrix(matrix)
85, m_col_ordering(eUndef)
86, m_state(eNone)
87{
88 if (init_and_start) {
89 init();
90 start();
91 }
92}
93
94/*---------------------------------------------------------------------------*/
95
96template <typename ValueT>
101
102/*---------------------------------------------------------------------------*/
103
104template <typename ValueT>
106StreamMatrixBuilderT<ValueT>::getNewInserter()
107{
108 Inserter* inserter = new Inserter(this, m_inserters.size());
109 m_inserters.add(inserter);
110 return *inserter;
111}
112
113/*---------------------------------------------------------------------------*/
114
115template <typename ValueT>
116typename StreamMatrixBuilderT<ValueT>::Inserter&
117StreamMatrixBuilderT<ValueT>::getInserter(Integer id)
118{
119 Integer size = m_inserters.size();
120 if ((id < 0) || (id >= size))
121 FatalErrorException(A_FUNCINFO, "Bad Inserter id");
122 return *m_inserters[id];
123}
124
125/*---------------------------------------------------------------------------*/
126
127template <typename ValueT>
128void StreamMatrixBuilderT<ValueT>::finalize()
129{
130 bool has_error = false;
131 for (auto iter = m_inserters.begin(); iter != m_inserters.end(); ++iter) {
132 Filler& filler = **iter;
133 if (!filler.isEnd()) {
134 if (m_trace)
135 m_trace->warning() << "Inserter #" << filler.getId() << " not at final index";
136 has_error = true;
137 }
138 }
139 if (has_error)
140 throw FatalErrorException(A_FUNCINFO, "All inserters are not at final index");
141
142 m_matrix_impl->updateTimestamp();
143 m_matrix.impl()->unlock();
144}
145
146/*---------------------------------------------------------------------------*/
147
148template <typename ValueT>
149void StreamMatrixBuilderT<ValueT>::end()
150{
151 _freeInserters();
152}
153
154/*---------------------------------------------------------------------------*/
155
156template <typename ValueT>
157void StreamMatrixBuilderT<ValueT>::allocate()
158{
159 computeProfile();
160}
161
162/*---------------------------------------------------------------------------*/
163
164template <typename ValueT>
165void StreamMatrixBuilderT<ValueT>::_freeInserters()
166{
167 for (auto iter = m_inserters.begin(); iter != m_inserters.end(); ++iter)
168 delete *iter;
169 m_inserters.resize(0);
170}
171
172/*---------------------------------------------------------------------------*/
173
174template <typename ValueT>
175void StreamMatrixBuilderT<ValueT>::init()
176{
177 if (m_state == eInit)
178 return;
179
180 m_matrix.impl()->lock();
181
182 m_matrix_impl = &m_matrix.impl()->template get<BackEnd::tag::simplecsr>(true);
183
184 // const ISpace& space = m_matrix_impl->rowSpace();
185 // if (space != m_matrix_impl->colSpace())
186 // throw FatalErrorException(
187 // "stream matrix builder must be used with square matrix");
188
189 const MatrixDistribution& dist = m_matrix_impl->distribution();
190
191 m_parallel_mng = dist.parallelMng();
192
193 m_matrix_impl->free();
194
195 m_local_size = dist.localRowSize();
196 m_global_size = dist.globalRowSize();
197 m_local_offset = dist.rowOffset();
198 const VBlock* vblock = m_matrix.impl()->vblock();
199 // XT 15/10/2015 It seems that sizes don't need block information even with fixed size
200 // block
201 if (vblock)
202 throw FatalErrorException(
203 A_FUNCINFO, "This builder works only with fixed block size");
204
205 m_col_ordering = eUndef;
206
207 m_state = eInit;
208}
209
210/*---------------------------------------------------------------------------*/
211
212template <typename ValueT>
213void StreamMatrixBuilderT<ValueT>::start()
214{
215 m_matrix_impl->free();
216 m_state = ePrepared;
217}
218
219/*---------------------------------------------------------------------------*/
220
221template <typename ValueT>
222void StreamMatrixBuilderT<ValueT>::fillZero()
223{
224 m_matrix_impl->internal()->getValues().fill(0.);
225}
226
227/*---------------------------------------------------------------------------*/
228
229template <typename ValueT>
231{
238 // ALIEN_ASSERT((m_state == ePrepared),("Unexpected state: %d vs
239 // %d",m_state,ePrepared));
240
241 // InternalSpace::StructInfo const& info = m_matrix.space().structInfo() ;
242
243 // Attributes from classes relocated into this method (never used elsewhere)
244
245 class InsBuildPos
246 {
247 public:
248 Integer m_build_position;
249 // list of doublet inserter position an inserter reference
250 std::vector<std::pair<BaseInserter*, Integer>> m_inserter_vector;
251
252 InsBuildPos()
253 {
254 m_build_position = -1;
255 m_inserter_vector.reserve(1);
256 }
257 };
258 typedef std::pair<Integer, Integer> BuildPos;
259#ifdef USE_VMAP
260 typedef VMap<Integer, BuildPos> RowCols;
261#else /* USE_VMAP */
262 typedef std::map<Integer, InsBuildPos> RowCols;
263#endif /* USE_VMAP */
264 UniqueArray<RowCols> row_cols;
265
266 if (m_parallel_mng == NULL) {
267 m_myrank = 0;
268 m_nproc = 1;
269 }
270 else {
271 m_myrank = m_parallel_mng->commRank();
272 m_nproc = m_parallel_mng->commSize();
273 }
274
275 m_ghost_size = 0;
276 m_offset.resize(m_nproc + 1);
277 {
278 Arccore::MessagePassing::mpAllGather(m_parallel_mng,
279 ConstArrayView<Integer>(1, &m_local_offset), m_offset.subView(0, m_nproc));
280 }
281 m_offset[m_nproc] = m_global_size;
282
283 // Utilitaire local (en attendant les lambda-functions)
284 class IsLocal
285 {
286 public:
287 IsLocal(const ConstArrayView<Integer> offset, const Integer myrank)
288 : m_offset(offset)
289 , m_myrank(myrank)
290 {}
291 bool operator()(Arccore::Integer col) const
292 {
293 return (col >= m_offset[m_myrank]) && (col < m_offset[m_myrank + 1]);
294 }
295
296 private:
297 const ConstArrayView<Integer> m_offset;
298 const Integer m_myrank;
299 } isLocal(m_offset, m_myrank);
300
301 SimpleCSRInternal::CSRStructInfo& profile = m_matrix_impl->internal()->getCSRProfile();
302 profile.init(m_local_size);
303
304 m_row_size.resize(m_local_size);
305 m_ghost_row_size.resize(m_local_size);
306 m_ghost_row_size.fill(0);
307 UniqueArray<Integer>& upper_diag_offset = profile.getUpperDiagOffset();
308 if (m_order_row_cols_opt) {
309 profile.setDiagFirst(false);
310 upper_diag_offset.resize(m_local_size);
311 m_row_size.fill(0);
312 row_cols.resize(m_local_size);
313 }
314 else {
315 profile.setDiagFirst(true);
316 m_row_size.fill(1);
317 row_cols.resize(m_local_size);
318 for (Integer row = 0; row < m_local_size; ++row) {
319 row_cols[row][m_local_offset + row].first = 0;
320 }
321 }
322
323 // LOOP on inserter to compute filling position
324 for (auto iter = m_inserters.begin(); iter != m_inserters.end(); ++iter) {
325 BaseInserter* ins = *iter;
326 ins->m_data_index.resize(ins->count());
327 ins->m_n.add(0); // position de end
328 if (m_trace)
329 m_trace->info() << "Inserter id=" << ins->getId() << " count=" << ins->count();
330 for (Integer i = 0; i < ins->count(); ++i) {
331 Integer row = ins->m_row_index[i] - m_local_offset;
332 Integer col = ins->m_col_index[i];
333 if (row == m_local_size) {
334 // case of ghost row
335 // save -1, latter will be turn to the null position of the CSR structure
336 ins->m_data_index[i] = -1;
337 if (m_trace)
338 m_trace->info() << "Ghost Row : " << i << " " << ins->m_row_index[i];
339 }
340 else {
341#ifdef USE_VMAP
342 std::pair<typename RowCols::iterator, bool> finder = row_cols[row].insert(col);
343#else /* USE_VMAP */
344 std::pair<typename RowCols::iterator, bool> finder =
345 row_cols[row].insert(std::pair<Integer, InsBuildPos>(col, InsBuildPos()));
346#endif /* USE_VMAP */
347 auto inner_iter = finder.first;
348 if (finder.second) {
349 Integer k = m_row_size[row];
350 Integer gk = m_ghost_row_size[row];
351 if (isLocal(col)) {
352 VALUE_OF(inner_iter) = k - gk;
353 ins->m_data_index[i] = k - gk;
354 }
355 else {
356 // be careful, position will increment with ghost_offset after
357 VALUE_OF(inner_iter) = gk;
358 ins->m_data_index[i] = gk;
359 ++m_ghost_row_size[row];
360 }
361 ++m_row_size[row];
362 }
363 else {
364 ins->m_data_index[i] = VALUE_OF(inner_iter);
365 }
366 }
367 }
368 }
369
370 ArrayView<Integer> row_offsets =
371 m_matrix_impl->internal()->getCSRProfile().getRowOffset();
372 m_matrix_size = 0;
373 for (Integer row = 0; row < m_local_size; ++row) {
374 row_offsets[row] = m_matrix_size;
375 m_matrix_size += m_row_size[row];
376 }
377 row_offsets[m_local_size] = m_matrix_size;
378
379 UniqueArray<Integer> kcols;
380 if (m_order_row_cols_opt)
381 kcols.resize(m_matrix_size);
382
383 profile.allocate();
384 ArrayView<Integer> cols = profile.getCols();
385
386 m_matrix_impl->allocate();
387 m_matrix_impl->internal()->getValues().fill(0.);
388
389 //Integer icount = 0;
390 Integer offset = 0;
391 if (m_order_row_cols_opt) {
392 for (Integer row = 0; row < m_local_size; ++row) {
393 Integer ghost_offset = m_row_size[row] - m_ghost_row_size[row];
394 int ordered_idx = 0;
395 for (typename RowCols::iterator iter = row_cols[row].begin();
396 iter != row_cols[row].end(); ++iter) {
397 Integer col_uid = KEY_OF(iter);
398 // increment position for ghost cols
399 if (!isLocal(col_uid))
400 VALUE_OF(iter) += ghost_offset;
401 cols[offset + ordered_idx] = col_uid;
402 kcols[offset + VALUE_OF(iter)] = offset + ordered_idx;
403 if (col_uid == row + m_local_offset) {
404 upper_diag_offset[row] = offset + ordered_idx;
405 }
406 ++ordered_idx;
407 //++icount;
408 }
409 offset += m_row_size[row];
410 }
411 }
412 else {
413 for (Integer row = 0; row < m_local_size; ++row) {
414 if (m_trace)
415 m_trace->info() << "ROW(" << row << ")";
416 Integer ghost_offset = m_row_size[row] - m_ghost_row_size[row];
417 // int ordered_idx = 0;
418 for (typename RowCols::iterator iter = row_cols[row].begin();
419 iter != row_cols[row].end(); ++iter) {
420 Integer col_uid = KEY_OF(iter);
421 // increment position for ghost cols
422 if (!isLocal(col_uid))
423 VALUE_OF(iter) += ghost_offset;
424 cols[offset + VALUE_OF(iter)] = col_uid;
425 //++icount;
426 }
427 offset += m_row_size[row];
428 }
429 }
430 // ALIEN_ASSERT((icount==m_matrix_size),("matrix total size problem")) ;
431 for (auto iter = m_inserters.begin(); iter != m_inserters.end(); ++iter) {
432 BaseInserter* ins = *iter;
433 for (Integer i = 0; i < ins->count(); ++i) {
434 Integer row = ins->m_row_index[i] - m_local_offset;
435 if (row == m_local_size) {
436 // Ghost row
437 ins->m_data_index[i] = m_matrix_size; // equivalent to the null position
438 }
439 else {
440 Integer col = ins->m_col_index[i];
441 Integer ghost_offset =
442 (isLocal(col) ? 0 : m_row_size[row] - m_ghost_row_size[row]);
443 if (m_order_row_cols_opt) {
444 Integer build_pos = ins->m_data_index[i] + ghost_offset;
445 ins->m_data_index[i] = kcols[row_offsets[row] + build_pos];
446 }
447 else
448 ins->m_data_index[i] += row_offsets[row] + ghost_offset;
449 }
450 }
451
452 Integer neq = 1;
453 if (m_matrix_impl->block())
454 neq = m_matrix_impl->block()->size();
455 const Integer block_size = neq * neq;
456 ins->setMatrixValues(m_matrix_impl->internal()->getDataPtr(), block_size);
457 ins->m_col_index.dispose();
458 ins->m_row_index.dispose();
459 }
460
461 if (m_nproc > 1)
462 m_matrix_impl->parallelStart(m_offset, m_parallel_mng);
463 else
464 m_matrix_impl->sequentialStart();
465
466 profile.getColOrdering() = SimpleCSRInternal::CSRStructInfo::eOwnAndGhost;
467 m_col_ordering = eOwnAndGhost;
468 m_state = eStart;
469
470 m_row_size.resize(0);
471 m_ghost_row_size.resize(0);
472}
473
474/*---------------------------------------------------------------------------*/
475
476} // namespace Alien
477
478/*---------------------------------------------------------------------------*/
479/*---------------------------------------------------------------------------*/
MultiMatrixImpl.h.
Interface for all matrices.
Definition IMatrix.h:51
Computes a matrix distribution.
Arccore::MessagePassing::IMessagePassingMng * parallelMng() const
Get the parallel manager.
Integer count()
Nombre de données dans l'inserter.
Integer size()
Nombre d'itération dans l'inserter.
UniqueArray< Integer > m_data_index
positon of entry in the Matrix CSR structure
Integer getId() const
Identifiant de l'inserter dans son StreamMatrixBuilder.
StreamMatrixBuilderT(Matrix &matrix, bool init_and_start=true)
Variable size block elements for block matrices.
Definition VBlock.h:46
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Definition BackEnd.h:17