Arcane  4.2.3.0
Developer documentation
Loading...
Searching...
No Matches
AlephMatrix.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/* AlephMatrix.cc (C) 2000-2026 */
9/* */
10/*---------------------------------------------------------------------------*/
11/*---------------------------------------------------------------------------*/
12
13#include "arcane/aleph/AlephArcane.h"
14#include "arcane/core/MeshVariableScalarRef.h"
15
16/*---------------------------------------------------------------------------*/
17/*---------------------------------------------------------------------------*/
18
19namespace Arcane
20{
21
22/*---------------------------------------------------------------------------*/
23/*---------------------------------------------------------------------------*/
24
25/******************************************************************************
26 *****************************************************************************/
27AlephMatrix::
28AlephMatrix(AlephKernel* kernel)
29: TraceAccessor(kernel->parallel()->traceMng())
30, m_kernel(kernel)
31, m_index(kernel->index())
32, m_setValue_idx(0)
33, m_addValue_idx(0)
34{
35 ItacFunction(AlephMatrix);
36 if (kernel->isInitialized() == false) {
37 debug() << "\33[1;32m[AlephMatrix::AlephMatrix] New Aleph matrix, but kernel is not initialized!\33[0m";
38 return;
39 }
40 // Retrieving the ranks used for this resolution
41 m_ranks = kernel->solverRanks(m_index);
42 // Boolean to know if we participate or not
43 m_participating_in_solver = kernel->subParallelMng(m_index) != NULL;
44 debug() << "\33[1;32m[AlephMatrix::AlephMatrix] New Aleph matrix\33[0m";
45 if (!m_participating_in_solver) {
46 debug() << "\33[1;32m[AlephMatrix::AlephMatrix] Not concerned by this one!\33[0m";
47 return;
48 }
49 debug() << "\33[1;32m[AlephMatrix::AlephMatrix] site size="
50 << m_kernel->subParallelMng(m_index)->commSize()
51 << " @"
52 << m_kernel->subParallelMng(m_index)->commRank() << "\33[0m";
53 // We are going to look for a matrix from the factory which provides the interface to external libraries
54 m_implementation = m_kernel->factory()->GetMatrix(m_kernel, m_index);
55 traceMng()->flush();
56}
57
58/******************************************************************************
59 *****************************************************************************/
60AlephMatrix::
61~AlephMatrix()
62{
63 ItacFunction(AlephMatrix);
64 debug() << "\33[1;32m\t\t[~AlephMatrix]\33[0m";
65 rowColMap::const_iterator i = m_row_col_map.begin();
66 for (; i != m_row_col_map.end(); ++i)
67 delete i->second;
68}
69
70/******************************************************************************
71 * Matrix 'create' with the 'void' API
72 * BaseForm[Hash["AlephMatrix::create(void)", "CRC32"], 16] = fff06e2
73 *****************************************************************************/
74void AlephMatrix::create(void)
75{
76 Timer::Action ta(m_kernel->subDomain(), "AlephMatrix::create");
77 debug() << "\33[1;32m[AlephMatrix::create(void)]\33[0m";
78 // If the kernel is not initialized, we have nothing to do
79 if (!m_kernel->isInitialized())
80 return;
81 // If there are 'others' and we are not part of them,
82 // we broadcast that a 'create' needs to be done
83 if (m_kernel->thereIsOthers() && !m_kernel->isAnOther())
84 m_kernel->world()->broadcast(UniqueArray<unsigned long>(1, 0xfff06e2l).view(), 0);
85 // We flush in anticipation of filling, it must be done even if configured
86 // However, we do not flush the one for addValue
87 m_setValue_idx = 0;
88}
89
90/******************************************************************************
91 * Matrix 'create' with the API that specifies the number of non-zero elements per row
92 * BaseForm[Hash["AlephMatrix::create(IntegerConstArrayView,bool)", "CRC32"], 16] = 5c3111b1
93 *****************************************************************************/
94void AlephMatrix::
95create(IntegerConstArrayView row_nb_element, bool has_many_elements)
96{
97 ARCANE_UNUSED(row_nb_element);
98 ARCANE_UNUSED(has_many_elements);
99 debug() << "\33[1;32m[AlephMatrix::create(old API)] API with row_nb_element + has_many_elements\33[0m";
100 this->create();
101}
102
106void AlephMatrix::
107reset(void)
108{
109 Timer::Action ta(m_kernel->subDomain(), "AlephMatrix::reset");
110 debug() << "\33[1;32m[AlephMatrix::reset]\33[0m";
111 m_setValue_val.fill(0.0);
112 m_addValue_val.fill(0.0);
113}
114
118void AlephMatrix::
119addValue(const VariableRef& rowVar, const ItemEnumerator& rowItm,
120 const VariableRef& colVar, const ItemEnumerator& colItm,
121 const Real val)
122{
123 addValue(rowVar, *rowItm, colVar, *colItm, val);
124}
125void AlephMatrix::addValue(const VariableRef& rowVar, const Item& rowItm,
126 const VariableRef& colVar, const Item& colItm,
127 const Real val)
128{
129 AlephInt row = m_kernel->indexing()->get(rowVar, rowItm);
130 AlephInt col = m_kernel->indexing()->get(colVar, colItm);
131 if (m_kernel->isInitialized()) {
132 const AlephInt row_offset = m_kernel->topology()->part()[m_kernel->rank()];
133 row += row_offset;
134 col += row_offset;
135 }
136 //debug()<<"[AlephMatrix::addValue] IVariable/Item add @ ["<<row<<","<<col<<"]="<<val;
137 addValue(row, col, val);
138}
139
140void AlephMatrix::
141updateKnownRowCol(Integer row,
142 Integer col,
143 Real val)
144{
145 //debug()<<"\33[1;32m[AlephMatrix::updateKnownRowCol]\33[0m";
146 m_addValue_row.add(row);
147 m_addValue_col.add(col);
148 m_addValue_val.add(val);
149 m_addValue_idx += 1;
150 // We do the same on the 'set' side to have the correct size
151 m_setValue_row.add(row);
152 m_setValue_col.add(col);
153 m_setValue_val.add(0.);
154}
155
156void AlephMatrix::
157rowMapMapCol(Integer row,
158 Integer col,
159 Real val)
160{
161 rowColMap::const_iterator iRowMap = m_row_col_map.find(row);
162 // If the row is not even known yet
163 // We add a map entry (map(m_addValue_idx))
164 if (iRowMap == m_row_col_map.end()) {
165 colMap* jMap = new colMap();
166 /*debug()<<"\33[1;32m[AlephMatrix::rowMapMapCol] row "
167 <<row<<" inconue, m_addValue_idx="
168 <<m_addValue_idx<<"\33[0m";*/
169 m_row_col_map.insert(std::make_pair(row, jMap));
170 jMap->insert(std::make_pair(col, m_addValue_idx));
171 updateKnownRowCol(row, col, val);
172 return;
173 }
174 // We focus on the second dimension
175 colMap* jMap = iRowMap->second;
176 colMap::const_iterator iColMap = jMap->find(col);
177 // If this column is not known for this row
178 // We add an entry
179 if (iColMap == jMap->end()) {
180 /*debug()<<"\33[1;32m[AlephMatrix::rowMapMapCol] col "
181 <<col<<" inconue, m_addValue_idx="
182 <<m_addValue_idx<<"\33[0m";*/
183 jMap->insert(std::make_pair(col, m_addValue_idx));
184 updateKnownRowCol(row, col, val);
185 return;
186 }
187 // Otherwise we add
188 //debug()<<"\33[1;32m[AlephMatrix::rowMapMapCol] hit\33[0m";
189 //debug()<<"[AlephMatrix::rowMapMapCol] += for ["<<row<<","<<col<<"]="<<val; traceMng()->flush();
190 m_addValue_val[iColMap->second] += val;
191}
192
196void AlephMatrix::
197addValue(Integer row, Integer col, Real val)
198{
199 //debug()<<"\33[32m[AlephMatrix::addValue] addValue("<<row<<","<<col<<")="<<val<<"\33[0m";
200 row = m_kernel->ordering()->swap(row);
201 col = m_kernel->ordering()->swap(col);
202 // Search for the cell (row,j) if it already exists
203 rowMapMapCol(row, col, val);
204}
205
209void AlephMatrix::
210setValue(const VariableRef& rowVar, const ItemEnumerator& rowItm,
211 const VariableRef& colVar, const ItemEnumerator& colItm,
212 const Real val)
213{
214 setValue(rowVar, *rowItm, colVar, *colItm, val);
215}
216
220void AlephMatrix::
221setValue(const VariableRef& rowVar, const Item& rowItm,
222 const VariableRef& colVar, const Item& colItm,
223 const Real val)
224{
225 Integer row = m_kernel->indexing()->get(rowVar, rowItm);
226 Integer col = m_kernel->indexing()->get(colVar, colItm);
227 //debug()<<"[AlephMatrix::setValue] dof #"<<m_setValue_idx<<" ["<<row<<","<<col<<"]="<<val;
228 if (m_kernel->isInitialized()) {
229 const Integer row_offset = m_kernel->topology()->part()[m_kernel->rank()];
230 row += row_offset;
231 col += row_offset;
232 }
233 setValue(row, col, val);
234}
235
239void AlephMatrix::
240setValue(Integer row, Integer col, Real val)
241{
242 // Re-ordering if necessary
243 row = m_kernel->ordering()->swap(row);
244 col = m_kernel->ordering()->swap(col);
245 // If the kernel has already been configured,
246 // we ensure that the 'geometry/support' has not changed between resolutions
247 if (m_kernel->configured()) {
248 if ((m_setValue_row[m_setValue_idx] != row) ||
249 (m_setValue_col[m_setValue_idx] != col))
250 throw FatalErrorException("Aleph::setValue", "Row|Col have changed!");
251 m_setValue_row[m_setValue_idx] = row;
252 m_setValue_col[m_setValue_idx] = col;
253 m_setValue_val[m_setValue_idx] = val;
254 }
255 else {
256 m_setValue_row.add(row);
257 m_setValue_col.add(col);
258 m_setValue_val.add(val);
259 }
260 m_setValue_idx += 1;
261}
262
266Int32 AlephMatrix::
267reIdx(Integer ij,
268 Array<Int32*>& known_items_own_address)
269{
270 return *known_items_own_address[ij];
271}
272
276void AlephMatrix::
277reSetValuesIn(AlephMatrix* thisMatrix,
278 Array<Int32*>& known_items_own_address)
279{
280 for (Integer k = 0, kMx = m_setValue_idx; k < kMx; k += 1) {
281 Integer i = reIdx(m_setValue_row[k], known_items_own_address);
282 Integer j = reIdx(m_setValue_col[k], known_items_own_address);
283 thisMatrix->setValue(i, j, m_setValue_val[k]);
284 }
285}
286
290void AlephMatrix::
291reAddValuesIn(AlephMatrix* thisMatrix,
292 Array<Int32*>& known_items_own_address)
293{
294 for (Integer k = 0, kMx = m_addValue_row.size(); k < kMx; k += 1) {
295 const Integer row = reIdx(m_addValue_row[k], known_items_own_address);
296 const Integer col = reIdx(m_addValue_col[k], known_items_own_address);
297 const Real val = m_addValue_val[k];
298 thisMatrix->addValue(row, col, val);
299 }
300}
301
305void AlephMatrix::
306assemble(void)
307{
308 ItacFunction(AlephMatrix);
309 Timer::Action ta(m_kernel->subDomain(), "AlephMatrix::assemble");
310 // If the kernel is not initialized, we still do nothing
311 if (!m_kernel->isInitialized()) {
312 debug() << "\33[1;32m[AlephMatrix::assemble] Trying to assemble a matrix"
313 << "from an uninitialized kernel!\33[0m";
314 return;
315 }
316 // If no [set|add]Value has been received, this is not normal
317 if (m_addValue_idx != 0 && m_setValue_idx != 0)
318 throw FatalErrorException("AlephMatrix::assemble", "Still exclusives [add||set]Value required!");
319 // If addValue have been captured, they must be 're-played'
320 // Warning: for now, adds and sets are disjoint!
321 if (m_addValue_idx != 0) {
322 debug() << "\33[1;32m[AlephMatrix::assemble] m_addValue_idx!=0\33[0m";
323 // We flush our setValues index
324 m_setValue_idx = 0;
325 Timer::Action ta(m_kernel->subDomain(), "Flatenning addValues");
326 debug() << "\t\33[32m[AlephMatrix::assemble] Flatenning addValues size=" << m_addValue_row.size() << "\33[0m";
327 for (Integer k = 0, kMx = m_addValue_row.size(); k < kMx; ++k) {
328 m_setValue_row[k] = m_addValue_row[k];
329 m_setValue_col[k] = m_addValue_col[k];
330 m_setValue_val[k] = m_addValue_val[k];
331 /*debug()<<"\t\33[32m[AlephMatrix::assemble] setValue ("<<m_setValue_row[k]
332 <<","<<m_setValue_col[k]<<")="<<m_setValue_val[k]<<"\33[0m";*/
333 m_setValue_idx += 1;
334 }
335 }
336 // If there are 'others' and we are not part of them, we inform them of the assembly
337 if (m_kernel->thereIsOthers() && !m_kernel->isAnOther()) {
338 debug() << "\33[1;32m[AlephMatrix::assemble] We inform the other kappas that we are assembling"
339 << "\33[0m";
340 m_kernel->world()->broadcast(UniqueArray<unsigned long>(1, 0x74f253cal).view(), 0);
341 // And we give them the info of m_setValue_idx
342 m_kernel->world()->broadcast(UniqueArray<Integer>(1, m_setValue_idx).view(), 0);
343 }
344 // We initialize the topology if it has not already been done
345 if (!m_kernel->isAnOther()) {
346 debug() << "\33[1;32m[AlephMatrix::assemble] Initializing topology"
347 << "\33[0m";
348 ItacRegion(topology->create, AlephMatrix);
349 m_kernel->topology()->create(m_setValue_idx);
350 }
351 // If we have not already calculated the number of non-zero elements per row
352 // it is time to trigger it
353 debug() << "\33[1;32m[AlephMatrix::assemble] Updating row_nb_element"
354 << "\33[0m";
355 if (!m_kernel->topology()->hasSetRowNbElements()) {
356 UniqueArray<Integer> row_nb_element;
357 row_nb_element.resize(m_kernel->topology()->nb_row_rank());
358 row_nb_element.fill(0);
359 // When we are not an Other, we must update row_nb_element if it was not specified during matrix->create
360 if (m_kernel->thereIsOthers() && !m_kernel->isAnOther()) {
361 debug() << "\33[1;32m[AlephMatrix::assemble] Kernel's topology has not set its nb_row_elements, now doing it!"
362 << "\33[0m";
363 const Integer row_offset = m_kernel->topology()->part()[m_kernel->rank()];
364 debug() << "\33[1;32m[AlephMatrix::assemble] row_offset=" << row_offset << "\33[0m";
365 debug() << "\33[1;32m[AlephMatrix::assemble] filled, row_nb_element.size=" << row_nb_element.size() << "\33[0m";
366 // We are doing it in one pass for now to get a maximum bound
367 for (Integer i = 0, iMx = m_setValue_row.size(); i < iMx; ++i)
368 row_nb_element[m_setValue_row.at(i) - row_offset] += 1;
369 }
370 m_kernel->topology()->setRowNbElements(row_nb_element);
371 debug() << "\33[1;32m[AlephMatrix::assemble] done hasSetRowNbElements"
372 << "\33[0m";
373 }
374 // In the case //, the solver prepares to retrieve matrix parts from others
375 debug() << "\33[1;32m[AlephMatrix::assemble] Récupération des parties de matrices"
376 << "\33[0m";
377 if (m_participating_in_solver && (!m_kernel->configured())) {
378 UniqueArray<Integer> nbValues(m_kernel->size());
379 {
380 ItacRegion(gathered_nb_setValued, AlephMatrix);
381 nbValues.fill(0);
382 for (Integer iCpu = 0; iCpu < m_kernel->size(); ++iCpu) {
383 if (m_kernel->rank() != m_ranks[iCpu])
384 continue;
385 //debug()<<"\33[1;32m[AlephMatrix::assemble] Adding nb_values from iCpu "<<iCpu<<"\33[0m";
386 nbValues[iCpu] = m_kernel->topology()->gathered_nb_setValued(iCpu);
387 }
388 }
389 {
390 ItacRegion(resize, AlephMatrix);
391 m_aleph_matrix_buffer_rows.resize(nbValues);
392 m_aleph_matrix_buffer_cols.resize(nbValues);
393 m_aleph_matrix_buffer_vals.resize(nbValues);
394 }
395 }
396 // If we are not in //, there is nothing else to do
397 if (!m_kernel->isParallel())
398 return;
399 // If I participate in the solution, I receive contributions from other participants
400 if (m_participating_in_solver) {
401 ItacRegion(iRecv, AlephMatrix);
402 debug() << "\33[1;32m[AlephMatrix::assemble] I am part of the solver, let's iRecv"
403 << "\33[0m";
404 // If I am the solver, I receive the rest of the matrices from either other cores or myself
405 for (Integer iCpu = 0; iCpu < m_kernel->size(); ++iCpu) {
406 // Except from myself
407 if (iCpu == m_kernel->rank())
408 continue;
409 // Except from those who do not participate
410 if (m_kernel->rank() != m_ranks[iCpu])
411 continue;
412 debug() << "\33[1;32m[AlephMatrix::assemble] "
413 << " recv " << m_kernel->rank()
414 << " <= " << iCpu
415 << " size=" << m_aleph_matrix_buffer_cols[iCpu].size() << "\33[0m";
416 m_aleph_matrix_mpi_data_requests.add(m_kernel->world()->recv(m_aleph_matrix_buffer_vals[iCpu], iCpu, false));
417 // Once configured, we know all the (i,j): no need to send them back
418 if (!m_kernel->configured()) {
419 m_aleph_matrix_mpi_data_requests.add(m_kernel->world()->recv(m_aleph_matrix_buffer_rows[iCpu], iCpu, false));
420 m_aleph_matrix_mpi_data_requests.add(m_kernel->world()->recv(m_aleph_matrix_buffer_cols[iCpu], iCpu, false));
421 }
422 }
423 }
424 // If I am an Arcane rank that has data to send, I do it
425 if ((m_kernel->rank() != m_ranks[m_kernel->rank()]) && (!m_kernel->isAnOther())) {
426 ItacRegion(iSend, AlephMatrix);
427 debug() << "\33[1;32m[AlephMatrix::assemble]"
428 << " send " << m_kernel->rank()
429 << " => " << m_ranks[m_kernel->rank()]
430 << " for " << m_setValue_val.size() << "\33[0m";
431 m_aleph_matrix_mpi_data_requests.add(m_kernel->world()->send(m_setValue_val, m_ranks[m_kernel->rank()], false));
432 if (!m_kernel->configured()) {
433 debug() << "\33[1;32m[AlephMatrix::assemble] iSend my row to " << m_ranks[m_kernel->rank()] << "\33[0m";
434 m_aleph_matrix_mpi_data_requests.add(m_kernel->world()->send(m_setValue_row, m_ranks[m_kernel->rank()], false));
435 debug() << "\33[1;32m[AlephMatrix::assemble] iSend my col to " << m_ranks[m_kernel->rank()] << "\33[0m";
436 m_aleph_matrix_mpi_data_requests.add(m_kernel->world()->send(m_setValue_col, m_ranks[m_kernel->rank()], false));
437 }
438 }
439}
440
444void AlephMatrix::
445create_really(void)
446{
447 ItacFunction(AlephMatrix);
448 Timer::Action ta(m_kernel->subDomain(), "AlephMatrix::create_really");
449 debug() << "\33[1;32m[AlephMatrix::create_really]"
450 << "\33[0m";
451 // We need a working matrix in all cases
452 debug() << "\33[1;32m[AlephMatrix::create_really] new MATRIX"
453 << "\33[0m";
454 // and we trigger the creation within the implementation
455 m_implementation->AlephMatrixCreate();
456 debug() << "\33[1;32m[AlephMatrix::create_really] done"
457 << "\33[0m";
458}
459
463void AlephMatrix::
464assemble_waitAndFill(void)
465{
466 ItacFunction(AlephMatrix);
467 Timer::Action ta(m_kernel->subDomain(), "AlephMatrix::assemble_waitAndFill");
468 debug() << "\33[1;32m[AlephMatrix::assemble_waitAndFill]"
469 << "\33[0m";
470 if (m_kernel->isParallel()) {
471 ItacRegion(Wait, AlephMatrix);
472 debug() << "\33[1;32m[AlephMatrix::assemble_waitAndFill] wait for "
473 << m_aleph_matrix_mpi_data_requests.size() << " Requests"
474 << "\33[0m";
475 m_kernel->world()->waitAllRequests(m_aleph_matrix_mpi_data_requests);
476 m_aleph_matrix_mpi_data_requests.clear();
477 debug() << "\33[1;32m[AlephMatrix::assemble_waitAndFill] clear"
478 << "\33[0m";
479 if (m_participating_in_solver == false) {
480 debug() << "\33[1;32m[AlephMatrix::assemble_waitAndFill] nothing more to do"
481 << "\33[0m";
482 }
483 }
484 // If I do not participate, I do not participate
485 if (!m_participating_in_solver)
486 return;
487 // Otherwise, we take the time to build the matrix; others should do the same
488 if (!m_kernel->configured()) {
489 ItacRegion(Create, AlephMatrix);
490 debug() << "\33[1;32m[AlephMatrix::assemble_waitAndFill] solver " << m_index << " create_really"
491 << "\33[0m";
493 }
494 // And then we proceed with filling the matrix
495 {
496 ItacRegion(Fill, AlephMatrix);
497 if (m_kernel->configured())
498 m_implementation->AlephMatrixSetFilled(false); // Activation of fill protection
499 debug() << "\33[1;32m[AlephMatrix::assemble_waitAndFill] " << m_index << " fill"
500 << "\33[0m";
501 AlephInt* bfr_row_implem;
502 AlephInt* bfr_col_implem;
503 double* bfr_val_implem;
504 for (int iCpu = 0; iCpu < m_kernel->size(); ++iCpu) {
505 if (m_kernel->rank() != m_ranks[iCpu])
506 continue;
507 if (iCpu == m_kernel->rank()) {
508 bfr_row_implem = m_setValue_row.data();
509 bfr_col_implem = m_setValue_col.data();
510 bfr_val_implem = m_setValue_val.data();
511 m_implementation->AlephMatrixFill(m_setValue_val.size(),
512 bfr_row_implem,
513 bfr_col_implem,
514 bfr_val_implem);
515 }
516 else {
517 bfr_row_implem = m_aleph_matrix_buffer_rows[iCpu].data();
518 bfr_col_implem = m_aleph_matrix_buffer_cols[iCpu].data();
519 bfr_val_implem = m_aleph_matrix_buffer_vals[iCpu].data();
520 m_implementation->AlephMatrixFill(m_aleph_matrix_buffer_vals[iCpu].size(),
521 bfr_row_implem,
522 bfr_col_implem,
523 bfr_val_implem);
524 }
525 }
526 }
527 { // We then declare the matrix as filled, and we start the configuration
528 ItacRegion(Cfg, AlephMatrix);
529 m_implementation->AlephMatrixSetFilled(true); // Deactivation of fill protection
530 if (!m_kernel->configured()) {
531 debug() << "\33[1;32m[AlephMatrix::assemble_waitAndFill] " << m_index << " MATRIX ASSEMBLE"
532 << "\33[0m";
533 int assrtnd = 0;
534 assrtnd = m_implementation->AlephMatrixAssemble();
535 debug() << "\33[1;32m[AlephMatrix::assemble_waitAndFill] AlephMatrixAssemble=" << assrtnd << "\33[0m";
536 // throw FatalErrorException("AlephMatrix::assemble_waitAndFill", "configuration failed");
537 }
538 }
539 debug() << "\33[1;32m[AlephMatrix::assemble_waitAndFill] done"
540 << "\33[0m";
541}
542
546void AlephMatrix::
547solve(AlephVector* x,
548 AlephVector* b,
549 Integer& nb_iteration,
550 Real* residual_norm,
551 AlephParams* solver_param,
552 bool async)
553{
554 ItacFunction(AlephMatrix);
555 Timer::Action ta(m_kernel->subDomain(), "AlephMatrix::solve");
556 debug() << "\33[1;32m[AlephMatrix::solve] Queuing solver " << m_index << "\33[0m";
557 m_kernel->postSolver(solver_param, this, x, b);
558 // If the post was specified to us, we do not trigger synchronous mode
559 if (async)
560 return;
561 debug() << "\33[1;32m[AlephMatrix::solve] SYNCHRONOUS MODE has been requested, syncing!"
562 << "\33[0m";
563 m_kernel->syncSolver(0, nb_iteration, residual_norm);
564 return;
565}
566
576void AlephMatrix::
577solveNow(AlephVector* x,
578 AlephVector* b,
579 AlephVector* tmp,
580 Integer& nb_iteration,
581 Real* residual_norm,
582 AlephParams* params)
583{
584 Timer::Action ta(m_kernel->subDomain(), "AlephMatrix::solveNow");
585 const bool dump_to_compare =
586 (m_index == 0) && // If we are at the first solution
587 (m_kernel->rank() == 0) && // and we are the 'master'
588 (params->writeMatrixToFileErrorStrategy()) && // and we requested a write_matrix!
589 (m_kernel->subDomain()->commonVariables().globalIteration() == 1) && // and the first or second iteration
590 (m_kernel->nbRanksPerSolver() == 1);
591 ItacFunction(AlephMatrix);
592 if (!m_participating_in_solver) {
593 debug() << "\33[1;32m[AlephMatrix::solveNow] Nothing to do here!"
594 << "\33[0m";
595 return;
596 }
597 debug() << "\33[1;32m[AlephMatrix::solveNow]"
598 << "\33[0m";
599 if (dump_to_compare) {
600 const Integer globalIteration = m_kernel->subDomain()->commonVariables().globalIteration();
601 String mtxFilename = String("m_aleph_matrix_A_") + globalIteration;
602 String rhsFilename = String("m_aleph_vector_b_") + globalIteration;
603 info() << "[AlephMatrix::solveNow] dumping matrix in file '" << mtxFilename << "'\n";
604 info() << "[AlephMatrix::solveNow] dumping rhs in file '" << rhsFilename << "'\n";
605 writeToFile(mtxFilename.localstr());
606 b->writeToFile(rhsFilename.localstr());
607 }
608 // Triggers the solution within the external library
609 m_implementation->AlephMatrixSolve(x, b, tmp,
610 nb_iteration,
611 residual_norm,
612 params);
613 if (dump_to_compare) {
614 const Integer globalIteration = m_kernel->subDomain()->commonVariables().globalIteration();
615 String lhsFilename = String("m_aleph_vector_x_") + globalIteration;
616 x->writeToFile(lhsFilename.localstr());
617 }
618 if (m_kernel->isCellOrdering())
619 debug() << "\33[1;32m[AlephMatrix::solveSync_waitAndFill] // nb_iteration="
620 << nb_iteration << ", residual_norm=" << *residual_norm << "\33[0m";
621 if (m_kernel->isParallel())
622 return;
623 debug() << "\33[1;32m[AlephMatrix::solveSync_waitAndFill] // nb_iteration="
624 << nb_iteration << ", residual_norm=" << *residual_norm << "\33[0m";
625 return;
626}
627
631void AlephMatrix::
632reassemble(Integer& nb_iteration,
633 Real* residual_norm)
634{
635 ItacFunction(AlephMatrix);
636 Timer::Action ta(m_kernel->subDomain(), "AlephMatrix::reassemble");
637 // If we are not in parallel mode, we are done with the solve
638 if (!m_kernel->isParallel())
639 return;
640 m_aleph_matrix_buffer_n_iteration.resize(1);
641 m_aleph_matrix_buffer_n_iteration[0] = nb_iteration;
642 m_aleph_matrix_buffer_residual_norm.resize(4);
643 m_aleph_matrix_buffer_residual_norm[0] = residual_norm[0];
644 m_aleph_matrix_buffer_residual_norm[1] = residual_norm[1];
645 m_aleph_matrix_buffer_residual_norm[2] = residual_norm[2];
646 m_aleph_matrix_buffer_residual_norm[3] = residual_norm[3];
647 // We must receive data
648 if (m_kernel->rank() != m_ranks[m_kernel->rank()] && !m_kernel->isAnOther()) {
649 debug() << "\33[1;32m[AlephMatrix::REassemble] " << m_kernel->rank()
650 << "<=" << m_ranks[m_kernel->rank()] << "\33[0m";
651 m_aleph_matrix_mpi_results_requests.add(m_kernel->world()->recv(m_aleph_matrix_buffer_n_iteration,
652 m_ranks[m_kernel->rank()], false));
653 m_aleph_matrix_mpi_results_requests.add(m_kernel->world()->recv(m_aleph_matrix_buffer_residual_norm,
654 m_ranks[m_kernel->rank()], false));
655 }
656 if (m_participating_in_solver) {
657 debug() << "\33[1;32m[AlephMatrix::REassemble] have participated, should send:"
658 << "\33[0m";
659 for (Integer iCpu = 0; iCpu < m_kernel->size(); ++iCpu) {
660 if (iCpu == m_kernel->rank())
661 continue;
662 if (m_kernel->rank() != m_ranks[iCpu])
663 continue;
664 debug() << "\33[1;32m[AlephMatrix::REassemble] " << m_kernel->rank() << " => " << iCpu << "\33[0m";
665 m_aleph_matrix_mpi_results_requests.add(m_kernel->world()->send(m_aleph_matrix_buffer_n_iteration,
666 iCpu, false));
667 m_aleph_matrix_mpi_results_requests.add(m_kernel->world()->send(m_aleph_matrix_buffer_residual_norm,
668 iCpu, false));
669 }
670 }
671}
672
676void AlephMatrix::
677reassemble_waitAndFill(Integer& nb_iteration, Real* residual_norm)
678{
679 ItacFunction(AlephMatrix);
680 Timer::Action ta(m_kernel->subDomain(), "AlephMatrix::reassemble_waitAndFill");
681 if (!m_kernel->isParallel())
682 return;
683 debug() << "\33[1;32m[AlephMatrix::REassemble_waitAndFill]"
684 << "\33[0m";
685 //if (m_kernel->isAnOther()) return;
686 m_kernel->world()->waitAllRequests(m_aleph_matrix_mpi_results_requests);
687 m_aleph_matrix_mpi_results_requests.clear();
688 if (!m_participating_in_solver) {
689 nb_iteration = m_aleph_matrix_buffer_n_iteration[0];
690 residual_norm[0] = m_aleph_matrix_buffer_residual_norm[0];
691 residual_norm[1] = m_aleph_matrix_buffer_residual_norm[1];
692 residual_norm[2] = m_aleph_matrix_buffer_residual_norm[2];
693 residual_norm[3] = m_aleph_matrix_buffer_residual_norm[3];
694 }
695 debug() << "\33[1;32m[AlephMatrix::REassemble_waitAndFill] // nb_iteration="
696 << nb_iteration << ", residual_norm=" << *residual_norm << "\33[0m";
697}
698
702void AlephMatrix::
703startFilling()
704{
705 ItacFunction(AlephMatrix);
706 /* Nothing here to do with this m_implementation */
707 debug() << "[AlephMatrix::startFilling] void"
708 << "\33[0m";
709}
710
714void AlephMatrix::
715writeToFile(const String file_name)
716{
717 ItacFunction(AlephMatrix);
718 debug() << "\33[1;32m[AlephMatrix::writeToFile] Dumping matrix to " << file_name << "\33[0m";
719 m_implementation->writeToFile(file_name);
720}
721
722/*---------------------------------------------------------------------------*/
723/*---------------------------------------------------------------------------*/
724
725} // namespace Arcane
726
727/*---------------------------------------------------------------------------*/
728/*---------------------------------------------------------------------------*/
Integer size() const
Number of elements in the vector.
void create_really(void)
create_really transmits the creation order to the external library
void setValue(const VariableRef &, const Item &, const VariableRef &, const Item &, const Real)
setValue from arguments in IVariables, Items, and Real
void writeToFile(const String)
Triggers the writing of the matrix to a file.
Integer reIdx(Integer, Array< Int32 * > &)
reIdx searches for the correspondence of the AlephIndexing
Parameters of a linear system.
Definition AlephParams.h:32
Vector of a linear system.
Definition AlephVector.h:33
Base class for 1D data vectors.
void fill(ConstReferenceType value)
Fills the array with the value value.
void resize(Int64 s)
Changes the number of elements in the array to s.
Enumerator over a list of entities.
Base class for a mesh element.
Definition Item.h:84
const char * localstr() const
Returns the conversion of the instance into UTF-8 encoding.
Definition String.cc:229
Positions the name of the currently executing action.
Definition Timer.h:119
TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium) const
Flow for a debug message.
TraceMessage info() const
Flow for an information message.
1D data vector with value semantics (STL style).
Reference to a variable.
Definition VariableRef.h:56
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Int32 Integer
Type representing an integer.
double Real
Type representing a real number.
int AlephInt
Default type for indexing rows and columns of matrices and vectors.
Definition AlephGlobal.h:50
std::int32_t Int32
Signed integer type of 32 bits.