Arcane  4.1.12.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-2024 */
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 warning() << "[AlephMatrix::solveNow] mtxFileName rhsFileName write_to_file";
604 writeToFile(mtxFilename.localstr());
605 b->writeToFile(rhsFilename.localstr());
606 }
607 // Triggers the solution within the external library
608 m_implementation->AlephMatrixSolve(x, b, tmp,
609 nb_iteration,
610 residual_norm,
611 params);
612 if (dump_to_compare) {
613 const Integer globalIteration = m_kernel->subDomain()->commonVariables().globalIteration();
614 String lhsFilename = String("m_aleph_vector_x_") + globalIteration;
615 x->writeToFile(lhsFilename.localstr());
616 }
617 if (m_kernel->isCellOrdering())
618 debug() << "\33[1;32m[AlephMatrix::solveSync_waitAndFill] // nb_iteration="
619 << nb_iteration << ", residual_norm=" << *residual_norm << "\33[0m";
620 if (m_kernel->isParallel())
621 return;
622 debug() << "\33[1;32m[AlephMatrix::solveSync_waitAndFill] // nb_iteration="
623 << nb_iteration << ", residual_norm=" << *residual_norm << "\33[0m";
624 return;
625}
626
630void AlephMatrix::
631reassemble(Integer& nb_iteration,
632 Real* residual_norm)
633{
634 ItacFunction(AlephMatrix);
635 Timer::Action ta(m_kernel->subDomain(), "AlephMatrix::reassemble");
636 // If we are not in parallel mode, we are done with the solve
637 if (!m_kernel->isParallel())
638 return;
639 m_aleph_matrix_buffer_n_iteration.resize(1);
640 m_aleph_matrix_buffer_n_iteration[0] = nb_iteration;
641 m_aleph_matrix_buffer_residual_norm.resize(4);
642 m_aleph_matrix_buffer_residual_norm[0] = residual_norm[0];
643 m_aleph_matrix_buffer_residual_norm[1] = residual_norm[1];
644 m_aleph_matrix_buffer_residual_norm[2] = residual_norm[2];
645 m_aleph_matrix_buffer_residual_norm[3] = residual_norm[3];
646 // We must receive data
647 if (m_kernel->rank() != m_ranks[m_kernel->rank()] && !m_kernel->isAnOther()) {
648 debug() << "\33[1;32m[AlephMatrix::REassemble] " << m_kernel->rank()
649 << "<=" << m_ranks[m_kernel->rank()] << "\33[0m";
650 m_aleph_matrix_mpi_results_requests.add(m_kernel->world()->recv(m_aleph_matrix_buffer_n_iteration,
651 m_ranks[m_kernel->rank()], false));
652 m_aleph_matrix_mpi_results_requests.add(m_kernel->world()->recv(m_aleph_matrix_buffer_residual_norm,
653 m_ranks[m_kernel->rank()], false));
654 }
655 if (m_participating_in_solver) {
656 debug() << "\33[1;32m[AlephMatrix::REassemble] have participated, should send:"
657 << "\33[0m";
658 for (Integer iCpu = 0; iCpu < m_kernel->size(); ++iCpu) {
659 if (iCpu == m_kernel->rank())
660 continue;
661 if (m_kernel->rank() != m_ranks[iCpu])
662 continue;
663 debug() << "\33[1;32m[AlephMatrix::REassemble] " << m_kernel->rank() << " => " << iCpu << "\33[0m";
664 m_aleph_matrix_mpi_results_requests.add(m_kernel->world()->send(m_aleph_matrix_buffer_n_iteration,
665 iCpu, false));
666 m_aleph_matrix_mpi_results_requests.add(m_kernel->world()->send(m_aleph_matrix_buffer_residual_norm,
667 iCpu, false));
668 }
669 }
670}
671
675void AlephMatrix::
676reassemble_waitAndFill(Integer& nb_iteration, Real* residual_norm)
677{
678 ItacFunction(AlephMatrix);
679 Timer::Action ta(m_kernel->subDomain(), "AlephMatrix::reassemble_waitAndFill");
680 if (!m_kernel->isParallel())
681 return;
682 debug() << "\33[1;32m[AlephMatrix::REassemble_waitAndFill]"
683 << "\33[0m";
684 //if (m_kernel->isAnOther()) return;
685 m_kernel->world()->waitAllRequests(m_aleph_matrix_mpi_results_requests);
686 m_aleph_matrix_mpi_results_requests.clear();
687 if (!m_participating_in_solver) {
688 nb_iteration = m_aleph_matrix_buffer_n_iteration[0];
689 residual_norm[0] = m_aleph_matrix_buffer_residual_norm[0];
690 residual_norm[1] = m_aleph_matrix_buffer_residual_norm[1];
691 residual_norm[2] = m_aleph_matrix_buffer_residual_norm[2];
692 residual_norm[3] = m_aleph_matrix_buffer_residual_norm[3];
693 }
694 debug() << "\33[1;32m[AlephMatrix::REassemble_waitAndFill] // nb_iteration="
695 << nb_iteration << ", residual_norm=" << *residual_norm << "\33[0m";
696}
697
701void AlephMatrix::
702startFilling()
703{
704 ItacFunction(AlephMatrix);
705 /* Nothing here to do with this m_implementation */
706 debug() << "[AlephMatrix::startFilling] void"
707 << "\33[0m";
708}
709
713void AlephMatrix::
714writeToFile(const String file_name)
715{
716 ItacFunction(AlephMatrix);
717 debug() << "\33[1;32m[AlephMatrix::writeToFile] Dumping matrix to " << file_name << "\33[0m";
718 m_implementation->writeToFile(file_name);
719}
720
721/*---------------------------------------------------------------------------*/
722/*---------------------------------------------------------------------------*/
723
724} // namespace Arcane
725
726/*---------------------------------------------------------------------------*/
727/*---------------------------------------------------------------------------*/
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 warning() const
Flow for a warning 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.