KratosMultiphysics
KRATOS Multiphysics (Kratos) is a framework for building parallel, multi-disciplinary simulation software, aiming at modularity, extensibility, and high performance. Kratos is written in C++, and counts with an extensive Python interface.
deflation_utils.h
Go to the documentation of this file.
1 // | / |
2 // ' / __| _` | __| _ \ __|
3 // . \ | ( | | ( |\__ `
4 // _|\_\_| \__,_|\__|\___/ ____/
5 // Multi-Physics
6 //
7 // License: BSD License
8 // Kratos default license: kratos/license.txt
9 //
10 // Main authors: Riccardo Rossi
11 //
12 //
13 
14 #if !defined(KRATOS_DEFLATION_UTILS )
15 #define KRATOS_DEFLATION_UTILS
16 
17 /* System includes */
18 
19 /* External includes */
20 
21 /* Project includes */
22 #include "includes/define.h"
23 #include "includes/model_part.h"
26 
27 namespace Kratos
28 {
29 
79 {
80 public:
83  typedef boost::numeric::ublas::compressed_matrix<double> SparseMatrixType;
84 
85  typedef boost::numeric::ublas::vector<double> SparseVectorType;
86 
105  void VisualizeAggregates(ModelPart::NodesContainerType& rNodes, Variable<double>& rVariable, const int max_reduced_size)
106  {
107  SparseMatrixType A(rNodes.size(),rNodes.size());
108  SparseMatrixType Adeflated;
109 
110  //first of all build the connectivty matrix
111  std::vector< std::vector<int> > index_list(rNodes.size());
112 
113  std::size_t total_size = 0;
114 
115  //renumber nodes consecutively
116  int new_id = 1;
117  for(ModelPart::NodesContainerType::iterator in = rNodes.begin(); in!=rNodes.end(); in++)
118  in->SetId(new_id++);
119 
120 
121  //constructing the system matrix row by row
122  std::size_t index_i;
124  in!=rNodes.end(); in++)
125  {
126  index_i = (in)->Id()-1;
127  auto& neighb_nodes = in->GetValue(NEIGHBOUR_NODES);
128 
129  std::vector<int>& indices = index_list[index_i];
130  indices.reserve(neighb_nodes.size()+1);
131 
132  //filling the first neighbours list
133  indices.push_back(index_i);
134  for( auto i = neighb_nodes.begin();
135  i != neighb_nodes.end(); i++)
136  {
137 
138  int index_j = i->Id()-1;
139  indices.push_back(index_j);
140  }
141 
142  //sorting the indices and elminating the duplicates
143  std::sort(indices.begin(),indices.end());
144  std::vector<int>::iterator new_end = std::unique(indices.begin(),indices.end());
145 
146  indices.erase(new_end,indices.end());
147 
148  total_size += indices.size();
149 
150  }
151 
152  A.reserve(total_size,false);
153 
154  //setting to zero the matrix (and the diagonal matrix)
155  for(unsigned int i=0; i<A.size1(); i++)
156  {
157  std::vector<int>& indices = index_list[i];
158  for(unsigned int j=0; j<indices.size(); j++)
159  {
160  A.push_back(i,indices[j] , 0.00);
161  }
162  }
163 // std::cout << "matrix constructed" << std::endl;
164 
165  //now call aggregation function to color the nodes
166  std::vector<int> w(rNodes.size());
167  ConstructW(max_reduced_size, A, w, Adeflated);
168 // std::cout << "aggregates constructed" << std::endl;
169 
170  //finally write the color to the nodes so that it can be visualized
171  int counter = 0;
172  for(ModelPart::NodesContainerType::iterator in=rNodes.begin(); in!=rNodes.end(); in++)
173  {
174  in->FastGetSolutionStepValue(rVariable) = w[counter++];
175  }
176 // std::cout << "finished" << std::endl;
177  }
178 
181  static void ConstructW(const std::size_t max_reduced_size, SparseMatrixType& rA, std::vector<int>& w, SparseMatrixType& deflatedA)
182  {
183  KRATOS_TRY
184 
185  std::size_t full_size = rA.size1();
186  w.resize(full_size,0);
187 
188  //call aggregation function to fill mw with "colors"
189  std::size_t reduced_size = standard_aggregation<int>(rA.size1(),rA.index1_data().begin(), rA.index2_data().begin(), &w[0]);
190 // for( int i=0; i<full_size; i++)
191 // std::cout << w[i] << std::endl;
192 
193  // Non-zero structure of deflatedA
194 
195  std::vector<std::set<std::size_t> > deflatedANZ(reduced_size);
196 
197  // Loop over non-zero structure of A and build non-zero structure of deflatedA
198  SparseMatrixType::iterator1 a_iterator = rA.begin1();
199 
200  for (std::size_t i = 0; i < full_size; i++)
201  {
202 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
203  for (SparseMatrixType::iterator2 row_iterator = a_iterator.begin() ;
204  row_iterator != a_iterator.end() ; ++row_iterator)
205  {
206 #else
207  for (typename SparseMatrixType::iterator2 row_iterator = begin(a_iterator,
208  boost::numeric::ublas::iterator1_tag());
209  row_iterator != end(a_iterator,
210  boost::numeric::ublas::iterator1_tag()); ++row_iterator )
211  {
212 #endif
213  deflatedANZ[w[a_iterator.index1()]].insert(w[row_iterator.index2()]);
214  }
215 
216  a_iterator++;
217  }
218 
219 // std::cout << "********** NZS built!" << std::endl;
220 
221  // Count the number of non-zeros in deflatedA
222  std::size_t NZ = 0;
223  for (std::size_t i = 0; i < reduced_size; i++)
224  NZ += deflatedANZ[i].size();
225 
226 // std::cout << "********** NZ = " << NZ << std::endl;
227 // KRATOS_WATCH(reduced_size);
228  deflatedA = SparseMatrixType(reduced_size, reduced_size,NZ);
229 
230  // Insert the non-zero structure into deflatedA
231  for(std::size_t i = 0 ; i < reduced_size ; i++)
232  {
233  for(std::set<std::size_t>::iterator j = deflatedANZ[i].begin() ; j != deflatedANZ[i].end() ; j++)
234  {
235  deflatedA.push_back(i,*j, 0.00);
236  }
237  }
238 // KRATOS_WATCH(__LINE__)
239 
240  if(reduced_size > max_reduced_size)
241  {
242  SparseMatrixType Areduced;
243  std::vector<int> wsmaller;
244 // KRATOS_WATCH(__LINE__)
245  //need to reduce further!! - do it recursively
246  ConstructW(max_reduced_size, deflatedA, wsmaller, Areduced);
247 // KRATOS_WATCH(__LINE__)
248  //now change deflatedA and w on the coarser size
249  for(unsigned int i=0; i<full_size; i++)
250  {
251  int color = w[i];
252  int new_color = wsmaller[color];
253  w[i] = new_color;
254  }
255  deflatedA.clear();
256  deflatedA = Areduced;
257 // KRATOS_WATCH(__LINE__)
258  reduced_size = wsmaller.size();
259  }
260 
261 // KRATOS_WATCH(reduced_size);
262 // std::cout << "reduction factor ="<<double(full_size)/double(reduced_size)<<std::endl;
263 
264 
265  KRATOS_CATCH("")
266  }
267 
268 
269 
270 
271 
273  static void ConstructW(const int max_reduced_size, SparseMatrixType& rA, std::vector<int>& w, SparseMatrixType& deflatedA, const std::size_t block_size)
274  {
275  if(block_size == 1)
276  {
277  ConstructW(max_reduced_size,rA, w, deflatedA);
278  }
279  else
280  {
281  //simple checks to verify blocks are effectively respected
282  if(rA.size1()%block_size != 0 || rA.size2()%block_size != 0)
283  KRATOS_THROW_ERROR(std::logic_error,"the number of rows is not a multiple of block_size. Can not use the block deflation","")
284  if(rA.nnz()%block_size != 0)
285  KRATOS_THROW_ERROR(std::logic_error,"the number of non zeros is not a multiple of block_size. Can not use the block deflation","")
286 
287  //construct Ascalar
288  SparseMatrixType Ascalar;
289  ConstructScalarMatrix(rA.size1(),block_size,rA.index1_data().begin(), rA.index2_data().begin(), Ascalar);
290 
291  //deflate it using the standard methods
292  SparseMatrixType deflatedAscalar;
293  std::vector<int> wscalar;
294  ConstructW(max_reduced_size/block_size,Ascalar, wscalar, deflatedAscalar);
295 
296  //compute w for the block structured problem
297 
298  std::vector<int> w(wscalar.size()*block_size);
299  for(std::size_t i=0; i<wscalar.size(); i++)
300  {
301  for(std::size_t j=0; j<block_size; j++)
302  {
303  w[i*block_size + j] = wscalar[i]*block_size+j;
304  }
305  }
306 
307  //compute deflatedA
308  SparseMatrixType deflatedA(deflatedAscalar.size1()*block_size,deflatedAscalar.size2()*block_size);
309  //do reserve!!
310  deflatedA.reserve(deflatedAscalar.nnz()*block_size*block_size);
311  ExpandScalarMatrix(rA.size1(),block_size,rA.index1_data().begin(), rA.index2_data().begin(), deflatedA);
312 
313 
314 
315  }
316  }
317 
318 
319 
320  //W is the deflation matrix, stored as a single vector of indices
321  //y is a vector of "full" size
322  //x is a vector of reduced size
323  //y = W*x;
324  static void ApplyW(const std::vector<int>& w, const SparseVectorType& x, SparseVectorType& y)
325  {
326  #pragma omp parallel for
327  for(int i=0; i<static_cast<int>(w.size()); i++)
328  {
329  y[i] = x[w[i]];
330  }
331  }
332 
333 
334  //W is the deflation matrix, stored as a single vector of indices
335  //y is a vector of "reduced" size
336  //s is a vector of "full" size
337  //y = Wtranspose*x;
338  static void ApplyWtranspose(const std::vector<int>& w, const SparseVectorType& x, SparseVectorType& y)
339  {
340  //first set to zero the destination vector
341  #pragma omp parallel for
342  for(int i=0; i<static_cast<int>(y.size()); i++)
343  y[i] = 0.0;
344 
345  //Pragma atomic does not work with MSVC 19.0.23506 ( aka Visual Studio 2015 Update1 )
346 #if(_MSC_FULL_VER == 190023506)
347  for(int i=0; i<static_cast<int>(w.size()); i++)
348  {
349  y[w[i]] += x[i];
350  }
351 #else
352  //now apply the Wtranspose
353  #pragma omp parallel for
354  for(int i=0; i<static_cast<int>(w.size()); i++) {
355  AtomicAdd(y[w[i]], x[i]);
356  }
357 #endif
358  }
359 
360  //*******************************************************************************
361  //*******************************************************************************
362  static void FillDeflatedMatrix( const SparseMatrixType& rA, std::vector<int>& w, SparseMatrixType& Ah)
363  {
364  KRATOS_TRY
365 
366  double* abegin = Ah.value_data().begin();
367  int size = Ah.value_data().size();
368  #pragma omp parallel for
369  for (int i = 0; i < size; i++)
370  {
371  *(abegin+i) = 0.0;
372  }
373 // TSparseSpaceType::SetToZero(Ah);
374 
375  // Now building Ah
376  SparseMatrixType::const_iterator1 a_iterator = rA.begin1();
377  int full_size = rA.size1();
378 
379  for (int i = 0; i < full_size; i++)
380  {
381 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
382  for (SparseMatrixType::const_iterator2 row_iterator = a_iterator.begin() ;
383  row_iterator != a_iterator.end() ; ++row_iterator)
384  {
385 #else
386  for (typename SparseMatrixType::iterator2 row_iterator = begin(a_iterator,
387  boost::numeric::ublas::iterator1_tag());
388  row_iterator != end(a_iterator,
389  boost::numeric::ublas::iterator1_tag()); ++row_iterator )
390  {
391 #endif
392  Ah(w[a_iterator.index1()], w[row_iterator.index2()]) += *row_iterator;
393  }
394  a_iterator++;
395  }
396 
397 
398 
399 // std::cout << "********** W^T * A * W built!" << std::endl;
400 
401 
402  KRATOS_CATCH("");
403  }
404 
405 
427 private:
441  /*
442  * Compute aggregates for a matrix A stored in CSR format
443  *
444  * Parameters:
445  * n_row - number of rows in A
446  * Ap[n_row + 1] - CSR row pointer
447  * Aj[nnz] - CSR column indices
448  * x[n_row] - aggregate numbers for each node
449  *
450  * Returns:
451  * The number of aggregates (== max(x[:]) + 1 )
452  *
453  * Notes:
454  * It is assumed that A is structurally symmetric.
455  * A may contain diagonal entries (self loops)
456  * Unaggregated nodes are marked with a -1
457  *
458  */
459  template <class I>
460  static I standard_aggregation(const I n_row,
461  const std::size_t Ap[],
462  const std::size_t Aj[],
463  I x[])
464  {
465  // Bj[n] == -1 means i-th node has not been aggregated
466  std::fill(x, x + n_row, 0);
467 
468  I next_aggregate = 1; // number of aggregates + 1
469 
470  //Pass #1
471  for(I i = 0; i < n_row; i++)
472  {
473  if(x[i])
474  {
475  continue; //already marked
476  }
477 
478  const I row_start = Ap[i];
479  const I row_end = Ap[i+1];
480 
481  //Determine whether all neighbors of this node are free (not already aggregates)
482  bool has_aggregated_neighbors = false;
483  bool has_neighbors = false;
484  for(I jj = row_start; jj < row_end; jj++)
485  {
486  const I j = Aj[jj];
487  if( i != j )
488  {
489  has_neighbors = true;
490  if( x[j] )
491  {
492  has_aggregated_neighbors = true;
493  break;
494  }
495  }
496  }
497 
498  if(!has_neighbors)
499  {
500  //isolated node, do not aggregate
501  x[i] = -n_row;
502  }
503  else if (!has_aggregated_neighbors)
504  {
505  //Make an aggregate out of this node and its neighbors
506  x[i] = next_aggregate;
507  for(I jj = row_start; jj < row_end; jj++)
508  {
509  x[Aj[jj]] = next_aggregate;
510  }
511  next_aggregate++;
512  }
513  }
514 
515  //Pass #2
516  // Add unaggregated nodes to any neighboring aggregate
517  for(I i = 0; i < n_row; i++)
518  {
519  if(x[i])
520  {
521  continue; //already marked
522  }
523 
524  for(I jj = static_cast<I>(Ap[i]); jj < static_cast<I>(Ap[i+1]); jj++)
525  {
526  const I j = Aj[jj];
527 
528  const I xj = x[j];
529  if(xj > 0)
530  {
531  x[i] = -xj;
532  break;
533  }
534  }
535  }
536 
537  next_aggregate--;
538 
539  //Pass #3
540  for(I i = 0; i < n_row; i++)
541  {
542  const I xi = x[i];
543 
544  if(xi != 0)
545  {
546  // node i has been aggregated
547  if(xi > 0)
548  x[i] = xi - 1;
549  else if(xi == -n_row)
550  x[i] = -1;
551  else
552  x[i] = -xi - 1;
553  continue;
554  }
555 
556  // node i has not been aggregated
557  const I row_start = Ap[i];
558  const I row_end = Ap[i+1];
559 
560  x[i] = next_aggregate;
561 
562  for(I jj = row_start; jj < row_end; jj++)
563  {
564  const I j = Aj[jj];
565 
566  if(x[j] == 0) //unmarked neighbors
567  {
568  x[j] = next_aggregate;
569  }
570  }
571  next_aggregate++;
572  }
573 
574 
575  return next_aggregate; //number of aggregates
576  }
577 
578 
579 
580 
581  static void ConstructScalarMatrix(const std::size_t n_row, const std::size_t block_size,
582  const std::size_t Ap[],
583  const std::size_t Aj[],
584  SparseMatrixType& Ascalar
585  )
586  {
587  Ascalar.resize(n_row/block_size,n_row/block_size,0.0);
588  std::size_t scalar_size = (Ap[n_row]-Ap[0])/(block_size*block_size);
589  Ascalar.reserve(scalar_size);
590 
591  for(std::size_t i = 0; i < n_row; i++)
592  {
593  if(i%block_size == 0)
594  {
595  std::size_t iscalar = i/block_size;
596  const std::size_t row_start = Ap[i];
597  const std::size_t row_end = Ap[i+1];
598 
599  for(std::size_t jj = row_start; jj < row_end; jj++)
600  {
601  const std::size_t j = Aj[jj];
602  if(j%block_size == 0)
603  {
604  std::size_t jscalar = j/block_size;
605  Ascalar.push_back(iscalar,jscalar,0.0);
606  }
607  }
608  }
609  }
610  }
611 
612  static void ExpandScalarMatrix(const std::size_t n_row, const std::size_t block_size,
613  const std::size_t Ap[],
614  const std::size_t Aj[],
615  SparseMatrixType& Aexpanded
616  )
617  {
618  Aexpanded.resize(n_row*block_size,n_row*block_size,0.0);
619  std::size_t expanded_size = (Ap[n_row]-Ap[0])*block_size*block_size;
620  Aexpanded.reserve(expanded_size);
621 
622  for(std::size_t i = 0; i < n_row; i++)
623  {
624  const std::size_t row_start = Ap[i];
625  const std::size_t row_end = Ap[i+1];
626 
627  for(std::size_t isub=0; isub<block_size; isub++)
628  {
629  std::size_t iexpanded = i*block_size + isub;
630  for(std::size_t jj = row_start; jj < row_end; jj++)
631  {
632  const std::size_t j = Aj[jj];
633 
634  for(std::size_t jsub=0; jsub<block_size; jsub++)
635  {
636  std::size_t jexpanded = j*block_size+jsub;
637  Aexpanded.push_back(iexpanded,jexpanded,0.0);
638  }
639  }
640  }
641  }
642  }
643 
668 }; /* Class ClassName */
669 
678 } /* namespace Kratos.*/
679 
680 #endif /* DEFLATION_UTILS defined */
Definition: deflation_utils.h:79
static void FillDeflatedMatrix(const SparseMatrixType &rA, std::vector< int > &w, SparseMatrixType &Ah)
Definition: deflation_utils.h:362
static void ApplyW(const std::vector< int > &w, const SparseVectorType &x, SparseVectorType &y)
Definition: deflation_utils.h:324
void VisualizeAggregates(ModelPart::NodesContainerType &rNodes, Variable< double > &rVariable, const int max_reduced_size)
Definition: deflation_utils.h:105
static void ApplyWtranspose(const std::vector< int > &w, const SparseVectorType &x, SparseVectorType &y)
Definition: deflation_utils.h:338
static void ConstructW(const int max_reduced_size, SparseMatrixType &rA, std::vector< int > &w, SparseMatrixType &deflatedA, const std::size_t block_size)
block version of ConstructW. To be used when multiple DOFS are associated to the same node.
Definition: deflation_utils.h:273
boost::numeric::ublas::compressed_matrix< double > SparseMatrixType
Definition: deflation_utils.h:83
boost::numeric::ublas::vector< double > SparseVectorType
Definition: deflation_utils.h:85
static void ConstructW(const std::size_t max_reduced_size, SparseMatrixType &rA, std::vector< int > &w, SparseMatrixType &deflatedA)
Definition: deflation_utils.h:181
A sorted associative container similar to an STL set, but uses a vector to store pointers to its data...
Definition: pointer_vector_set.h:72
boost::indirect_iterator< typename TContainerType::iterator > iterator
Definition: pointer_vector_set.h:95
size_type size() const
Returns the number of elements in the container.
Definition: pointer_vector_set.h:502
iterator begin()
Returns an iterator pointing to the beginning of the container.
Definition: pointer_vector_set.h:278
iterator end()
Returns an iterator pointing to the end of the container.
Definition: pointer_vector_set.h:314
#define KRATOS_THROW_ERROR(ExceptionType, ErrorMessage, MoreInfo)
Definition: define.h:77
#define KRATOS_CATCH(MoreInfo)
Definition: define.h:110
#define KRATOS_TRY
Definition: define.h:109
end
Definition: DEM_benchmarks.py:180
REF: G. R. Cowper, GAUSSIAN QUADRATURE FORMULAS FOR TRIANGLES.
Definition: mesh_condition.cpp:21
void AtomicAdd(TDataType &target, const TDataType &value)
Definition: atomic_utilities.h:55
color
Definition: all_t_win_vs_m_fixed_error.py:230
y
Other simbols definition.
Definition: generate_axisymmetric_navier_stokes_element.py:54
w
Definition: generate_convection_diffusion_explicit_element.py:108
int block_size
Definition: generate_total_lagrangian_mixed_volumetric_strain_element.py:16
int j
Definition: quadrature.py:648
int counter
Definition: script_THERMAL_CORRECT.py:218
A
Definition: sensitivityMatrix.py:70
x
Definition: sensitivityMatrix.py:49
integer i
Definition: TensorModule.f:17