arma::mat Methods::implicitJacobi(double time) { /* method implicit Jacobi */ arma::mat uPrev(n,n, arma::fill::zeros); //empty matrix for previous values arma::mat uNew(n,n, arma::fill::zeros); //empty matrix for new values arma::mat temp(n,n, arma::fill::zeros); //empty matrix for temporary values of uPrev double threshold = 0.000001; //convergance threshold double diff = threshold + 1; //difference of uPrev and temp //set initial value for(int j=0; j<n ;j++) { for(int i=0; i<n ;i++) { uPrev(i,j) = (1-j*h)*std::exp(i*h); //steady-state } //end j } //end i temp = uPrev; //set intial guess as previous value while(diff > threshold) { /* calculate new values */ for(int i=1; i<n-1 ;i++) { for(int j=1; j<n-1 ;j++) { uNew(i,j) = (1./(1+4*alpha))*(uPrev(i,j) + alpha*(temp(i+1,j)+temp(i-1,j)+temp(i,j+1)+temp(i,j-1))); } //end j } //end i for(int k=0; k<n ;k++) { /* set boundary conditions (assume x=y=[0,1]) */ double kn = float(k)/n; uNew(0,k) = (1-kn)*std::exp(time); uNew(n-1,k) = (1-kn)*std::exp(1+time); uNew(k,0) = std::exp(kn+time); uNew(k,n-1) = 0; } //end k diff = 0; //reset diff for(int i=0; i<n ;i++) { /* calculate difference */ for(int j=0; j<n ;j++) { diff += std::abs(temp(i,j) - uNew(i,j)); } //end i } //end j diff /= n*n; //assuming our matrix is square temp = uPrev; uPrev = uNew; //keep temp } //end while return uNew; } //end function implicitJacobi
arma::mat Methods::explicitEuler2D(double time) { /* methods explicit euler (in 2D) */ arma::mat uPrev(n,n, arma::fill::zeros); //empty vector for previous values arma::mat uNew(n,n, arma::fill::zeros); //empty vector for new values //set initial value for(int j=0; j<n ;j++) { for(int i=0; i<n ;i++) { uPrev(i,j) = (1-j*h)*std::exp(i*h); //steady-state } //end j } //end i for(int t=1; t<=(time/wlk->dt) ;t++) { /* calculate new values */ for(int i=1; i<n-1 ;i++) { for(int j=1; j<n-1 ;j++) { uNew(i,j) = uPrev(i,j) + alpha*(uPrev(i+1,j)+uPrev(i-1,j) +uPrev(i,j+1)+uPrev(i,j-1)-4*uPrev(i,j)); } //end j } //end i for(int k=0; k<n ;k++) { /* set boundary conditions (assume x=y=[0,1]) */ double kn = float(k)/n; uNew(0,k) = (1-kn)*std::exp(time); uNew(n-1,k) = (1-kn)*std::exp(1+time); uNew(k,0) = std::exp(kn+time); uNew(k,n-1) = 0; } //end k uPrev = uNew; //update value } //end t return uNew; } //end function explicitEuler2D
void StochBlockJacobiSolver::solve(const Array<LinearOperator<double> >& KBlock, const Array<int>& hasNonzeroMatrix, const Array<Vector<double> >& fBlock, Array<Vector<double> >& xBlock) const { int L = KBlock.size(); int P = pcBasis_.nterms(); int Q = fBlock.size(); /* * Solve the equations using block Gauss-Jacobi iteration */ Array<Vector<double> > uPrev(P); Array<Vector<double> > uCur(P); for (int i=0; i<P; i++) { TEUCHOS_TEST_FOR_EXCEPTION(fBlock[0].ptr().get()==0, std::runtime_error, "empty RHS vector block i=[" << i << "]"); uPrev[i] = fBlock[0].copy(); uCur[i] = fBlock[0].copy(); uPrev[i].zero(); uCur[i].zero(); } if (verbosity_) Out::root() << "starting Jacobi loop" << std::endl; bool converged = false; for (int iter=0; iter<maxIters_; iter++) { if (verbosity_) Out::root() << "Jacobi iter=" << iter << std::endl; bool haveNonConvergedBlock = false; double maxErr = -1.0; int numNonzeroBlocks = 0; for (int i=0; i<P; i++) { if (verbosity_) Out::root() << "Iter " << iter << ": block row i=" << i << " of " << P << " ..." << ends; Vector<double> b = fBlock[0].copy(); b.zero(); int nVecAdds = 0; for (int j=0; j<Q; j++) { double c_ij0 = pcBasis_.expectation(i,j,0); if (std::fabs(c_ij0) > 0.0) { b = b + c_ij0 * fBlock[j]; nVecAdds++; } if (j>=L) continue; if (!hasNonzeroMatrix[j]) continue; Vector<double> tmp = fBlock[0].copy(); tmp.zero(); bool blockIsNeeded = false; for (int k=0; k<P; k++) { if (j==0 && k==i) continue; double c_ijk = pcBasis_.expectation(i,j,k); if (std::fabs(c_ijk) > 0.0) { tmp = tmp + c_ijk * uPrev[k]; nVecAdds++; blockIsNeeded = true; } } numNonzeroBlocks += blockIsNeeded; b = (b - KBlock[j]*tmp); nVecAdds++; } b = b * (1.0/pcBasis_.expectation(i,i,0)); if (verbosity_) Out::root() << "num vec adds = " << nVecAdds << std::endl; diagonalSolver_.solve(KBlock[0], b, uCur[i]); double err = (uCur[i]-uPrev[i]).norm2(); if (err > convTol_) haveNonConvergedBlock=true; if (err > maxErr) maxErr = err; } /* update solution blocks */ for (int i=0; i<P; i++) uPrev[i] = uCur[i].copy(); /* done all block rows -- check convergence */ if (!haveNonConvergedBlock) { if (verbosity_) Out::root() << "=======> max err=" << maxErr << std::endl; if (verbosity_) Out::root() << "=======> converged! woo-hoo!" << std::endl; if (verbosity_) Out::root() << "estimated storage cost: " << setprecision(3) << 100*((double) L)/((double) numNonzeroBlocks) << " percent of monolithic storage" << std::endl; converged = true; break; } else { if (verbosity_) Out::root() << "maxErr=" << maxErr << ", trying again" << std::endl; } } TEUCHOS_TEST_FOR_EXCEPT(!converged); xBlock = uCur; }