CEPS  24.01
Cardiac ElectroPhysiology Simulator
PETScMatrix.cpp
Go to the documentation of this file.
1 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2  This file is part of CEPS.
3 
4  CEPS is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  CEPS is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with CEPS (see file LICENSE at root of project).
16  If not, see <https://www.gnu.org/licenses/>.
17 
18 
19  Copyright 2019-2024 Inria, Universite de Bordeaux
20 
21  Authors, in alphabetical order:
22 
23  Pierre-Elliott BECUE, Florian CARO, Yves COUDIERE(*), Andjela DAVIDOVIC,
24  Charlie DOUANLA-LONTSI, Marc FUENTES, Mehdi JUHOOR, Michael LEGUEBE(*),
25  Pauline MIGERDITICHAN, Valentin PANNETIER(*), Nejib ZEMZEMI.
26  * : currently active authors
27 
28 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
32 
34  m_A (nullptr),
35  m_lo (0U),
36  m_hi (0U),
37  m_properlySet(false)
38 {
39  // Users MUST call DistributedMatrix::setNonZeroStructure(...)
40  // and setSize
41  // after calling this constructor to actually create the matrix
42  MatCreate(ceps::getCommunicator(), &m_A);
43  MatSetType(m_A, MATAIJ);
44  MatSetUp(m_A);
45 }
46 
48  m_A (nullptr),
49  m_lo (0U),
50  m_hi (0U),
51  m_properlySet(false)
52 {
53  // Users MUST call DistributedMatrix::setNonZeroStructure(...)
54  // after calling this constructor to actually create the matrix
55  MatCreate(ceps::getCommunicator(),&m_A);
56  setSize(M, N, m, n);
57  MatSetType(m_A, MATAIJ);
58  MatSetUp(m_A);
59 }
60 
62  m_A (nullptr),
63  m_lo (0U),
64  m_hi (0U),
65  m_properlySet(true)
66 {
67  templateMatrix.duplicate(*this, copyValues);
68  MatGetOwnershipRange(m_A, &m_lo, &m_hi);
69  MatSetUp(m_A);
70 }
71 
73  m_A (nullptr),
74  m_lo (0U),
75  m_hi (0U),
76  m_properlySet(false)
77 {
78  MatCreate(ceps::getCommunicator(), &m_A);
79  load(file);
80  MatSetUp(m_A);
81 }
82 
84 {
85  if (ceps::isValidPtr(m_A))
86  MatDestroy(&m_A);
87 }
88 
89 void
91 {
92  PetscBool pflag = flag ? PETSC_TRUE : PETSC_FALSE;
93  MatSetOption (m_A, MAT_IGNORE_OFF_PROC_ENTRIES, pflag);
94  return;
95 }
96 
97 void
99 {
100  PetscBool pflag = flag ? PETSC_TRUE : PETSC_FALSE;
101 
102  MatSetOption(m_A, MAT_SYMMETRIC, pflag);
103  MatSetOption(m_A, MAT_SYMMETRY_ETERNAL, pflag);
104  return;
105 }
106 
107 void
109 {
110  CEPS_ABORT_IF( not ((M >= 0 && N >= 0) or (m >= 0 && n >= 0)),
111  "Invalid matrix sizes provided : got " << CEPS_DISPLAY_VAL (M, N, m, n)
112  );
113  MatSetSizes(m_A, m, n, M, N);
114  return;
115 }
116 
117 void
119 {
120  if (ceps::isParallel())
121  {
122  MatMPIAIJSetPreallocation(m_A, 0, d_nnz, 0, o_nnz);
123  }
124  else
125  MatSeqAIJSetPreallocation(m_A, 0, d_nnz);
126  MatGetOwnershipRange(m_A, &m_lo, &m_hi);
127  // now ok to use this matrix
128  m_properlySet = true;
129  return;
130 }
131 
132 void
134 {
135  if (ceps::isParallel())
136  MatMPIAIJSetPreallocation(m_A, d_nz, nullptr, o_nz, nullptr);
137  else
138  MatSeqAIJSetPreallocation(m_A, d_nz, nullptr);
139  MatGetOwnershipRange(m_A, &m_lo, &m_hi);
140  // now ok to use this matrix
141  m_properlySet = true;
142  return;
143 }
144 
145 void
147 {
148  MatSetValue(m_A, row, column, value, INSERT_VALUES);
149  return;
150 }
151 
152 void
154 {
155  MatSetValue(m_A, row, column, value, ADD_VALUES);
156  return;
157 }
158 
159 void
161  CepsMathScalar *values,
162  CepsInt nbRows,
163  CepsInt nbColumns,
164  const CepsGlobalIndex *rowIndices,
165  const CepsGlobalIndex *columnIndices
166 )
167 {
168  MatGetValues(m_A, nbRows, rowIndices, nbColumns, columnIndices, values);
169  return;
170 }
171 
172 void
174  const CepsMathScalar *values,
175  CepsInt nbRows,
176  CepsInt nbColumns,
177  const CepsGlobalIndex *rowIndices,
178  const CepsGlobalIndex *columnIndices
179 )
180 {
181  MatSetValues(m_A, nbRows, rowIndices, nbColumns, columnIndices, values, INSERT_VALUES);
182  return;
183 }
184 
185 void
187  const CepsMathScalar *values,
188  CepsInt nbRows,
189  CepsInt nbColumns,
190  const CepsGlobalIndex *rowIndices,
191  const CepsGlobalIndex *columnIndices
192 )
193 {
194  MatSetValues(m_A, nbRows, rowIndices, nbColumns, columnIndices, values, ADD_VALUES);
195  return;
196 }
197 
198 void
200  CepsInt nbRows,
201  CepsGlobalIndex *rows,
202  CepsMathScalar diagonalValue
203 )
204 {
205  MatSetOption(m_A, MAT_KEEP_NONZERO_PATTERN, PETSC_TRUE);
206  MatZeroRowsColumns(m_A, nbRows, rows, diagonalValue, nullptr, nullptr);
207  return;
208 }
209 
210 void
212 {
213  MatSetOption(m_A, MAT_KEEP_NONZERO_PATTERN, PETSC_TRUE);
214  MatSetOption(m_A, MAT_NO_OFF_PROC_ZERO_ROWS, PETSC_FALSE);
215  MatZeroRows (m_A, nbRows, rows, diagonalValue, PETSC_NULL, PETSC_NULL);
216  return;
217 }
218 
219 void
221 {
222  MatZeroEntries(m_A);
223  return;
224 }
225 
226 void
228 {
229  CepsInt mGlobal, nGlobal;
230  MatGetSize(m_A, &mGlobal, &nGlobal);
231  CEPS_ABORT_IF(mGlobal != nGlobal,
232  "cannot set non-square matrix to identity.\nCurrent size is ("
233  << mGlobal << "," << nGlobal << ")"
234  );
235 
236  // proceed by setting non-zero structure: 1 value per row in
237  // diagonal, 0 elsewhere
238  this->setNonZeroStructure(1,0);
239  CepsGlobalIndex i;
240  for (i=m_lo; i<m_hi; i++)
241  setValue(1.0,i,i);
242  return;
243 }
244 
245 void
247 {
248  if (sameNonZeroStructure)
249  MatAXPY(m_A, a, X.m_A, SAME_NONZERO_PATTERN);
250  else
251  MatAXPY(m_A, a, X.m_A, DIFFERENT_NONZERO_PATTERN);
252  return;
253 }
254 
257 {
258  assertAssembled("computing L infty norm");
259  CepsReal res = 0.0;
260  MatNorm(m_A, NORM_INFINITY, &res);
261  return res;
262 }
263 
266 {
267  assertAssembled("computing L 1 norm");
268  CepsReal res = 0.0;
269  MatNorm(m_A, NORM_1, &res);
270  return res;
271 }
272 
275 {
276  assertAssembled("computing L 2 norm");
277  CepsReal res = 0.0;
278  MatNorm(m_A, NORM_FROBENIUS, &res);
279  return res;
280 }
281 
282 void
284 {
285  // Not to be used on a non-finalized matrix. Call
286  // DistributedMatrix::finalize() before copying. <br>
287  assertAssembled("calling copy");
288  MatCopy (m_A, A.m_A, DIFFERENT_NONZERO_PATTERN);
289  return;
290 }
291 
292 void
294 {
295  // Not to be used on a non-finalized matrix. Call
296  // DistributedMatrix::finalize() before copying. <br>
297  if (flag)
298  MatDuplicate(m_A, MAT_COPY_VALUES, &(A.m_A));
299  else
300  MatDuplicate(m_A, MAT_DO_NOT_COPY_VALUES, &(A.m_A));
301  A.m_lo = m_lo;
302  A.m_hi = m_hi;
303  A.m_properlySet = true;
304  return;
305 }
306 
307 void
309 {
310  checkProperlySet ();
311  MatGetSize (m_A, M, N);
312  return;
313 }
314 
315 void
317 {
318  checkProperlySet ();
319  MatGetLocalSize (m_A, m, n);
320  return;
321 }
322 
323 void
325 {
326  checkProperlySet ();
327  *lo = m_lo;
328  *hi = m_hi;
329 }
330 
331 void
333  const CepsMathScalar **values,
334  CepsGlobalIndex row,
335  CepsInt *nbNonZero,
336  const CepsGlobalIndex **cols
337 ) const
338 {
339  CEPS_ABORT_IF (row < m_lo or row >= m_hi,
340  "Trying to access row " << row << "on process that owns range " << m_lo << "to " << m_hi
341  );
342  MatGetRow (m_A, row, nbNonZero, cols, values);
343  return;
344 }
345 
346 void
348  const CepsMathScalar **values,
349  CepsGlobalIndex row,
350  CepsInt *nbNonZero,
351  const CepsGlobalIndex **cols
352 )
353 {
354  MatRestoreRow (m_A, row, nbNonZero, cols, values);
355  return;
356 }
357 
358 void
360 {
361  /*
362  * PETSc implementation:
363  * Due to the way PETSc is designed, we cannot directly return
364  * a pointer to the buffer holding the local values in the matrix;
365  * that would require 2 function calls: one to get the pointer
366  * and another to release it to ensure that the "application does not
367  * bleed memory"(c.f PETSc doc).
368  * What we do here is we <B>copy</B> the non-zero values from the local buffer
369  * into a vector.
370  * Obviously, the values in the matrix are not altered.
371  */
372 
373  checkProperlySet ();
374  assertAssembled("accessing memory");
375  CEPS_ABORT_IF (row < m_lo or row >= m_hi,
376  "Trying to access row " << row << "on process that owns range " << m_lo << "to " << m_hi
377  );
378 
379 
380  rowValues.clear();
381 
382  CepsInt nbNonZero;
383 
384  const CepsMathScalar *vals;
385  MatGetRow(m_A, row, &nbNonZero, nullptr, &vals);
386 
387  rowValues.reserve(nbNonZero);
388  // copy the values
389  rowValues.insert(rowValues.begin(),vals,vals+nbNonZero);
390 
391  // restore array
392  MatRestoreRow(m_A, row, &nbNonZero, nullptr, &vals);
393 }
394 
395 void
397  const
398 {
399 
401  assertAssembled("accessing memory");
402  CEPS_ABORT_IF (row < m_lo or row >= m_hi,
403  "Trying to access row " << row << " on process that owns range " << m_lo << " to " << m_hi
404  );
405 
406 
407  rowValues.clear();
408  // resize it to global size
409  CepsInt M, N;
410  this->getSize(&M, &N);
411  rowValues.resize(N, 0.0);
412 
413  CepsInt nbNonZero;
414  const CepsGlobalIndex *cols;
415  const CepsMathScalar *vals;
416  MatGetRow(m_A, row, &nbNonZero, &cols, &vals);
417 
418  // iterate on non zero values
419  for (CepsGlobalIndex i = 0; i < nbNonZero; i++)
420  rowValues[cols[i]] = vals[i];
421 
422  // restore array
423  MatRestoreRow(m_A, row, &nbNonZero, &cols, &vals);
424  return;
425 }
426 
427 void
429 {
430  // Compatibility check
431  CepsGlobalIndex loV, loA, hiV, hiA;
432  v.getLocalRange(&loV, &hiV);
433  getLocalRange(&loA, &hiA);
434  CEPS_ABORT_IF (loV != loA or hiV != hiA,
435  "Incompatible decompositions of vector and matrix for column "
436  << "insertion." << std::endl << "Matrix has local range (" << loA << "," << hiA
437  << ") whereas vector has local range (" << loV << "," << hiV << ")"
438  );
439 
440  CepsInt nbCols = 1;
441  CepsInt nbRows = hiA - loA;
442  CepsGlobalIndex *rowIndices = new CepsGlobalIndex[nbRows];
443  for (CepsGlobalIndex i = loA; i < hiA; ++i)
444  rowIndices[i - loA] = i;
445  CepsGlobalIndex colIndices[1] = {column};
446 
447  v.getLocalData();
448  MatGetValues(m_A, nbRows, rowIndices, nbCols, colIndices, v.m_localData);
449  v.releaseLocalData();
450  ceps::destroyTabular(rowIndices);
451  return;
452 }
453 
454 void
456 {
457  // Compatibility check
458  CepsGlobalIndex loV, loA, hiV, hiA;
459  v.getLocalRange (&loV, &hiV);
460  getLocalRange (&loA, &hiA);
461  CEPS_ABORT_IF (loV != loA or hiV != hiA,
462  "Incompatible decompositions of vector and matrix for column "
463  << "insertion." << std::endl << "Matrix has local range (" << loA << "," << hiA
464  << ") whereas vector has local range (" << loV << "," << hiV << ")"
465  );
466 
467  CepsInt nbCols = 1;
468  CepsInt nbRows = hiA - loA;
469  CepsGlobalIndex *rowIndices = new CepsGlobalIndex[nbRows];
470  for (CepsGlobalIndex i = loA; i < hiA; ++i)
471  rowIndices[i - loA] = i;
472  CepsGlobalIndex colIndices[1] = {column};
473 
474  v.getLocalData();
475  MatSetValues(m_A, nbRows, rowIndices, nbCols, colIndices, v.m_localData, INSERT_VALUES);
476  finalize();
477  v.releaseLocalData();
478  ceps::destroyTabular(rowIndices);
479  return;
480 }
481 
482 void
484 {
485  // Compatibility check
486  CepsGlobalIndex loV, loA, hiV, hiA;
487  v.getLocalRange(&loV, &hiV);
488  getLocalRange(&loA, &hiA);
489  CEPS_ABORT_IF (loV != loA or hiV != hiA,
490  "Incompatible decompositions of vector and matrix for column "
491  << "insertion." << std::endl << "Matrix has local range (" << loA << "," << hiA
492  << ") whereas vector has local range (" << loV << "," << hiV << ")"
493  );
494 
495  v.getLocalData();
496  MatGetDiagonal(m_A, v.m_v);
497  v.releaseLocalData();
498 }
499 
500 void
502 {
504  CepsInt lo = 0, hi = 0;
505  v.getLocalRange(&lo, &hi);
506  v.getLocalData();
507  for (CepsInt i = lo; i < hi; i++)
508  v[i] = static_cast<CepsReal>(std::abs(v[i]) > epsilon);
509  v.releaseLocalData();
510 }
511 
512 void
514 {
515  PetscViewer fd;
516  PetscViewerBinaryOpen(ceps::getCommunicator (), fileName.c_str (), FILE_MODE_WRITE, &fd);
517  MatView(m_A, fd);
518  PetscViewerDestroy(&fd);
519  return;
520 }
521 
522 void
524 {
525  PetscViewer fd;
526  PetscViewerBinaryOpen(ceps::getCommunicator(),fileName.c_str(),FILE_MODE_READ,&fd);
527  MatLoad(m_A,fd);
528  PetscViewerDestroy(&fd);
529 
530  m_properlySet = true;
531  return;
532 }
533 
534 void
536 {
537  MatAssemblyBegin (m_A, MAT_FINAL_ASSEMBLY);
538  return;
539 }
540 
541 void
543 {
544  MatAssemblyEnd(m_A, MAT_FINAL_ASSEMBLY);
545  return;
546 }
547 
548 void
550 {
551  beginAssembly();
552  endAssembly ();
553  return;
554 }
555 
556 void
558 {
559  MatAssemblyBegin(m_A, MAT_FLUSH_ASSEMBLY);
560  MatAssemblyEnd (m_A, MAT_FLUSH_ASSEMBLY);
561  return;
562 }
563 
564 CepsBool
566 {
567  PetscBool set, flag = PETSC_FALSE;
568  MatIsSymmetricKnown(m_A, &set, &flag);
569 
570  return (flag == PETSC_FALSE ? false : true);
571 }
572 
573 CepsBool
575 {
576  PetscBool assembled;
577 
578  MatAssembled(m_A, &assembled);
579 
580  return (assembled == PETSC_FALSE ? false : true);
581 }
582 
583 void
585 {
586  CepsString message = "Not to be used on a non-finalized matrix. ";
587  if (not info.empty())
588  message += "Call DistributedMatrix::finalize() before " + info;
589  CEPS_ABORT_IF(not isAssembled(),message);
590  return;
591 }
592 
593 void
595 {
597  MatView(m_A, PETSC_VIEWER_STDOUT_WORLD);
598  return;
599 }
600 
601 void
603 {
605  "canot use this matrix as it is not properly set.\nCheck if "
606  "sizes and memory preallocation are correct"
607  );
608  return;
609 }
610 
613 {
614  MatScale (m_A, scalar);
615  return *this;
616 }
#define CEPS_DISPLAY_VAL(...)
Generates a string with the names and values of the arguments of the macro, supports up to ten argume...
#define CEPS_ABORT_IF(condition, message)
Stops the execution with a message if condition is true. If testing is enabled, only throws a runtime...
std::basic_string< CepsChar > CepsString
C++ format string.
Definition: CepsTypes.hpp:128
CepsScalar CepsMathScalar
Real numbers.
Definition: CepsTypes.hpp:133
std::vector< _Type, _Alloc > CepsVector
C++ vector.
Definition: CepsTypes.hpp:155
bool CepsBool
Booleans.
Definition: CepsTypes.hpp:124
CepsIndex CepsGlobalIndex
Many uses. Has to be signed for PETSc.
Definition: CepsTypes.hpp:218
float CepsReal
Need single precision floating point.
Definition: CepsTypes.hpp:100
int32_t CepsInt
Need 32 bit integer.
Definition: CepsTypes.hpp:106
Sparse matrix distributed between process.
void zero()
Zeroes all entries.
CepsMathScalar lInfNorm() const
-norm of matrix
CepsMathScalar l2Norm() const
-norm of matrix
void add(DistributedMatrix &X, CepsMathScalar a, CepsBool sameNonZeroStructure=true)
Adds a*X to this.
void getEntireLocalRow(CepsVector< CepsMathScalar > &rowValues, CepsGlobalIndex row) const
Get a copy of all values stored in a local row, including zeros.
void zeroRows(CepsInt nbRows, CepsGlobalIndex *rows, CepsMathScalar diagonalValue=1.0)
Sets the indicated rows to zero.
void releaseLocalRow(const CepsMathScalar **values, CepsGlobalIndex row, CepsInt *nbNonZero, const CepsGlobalIndex **nonZeroCols)
Release access to the values of matrix row after reading.
CepsBool isSymmetric() const
True if matrix is symmetric.
void setValue(CepsMathScalar value, CepsGlobalIndex i, CepsGlobalIndex j)
Sets A(i,j) (replace if existing)
void identity()
Sets to identity matrix. Fails if matrix is not square.
void setSymmetric(CepsBool flag=true)
Set whether this matrix is symmetric or not.
Definition: PETScMatrix.cpp:98
void getLocalSize(CepsInt *m, CepsInt *n) const
Get the local size of the matrix.
CepsGlobalIndex m_lo
Index of first local row.
void ignoreOffProcEntries(CepsBool flag)
Choose to ignore entries destined to other processes when setting or adding values in the matrix.
Definition: PETScMatrix.cpp:90
void setNonZeroStructure(const CepsInt d_nnz[], const CepsInt o_nnz[])
Set the matrix non-zero structure.
void getDiagonalAsDistributedVector(DistributedVector &v) const
Fills a DistributedVector with values of diagonal.
void flush()
Use when switching between calls to adding and setting values.
void beginAssembly()
Begin matrix assembly.
CepsBool isAssembled() const
Safety check.
void addValue(CepsMathScalar value, CepsGlobalIndex i, CepsGlobalIndex j)
Adds value to A(i,j) (sets if not existing already)
void checkProperlySet() const
Will fail if matrix is not properly set (correct sizes and memory preallocation).
DistributedMatrix & operator*=(const CepsMathScalar &scalar)
Short mult by scalar.
void copy(DistributedMatrix &A) const
Copy values from this matrix to matrix A of same non-zero structure.
void getLocalRow(const CepsMathScalar **values, CepsGlobalIndex row, CepsInt *nbNonZero, const CepsGlobalIndex **nonZeroCols) const
Read-only access to the values of matrix row.
void assertAssembled(CepsString info="") const
Safetier check.
DistributedMatrix()
Empty constructor.
Definition: PETScMatrix.cpp:33
void setSize(CepsInt M, CepsInt N, CepsInt m, CepsInt n)
Set distributed matrix global and local size.
void setValues(const CepsMathScalar *values, CepsInt nbRows, CepsInt nbColumns, const CepsGlobalIndex *rowIndices, const CepsGlobalIndex *columnIndices)
Set multiple values in the matrix at once.
void getDiagonalFootPrintAsDistributedVector(DistributedVector &v, CepsReal epsilon=1E-12) const
Fills a DistributedVector with the footprint (zero or non-zero) of diagonal.
void setColumnAsDistributedVector(DistributedVector &v, CepsGlobalIndex column)
Sets the values of a distributed vector in matrix column.
void getLocalRange(CepsGlobalIndex *lo, CepsGlobalIndex *hi) const
Get the range of rows owned by current process.
CepsGlobalIndex m_hi
Index of last local row +1.
void addValues(const CepsMathScalar *values, CepsInt nbRows, CepsInt nbColumns, const CepsGlobalIndex *rowIndices, const CepsGlobalIndex *columnIndices)
Add multiple values in the matrix at once.
void duplicate(DistributedMatrix &dest, CepsBool copyValues) const
Copy non-zero structure to dest matrix. Optionally values.
CepsBool m_properlySet
Safety flag to check for sizes and memory preallocation.
PetscMatrix m_A
The main object.
void getColumnAsDistributedVector(DistributedVector &v, CepsGlobalIndex column) const
Fills a DistributedVector with values of column.
void save(const CepsString &filename)
Matrix is saved in binary format.
void getSize(CepsInt *M, CepsInt *N) const
Get the global size of the matrix.
void load(const CepsString &filename)
Matrix is loaded from specified file in binary format.
void endAssembly()
Wait for the end of matrix assembly.
~DistributedMatrix()
Destructor. The underlying object is cleaned.
Definition: PETScMatrix.cpp:83
void zeroRowsAndColumns(CepsInt nbRows, CepsGlobalIndex *rows, CepsMathScalar diagonalValue=1.0)
Sets the indicated rows and columns values to zero for symmetric matrices.
void finalize()
Performs assembly.
CepsMathScalar l1Norm() const
-norm of matrix
void getValues(CepsMathScalar *values, CepsInt nbRows, CepsInt nbColumns, const CepsGlobalIndex *rowIndices, const CepsGlobalIndex *columnIndices)
Get multiple values in the matrix.
void view() const
Displays the matrix on standard output.
Structure to hold spatially dependant data and distribute it between process.
CepsMathScalar * m_localData
virtual void getLocalData()
Enables direct access to the stored local values.
PetscVector m_v
The underlying vector.
virtual void releaseLocalData()
Release the pointer on the local data.
void getLocalRange(CepsGlobalIndex *lo, CepsGlobalIndex *hi) const
Get the range of rows owned by current process.
void destroyTabular(_Type &)
Destroy[delete] any type.
Definition: CepsMemory.hpp:149
MPI_Comm getCommunicator()
Get the communicator.
CepsBool isValidPtr(_Type *ptr)
Tells if pointer is not null.
Definition: CepsMemory.hpp:61
CepsBool isParallel()
Is there more than 1 process currently working ?