template <class Scalar> inline SolverState<Scalar> BlockTriangularSolver<Scalar> ::solve(const LinearOperator<Scalar>& op, const Vector<Scalar>& rhs, Vector<Scalar>& soln) const { int nRows = op.numBlockRows(); int nCols = op.numBlockCols(); soln = op.domain().createMember(); // bool converged = false; TEST_FOR_EXCEPTION(nRows != rhs.space().numBlocks(), std::runtime_error, "number of rows in operator " << op << " not equal to number of blocks on RHS " << rhs); TEST_FOR_EXCEPTION(nRows != nCols, std::runtime_error, "nonsquare block structure in block triangular " "solver: nRows=" << nRows << " nCols=" << nCols); bool isUpper = false; bool isLower = false; for (int r=0; r<nRows; r++) { for (int c=0; c<nCols; c++) { if (op.getBlock(r,c).ptr().get() == 0 || dynamic_cast<const SimpleZeroOp<Scalar>* >(op.getBlock(r,c).ptr().get())) { TEST_FOR_EXCEPTION(r==c, std::runtime_error, "zero diagonal block (" << r << ", " << c << " detected in block " "triangular solver. Operator is " << op); continue; } else { if (r < c) isUpper = true; if (c < r) isLower = true; } } } TEST_FOR_EXCEPTION(isUpper && isLower, std::runtime_error, "block triangular solver detected non-triangular operator " << op); bool oneSolverFitsAll = false; if ((int) solvers_.size() == 1 && nRows != 1) { oneSolverFitsAll = true; } for (int i=0; i<nRows; i++) { int r = i; if (isUpper) r = nRows - 1 - i; Vector<Scalar> rhs_r = rhs.getBlock(r); for (int j=0; j<i; j++) { int c = j; if (isUpper) c = nCols - 1 - j; if (op.getBlock(r,c).ptr().get() != 0) { rhs_r = rhs_r - op.getBlock(r,c) * soln.getBlock(c); } } SolverState<Scalar> state; Vector<Scalar> soln_r; if (oneSolverFitsAll) { state = solvers_[0].solve(op.getBlock(r,r), rhs_r, soln_r); } else { state = solvers_[r].solve(op.getBlock(r,r), rhs_r, soln_r); } if (nRows > 1) soln.setBlock(r, soln_r); else soln = soln_r; if (state.finalState() != SolveConverged) { return state; } } return SolverState<Scalar>(SolveConverged, "block solves converged", 0, ScalarTraits<Scalar>::zero()); }
int main(int argc, char *argv[]) { int stat = 0; try { GlobalMPISession session(&argc, &argv); MPIComm::world().synchronize(); Out::os() << "go!" << std::endl; VectorType<double> type = new EpetraVectorType(); Array<int> domainBlockSizes = tuple(2,3,4); Array<int> rangeBlockSizes = tuple(2,2); Array<VectorSpace<double> > domainBlocks(domainBlockSizes.size()); Array<VectorSpace<double> > rangeBlocks(rangeBlockSizes.size()); for (int i=0; i<domainBlocks.size(); i++) { domainBlocks[i] = type.createEvenlyPartitionedSpace(MPIComm::world(), domainBlockSizes[i]); } for (int i=0; i<rangeBlocks.size(); i++) { rangeBlocks[i] = type.createEvenlyPartitionedSpace(MPIComm::world(), rangeBlockSizes[i]); } VectorSpace<double> domain = blockSpace(domainBlocks); VectorSpace<double> range = blockSpace(rangeBlocks); double blockDensity = 0.75; double onProcDensity = 0.5; double offProcDensity = 0.1; RandomBlockMatrixBuilder<double> builder(domain, range, blockDensity, onProcDensity, offProcDensity, type); LinearOperator<double> A = builder.getOp(); Out::os() << "A num block rows = " << A.numBlockRows() << std::endl; Out::os() << "A num block cols = " << A.numBlockCols() << std::endl; Vector<double> x = domain.createMember(); Out::os() << "randomizing trial vector" << std::endl; x.randomize(); Array<Vector<double> > xBlock(domain.numBlocks()); for (int i=0; i<xBlock.size(); i++) { xBlock[i] = x.getBlock(i); } Vector<double> xx = x.copy(); Out::os() << "------------------------------------------------------------" << std::endl; Out::os() << "computing A*x..." << std::endl; Vector<double> y0 = A * x; for (int i=0; i<y0.space().numBlocks(); i++) { Out::os() << "y0[" << i << "] = " << std::endl << y0.getBlock(i) << std::endl; } Vector<double> y1 = range.createMember(); Out::os() << "------------------------------------------------------------" << std::endl; Out::os() << "computing A*x block-by-block..." << std::endl; Array<Vector<double> > yBlock(range.numBlocks()); for (int i=0; i<yBlock.size(); i++) { yBlock[i] = range.getBlock(i).createMember(); yBlock[i].zero(); for (int j=0; j<xBlock.size(); j++) { LinearOperator<double> Aij = A.getBlock(i,j); if (Aij.ptr().get() != 0) { Out::os() << "A(" << i << ", " << j << ") = " << std::endl << Aij << std::endl; } else { Out::os() << "A(" << i << ", " << j << ") = 0 " << std::endl; } Out::os() << "x[" << j << "] = " << std::endl << xBlock[j] << std::endl; if (Aij.ptr().get()==0) continue; yBlock[i] = yBlock[i] + Aij * xBlock[j]; } y1.setBlock(i, yBlock[i]); } for (int i=0; i<y1.space().numBlocks(); i++) { Out::os() << "y1[" << i << "] = " << std::endl << y1.getBlock(i) << std::endl; } double err = (y1 - y0).norm2(); Out::os() << "error = " << err << std::endl; double tol = 1.0e-13; if (err < tol) { Out::os() << "block op test PASSED" << std::endl; } else { stat = -1; Out::os() << "block op test FAILED" << std::endl; } } catch(std::exception& e) { stat = -1; Out::os() << "Caught exception: " << e.what() << std::endl; } return stat; }
Preconditioner<double> PCDPreconditionerFactory:: createPreconditioner(const LinearOperator<double>& K) const { Tabs tab; LinearOperator<double> F = K.getBlock(0,0); // F.setName("F"); LinearOperator<double> FInv = inverse(F, FSolver_); // FInv.setName("FInv"); LinearOperator<double> Bt = K.getBlock(0,1); // Bt.setName("Bt"); LinearOperator<double> Fp = FpProb_.getOperator(); LinearOperator<double> Mp = MpProb_.getOperator(); // Mp.setName("Mp"); LinearOperator<double> MpInv = inverse(Mp, MpSolver_); // MpInv.setName("MpInv"); LinearOperator<double> Ap = ApProb_.getOperator(); // Ap.setName("Ap"); LinearOperator<double> ApInv = inverse(Ap, ApSolver_); // ApInv.setName("ApInv"); VectorSpace<double> pDomain = Bt.domain(); VectorSpace<double> uDomain = F.domain(); LinearOperator<double> Iu = identityOperator(uDomain); // Iu.setName("Iu"); LinearOperator<double> Ip = identityOperator(pDomain); // Ip.setName("Ip"); LinearOperator<double> XInv = MpInv * Fp * ApInv; VectorSpace<double> rowSpace = K.range(); VectorSpace<double> colSpace = K.domain(); LinearOperator<double> Q1 = makeBlockOperator(colSpace, rowSpace); // Q1.setName("Q1"); LinearOperator<double> Q2 = makeBlockOperator(colSpace, rowSpace); // Q2.setName("Q2"); LinearOperator<double> Q3 = makeBlockOperator(colSpace, rowSpace); //Q3.setName("Q3"); Q1.setBlock(0, 0, FInv); Q1.setBlock(1, 1, Ip); Q1.endBlockFill(); Q2.setBlock(0, 0, Iu); Q2.setBlock(0, 1, -1.0*Bt); Q2.setBlock(1, 1, Ip); Q2.endBlockFill(); Q3.setBlock(0, 0, Iu); Q3.setBlock(1, 1, -1.0*XInv); Q3.endBlockFill(); LinearOperator<double> P1 = Q2 * Q3; LinearOperator<double> PInv = Q1 * P1; return new GenericRightPreconditioner<double>(PInv); }