/* $Id: sysmatsp.cc,v 1.4 1997/07/11 09:46:14 bzferdma Exp $ (C)opyright 1996 by Konrad-Zuse-Center, Berlin All rights reserved. Part of the Kaskade distribution */ #include "sysmatsp.h" #include "utils.h" #include "numerics.h" #include "connect.h" #include "dirichlet.h" #include "cmdpars.h" extern CmdPars Cmd; //------------------------------------------------------------------------- SparseMatrix:: SparseMatrix(ConnectionPattern& cPattern, symmetryType symmetry0, int spaceDim0) : SystemMatrix(symmetry0), MA28Matrix(spaceDim0), dimension(0), decomposed(False), ILUDecomposed(False), D(1), L(0), U(0), col(1), end(1), dirichlet(1), symU(0), symCol(1), symEnd(1) { allocate(cPattern); dimension = D.high(); } //------------------------------------------------------------------------- // -- construct A for eigenvalue problems (A = A0 + lambda*B0) // or simply make a copy (B=0) SparseMatrix:: SparseMatrix(int spaceDim0, SystemMatrix* A0, SystemMatrix* B0, Num lambda) : SystemMatrix(A0->symmetry), MA28Matrix(spaceDim0), D(1), L(0), U(0), col(1), end(1), dirichlet(1), symU(0), symCol(1), symEnd(1) { int i, k; SparseMatrix* Asp, *B; Asp = A0->castToSparseMatrix(); if (B0) B = B0->castToSparseMatrix(); else B = 0; const int nlow = (Asp->D).l; const int nhigh = (Asp->D).h; D.resize(nlow, nhigh); if (B) FORALL(D,i) D[i] = (Asp->D)[i] - lambda * (B->D)[i]; else FORALL(D,i) D[i] = (Asp->D)[i]; int noOfEntries = (Asp->L)->size(); if (noOfEntries == 0) // no off-diagonal terms { L = U = 0; return; } end.resize(nlow-1,nhigh); col.resize(noOfEntries); L = new Vector(noOfEntries); if (symmetry == asym) U = new Vector(noOfEntries); else U = L; FORALL(Asp->end,i) end[i] = (Asp->end)[i]; if (B) { FORALL(D,i) for (k=end[i-1]+1; k<=end[i]; ++k) { col[k] = Asp->col[k]; (*L)[k] = (*Asp->L)[k] - lambda * (*B->L)[k]; if (symmetry == asym) (*U)[k] = (*Asp->U)[k] - lambda * (*B->U)[k]; } } else { FORALL(D,i) for (k=end[i-1]+1; k<=end[i]; ++k) { col[k] = Asp->col[k]; (*L)[k] = (*Asp->L)[k]; (*U)[k] = (*Asp->U)[k]; } } dimension = D.high() - D.low() + 1; } //------------------------------------------------------------------------- SparseMatrix:: ~SparseMatrix() { removeSymmetricExpansion(); if (L == U) delete L; else { delete L; delete U; } } //------------------------------------------------------------------------- void SparseMatrix:: allocate(ConnectionPattern& cPattern) { int i, n; const int nlow = cPattern.l(); const int nhigh = cPattern.h(); D.resize(nlow, nhigh); int noOfEntries = 0; for (i=nlow; i<=nhigh; ++i) noOfEntries += cPattern.noOfElements(i); if (noOfEntries == 0) // no off-diagonal terms { L = U = 0; return; } end.resize(nlow-1,nhigh); col.resize(noOfEntries); L = new Vector(noOfEntries); if (symmetry == asym) U = new Vector(noOfEntries); else U = L; NeighbourNode* nnp; int index = 0; end[nlow-1] = index; // care for end[i-1] in case i=nlow ! for (i=nlow; i<=nhigh; ++i) // all rows { for (nnp=cPattern.first(i); nnp; nnp=nnp->next) { n = nnp->neighbour; if (n >= i) { cout << "\n*** Error in sparse node pattern: row = " << i << " column = " << n << "\n"; cout.flush(); abort(); } col[++index] = n; } end[i] = index; } } //------------------------------------------------------------------------- void SparseMatrix:: removeLU() { if (U != L) delete U; delete L; L = U = 0; end.resize(1); col.resize(1); } //------------------------------------------------------------------------- void SparseMatrix:: printMatLabFormat() const { char s[10]; printf ("\n--- print A ? "); fgets(s,10,stdin); strToLower(s); if (!strchr(s,'y')) return; FILE* f; f = fopen("sparsematrix","w"); int i, j; FORALL(D,i) { for (j=end[i-1]+1; j<=end[i]; ++j) if (L) fprintf(f,"a(%1d,%1d)=%g\n", i, col[j], ::real((*L)[j])); fprintf(f,"a(%1d,%1d)=%g\n", i, i, ::real(D[i])); } fclose(f); printf("--- file 'sparsematrix' created \n"); } //------------------------------------------------------------------------- void SparseMatrix:: print() const { int i, j; if (decomposed || ILUDecomposed) { cout << "\n* Matrix decomposed: print() not available\n"; return; } cout << "\n--- Sparse Matrix diagonal: \n\n"; D.print(); cout << "\nLower Triangle:"; if (L) FORALL(D,i) { cout << "\nrow " << i << " : "; for (j=end[i-1]+1; j<=end[i]; ++j) cout << " " << (*L)[j] << "[" << col[j] << "]"; } if (U != L) { cout << "\n\nUpper Triangle:"; FORALL(D,i) { cout << "\ncol " << i << " : "; for (j=end[i-1]+1; j<=end[i]; ++j) cout << " " << (*U)[j] << "[" << col[j] << "]"; } } if (symU) { cout << "\n\nSymmetric Upper Triangle:"; FORALL(D,i) { cout << "\nrow " << i << " : "; for (j=symEnd[i-1]+1; j<=symEnd[i]; ++j) cout << " " << (*symU)[j] << "[" << symCol[j] << "]"; } } cout << "\n"; } //------------------------------------------------------------------------- int SparseMatrix:: memSpace(int print) const { int space = D.memSpace() + col.memSpace() + end.memSpace(); if (L) space += L->memSpace(); if (symmetry == asym && U) space += U->memSpace(); space += dirichlet.memSpace(); space += MA28MemSpace(); if (print) cout << "\n Memory allocated for sparse matrix (dim=" << Dim() << "): " << Form("%1.6f", float(space)/1e6) << " MB\n"; return space; } //------------------------------------------------------------------------- void SparseMatrix:: setDirichletBCs(DirichletBCs& dirichletBCs, Vector& b, Vector& bSave, Num& Fct0, Num& E0) { int i; if (symmetry == sym) setSymDirichletBCs(dirichletBCs, b, bSave, Fct0, E0); else setASymDirichletBCs(dirichletBCs, b, bSave, Fct0, E0); dirichlet.resize(Dim()); FORALL(dirichlet,i) { if (dirichletBCs.isSet(i)) dirichlet[i] = True; else dirichlet[i] = False; } } //------------------------------------------------------------------------- void SparseMatrix:: setASymDirichletBCs(DirichletBCs& dirichletBCs, Vector& b, Vector& bSave, Num& Fct0, Num& E0) { int i, j, icol; Num value; FORALL(bSave,i) bSave[i] = 0.0; Fct0 = 0.0; E0 = 0.0; FORALL(D,i) { if (dirichletBCs.isSet(i)) // row with Dir. BC { value = dirichletBCs.value(i); for (j=end[i-1]+1; j<=end[i]; ++j) // along row { icol = col[j]; if (dirichletBCs.isSet(icol)) Fct0 += 0.5 * (*L)[j] * value * dirichletBCs.value(icol); else bSave[icol] += 0.5 * (*L)[j] * value; (*L)[j] = 0.0; } Fct0 -= b[i]*value; // - u0*b0 Fct0 += D[i]*value*value; // u0*Add*u0 E0 += b[i]*value; E0 -= D[i]*value*value; b[i] = D[i]*value; } for (j=end[i-1]+1; j<=end[i]; ++j) // column up { icol = col[j]; // here icol is the row index if (dirichletBCs.isSet(icol)) { if (dirichletBCs.isSet(i)) Fct0 += 0.5* (*U)[j] * dirichletBCs.value(i) * dirichletBCs.value(icol); else bSave[i] += 0.5* (*U)[j] * dirichletBCs.value(icol); (*U)[j] = 0.0; } } } } //------------------------------------------------------------------------- void SparseMatrix:: setSymDirichletBCs(DirichletBCs& dirichletBCs, Vector& b, Vector& /*bSave*/, Num& Fct0, Num& /*E0*/) { int i, j, icol; Num value; Fct0 = 0.0; FORALL(D,i) { if (dirichletBCs.isSet(i)) // row with Dir. BC { value = dirichletBCs.value(i); for (j=end[i-1]+1; j<=end[i]; ++j) { icol = col[j]; if (dirichletBCs.isSet(icol)) Fct0 += (*L)[j] * value * dirichletBCs.value(icol); else b[icol] -= (*L)[j] * value; (*L)[j] = 0.0; } Fct0 -= b[i]*value; // - u0*b0 Fct0 += D[i]*value*value; // u0*Add*u0 (0.5*... + 0.5*...) b[i] = D[i]*value; } else { for (j=end[i-1]+1; j<=end[i]; ++j) { icol = col[j]; if (dirichletBCs.isSet(icol)) { b[i] -= (*L)[j] * dirichletBCs.value(icol); // ADF*u0 (*L)[j] = 0.0; } } } } } //------------------------------------------------------------------------- Num& SparseMatrix:: operator() (int n1, int n2) { int i; //if (n1==0 || n2==0) // !!! // { cout << "\n*** SparseMatrix::operator(): node number 0\n"; cout.flush(); abort(); } if (n1 == n2) return D[n1]; if (n1 > n2) // lower triangle { i = end[n1]; while (col[i] != n2) --i; return (*L)[i]; } else { i = end[n2]; while (col[i] != n1) --i; return (*U)[i]; } } //------------------------------------------------------------------------- void SparseMatrix:: reset() { int i, k; FORALL(D,i) D[i] = 0.0; FORALL(D,i) for (k=end[i-1]+1; k<=end[i]; ++k) (*L)[k] = (*U)[k] = 0.0; } //------------------------------------------------------------------------- //------------------------------------------------------------------------- void SparseMatrix:: Mult(Vector& lhs, Vector& rhs) { int i, k; if (lhs.v == rhs.v) callError("Mult"); FORALL(D,i) lhs[i] = D[i] * rhs[i]; FORALL(D,i) for (k=end[i-1]+1; k<=end[i]; ++k) { lhs[i] += (*L)[k] * rhs[col[k]]; lhs[col[k]] += (*U)[k] * rhs[i]; } } //------------------------------------------------------------------------- void SparseMatrix:: ATMult(Vector& lhs, Vector& rhs) { int i, k; if (lhs.v == rhs.v) callError("ATMult"); FORALL(D,i) lhs[i] = conj(D[i]) * rhs[i]; FORALL(D,i) for (k=end[i-1]+1; k<=end[i]; ++k) { lhs[i] += conj((*U)[k]) * rhs[col[k]]; lhs[col[k]] += conj((*L)[k]) * rhs[i]; } } //------------------------------------------------------------------------- //------------------------------------------------------------------------- void SparseMatrix:: smoothNode(int no, Vector& e, const Vector& r) { int k; Num sum = 0.0; for (k=end[no-1]+1; k<=end[no]; ++k) sum += (*L)[k] * e[col[k]]; if (symU) for (k=symEnd[no-1]+1; k<=symEnd[no]; ++k) sum += (*symU)[k] * e[symCol[k]]; e[no] = (r[no] - sum) / D[no]; } //------------------------------------------------------------------------- Num SparseMatrix:: MultRow(int row, const Vector& e) { int k; Num sum = D[row] * e[row]; for (k=end[row-1]+1; k<=end[row]; ++k) sum += (*L)[k] * e[col[k]]; if (symU) for (k=symEnd[row-1]+1; k<=symEnd[row]; ++k) sum += (*symU)[k]* e[symCol[k]]; return sum; } //------------------------------------------------------------------------- void SparseMatrix:: DiagMult(Vector& lhs, Vector& rhs, Real omega) { int i; if (equal(omega,1.0)) FORALL(D,i) lhs[i] = D[i] * rhs[i]; else FORALL(D,i) lhs[i] = D[i] * rhs[i] * omega; } //------------------------------------------------------------------------- void SparseMatrix:: DiagDiv(Vector& lhs, Vector& rhs, Real omega) { int i; if (equal(omega,1.0)) FORALL(D,i) lhs[i] = rhs[i] / D[i]; else FORALL(D,i) lhs[i] = omega * rhs[i] / D[i]; } //------------------------------------------------------------------------- // lhs = L * rhs: void SparseMatrix:: LMult(Vector& lhs, Vector& rhs) { int i, k; if (lhs.v == rhs.v) callError("LMult"); FORALL(D,i) { lhs[i] = 0.0; for (k=end[i-1]+1; k<=end[i]; ++k) lhs[i] += (*L)[k] * rhs[col[k]]; } } //------------------------------------------------------------------------- // lhs = UMult * rhs void SparseMatrix:: UMult(Vector& lhs, Vector& rhs) { int i, k; if (lhs.v == rhs.v) callError("UMult"); FORALL(D,i) lhs[i] = 0.0; FORALL(D,i) for (k=end[i-1]+1; k<=end[i]; ++k) lhs[col[k]] += (*U)[k] * rhs[i]; } //------------------------------------------------------------------------- //------------------------------------------------------------------------- // F = D + omega*L of Matrix A; lhs = F*rhs; void SparseMatrix:: F(Vector& lhs, Vector& rhs, Real omega) { int i, k; Num sum; if (lhs.v == rhs.v) callError("F"); FORALL(D,i) lhs[i] = D[i] * rhs[i]; if (equal(omega,1.0)) { FORALL(D,i) { sum = 0.0; for (k=end[i-1]+1; k<=end[i]; ++k) sum += (*L)[k] *rhs[col[k]]; lhs[i] += sum; } } else { FORALL(D,i) { sum = 0.0; for (k=end[i-1]+1; k<=end[i]; ++k) sum += (*L)[k] *rhs[col[k]]; lhs[i] += omega*sum; } } } //------------------------------------------------------------------------- // FT = D + omega*U of Matrix A; lhs = FT*rhs void SparseMatrix:: FT(Vector& lhs, Vector& rhs, Real omega) { int i, k; if (lhs.v == rhs.v) callError("FT"); FORALL(D,i) lhs[i] = 0.0; FORALL(D,i) for (k=end[i-1]+1; k<=end[i]; ++k) lhs[col[k]] += (*U)[k] * rhs[i]; if (equal(omega,1.0)) { FORALL(D,i) lhs[i] = lhs[i] + D[i]*rhs[i]; } else { FORALL(D,i) lhs[i] = omega*lhs[i] + D[i]*rhs[i]; } } //------------------------------------------------------------------------- // Fm1: F = D + omega*L of Matrix A; lhs = F**(-1) * rhs; void SparseMatrix:: Fm1 (Vector& lhs, Vector& rhs, Real omega) { int i, k; Num sum; if (lhs.v != rhs.v) FORALL(D,i) lhs[i] = rhs[i]; if (equal(omega,1.0)) { FORALL(D,i) { sum = 0.0; for (k=end[i-1]+1; k<=end[i]; ++k) sum += (*L)[k] * lhs[col[k]]; lhs[i] = (lhs[i] - sum) / D[i]; } } else { FORALL(D,i) { sum = 0.0; for (k=end[i-1]+1; k<=end[i]; ++k) sum += (*L)[k] * lhs[col[k]]; lhs[i] = (lhs[i] - omega*sum) / D[i]; } } } //------------------------------------------------------------------------- // FmT: FT = D + omega*U of Matrix A; lhs = F**(-t) * rhs; void SparseMatrix:: FmT (Vector& lhs, Vector& rhs, Real omega) { int i, k; Num sum; if (lhs.v != rhs.v) FORALL(D,i) lhs[i] = rhs[i]; if (equal(omega,1.0)) { FORALL_DOWNWARD(D,i) { lhs[i] /= D[i]; sum = lhs[i]; for (k=end[i-1]+1; k<=end[i]; ++k) lhs[col[k]] -= sum * (*U)[k]; } } else { FORALL_DOWNWARD(D,i) { lhs[i] /= D[i]; sum = omega*lhs[i]; for (k=end[i-1]+1; k<=end[i]; ++k) lhs[col[k]] -= sum * (*U)[k]; } } } //------------------------------------------------------------------------- //------------------------------------------------------------------------- Real SparseMatrix:: omegaOpt(int mode) const { int i, k; Vector z(Dim()); Num skew, sym; Real omega, sum; FORALL(D,i) z[i] = 0.0; z[1] = 1.0; for (i=2; i<=D.h; i++) for (k=end[i-1]+1; k<=end[i]; ++k) { sym = 0.5*((*L)[k] + (*U)[k]); skew = 0.5*((*L)[k] - (*U)[k]); sum = Abs(sym) + Abs(skew); z[i] += sum; z[col[k]] += sum; } omega = 1.4; FORALL(D,i) { if (z[i] > 0.0) omega = Min(omega, Abs(D[i])/z[i]); } if (mode==multiGrid || mode==multiLevel) return omega; else return 1./(omega - 0.5*(omega-1)); // reduce and invert value } //------------------------------------------------------------------------- void SparseMatrix:: resetDirichletEntries(Vector& r) const { int i; FORALL(dirichlet,i) { if (dirichlet[i]) r[i] = 0.0; } } //------------------------------------------------------------------------- // create the upper triangle of the matrix (a formal symmetric expansion of U) void SparseMatrix:: symmetricExpansion() { int i, k, pos; delete symU; symU = new Vector(U->low(),U->high()); symCol.resize(col.low(),col.high()); symEnd.resize(end.low(),end.high()); Vector noOfEntries(Dim()); FORALL(noOfEntries,i) noOfEntries[i] = 0; FORALL(D,i) // count entries in each row in upper triangle { for (k=end[i-1]+1; k<=end[i]; ++k) ++noOfEntries[col[k]]; } symEnd[symEnd.l] = 0; // for row '-1' FORALL(noOfEntries,i) symEnd[i] = symEnd[i-1] + noOfEntries[i]; FORALL(noOfEntries,i) noOfEntries[i] = 0; FORALL(D,i) // fill the upper triangle { for (k=end[i-1]+1; k<=end[i]; ++k) { pos = symEnd[col[k]-1] + 1 + noOfEntries[col[k]]; ++noOfEntries[col[k]]; symCol[pos] = i; (*symU)[pos] = (*U)[k]; } } } //------------------------------------------------------------------------- void SparseMatrix:: removeSymmetricExpansion() { if (symU==0) return; delete symU; symU = 0; symCol.resize(1); symEnd.resize(1); } //------------------------------------------------------------------------- /* // Sparse Incomplete LU-Decomposition: A = L*U = L*D*LT void SparseMatrix:: ILUDecompose(Real weight) { int i, k, m, n, r; Bool found; Num e; symmetricExpansion(); if (Cmd.isTrue("printILU")) { cout << "\nMatrix before Factorization:\n"; print(); } for (r=1; r < Dim(); ++r) { for (i=r+1; i <= Dim(); ++i) // all subsequent rows i { for (k=end[i-1]+1; k<=end[i]; ++k) // search A(i,r), the { // 'row factor' if (col[k]==r && !equal((*L)[k],0.0)) // A(i,r) != 0 { e = (*L)[k]/D[r]; // e = l(i,r)=A(i,r)/A(r,r) (*L)[k] = e; // -- apply e to the rest of this row // in the upper triangle: for (m=symEnd[r-1]+1; m<=symEnd[r]; ++m) { if (!equal((*symU)[m],0.0)) // (*symU)[m]=A(r,j) { const j = symCol[m]; // -- search corresponding element of column j: found = False; if (i==j) // is it the diagonal ? { D[i] -= e * (*symU)[m]; found = True; } if (!found) // search upper triangle { for (n=symEnd[i-1]+1; n<=symEnd[i]; ++n) { if (symCol[n]==j) { (*symU)[n] -= e * (*symU)[m]; found = True; } } } if (!found) // ... and lower triangle { for (n=end[i-1]+1; n<=end[i]; ++n) { if (col[n]==j) { (*L)[n] -= e * (*symU)[m]; found = True; } } } if (!found) D[i] -= weight * e * (*symU)[m]; } } break; } } } } if (Cmd.isTrue("printILU")) { cout << "\nMatrix after Factorization:\n"; print(); } if (symmetry != sym) { // store symU to U !!! cout << "\n*** SparseMatrix:: ILUDecompose not implemented for" << " non-symmetric matrices\n"; cout.flush(); abort(); } removeSymmetricExpansion(); } //------------------------------------------------------------------------- // A**(-1) = L**(-T) * D**(-1) * L**(-1) void SparseMatrix:: ILUFBSubst(Vector& lhs, Vector& rhs) const { int i, k; Num sum; if (lhs.v != rhs.v) FORALL(D,i) lhs[i] = rhs[i]; FORALL(D,i) { sum = 0.0; for (k=end[i-1]+1; k<=end[i]; ++k) sum += (*L)[k] * lhs[col[k]]; lhs[i] = lhs[i] - sum; } FORALL(D,i) lhs[i] /= D[i]; FORALL_DOWNWARD(D,i) { sum = lhs[i]; for (k=end[i-1]+1; k<=end[i]; ++k) lhs[col[k]] -= sum * (*U)[k]; } } */ //------------------------------------------------------------------------- //------------------------------------------------------------------------- void SparseMatrix:: countEntries(int* dim, int* nEntries) { int i, k; int n = dimension; FORALL(D,i) { for (k=end[i-1]+1; k<=end[i]; ++k) n += 2; } *nEntries = n; *dim = dimension; } //------------------------------------------------------------------------- void SparseMatrix:: Decompose(Bool removeOriginal) { if (decomposed) return; MA28Decompose(); if (removeOriginal) { removeLU(); D.resize(1); } decomposed = True; } //------------------------------------------------------------------------- void SparseMatrix:: ILUDecompose(Real dropTol) { if (ILUDecomposed || decomposed) return; MA28Decompose(dropTol); ILUDecomposed = True; } //------------------------------------------------------------------------- void SparseMatrix:: FBSubst(Vector& lhs, Vector& rhs) { if (!decomposed) { cout << "\n*** SparseMatrix::FBSubst(...) : Matrix not decomposed\n"; cout.flush(); abort(); } int i; FORALL(lhs,i) lhs[i] = rhs[i]; Num* b = lhs.v + lhs.low(); MA28FBSubst(b); } //------------------------------------------------------------------------- void SparseMatrix:: ILUFBSubst(Vector& lhs, Vector& rhs) { int i; if (!ILUDecomposed) FBSubst(lhs, rhs); else { FORALL(lhs,i) lhs[i] = rhs[i]; Num* b = lhs.v + lhs.low(); MA28FBSubst(b); } } //------------------------------------------------------------------------- void SparseMatrix:: fillMA28Vectors() { int i,k,n; n = -1; // start with 0 in ma28-arrays FORALL(D,i) // array A must start with diagonal { ++n; A [n] = D[i]; IRN[n] = i; ICN[n] = i; } FORALL(D,i) { for (k=end[i-1]+1; k<=end[i]; ++k) { ++n; A [n] = (*L)[k]; IRN[n] = i; ICN[n] = col[k]; ++n; A [n] = (*U)[k]; IRN[n] = col[k]; ICN[n] = i; } } }