Arcane  4.2.1.0
Developer documentation
Loading...
Searching...
No Matches
DistributedSPMM.cc
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/*
10 * This file is based on the work on AMGCL library (version march 2026)
11 * which can be found at https://github.com/ddemidov/amgcl.
12 *
13 * Copyright (c) 2012-2022 Denis Demidov <dennis.demidov@gmail.com>
14 * SPDX-License-Identifier: MIT
15 */
16/*---------------------------------------------------------------------------*/
17/*---------------------------------------------------------------------------*/
18
19#include "arccore/alina/BuiltinBackend.h"
20#include "arccore/alina/StaticMatrix.h"
21#include "arccore/alina/Adapters.h"
22#include "arccore/alina/DistributedMatrix.h"
23#include "arccore/alina/IO.h"
24
25#include "arccore/alina/Profiler.h"
26
27#include <iostream>
28#include <vector>
29
30using namespace Arcane;
31
32namespace math = Alina::math;
33
34template <class Val>
35void assemble(int n, int beg, int end,
36 std::vector<int>& ptr,
37 std::vector<int>& col,
38 std::vector<Val>& val)
39{
40 int chunk = end - beg;
41
42 ptr.clear();
43 ptr.reserve(chunk + 1);
44 ptr.push_back(0);
45 col.clear();
46 col.reserve(chunk * 4);
47 val.clear();
48 val.reserve(chunk * 4);
49
50 for (int j = beg, i = 0; j < end; ++j, ++i) {
51 if (j > 0) {
52 col.push_back(j - 1);
53 val.push_back(-math::identity<Val>());
54 }
55
56 col.push_back(j);
57 val.push_back(2 * math::identity<Val>());
58
59 if (j + 1 < n) {
60 col.push_back(j + 1);
61 val.push_back(-math::identity<Val>());
62 }
63
64 if (j + 5 < n) {
65 col.push_back(j + 5);
66 val.push_back(-0.1 * math::identity<Val>());
67 }
68
69 ptr.push_back(col.size());
70 }
71}
72
73template <class Val>
74void test()
75{
76 // In case of block, Rhs may be a StaticMatrix.
77 using Rhs = math::rhs_of<Val>::type;
78 using ScalarRhs = math::scalar_of<Rhs>::type;
79 int nb_scalar_for_rhs = sizeof(Rhs) / sizeof(ScalarRhs);
80
81 Alina::mpi_communicator comm(MPI_COMM_WORLD);
82 IMessagePassingMng* pm = comm.m_message_passing_mng.get();
83
84 int n = 16;
85 int chunk_len = (n + comm.size - 1) / comm.size;
86 int chunk_beg = std::min(n, chunk_len * comm.rank);
87 int chunk_end = std::min(n, chunk_len * (comm.rank + 1));
88 int chunk = chunk_end - chunk_beg;
89
90 UniqueArray<int> chunks(comm.size);
91 ConstArrayView<int> sent_chunk(1,&chunk);
92 mpAllGather(pm,sent_chunk,chunks);
93
94 std::vector<int> ptr;
95 std::vector<int> col;
96 std::vector<Val> val;
97 std::vector<Rhs> x(chunk);
98 std::vector<Rhs> y(chunk);
99
100 assemble(n, chunk_beg, chunk_end, ptr, col, val);
101
102 for (int i = 0; i < chunk; ++i)
103 x[i] = math::constant<Rhs>(drand48());
104
105 typedef Alina::BuiltinBackend<Val> Backend;
107
108 Matrix A(comm, std::tie(chunk, ptr, col, val), chunk);
109
110 auto B = Alina::product(A, A);
111 B->move_to_backend();
112
113 Alina::backend::spmv(1, *B, x, 0, y);
114
115 // Because Rhs may be a StaticMatrix and it is not a basic type
116 // we convert it to an array of basic type (which is math::scalar_of<Rhs>::type).
119 Span<const ScalarRhs> scalar_x_view(reinterpret_cast<ScalarRhs*>(x.data()), x.size() * nb_scalar_for_rhs);
120 Span<const ScalarRhs> scalar_r_view(reinterpret_cast<ScalarRhs*>(y.data()), y.size() * nb_scalar_for_rhs);
121 mpGatherVariable(pm, scalar_x_view, scalarX, 0);
122 mpGatherVariable(pm, scalar_r_view, scalarR, 0);
123
124 if (comm.rank == 0) {
125 std::cout << "Doing verification size=" << scalarX.size() << "\n";
126 Rhs* scalar_x_begin = reinterpret_cast<Rhs*>(scalarX.data());
127 std::vector<Rhs> X(scalar_x_begin, scalar_x_begin + n);
128
129 Rhs* scalar_r_begin = reinterpret_cast<Rhs*>(scalarR.data());
130 std::vector<Rhs> R(scalar_r_begin, scalar_r_begin + n);
131
132 std::vector<Rhs> Y(n);
133 assemble(n, 0, n, ptr, col, val);
134
135 Alina::CSRMatrix<Val> A(std::tie(n, ptr, col, val));
136 Alina::backend::spmv(1, *product(A, A), X, 0, Y);
137
138 double s = 0;
139 for (int i = 0; i < n; ++i) {
140 double d = math::norm(R[i] - Y[i]);
141 s += d * d;
142 }
143 std::cout << "Error: " << s << std::endl;
144 }
145}
146
147int main(int argc, char* argv[])
148{
149 MPI_Init(&argc, &argv);
150
151 test<double>();
152 test<Alina::StaticMatrix<double, 2, 2>>();
153 MPI_Finalize();
154}
Integer size() const
Number of elements in the vector.
Distributed Matrix using message passing.
const T * data() const
Access to the root of the array without any protection.
Constant view of an array of type T.
Matrix class, to be used by user.
Interface of the message passing manager.
View of an array of elements of type T.
Definition Span.h:633
1D data vector with value semantics (STL style).
C void mpGatherVariable(IMessagePassingMng *pm, Span< const char > send_buf, Array< char > &recv_buf, Int32 rank)
void mpAllGather(IMessagePassingMng *pm, const ISerializer *send_serializer, ISerializer *receive_serialize)
allGather() message for serialization
Definition Messages.cc:309
Namespace for mathematical functions.
Definition MathUtils.h:36
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Sparse matrix stored in CSR (Compressed Sparse Row) format.
Definition CSRMatrix.h:98
Convenience wrapper around MPI_Comm.