#include "getmatrix.h" #include "userset.h" #include #include #include #include #include #include #include using namespace std; // general routine for lin. triangular elements void CalcElem(int const ial[3], double const xc[], double ske[3][3], double fe[3]) //void CalcElem(const int* __restrict__ ial, const double* __restrict__ xc, double* __restrict__ ske[3], double* __restrict__ fe) { const int i1 = 2 * ial[0], i2 = 2 * ial[1], i3 = 2 * ial[2]; const double x13 = xc[i3 + 0] - xc[i1 + 0], y13 = xc[i3 + 1] - xc[i1 + 1], x21 = xc[i1 + 0] - xc[i2 + 0], y21 = xc[i1 + 1] - xc[i2 + 1], x32 = xc[i2 + 0] - xc[i3 + 0], y32 = xc[i2 + 1] - xc[i3 + 1]; const double jac = fabs(x21 * y13 - x13 * y21); ske[0][0] = 0.5 / jac * (y32 * y32 + x32 * x32); ske[0][1] = 0.5 / jac * (y13 * y32 + x13 * x32); ske[0][2] = 0.5 / jac * (y21 * y32 + x21 * x32); ske[1][0] = ske[0][1]; ske[1][1] = 0.5 / jac * (y13 * y13 + x13 * x13); ske[1][2] = 0.5 / jac * (y21 * y13 + x21 * x13); ske[2][0] = ske[0][2]; ske[2][1] = ske[1][2]; ske[2][2] = 0.5 / jac * (y21 * y21 + x21 * x21); const double xm = (xc[i1 + 0] + xc[i2 + 0] + xc[i3 + 0]) / 3.0, ym = (xc[i1 + 1] + xc[i2 + 1] + xc[i3 + 1]) / 3.0; //fe[0] = fe[1] = fe[2] = 0.5 * jac * FunctF(xm, ym) / 3.0; fe[0] = fe[1] = fe[2] = 0.5 * jac * fNice(xm, ym) / 3.0; } // general routine for lin. triangular elements, // non-symm. matrix // node numbering in element: a s c e n d i n g indices !! // GH: deprecated 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[]) { for (int i = 0; i < 3; ++i) { const int ii = ial[i], // row ii (global index) id1 = id[ii], // start and id2 = id[ii + 1]; // end of row ii in matrix int ip = id1; for (int j = 0; j < 3; ++j) // no symmetry assumed { const int jj = ial[j]; bool not_found = true; do // find entry jj (global index) in row ii { not_found = (ik[ip] != jj); ++ip; } while (not_found && ip < id2); #ifndef NDEBUG // compiler option -DNDEBUG switches off the check if (not_found) // no entry found !! { cout << "Error in AddElem: (" << ii << "," << jj << ") [" << ial[0] << "," << ial[1] << "," << ial[2] << "]\n"; assert(!not_found); } #endif sk[ip - 1] += ske[i][j]; } f[ii] += fe[i]; } } // ---------------------------------------------------------------------------- // #################################################################### CRS_Matrix::CRS_Matrix(Mesh const &mesh) : _mesh(mesh), _nrows(0), _nnz(0), _id(0), _ik(0), _sk(0) { Derive_Matrix_Pattern(); return; } void CRS_Matrix::Derive_Matrix_Pattern() { int const nelem(_mesh.Nelems()); int const ndof_e(_mesh.NdofsElement()); auto const &ia(_mesh.GetConnectivity()); // Determine the number of matrix rows _nrows = *max_element(ia.cbegin(), ia.cbegin() + ndof_e * nelem); ++_nrows; // node numberng: 0 ... nnode-1 assert(*min_element(ia.cbegin(), ia.cbegin() + ndof_e * nelem) == 0); // numbering starts with 0 ? // Collect for each node those nodes it is connected to (multiple entries) // Detect the neighboring nodes vector< list > cc(_nrows); // cc[i] is the list of nodes a node i is connected to for (int i = 0; i < nelem; ++i) { int const idx = ndof_e * i; for (int k = 0; k < ndof_e; ++k) { list &cck = cc.at(ia[idx + k]); cck.insert( cck.end(), ia.cbegin() + idx, ia.cbegin() + idx + ndof_e ); } } // Delete the multiple entries _nnz = 0; for (auto &it : cc) { it.sort(); it.unique(); _nnz += static_cast(it.size()); // cout << it.size() << " :: "; copy(it->begin(),it->end(), ostream_iterator(cout," ")); cout << endl; } // CSR data allocation _id.resize(_nrows + 1); // Allocate memory for CSR row pointer _ik.resize(_nnz); // Allocate memory for CSR column index vector // copy CSR data _id[0] = 0; // begin of first row for (size_t i = 0; i < cc.size(); ++i) { //cout << i << " " << nid.at(i) << endl;; const list &ci = cc.at(i); const auto nci = static_cast(ci.size()); _id[i + 1] = _id[i] + nci; // begin of next line copy(ci.begin(), ci.end(), _ik.begin() + _id[i] ); } assert(_nnz == _id[_nrows]); _sk.resize(_nnz); // Allocate memory for CSR column index vector return; } void CRS_Matrix::Debug() const { // ID points to first entry of row // no symmetry assumed cout << "\nMatrix (nnz = " << _id[_nrows] << ")\n"; for (int row = 0; row < _nrows; ++row) { cout << "Row " << row << " : "; int const id1 = _id[row]; int const id2 = _id[row + 1]; for (int j = id1; j < id2; ++j) { cout.setf(ios::right, ios::adjustfield); cout << "[" << setw(2) << _ik[j] << "] " << setw(4) << _sk[j] << " "; } cout << endl; } return; } void CRS_Matrix::CalculateLaplace(vector &f) { assert(_mesh.NdofsElement() == 3); // only for triangular, linear elements //cout << _nnz << " vs. " << _id[_nrows] << " " << _nrows<< endl; assert(_nnz == _id[_nrows]); for (int k = 0; k < _nrows; ++k) { _sk[k] = 0.0; } for (int k = 0; k < _nrows; ++k) { f[k] = 0.0; } double ske[3][3], fe[3]; // Loop over all elements auto const nelem = _mesh.Nelems(); auto const &ia = _mesh.GetConnectivity(); auto const &xc = _mesh.GetCoords(); for (int i = 0; i < nelem; ++i) { CalcElem(ia.data() + 3 * i, xc.data(), ske, fe); //AddElem(ia.data()+3 * i, ske, fe, _id.data(), _ik.data(), _sk.data(), f.data()); // GH: deprecated AddElem_3(ia.data() + 3 * i, ske, fe, f); } //Debug(); return; } void CRS_Matrix::ApplyDirichletBC(std::vector const &u, std::vector &f) { double const PENALTY = 1e6; auto const idx = _mesh.Index_DirichletNodes(); int const nidx = static_cast(idx.size()); for (int row = 0; row < nidx; ++row) { int const k = idx[row]; int const id1 = fetch(k, k); // Find diagonal entry of row assert(id1 >= 0); _sk[id1] += PENALTY; // matrix weighted scaling feasible f[k] += PENALTY * u[k]; } return; } void CRS_Matrix::GetDiag(vector &d) const { assert( _nrows == static_cast(d.size()) ); for (int row = 0; row < _nrows; ++row) { const int ia = fetch(row, row); // Find diagonal entry of row assert(ia >= 0); d[row] = _sk[ia]; } return; } bool CRS_Matrix::Compare2Old(int nnode, int const id[], int const ik[], double const sk[]) const { bool bn = (nnode == _nrows); // number of rows if (!bn) { cout << "######### Error: " << "number of rows" << endl; } bool bz = (id[nnode] == _nnz); // number of non zero elements if (!bz) { cout << "######### Error: " << "number of non zero elements" << endl; } bool bd = equal(id, id + nnode + 1, _id.cbegin()); // row starts if (!bd) { cout << "######### Error: " << "row starts" << endl; } bool bk = equal(ik, ik + id[nnode], _ik.cbegin()); // column indices if (!bk) { cout << "######### Error: " << "column indices" << endl; } bool bv = equal(sk, sk + id[nnode], _sk.cbegin()); // values if (!bv) { cout << "######### Error: " << "values" << endl; } return bn && bz && bd && bk && bv; } void CRS_Matrix::Mult(vector &w, vector const &u) const { assert( _nrows == static_cast(w.size()) ); assert( w.size() == u.size() ); for (int row = 0; row < _nrows; ++row) { double wi = 0.0; for (int ij = _id[row]; ij < _id[row + 1]; ++ij) { wi += _sk[ij] * u[ _ik[ij] ]; } w[row] = wi; } return; } void CRS_Matrix::Defect(vector &w, vector const &f, vector const &u) const { assert( _nrows == static_cast(w.size()) ); assert( w.size() == u.size() && u.size() == f.size() ); for (int row = 0; row < _nrows; ++row) { double wi = f[row]; for (int ij = _id[row]; ij < _id[row + 1]; ++ij) { wi -= _sk[ij] * u[ _ik[ij] ]; } w[row] = wi; } return; } int CRS_Matrix::fetch(int const row, int const col) const { int const id2 = _id[row + 1]; // end and int ip = _id[row]; // start of recent row (global index) while (ip < id2 && _ik[ip] != col) // find index col (global index) { ++ip; } if (ip >= id2) { ip = -1; #ifndef NDEBUG // compiler option -DNDEBUG switches off the check cout << "No column " << col << " in row " << row << endl; assert(ip >= id2); #endif } return ip; } void CRS_Matrix::AddElem_3(int const ial[3], double const ske[3][3], double const fe[3], vector &f) { for (int i = 0; i < 3; ++i) { const int ii = ial[i]; // row ii (global index) for (int j = 0; j < 3; ++j) // no symmetry assumed { const int jj = ial[j]; // column jj (global index) int ip = fetch(ii, jj); // find column entry jj in row ii #ifndef NDEBUG // compiler option -DNDEBUG switches off the check if (ip < 0) // no entry found !! { cout << "Error in AddElem: (" << ii << "," << jj << ") [" << ial[0] << "," << ial[1] << "," << ial[2] << "]\n"; assert(ip >= 0); } #endif _sk[ip] += ske[i][j]; } f[ii] += fe[i]; } }