jacobi.template
getmatrix.cpp
Go to the documentation of this file.
1 #include "getmatrix.h"
2 #include "userset.h"
3 
4 #include "omp.h"
5 #include <algorithm>
6 #include <cassert>
7 #include <cmath>
8 #include <ctime> // contains clock()
9 #include <iomanip>
10 #include <iostream>
11 #include <list>
12 #include <vector>
13 using namespace std;
14 
15 // ####################################################################
16 
17 Matrix::Matrix(int const nrows, int const ncols)
18  : _nrows(nrows), _ncols(ncols), _dd(0)
19 {}
20 
21 //Matrix::Matrix()
22  //: Matrix(0,0)
23 //{}
24 
25 
27 {}
28 
29 //vector<double> const & Matrix::GetDiag() const
30 //{
31  //if ( 0==_dd.size() )
32  //{
33  //_dd.resize(Nrows());
34  //this->GetDiag(_dd);
35  //}
36  //assert( Nrows()==static_cast<int>(_dd.size()) );
37  //return _dd;
38 //}
39 
40 // ####################################################################
41 
43  : Matrix(0,0), _nnz(0), _id(0), _ik(0), _sk(0)
44 {}
45 
47 {}
48 
49 void CRS_Matrix::Mult(vector<double> &w, vector<double> const &u) const
50 {
51  assert( _ncols==static_cast<int>(u.size()) ); // compatibility of inner dimensions
52  assert( _nrows==static_cast<int>(w.size()) ); // compatibility of outer dimensions
53 
54  for (int row = 0; row < _nrows; ++row)
55  {
56  double wi = 0.0;
57  for (int ij = _id[row]; ij < _id[row + 1]; ++ij)
58  {
59  wi += _sk[ij] * u[ _ik[ij] ];
60  }
61  w[row] = wi;
62  }
63  return;
64 }
65 
66 void CRS_Matrix::Defect(vector<double> &w,
67  vector<double> const &f, vector<double> const &u) const
68 {
69  assert( _ncols==static_cast<int>(u.size()) ); // compatibility of inner dimensions
70  assert( _nrows==static_cast<int>(w.size()) ); // compatibility of outer dimensions
71  assert( w.size()==f.size() );
72 
73 #pragma omp parallel for
74  for (int row = 0; row < _nrows; ++row)
75  {
76  double wi = f[row];
77  for (int ij = _id[row]; ij < _id[row + 1]; ++ij)
78  {
79  wi -= _sk[ij] * u[ _ik[ij] ];
80  }
81  w[row] = wi;
82  }
83  return;
84 }
85 
86 void CRS_Matrix::GetDiag(vector<double> &d) const
87 {
88  // be carefull when using a rectangular matrix
89  int const nm = min(_nrows, _ncols);
90 
91  assert( nm==static_cast<int>(d.size()) ); // instead of stopping we could resize d and warn the user
92 
93  for (int row = 0; row < nm; ++row)
94  {
95  const int ia = fetch(row, row); // Find diagonal entry of row
96  assert(ia >= 0);
97  d[row] = _sk[ia];
98  }
99  return;
100 }
101 
102 inline
103 int CRS_Matrix::fetch(int const row, int const col) const
104 {
105  int const id2 = _id[row + 1]; // end and
106  int ip = _id[row]; // start of recent row (global index)
107 
108  while (ip < id2 && _ik[ip] != col) // find index col (global index)
109  {
110  ++ip;
111  }
112  if (ip >= id2)
113  {
114  ip = -1;
115 #ifndef NDEBUG // compiler option -DNDEBUG switches off the check
116  cout << "No column " << col << " in row " << row << endl;
117  assert(ip >= id2);
118 #endif
119  }
120  return ip;
121 }
122 
123 void CRS_Matrix::Debug() const
124 {
125 // ID points to first entry of row
126 // no symmetry assumed
127  cout << "\nMatrix (" << _nrows << " x " << _ncols << " with nnz = " << _id[_nrows] << ")\n";
128 
129  for (int row = 0; row < _nrows; ++row)
130  {
131  cout << "Row " << row << " : ";
132  int const id1 = _id[row];
133  int const id2 = _id[row + 1];
134  for (int j = id1; j < id2; ++j)
135  {
136  cout.setf(ios::right, ios::adjustfield);
137  cout << "[" << setw(2) << _ik[j] << "] " << setw(4) << _sk[j] << " ";
138  }
139  cout << endl;
140  }
141  return;
142 }
143 
144 
145 
146 bool CRS_Matrix::Compare2Old(int nnode, int const id[], int const ik[], double const sk[]) const
147 {
148  bool bn = (nnode==_nrows); // number of rows
149  if (!bn)
150  {
151  cout << "######### Error: " << "number of rows" << endl;
152  }
153 
154  bool bz = (id[nnode]==_nnz); // number of non zero elements
155  if (!bz)
156  {
157  cout << "######### Error: " << "number of non zero elements" << endl;
158  }
159 
160  bool bd = equal(id,id+nnode+1,_id.cbegin()); // row starts
161  if (!bd)
162  {
163  cout << "######### Error: " << "row starts" << endl;
164  }
165 
166  bool bk = equal(ik,ik+id[nnode],_ik.cbegin()); // column indices
167  if (!bk)
168  {
169  cout << "######### Error: " << "column indices" << endl;
170  }
171 
172  bool bv = equal(sk,sk+id[nnode],_sk.cbegin()); // values
173  if (!bv)
174  {
175  cout << "######### Error: " << "values" << endl;
176  }
177 
178  return bn && bz && bd && bk && bv;
179 }
180 
181 
182 // ####################################################################
183 
185  : CRS_Matrix(), _mesh(mesh)
186 {
188  return;
189 }
190 
192 {}
193 
195 {
196  cout << "\n############ FEM_Matrix::Derive_Matrix_Pattern ";
197  double tstart = clock();
198  int const nelem(_mesh.Nelems());
199  int const ndof_e(_mesh.NdofsElement());
200  auto const &ia(_mesh.GetConnectivity());
201 // Determine the number of matrix rows
202  _nrows = *max_element(ia.cbegin(), ia.cbegin() + ndof_e * nelem);
203  ++_nrows; // node numberng: 0 ... nnode-1
204  assert(*min_element(ia.cbegin(), ia.cbegin() + ndof_e * nelem) == 0); // numbering starts with 0 ?
205 
206 // CSR data allocation
207  _id.resize(_nrows + 1); // Allocate memory for CSR row pointer
208 //##########################################################################
209  auto const v2v=_mesh.Node2NodeGraph();
210  _nnz=0; // number of connections
211  _id[0] = 0; // start of matrix row zero
212  for (size_t v = 0; v<v2v.size(); ++v )
213  {
214  _id[v+1] = _id[v] + v2v[v].size();
215  _nnz += v2v[v].size();
216  }
217  assert(_nnz == _id[_nrows]);
218  _sk.resize(_nnz); // Allocate memory for CSR column index vector
219 
220 // CSR data allocation
221  _ik.resize(_nnz); // Allocate memory for CSR column index vector
222 // Copy column indices
223  int kk = 0;
224  for (size_t v = 0; v<v2v.size(); ++v )
225  {
226  for (size_t vi=0; vi<v2v[v].size(); ++vi)
227  {
228  _ik[kk] = v2v[v][vi];
229  ++kk;
230  }
231  }
232  _ncols = *max_element(_ik.cbegin(), _ik.cend()); // maximal column number
233  ++_ncols; // node numbering: 0 ... nnode-1
234  //cout << _nrows << " " << _ncols << endl;
235  assert(_ncols==_nrows);
236 
237  double duration = (clock() - tstart) / CLOCKS_PER_SEC;
238  cout << "finished in " << duration << " sec. ########\n";
239 
240  return;
241 }
242 
243 
245 {
246  cout << "\n############ FEM_Matrix::Derive_Matrix_Pattern slow ";
247  double tstart = clock();
248  int const nelem(_mesh.Nelems());
249  int const ndof_e(_mesh.NdofsElement());
250  auto const &ia(_mesh.GetConnectivity());
251 // Determine the number of matrix rows
252  _nrows = *max_element(ia.cbegin(), ia.cbegin() + ndof_e * nelem);
253  ++_nrows; // node numberng: 0 ... nnode-1
254  assert(*min_element(ia.cbegin(), ia.cbegin() + ndof_e * nelem) == 0); // numbering starts with 0 ?
255 
256 // Collect for each node those nodes it is connected to (multiple entries)
257 // Detect the neighboring nodes
258  vector< list<int> > cc(_nrows); // cc[i] is the list of nodes a node i is connected to
259  for (int i = 0; i < nelem; ++i)
260  {
261  int const idx = ndof_e * i;
262  for (int k = 0; k < ndof_e; ++k)
263  {
264  list<int> &cck = cc[ia[idx + k]];
265  cck.insert( cck.end(), ia.cbegin() + idx, ia.cbegin() + idx + ndof_e );
266  }
267  }
268 // Delete the multiple entries
269  _nnz = 0;
270  for (auto &it : cc)
271  {
272  it.sort();
273  it.unique();
274  _nnz += it.size();
275  // cout << it.size() << " :: "; copy(it->begin(),it->end(), ostream_iterator<int,char>(cout," ")); cout << endl;
276  }
277 
278 // CSR data allocation
279  _id.resize(_nrows + 1); // Allocate memory for CSR row pointer
280  _ik.resize(_nnz); // Allocate memory for CSR column index vector
281 
282 // copy CSR data
283  _id[0] = 0; // begin of first row
284  for (size_t i = 0; i < cc.size(); ++i)
285  {
286  //cout << i << " " << nid.at(i) << endl;;
287  const list<int> &ci = cc[i];
288  const auto nci = static_cast<int>(ci.size());
289  _id[i + 1] = _id[i] + nci; // begin of next line
290  copy(ci.begin(), ci.end(), _ik.begin() + _id[i] );
291  }
292 
293  assert(_nnz == _id[_nrows]);
294  _sk.resize(_nnz); // Allocate memory for CSR column index vector
295 
296  _ncols = *max_element(_ik.cbegin(), _ik.cend()); // maximal column number
297  ++_ncols; // node numbering: 0 ... nnode-1
298  //cout << _nrows << " " << _ncols << endl;
299  assert(_ncols==_nrows);
300 
301  double duration = (clock() - tstart) / CLOCKS_PER_SEC;
302  cout << "finished in " << duration << " sec. ########\n";
303 
304  return;
305 }
306 
307 
308 void FEM_Matrix::CalculateLaplace(vector<double> &f)
309 {
310  cout << "\n############ FEM_Matrix::CalculateLaplace ";
311  //double tstart = clock();
312  double tstart = omp_get_wtime(); // OpenMP
313  assert(_mesh.NdofsElement() == 3); // only for triangular, linear elements
314  //cout << _nnz << " vs. " << _id[_nrows] << " " << _nrows<< endl;
315  assert(_nnz == _id[_nrows]);
316 
317  for (int k = 0; k < _nrows; ++k)
318  {
319  _sk[k] = 0.0;
320  }
321  for (int k = 0; k < _nrows; ++k)
322  {
323  f[k] = 0.0;
324  }
325 
326  double ske[3][3], fe[3];
327  // Loop over all elements
328  auto const nelem = _mesh.Nelems();
329  auto const &ia = _mesh.GetConnectivity();
330  auto const &xc = _mesh.GetCoords();
331 
332 #pragma omp parallel for private(ske,fe)
333  for (int i = 0; i < nelem; ++i)
334  {
335  CalcElem(ia.data()+3 * i, xc.data(), ske, fe);
336  //AddElem(ia.data()+3 * i, ske, fe, _id.data(), _ik.data(), _sk.data(), f.data()); // GH: deprecated
337  AddElem_3(ia.data()+3 * i, ske, fe, f);
338  }
339 
340  //double duration = (clock() - tstart) / CLOCKS_PER_SEC;
341  double duration = omp_get_wtime() - tstart; // OpenMP
342  cout << "finished in " << duration << " sec. ########\n";
343  //Debug();
344 
345  return;
346 }
347 
348 //void FEM_Matrix::ApplyDirichletBC(std::vector<double> const &u, std::vector<double> &f)
349 //{
350  //double const PENALTY = 1e6;
351  //auto const idx = _mesh.Index_DirichletNodes();
352  //int const nidx = idx.size();
353 
354  //for (int i=0; i<nidx; ++i)
355  //{
356  //int const k = idx[i];
357  //int const id1 = fetch(k, k); // Find diagonal entry of k
358  //assert(id1 >= 0);
359  //_sk[id1] += PENALTY; // matrix weighted scaling feasible
360  //f[k] += PENALTY * u[k];
361  //}
362 
363  //return;
364 //}
365 
366 void FEM_Matrix::ApplyDirichletBC(std::vector<double> const &u, std::vector<double> &f)
367 {
368  auto const idx = _mesh.Index_DirichletNodes();
369  int const nidx = idx.size();
370 
371  for (int i=0; i<nidx; ++i)
372  {
373  int const row = idx[i];
374  for (int ij=_id[row]; ij<_id[row+1]; ++ij)
375  {
376  int const col=_ik[ij];
377  if (col==row)
378  {
379  _sk[ij] = 1.0;
380  f[row] = u[row];
381  }
382  else
383  {
384  int const id1 = fetch(col, row); // Find entry (col,row)
385  assert(id1 >= 0);
386  f[col] -= _sk[id1]*u[row];
387  _sk[id1] = 0.0;
388  _sk[ij] = 0.0;
389  }
390  }
391  }
392 
393  return;
394 }
395 
396 
397 
398 void FEM_Matrix::AddElem_3(int const ial[3], double const ske[3][3], double const fe[3], vector<double> & f)
399 {
400  for (int i = 0; i < 3; ++i)
401  {
402  const int ii = ial[i]; // row ii (global index)
403  for (int j = 0; j < 3; ++j) // no symmetry assumed
404  {
405  const int jj = ial[j]; // column jj (global index)
406  const int ip = fetch(ii,jj); // find column entry jj in row ii
407 #ifndef NDEBUG // compiler option -DNDEBUG switches off the check
408  if (ip<0) // no entry found !!
409  {
410  cout << "Error in AddElem: (" << ii << "," << jj << ") ["
411  << ial[0] << "," << ial[1] << "," << ial[2] << "]\n";
412  assert(ip>=0);
413  }
414 #endif
415 #pragma omp atomic
416  _sk[ip] += ske[i][j];
417  }
418 #pragma omp atomic
419  f[ii] += fe[i];
420  }
421 }
422 
423 // ####################################################################
424 
425 
426 //Prolongation::Prolongation(Mesh const & cmesh, Mesh const & fmesh)
427  //: CRS_Matrix(), _cmesh(cmesh), _fmesh(fmesh)
428 //{
429  //Derive_Matrix_Pattern();
430  //return;
431 //}
432 
433 
434 //void Prolongation::Derive_Matrix_Pattern()
435 //{
436  //cout << "\n ***** Subject to ongoing imlementation. *****\n";
437 //}
438 
439 // ####################################################################
440 // *********************************************************************
441 
442 
443 // general routine for lin. triangular elements
444 
445 void CalcElem(int const ial[3], double const xc[], double ske[3][3], double fe[3])
446 //void CalcElem(const int* __restrict__ ial, const double* __restrict__ xc, double* __restrict__ ske[3], double* __restrict__ fe)
447 {
448  const int i1 = 2 * ial[0], i2 = 2 * ial[1], i3 = 2 * ial[2];
449  const double x13 = xc[i3 + 0] - xc[i1 + 0], y13 = xc[i3 + 1] - xc[i1 + 1],
450  x21 = xc[i1 + 0] - xc[i2 + 0], y21 = xc[i1 + 1] - xc[i2 + 1],
451  x32 = xc[i2 + 0] - xc[i3 + 0], y32 = xc[i2 + 1] - xc[i3 + 1];
452  const double jac = fabs(x21 * y13 - x13 * y21);
453 
454  ske[0][0] = 0.5 / jac * (y32 * y32 + x32 * x32);
455  ske[0][1] = 0.5 / jac * (y13 * y32 + x13 * x32);
456  ske[0][2] = 0.5 / jac * (y21 * y32 + x21 * x32);
457  ske[1][0] = ske[0][1];
458  ske[1][1] = 0.5 / jac * (y13 * y13 + x13 * x13);
459  ske[1][2] = 0.5 / jac * (y21 * y13 + x21 * x13);
460  ske[2][0] = ske[0][2];
461  ske[2][1] = ske[1][2];
462  ske[2][2] = 0.5 / jac * (y21 * y21 + x21 * x21);
463 
464  const double xm = (xc[i1 + 0] + xc[i2 + 0] + xc[i3 + 0]) / 3.0,
465  ym = (xc[i1 + 1] + xc[i2 + 1] + xc[i3 + 1]) / 3.0;
466  //fe[0] = fe[1] = fe[2] = 0.5 * jac * FunctF(xm, ym) / 3.0;
467  fe[0] = fe[1] = fe[2] = 0.5 * jac * fNice(xm, ym) / 3.0;
468 }
469 
470 void CalcElem_Masse(int const ial[3], double const xc[], double const cm, double ske[3][3])
471 {
472  const int i1 = 2 * ial[0], i2 = 2 * ial[1], i3 = 2 * ial[2];
473  const double x13 = xc[i3 + 0] - xc[i1 + 0], y13 = xc[i3 + 1] - xc[i1 + 1],
474  x21 = xc[i1 + 0] - xc[i2 + 0], y21 = xc[i1 + 1] - xc[i2 + 1];
475  //x32 = xc[i2 + 0] - xc[i3 + 0], y32 = xc[i2 + 1] - xc[i3 + 1];
476  const double jac = fabs(x21 * y13 - x13 * y21);
477 
478  ske[0][0] += jac/12.0;
479  ske[0][1] += jac/24.0;
480  ske[0][2] += jac/24.0;
481  ske[1][0] += jac/24.0;
482  ske[1][1] += jac/12.0;
483  ske[1][2] += jac/24.0;
484  ske[2][0] += jac/24.0;
485  ske[2][1] += jac/24.0;
486  ske[2][2] += jac/12.0;
487 
488  return;
489 }
490 
491 
492 // general routine for lin. triangular elements,
493 // non-symm. matrix
494 // node numbering in element: a s c e n d i n g indices !!
495 // GH: deprecated
496 void AddElem(int const ial[3], double const ske[3][3], double const fe[3],
497  int const id[], int const ik[], double sk[], double f[])
498 {
499  for (int i = 0; i < 3; ++i)
500  {
501  const int ii = ial[i], // row ii (global index)
502  id1 = id[ii], // start and
503  id2 = id[ii + 1]; // end of row ii in matrix
504  int ip = id1;
505  for (int j = 0; j < 3; ++j) // no symmetry assumed
506  {
507  const int jj = ial[j];
508  bool not_found = true;
509  do // find entry jj (global index) in row ii
510  {
511  not_found = (ik[ip] != jj);
512  ++ip;
513  }
514  while (not_found && ip < id2);
515 
516 #ifndef NDEBUG // compiler option -DNDEBUG switches off the check
517  if (not_found) // no entry found !!
518  {
519  cout << "Error in AddElem: (" << ii << "," << jj << ") ["
520  << ial[0] << "," << ial[1] << "," << ial[2] << "]\n";
521  assert(!not_found);
522  }
523 #endif
524  sk[ip - 1] += ske[i][j];
525  }
526  f[ii] += fe[i];
527  }
528 }
529 
530 
531 // ----------------------------------------------------------------------------
532 
533 // #####################################################################
534 
536 : Matrix( 0, 0 ), _iv(), _vv()
537 {
538 }
539 
540 BisectInterpolation::BisectInterpolation(std::vector<int> const & fathers)
541 : Matrix( static_cast<int>(fathers.size())/2, 1+*max_element(fathers.cbegin(),fathers.cend()) ),
542  _iv(fathers), _vv(fathers.size(),0.5)
543 {
544 }
545 
547 {}
548 
549 void BisectInterpolation::GetDiag(vector<double> &d) const
550 {
551  assert( Nrows()==static_cast<int>(d.size()) );
552 
553  for (int k=0; k<Nrows(); ++k)
554  {
555  if ( _iv[2*k]==_iv[2*k+1] )
556  {
557  d[k] = 1.0;
558  }
559  else
560  {
561  d[k] = 0.0;
562  }
563  }
564  return;
565 }
566 
567 void BisectInterpolation::Mult(vector<double> &wf, vector<double> const &uc) const
568 {
569  assert( Nrows()==static_cast<int>(wf.size()) );
570  assert( Ncols()==static_cast<int>(uc.size()) );
571 
572 #pragma omp parallel for
573  for (int k=0; k<Nrows(); ++k)
574  {
575  wf[k] = _vv[2*k]*uc[_iv[2*k]] + _vv[2*k+1]*uc[_iv[2*k+1]];
576  }
577  return;
578 }
579 
580 //void BisectInterpolation::MultT(vector<double> const &wf, vector<double> &uc) const
581 //{
582  //assert( Nrows()==static_cast<int>(wf.size()) );
583  //assert( Ncols()==static_cast<int>(uc.size()) );
586  //for (int k=0; k<Ncols(); ++k) uc[k] = 0.0;
587 //#pragma omp parallel for
588  //for (int k=0; k<Nrows(); ++k)
589  //{
590 //#pragma omp atomic
591  //uc[_iv[2*k] ] += _vv[2*k ]*wf[k];
592 //#pragma omp atomic
593  //uc[_iv[2*k+1]] += _vv[2*k+1]*wf[k];
594  //}
595  //return;
596 //}
597 
598 void BisectInterpolation::MultT(vector<double> const &wf, vector<double> &uc) const
599 {
600  assert( Nrows()==static_cast<int>(wf.size()) );
601  assert( Ncols()==static_cast<int>(uc.size()) );
602 // GH: atomic slows down the code ==> use different storage for MultT operation (CRS-matrix?)
603 //#pragma omp parallel for
604  for (int k=0; k<Ncols(); ++k) uc[k] = 0.0;
605 #pragma omp parallel for
606  for (int k=0; k<Nrows(); ++k)
607  {
608  if (_iv[2*k]!=_iv[2*k+1])
609  {
610 #pragma omp atomic
611  uc[_iv[2*k] ] += _vv[2*k ]*wf[k];
612 #pragma omp atomic
613  uc[_iv[2*k+1]] += _vv[2*k+1]*wf[k];
614  }
615  else
616  {
617 #pragma omp atomic
618  uc[_iv[2*k] ] += 2.0*_vv[2*k ]*wf[k]; // uses a property of class BisectInterpolation
619  }
620  }
621  return;
622 }
623 
624 void BisectInterpolation::Defect(vector<double> &w,
625  vector<double> const &f, vector<double> const &u) const
626 {
627  assert( Nrows()==static_cast<int>(w.size()) );
628  assert( Ncols()==static_cast<int>(u.size()) );
629  assert( w.size()==f.size() );
630 
631  for (int k=0; k<Nrows(); ++k)
632  {
633  w[k] = f[k] - _vv[2*k]*u[_iv[2*k]] + _vv[2*k+1]*u[_iv[2*k+1]];
634  }
635  return;
636 }
637 
639 {
640  for (int k=0; k<Nrows(); ++k)
641  {
642  cout << k << " : fathers(" << _iv[2*k] << "," << _iv[2*k+1] << ") ";
643  cout << "weights(" << _vv[2*k] << "," << _vv[2*k+1] << endl;
644  }
645  cout << endl;
646  return;
647 }
648 
649 int BisectInterpolation::fetch(int row, int col) const
650 {
651  int idx(-1);
652  if (_iv[2*row ] == col) idx = 2*row;
653  if (_iv[2*row+1] == col) idx = 2*row+1;
654  assert(idx>=0);
655  return idx;
656 }
657 
658 // #####################################################################
659 
660 BisectIntDirichlet::BisectIntDirichlet(std::vector<int> const & fathers, std::vector<int> const & idxc_dir)
661  : BisectInterpolation(fathers)
662 {
663  vector<bool> bdir(Ncols(), false); // Indicator for Dirichlet coarse nodes
664  for (size_t kc=0; kc<idxc_dir.size(); ++kc)
665  {
666  bdir.at(idxc_dir[kc]) = true; // Mark Dirichlet node from coarse mesh
667  }
668 
669  for (size_t j=0; j<_iv.size(); ++j)
670  {
671  if ( bdir.at(_iv[j]) ) _vv[j] = 0.0; // set weight to zero iff (at least) one father is Dirichlet node
672  }
673  return;
674 }
675 
676 
678 {}
679 
680 
681 // #####################################################################
682 
683 void DefectRestrict(CRS_Matrix const & SK, BisectInterpolation const& P,
684  vector<double> &fc, vector<double> &ff, vector<double> &uf)
685 {
686  assert( P.Nrows()==static_cast<int>(ff.size()) );
687  assert( P.Ncols()==static_cast<int>(fc.size()) );
688  assert( ff.size()==uf.size() );
689  assert( P.Nrows()==SK.Nrows() );
690 
691 //#pragma omp parallel for
692  for (int k=0; k<P.Ncols(); ++k) fc[k] = 0.0;
693 
694 // GH: atomic slows down the code ==> use different storage for MultT operation (CRS-matrix?)
695 #pragma omp parallel for
696  for (int row = 0; row < SK._nrows; ++row)
697  {
698  double wi = ff[row];
699  for (int ij = SK._id[row]; ij < SK._id[row + 1]; ++ij)
700  {
701  wi -= SK._sk[ij] * uf[ SK._ik[ij] ];
702  }
703 
704  const int i1=P._iv[2*row];
705  const int i2=P._iv[2*row+1];
706  if (i1!=i2)
707  {
708 #pragma omp atomic
709  fc[i1] += P._vv[2*row ]*wi;
710 #pragma omp atomic
711  fc[i2] += P._vv[2*row +1]*wi;
712  }
713  else
714  {
715 #pragma omp atomic
716  fc[i1] += 2.0*P._vv[2*row ]*wi; // uses a property of class BisectInterpolation
717  }
718  }
719  return;
720 }
Matrix::_nrows
int _nrows
number of rows in matrix
Definition: getmatrix.h:120
xc
xc
Definition: ascii_read_meshvector.m:30
DefectRestrict
void DefectRestrict(CRS_Matrix const &SK, BisectInterpolation const &P, vector< double > &fc, vector< double > &ff, vector< double > &uf)
Definition: getmatrix.cpp:683
BisectInterpolation::MultT
void MultT(std::vector< double > const &wf, std::vector< double > &uc) const
Definition: getmatrix.cpp:598
Matrix::~Matrix
virtual ~Matrix()
Definition: getmatrix.cpp:26
FEM_Matrix::Derive_Matrix_Pattern
void Derive_Matrix_Pattern()
Definition: getmatrix.h:265
fNice
double fNice(double const x, double const y)
Definition: userset.h:28
FEM_Matrix::CalculateLaplace
void CalculateLaplace(std::vector< double > &f)
Definition: getmatrix.cpp:308
BisectInterpolation
‍**
Definition: getmatrix.h:374
AddElem
void AddElem(int const ial[3], double const ske[3][3], double const fe[3], int const id[], int const ik[], double sk[], double f[])
Definition: getmatrix.cpp:496
CRS_Matrix::fetch
int fetch(int row, int col) const override
Definition: getmatrix.cpp:103
BisectInterpolation::fetch
int fetch(int row, int col) const override
Definition: getmatrix.cpp:649
Mesh::Node2NodeGraph
std::vector< std::vector< int > > Node2NodeGraph() const
Definition: geom.h:282
CRS_Matrix::Compare2Old
bool Compare2Old(int nnode, int const id[], int const ik[], double const sk[]) const
Definition: getmatrix.cpp:146
FEM_Matrix::AddElem_3
void AddElem_3(int const ial[3], double const ske[3][3], double const fe[3], std::vector< double > &f)
‍**
Definition: getmatrix.cpp:398
CRS_Matrix::_ik
std::vector< int > _ik
column indices
Definition: getmatrix.h:226
Mesh::GetConnectivity
const std::vector< int > & GetConnectivity() const
Definition: geom.h:120
CRS_Matrix::Mult
void Mult(std::vector< double > &w, std::vector< double > const &u) const override
‍**
Definition: getmatrix.cpp:49
BisectInterpolation::Mult
void Mult(std::vector< double > &wf, std::vector< double > const &uc) const override
‍**
Definition: getmatrix.cpp:567
BisectInterpolation::_iv
std::vector< int > _iv
fathers[nnode][2] of fine grid nodes, double entries denote injection points
Definition: getmatrix.h:465
Mesh
Definition: geom.h:13
CRS_Matrix::_sk
std::vector< double > _sk
non-zero values
Definition: getmatrix.h:227
userset.h
BisectInterpolation::Defect
void Defect(std::vector< double > &w, std::vector< double > const &f, std::vector< double > const &u) const override
Definition: getmatrix.cpp:624
CRS_Matrix::Defect
void Defect(std::vector< double > &w, std::vector< double > const &f, std::vector< double > const &u) const override
Definition: getmatrix.cpp:66
FEM_Matrix::Derive_Matrix_Pattern_slow
void Derive_Matrix_Pattern_slow()
Definition: getmatrix.cpp:244
Matrix::Nrows
int Nrows() const
Definition: getmatrix.h:47
u
u
Definition: laplacian.m:3
v
v
Definition: ascii_read_meshvector.m:40
CRS_Matrix::Debug
void Debug() const override
Definition: getmatrix.cpp:123
BisectInterpolation::Debug
void Debug() const override
Definition: getmatrix.cpp:638
BisectInterpolation::~BisectInterpolation
~BisectInterpolation() override
Definition: getmatrix.cpp:546
BisectInterpolation::BisectInterpolation
BisectInterpolation()
Definition: getmatrix.cpp:535
FEM_Matrix::ApplyDirichletBC
void ApplyDirichletBC(std::vector< double > const &u, std::vector< double > &f)
Definition: getmatrix.cpp:366
BisectInterpolation::_vv
std::vector< double > _vv
weights[nnode][2] of fathers for grid nodes
Definition: getmatrix.h:466
CRS_Matrix::~CRS_Matrix
virtual ~CRS_Matrix() override
Definition: getmatrix.cpp:46
Matrix::Matrix
Matrix(int nrows, int ncols)
Definition: getmatrix.cpp:17
BisectIntDirichlet::BisectIntDirichlet
BisectIntDirichlet()
Definition: getmatrix.h:488
FEM_Matrix::_mesh
const Mesh & _mesh
reference to discretization
Definition: getmatrix.h:316
CRS_Matrix::CRS_Matrix
CRS_Matrix()
Definition: getmatrix.cpp:42
CRS_Matrix::_nnz
int _nnz
number of non-zero entries
Definition: getmatrix.h:224
CalcElem
void CalcElem(int const ial[3], double const xc[], double ske[3][3], double fe[3])
Definition: getmatrix.cpp:445
ia
ia
Definition: ascii_read_meshvector.m:35
BisectIntDirichlet::~BisectIntDirichlet
~BisectIntDirichlet() override
Definition: getmatrix.cpp:677
FEM_Matrix::~FEM_Matrix
~FEM_Matrix() override
Definition: getmatrix.cpp:191
size
e, 2 size()
Matrix::GetDiag
const std::vector< double > & GetDiag() const
Definition: getmatrix.h:78
Matrix::Ncols
int Ncols() const
Definition: getmatrix.h:56
FEM_Matrix::FEM_Matrix
FEM_Matrix(Mesh const &mesh)
Definition: getmatrix.cpp:184
Matrix::_ncols
int _ncols
number of columns in matrix
Definition: getmatrix.h:121
FEM_Matrix::Derive_Matrix_Pattern_fast
void Derive_Matrix_Pattern_fast()
Definition: getmatrix.cpp:194
nnode
function vertex minimal boundary edge info in an ASCII file Matlab indexing is stored(starts with 1). % % The output file format is compatible with Mesh_2d_3_matlab nnode
Definition: ascii_write_mesh.m:23
CRS_Matrix
Definition: getmatrix.h:131
getmatrix.h
Matrix
Definition: getmatrix.h:11
nelem
nelem
Definition: ascii_read_meshvector.m:24
CalcElem_Masse
void CalcElem_Masse(int const ial[3], double const xc[], double const cm, double ske[3][3])
Definition: getmatrix.cpp:470
Mesh::Index_DirichletNodes
virtual std::vector< int > Index_DirichletNodes() const
Definition: geom.cpp:260
Mesh::GetCoords
const std::vector< double > & GetCoords() const
Definition: geom.h:151
Mesh::Nelems
int Nelems() const
Definition: geom.h:62
CRS_Matrix::_id
std::vector< int > _id
start indices of matrix rows
Definition: getmatrix.h:225
Mesh::NdofsElement
int NdofsElement() const
Definition: geom.h:80