/* $Id: sysmatml.cc,v 1.3 1996/10/11 09:10:11 roitzsch Exp $ (C)opyright 1996 by Konrad-Zuse-Center, Berlin All rights reserved. Part of the Kaskade distribution */ #include "sysmatml.h" #include "utils.h" #include "numerics.h" #include "dirichlet.h" #include "family.h" //------------------------------------------------------------------------- StaticAllocator NodeNeighbour:: alloc(ElementsInBlock); StaticAllocator AsymNodeNeighbour:: alloc(ElementsInBlock); //------------------------------------------------------------------------- //------------------------------------------------------------------------- MLSparseMatrix:: MLSparseMatrix(symmetryType symmetry0, int spaceDim0, int dim) : MLMatrix(symmetry0), MA28Matrix(spaceDim0), dimension(dim), decomposed(False), ILUDecomposed(False), D(dim), L(dim), symU(0), mark(dim), dirichlet(dim), smooth(dim) { int i; FORALL(mark,i) mark[i] = False; FORALL(smooth,i) smooth[i] = True; FORALL(dirichlet,i) dirichlet[i] = False; FORALL(L,i) L[i] = 0; reset(); } //------------------------------------------------------------------------- MLSparseMatrix:: ~MLSparseMatrix() { removeLU(); } //------------------------------------------------------------------------- void MLSparseMatrix:: extend(int noOfNodes) { int i; if (noOfNodes != dimension) // matrix will be really extended { MA28RemoveLUFactorization(); decomposed = False; ILUDecomposed = False; } dimension = noOfNodes; removeLU(); D.resize(noOfNodes); L.resize(noOfNodes); FORALL(L,i) L[i] = 0; dirichlet.resize(noOfNodes); mark.resize(noOfNodes); smooth.resize(noOfNodes); FORALL(smooth,i) smooth[i] = True; FORALL(mark,i) mark[i] = False; FORALL(smooth,i) smooth[i] = True; FORALL(dirichlet,i) dirichlet[i] = False; reset(); } //------------------------------------------------------------------------- Num& MLSparseMatrix:: operator() (int row, int col) { NodeNeighbour *np; int r,c; if (row == col) return D[row]; if (row > col) { r = row; c = col; } else { r = col; c = row; } for (np=L[r]; np; np=np->next) { if (np->node == c) { if (row > col) return np->Aij(); else return np->Aji(); } } // -- neighbour entry not found: insert a new entry NodeNeighbour* newNeigh; if (symmetry == sym) newNeigh = new NodeNeighbour; else newNeigh = new AsymNodeNeighbour; newNeigh->node = c; newNeigh->next = L[r]; L[r] = newNeigh; if (row > col) return newNeigh->Aij(); else return newNeigh->Aji(); } //------------------------------------------------------------------------- void MLSparseMatrix:: reset() { int i; FORALL(D,i) resetRow(i); } //------------------------------------------------------------------------- void MLSparseMatrix:: resetRow(int node) { NodeNeighbour* np; D[node] = 0.0; for (np=L[node]; np; np=np->next) np->Aij() = np->Aji() = 0.0; } //------------------------------------------------------------------------- void MLSparseMatrix:: removeRow(int node) { NodeNeighbour* np, *toRem; if (L[node] == 0) return; np = L[node]; L[node] = 0; while (np) { toRem = np; np = np->next; delete toRem; } } //------------------------------------------------------------------------- void MLSparseMatrix:: removeLU() { int i; removeSymmetricExpansion(); FORALL(L,i) removeRow(i); } //------------------------------------------------------------------------- void MLSparseMatrix:: markNodes() { int i; FORALL(mark,i) mark[i] = 1; } void MLSparseMatrix:: unMarkNodes() { int i; FORALL(mark,i) mark[i] = 0; } //------------------------------------------------------------------------- /* // -- reset coupling terms between all marked (==changed) nodes void MLSparseMatrix:: resetMarkedEntries() { NodeNeighbour* np; int i; FORALL(D,i) if (mark[i]) { D[i] = 0.0; for (np=L[i]; np; np=np->next) np->Aij() = np->Aji() = 0.0; } else { for (np=L[i]; np; np=np->next) if (mark[np->node]) np->Aij() = np->Aji() = 0.0; } } */ //------------------------------------------------------------------------- void MLSparseMatrix:: print() const { NodeNeighbour* np; int i; if (decomposed || ILUDecomposed) { cout << "\n* Matrix decomposed: print() not available\n"; return; } cout << "\n--- MLSparse Matrix diagonal: \n\n"; FORALL(D,i) cout << D[i] << " "; cout << "\nLower Triangle:"; FORALL(D,i) { cout << "\nrow " << i << " : "; for (np=L[i]; np; np=np->next) cout << " " << np->Aij() << "[" << np->node << "]"; } if (symmetry == asym) { cout << "\nUpper Triangle:"; FORALL(D,i) { cout << "\ncol " << i << " : "; for (np=L[i]; np; np=np->next) cout << " " << np->Aji() << "[" << np->node << "]"; } } if (symU) { cout << "\nSymmetric Expansion: \n"; FORALL(*symU,i) { cout << "\nrow " << i << " : "; for (np=(*symU)[i]; np; np=np->next) cout << " " << np->Aij() << "[" << np->node << "]"; } } cout << "\n"; } //------------------------------------------------------------------------- int MLSparseMatrix:: memSpace(Bool print) const { int space = 0; space += L.memSpace(); space += D.memSpace(); space += mark.memSpace(); space += smooth.memSpace(); space += dirichlet.memSpace(); if (symU) space += symU->memSpace(); space += MA28MemSpace(); if (print) cout << "\n Memory allocated for MLSparseMatrix without LU: " << Form("%1.6f", float(space)/1e6) << " MB\n"; return space; } //------------------------------------------------------------------------- int MLSparseMatrix:: memSpaceLU(Bool print) const { int i, space = 0; FORALL(L,i) if (L[i]) { space += L[i]->alloc.MemSpace(); break; } if (print) cout << "\n Memory allocated for LU in MLSparseMatrices: " << Form("%1.6f", float(space)/1e6) << " MB\n"; return space; } //------------------------------------------------------------------------- void MLSparseMatrix:: smoothNode(int no, Vector& e, const Vector& r) { NodeNeighbour* np; Num sum = 0.0; if (dirichlet[no]) return; for (np=L[no]; np; np=np->next) sum += np->Aij() * e[np->node]; for (np=(*symU)[no]; np; np=np->next) sum += np->Aij() * e[np->node]; e[no] = (r[no] - sum) / D[no]; } //------------------------------------------------------------------------- Num MLSparseMatrix:: MultRow(int no, const Vector& e) { NodeNeighbour* np; Num sum = D[no] * e[no]; for (np=L[no]; np; np=np->next) sum += np->Aij() * e[np->node]; for (np=(*symU)[no]; np; np=np->next) sum += np->Aij() * e[np->node]; return sum; } //------------------------------------------------------------------------- void MLSparseMatrix:: DiagDiv(Vector& lhs, Vector& rhs, Real omega) { int i; FORALL(D,i) lhs[i] = rhs[i] / D[i]; if (!equal(omega,1.0)) FORALL(D,i) lhs[i] *= omega; } //------------------------------------------------------------------------- void MLSparseMatrix:: DiagMult(Vector& lhs, Vector& rhs,Real omega) { int i; FORALL(D,i) lhs[i] = rhs[i] * D[i]; if (!equal(omega,1.0)) FORALL(D,i) lhs[i] *= omega; } //------------------------------------------------------------------------- void MLSparseMatrix:: Mult(Vector& lhs, Vector& rhs) { NodeNeighbour* np; int i; if (lhs.v == rhs.v) callError("Mult"); FORALL(D,i) lhs[i] = D[i] * rhs[i]; FORALL(D,i) { for (np=L[i]; np; np=np->next) { lhs[i] += np->Aij() * rhs[np->node]; lhs[np->node] += np->Aji() * rhs[i]; } } } //------------------------------------------------------------------------- void MLSparseMatrix:: ATMult(Vector& lhs, Vector& rhs) { NodeNeighbour* np; int i; if (lhs.v == rhs.v) callError("ATMult"); FORALL(D,i) lhs[i] = D[i] * rhs[i]; FORALL(D,i) { for (np=L[i]; np; np=np->next) { lhs[i] += conj(np->Aji()) * rhs[np->node]; lhs[np->node] += conj(np->Aij()) * rhs[i]; } } } //------------------------------------------------------------------------- void MLSparseMatrix:: LMult(Vector& lhs, Vector& rhs) { NodeNeighbour* np; int i; if (lhs.v == rhs.v) callError("LMult"); FORALL(D,i) { lhs[i] = 0.0; for (np=L[i]; np; np=np->next) lhs[i] += np->Aij() * rhs[np->node]; } } //------------------------------------------------------------------------- void MLSparseMatrix:: UMult(Vector& lhs, Vector& rhs) { NodeNeighbour* np; int i; if (lhs.v == rhs.v) callError("UMult"); FORALL(D,i) lhs[i] = 0.0; FORALL(D,i) { for (np=L[i]; np; np=np->next) lhs[np->node] += np->Aji() * rhs[i]; } } //------------------------------------------------------------------------- //------------------------------------------------------------------------- // F = D + omega*L of Matrix A; lhs = F*rhs; void MLSparseMatrix:: F(Vector& lhs, Vector& rhs, Real omega) { NodeNeighbour* np; int i; Num sum; if (lhs.v == rhs.v) callError("F"); FORALL(D,i) lhs[i] = D[i] * rhs[i]; if (equal(omega,1.0)) { FORALL_DOWNWARD(D,i) { sum = 0.0; for (np=L[i]; np; np=np->next) sum += np->Aij() * rhs[np->node]; lhs[i] += sum; } } else { FORALL_DOWNWARD(D,i) { sum = 0.0; for (np=L[i]; np; np=np->next) sum += np->Aij() * rhs[np->node]; lhs[i] += omega*sum; } } } //------------------------------------------------------------------------- // FT = D + omega*U of Matrix A; lhs = FT*rhs void MLSparseMatrix:: FT(Vector& lhs, Vector& rhs, Real omega) { NodeNeighbour* np; int i; if (lhs.v == rhs.v) callError("FT"); FORALL(D,i) lhs[i] = 0.0; FORALL(D,i) { for (np=L[i]; np; np=np->next) lhs[np->node] += np->Aji() * 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 MLSparseMatrix:: Fm1(Vector& lhs, Vector& rhs, Real omega) { NodeNeighbour* np; int i; 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 (np=L[i]; np; np=np->next) sum += np->Aij() * lhs[np->node]; lhs[i] = (lhs[i] - sum) / D[i]; } } else { FORALL(D,i) { sum = 0.0; for (np=L[i]; np; np=np->next) sum += np->Aij() * lhs[np->node]; lhs[i] = (lhs[i] - omega*sum) / D[i]; } } } //------------------------------------------------------------------------- // FmT: FT = D + omega*U of Matrix A; lhs = F**(-t) * rhs; void MLSparseMatrix:: FmT(Vector& lhs, Vector& rhs, Real omega) { NodeNeighbour* np; int i; 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 (np=L[i]; np; np=np->next) lhs[np->node] -= sum * np->Aji(); } } else { FORALL_DOWNWARD(D,i) { lhs[i] /= D[i]; sum = omega*lhs[i]; for (np=L[i]; np; np=np->next) lhs[np->node] -= sum * np->Aji(); } } } //------------------------------------------------------------------------- //------------------------------------------------------------------------- Real MLSparseMatrix:: omegaOpt(int mode) const { NodeNeighbour* np; int i; 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.high(); ++i) for (np=L[i]; np; np=np->next) { sym = 0.5*(np->Aij() + np->Aji()); skew = 0.5*(np->Aij() - np->Aji()); sum = Abs(sym) + Abs(skew); z[i] += sum; z[np->node] += 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 MLSparseMatrix:: restoreDirichletEntries() { NodeNeighbour* np, *nextDir; int i; FORALL(D,i) { if (L[i] == 0) // a 'dirichlet row' L[i] = nodes[i]->firstDirichlet; else // move entry by entry { nextDir = nodes[i]->firstDirichlet; while (nextDir) { np = nextDir; nextDir = nextDir->next; np->next = nodes[i]->first; nodes[i]->first = np; } } nodes[i]->firstDirichlet = 0; } } //------------------------------------------------------------------------- void MLSparseMatrix:: removeDirichletEntries() { NodeNeighbour* np, *prev=0, *toRem; int i; FORALL(D,i) { if (nodes[i]->dirichlet) // remove all entries of row { np = nodes[i]->first; nodes[i]->first = 0; while (np) { toRem = np; np = np->next; delete toRem; } } else // remove entries coupled to a dirichlet neighbour { np = nodes[i]->first; while (np) { if (nodes[np->node]->dirichlet) { if (np == nodes[i]->first) nodes[i]->first = np->next; else prev->next = np->next; toRem = np; np = np->next; delete toRem; } else { prev = np; np = np->next; } } } } } */ //------------------------------------------------------------------------- void MLSparseMatrix:: 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 MLSparseMatrix:: setSymDirichletBCs(DirichletBCs& dirichletBCs, Vector& b, Vector& /*bS*/, Num& Fct0, Num& /*E0*/) { NodeNeighbour* np, *next, *prev=0; int i, icol; Num value; Fct0 = 0.0; FORALL(D,i) { if (dirichletBCs.isSet(i)) // row with Dir. BC { value = dirichletBCs.value(i); for (np=L[i]; np; np=np->next) { icol = np->node; if (dirichletBCs.isSet(icol)) Fct0 += np->Aij() * value * dirichletBCs.value(icol); else b[icol] -= np->Aij() * value; } Fct0 -= b[i] * value; // - u0*b0 Fct0 += D[i] * value * value; b[i] = D[i] * value; removeRow(i); } else { for (np=L[i]; np; np=next) { next = np->next; icol = np->node; if (dirichletBCs.isSet(icol)) { b[i] -= np->Aij() * dirichletBCs.value(icol); // ADF*u0 // -- remove np: if (np == L[i]) L[i] = np->next; else prev->next = np->next; delete np; } else prev = np; } } } } //------------------------------------------------------------------------- void MLSparseMatrix:: setASymDirichletBCs(DirichletBCs& dirichletBCs, Vector& b, Vector& bSave, Num& Fct0, Num& E0) { NodeNeighbour* np; int i, 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 (np=L[i]; np; np=np->next) { icol = np->node; if (dirichletBCs.isSet(icol)) Fct0 += 0.5 * np->Aij() * value * dirichletBCs.value(icol); else bSave[icol] += 0.5 * np->Aij() * value; np->Aij() = 0.0; } Fct0 -= b[i] * value; // - u0*b0 Fct0 += D[i] * value * value; E0 += b[i] * value; E0 -= D[i] * value * value; b[i] = D[i] * value; } for (np=L[i]; np; np=np->next) // column up { icol = np->node; if (dirichletBCs.isSet(icol)) { if (dirichletBCs.isSet(i)) Fct0 += 0.5 * np->Aji() * dirichletBCs.value(i) * dirichletBCs.value(icol); else bSave[i] += 0.5 * np->Aji() * dirichletBCs.value(icol); np->Aji() = 0.0; } } } } //------------------------------------------------------------------------- void MLSparseMatrix:: resetDirichletEntries(Vector& r) const { int i; FORALL(dirichlet,i) { if (dirichlet[i]) r[i] = 0.0; } } //------------------------------------------------------------------------- void MLSparseMatrix:: GalerkinRestriction(MLMatrix& Ah0, Generation& generation, const Vector* critical) { NodeNeighbour* np; Son* son, *son2; int i, k, m, nFathers, nFathers2, father, father2; Real weight, weight2, fact; if (generation.castToMCGeneration()) { cout << "\n*** MLSparseMatrix : generation is MCGeneration\n"; cout.flush(); abort(); } MLSparseMatrix* Ah = Ah0.castToMLSparseMatrix(); removeLU(); reset(); FORALL(Ah->D,i) { if (critical) if ((*critical)[i]) continue; son = generation.getSon(i); nFathers = son->NoOfFathers(); // -- restrict diagonal term: if (nFathers == 1) { father = son->getFather(); if (mark[father]) D[father] += Ah->D[i]; } else { for (k=1; k<=nFathers; ++k) for (m=1; m<=k; ++m) { father = son->getFather(k); father2 = son->getFather(m); if (dirichlet[father] || dirichlet[father2]) continue; if (mark[father] || mark[father2]) { weight = son->getWeight(k); weight2 = son->getWeight(m); fact = weight * weight2; (*this)(father,father2) += fact * Ah->D[i]; if (symmetry==asym && father!=father2) (*this)(father2,father) += fact * Ah->D[i]; } } } // -- off-diagonal terms: for (np=Ah->L[i]; np; np=np->next) { if (critical) if ((*critical)[np->node]) continue; son2 = generation.getSon(np->node); nFathers2 = son2->NoOfFathers(); for (k=1; k<=nFathers; ++k) for (m=1; m<=nFathers2; ++m) { father = son ->getFather(k); father2 = son2->getFather(m); if (dirichlet[father] || dirichlet[father2]) continue; if (mark[father] || mark[father2]) { weight = son ->getWeight(k); weight2 = son2->getWeight(m); fact = weight*weight2; if (symmetry == sym) { if (father == father2) fact *= 2.0; (*this)(father,father2) += fact * np->Aij(); } else { (*this)(father,father2) += fact * np->Aij(); (*this)(father2,father) += fact * np->Aji(); } } } } } } //------------------------------------------------------------------------- void MLSparseMatrix:: symmetricExpansion() { NodeNeighbour* np, *newN; int i; removeSymmetricExpansion(); symU = new Vector(Dim()); FORALL(*symU,i) (*symU)[i] = 0; FORALL(D,i) { for (np=L[i]; np; np=np->next) { newN = new NodeNeighbour; newN->Aij() = np->Aji(); newN->node = i; // exchange column and row newN->next = (*symU)[np->node]; (*symU)[np->node] = newN; } } } //------------------------------------------------------------------------- void MLSparseMatrix:: removeSymmetricExpansion() { int i; NodeNeighbour* np, *toRem; if (symU == 0) return; FORALL(*symU,i) { np = (*symU)[i]; while(np) { toRem = np; np = np->next; delete toRem; } } delete symU; symU = 0; } //------------------------------------------------------------------------- //------------------------------------------------------------------------- void LocalMLSparseMatrix:: smoothNode(int node, Vector& e, const Vector& r) { NodeNeighbour* np; Num sum = 0.0; if (!smooth[node]) return; if (dirichlet[node]) return; for (np=L[node]; np; np=np->next) sum += np->Aij() * e[np->node]; for (np=(*symU)[node]; np; np=np->next) sum += np->Aji() * e[np->node]; e[node] = (r[node] - sum) / D[node]; } //------------------------------------------------------------------------- void LocalMLSparseMatrix:: DiagDiv(Vector& lhs, Vector& rhs, Real omega) { int i; if (equal(omega,1.0)) FORALL(D,i) { if (smooth[i]) lhs[i] = rhs[i] / D[i]; else lhs[i] = 0.0; } else FORALL(D,i) { if (smooth[i]) lhs[i] = omega * rhs[i] / D[i]; else lhs[i] = 0.0; } } //------------------------------------------------------------------------- void LocalMLSparseMatrix:: DiagMult(Vector& lhs, Vector& rhs, Real omega) { int i; if (equal(omega,1.0)) FORALL(D,i) { if (smooth[i]) lhs[i] = rhs[i] * D[i]; //else lhs[i] = 0.0; } else FORALL(D,i) { if (smooth[i]) lhs[i] = omega * rhs[i] * D[i]; //else lhs[i] = 0.0; } } //------------------------------------------------------------------------- // F = D + omega*L of Matrix A; lhs = F*rhs; void LocalMLSparseMatrix:: F(Vector& /*lhs*/, Vector& /*rhs*/, Real /*omega*/) { notImplemented("LocalMLSparseMatrix:: F"); } //------------------------------------------------------------------------- // FT = D + omega*U of Matrix A; lhs = FT*rhs void LocalMLSparseMatrix:: FT(Vector& /*lhs*/, Vector& /*rhs*/, Real /*omega*/) { notImplemented("LocalMLSparseMatrix:: F"); } //------------------------------------------------------------------------- // Fm1: F = D + omega*L of Matrix A; lhs = F**(-1) * rhs; void LocalMLSparseMatrix:: Fm1(Vector& lhs, Vector& rhs, Real omega) { NodeNeighbour* np; int i; Num sum; FORALL(D,i) { if (smooth[i]) lhs[i] = rhs[i]; } if (equal(omega,1.0)) { FORALL(D,i) if (smooth[i]) { sum = 0.0; for (np=L[i]; np; np=np->next) sum += np->Aij() * lhs[np->node]; lhs[i] = (lhs[i] - sum) / D[i]; } } else { FORALL(D,i) if (smooth[i]) { sum = 0.0; for (np=L[i]; np; np=np->next) sum += np->Aij() * lhs[np->node]; lhs[i] = (lhs[i] - omega*sum) / D[i]; } } } //------------------------------------------------------------------------- // FmT: FT = D + omega*U of Matrix A; lhs = F**(-T) * rhs; void LocalMLSparseMatrix:: FmT(Vector& lhs, Vector& rhs, Real omega) { NodeNeighbour* np; int i; Num sum; FORALL(D,i) { if (smooth[i]) lhs[i] = rhs[i]; } if (equal(omega,1.0)) { FORALL_DOWNWARD(D,i) { if (smooth[i]) lhs[i] /= D[i]; sum = lhs[i]; for (np=L[i]; np; np=np->next) if (smooth[np->node]) lhs[np->node] -= sum * np->Aji(); } } else { FORALL_DOWNWARD(D,i) { if (smooth[i]) lhs[i] /= D[i]; sum = omega*lhs[i]; for (np=L[i]; np; np=np->next) if (smooth[np->node]) lhs[np->node] -= sum * np->Aji(); } } } //------------------------------------------------------------------------- void LocalMLSparseMatrix:: removeNonSmoothedEntries() { NodeNeighbour* np, *prev=0, *toRem; int i; FORALL(D,i) { if (!smooth[i]) { D[i] = 0.0; // may never be used np = L[i]; while (np) { if (!smooth[np->node]) { if (np == L[i]) L[i] = np->next; else prev->next = np->next; toRem = np; np = np->next; delete toRem; } else { prev = np; np = np->next; } } } } } //------------------------------------------------------------------------- //------------------------------------------------------------------------- void MLSparseMatrix:: countEntries(int* dim, int* nEntries) { int i; NodeNeighbour* np; int n = dimension; FORALL(D,i) { for (np=L[i]; np; np=np->next) n += 2; } *nEntries = n; *dim = dimension; } //------------------------------------------------------------------------- void MLSparseMatrix:: Decompose(Bool removeOriginal) { if (decomposed) return; MA28Decompose(); if (removeOriginal) { removeLU(); D.resize(1); } decomposed = True; } //------------------------------------------------------------------------- void MLSparseMatrix:: ILUDecompose(Real dropTol) { if (ILUDecomposed || decomposed) return; MA28Decompose(dropTol); ILUDecomposed = True; } //------------------------------------------------------------------------- void MLSparseMatrix:: FBSubst(Vector& lhs, Vector& rhs) { if (!decomposed) { cout << "\n*** MLSparseMatrix::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 MLSparseMatrix:: 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 MLSparseMatrix:: fillMA28Vectors() { int i, n; NodeNeighbour* np; 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 (np=L[i]; np; np=np->next) { ++n; A [n] = np->Aij(); IRN[n] = i; ICN[n] = np->node; ++n; A [n] = np->Aji(); IRN[n] = np->node; ICN[n] = i; } } }