def cgs(a, phi, b, tol, verbose=False, max_iter=-1): # ----------------------------------------------------------------------------- """ Args: a: ...... Object of the type "Matrix", holding the system matrix. phi: .... Object of the type "Unknown" to be solved. b: ...... Three-dimensional array holding the source term. tol: .... Absolute solver tolerance verbose: Logical variable setting if solver will be verbose (print info on Python console) or not. max_iter: Maxiumum number of iterations. Returns: x: Three-dimensional array with solution. """ if verbose is True: write.at(__name__) # Helping variable x = phi.val # Intitilize arrays p = zeros(x.shape) p_hat = Unknown("vec_p_hat", phi.pos, x.shape, -1, per=phi.per, verbose=False) q = zeros(x.shape) r = zeros(x.shape) r_tilda = zeros(x.shape) u = zeros(x.shape) u_hat = Unknown("vec_u_hat", phi.pos, x.shape, -1, per=phi.per, verbose=False) v_hat = zeros(x.shape) # r = b - A * x r[:, :, :] = b[:, :, :] - mat_vec_bnd(a, phi) # Chose r~ r_tilda[:, :, :] = r[:, :, :] # --------------- # Iteration loop # --------------- if max_iter == -1: max_iter = prod(phi.val.shape) for i in range(1, max_iter): if verbose is True: print(" iteration: %3d:" % (i), end="") # rho = r~ * r rho = vec_vec(r_tilda, r) # If rho == 0 method fails if abs(rho) < TINY * TINY: if verbose is True == True: write.at(__name__) print(" Fails becuase rho = %12.5e" % rho) return x if i == 1: # u = r u[:, :, :] = r[:, :, :] # p = u p[:, :, :] = u[:, :, :] else: # beta = rho / rho_old beta = rho / rho_old # u = r + beta q u[:, :, :] = r[:, :, :] + beta * q[:, :, :] # p = u + beta (q + beta p) p[:, :, :] = u[:, :, :] + beta * (q[:, :, :] + beta * p[:, :, :]) # Solve M p_hat = p p_hat.val[:, :, :] = p[:, :, :] / a.C[:, :, :] # v^ = A * p^ v_hat[:, :, :] = mat_vec_bnd(a, p_hat) # alfa = rho / (r~ * v^) alfa = rho / vec_vec(r_tilda, v_hat) # q = u - alfa v^ q[:, :, :] = u[:, :, :] - alfa * v_hat[:, :, :] # Solve M u^ = u + q u_hat.val[:, :, :] = (u[:, :, :] + q[:, :, :]) / a.C[:, :, :] # x = x + alfa u^ x[:, :, :] += alfa * u_hat.val[:, :, :] # q^ = A u^ q_hat = mat_vec_bnd(a, u_hat) # r = r - alfa q^ r[:, :, :] -= alfa * q_hat[:, :, :] # Compute residual res = norm(r) if verbose is True: print("%12.5e" % res) # If tolerance has been reached, get out of here if res < tol: return x # Prepare for next iteration rho_old = rho return x # end of function
def jacobi(a, phi, b, tol, verbose=False, max_iter=-1): # ----------------------------------------------------------------------------- """ Args: a: ...... Object of the type "Matrix", holding the system matrix. phi: .... Object of the type "Unknown" to be solved. b: ...... Three-dimensional array holding the source term. tol: .... Absolute solver tolerance verbose: Logical variable setting if solver will be verbose (print info on Python console) or not. max_iter: Maxiumum number of iterations. Returns: phi.val: Three-dimensional array with solution. """ if verbose is True: write.at(__name__) sum = zeros(phi.val.shape) r = zeros(phi.val.shape) if max_iter == -1: max_iter = prod(phi.val.shape) # Under-relaxation factor alfa = 0.9 # Main iteration loop for iter in range(0, max_iter): if verbose is True: print(" iteration: %3d:" % (iter), end="") # Add source term sum[:] = b[:] # Add contribution from west and east sum[:1, :, :] += a.W[:1, :, :] * phi.bnd[W].val[:1, :, :] sum[-1:, :, :] += a.E[-1:, :, :] * phi.bnd[E].val[:1, :, :] # Add up west and east neighbors from the inside sum[1:, :, :] += a.W[1:, :, :] * phi.val[:-1, :, :] sum[:-1, :, :] += a.E[:-1, :, :] * phi.val[1:, :, :] # Add contribution from south and north sum[:, :1, :] += a.S[:, :1, :] * phi.bnd[S].val[:, :1, :] sum[:, -1:, :] += a.N[:, -1:, :] * phi.bnd[N].val[:, :1, :] # Add up south and north neighbors from the inside sum[:, 1:, :] += a.S[:, 1:, :] * phi.val[:, :-1, :] sum[:, :-1, :] += a.N[:, :-1, :] * phi.val[:, 1:, :] # Add contribution from bottom and top sum[:, :, :1] += a.B[:, :, :1] * phi.bnd[B].val[:, :, :1] sum[:, :, -1:] += a.T[:, :, -1:] * phi.bnd[T].val[:, :, :1] # Add up south and north neighbors from the inside sum[:, :, 1:] += a.B[:, :, 1:] * phi.val[:, :, :-1] sum[:, :, :-1] += a.T[:, :, :-1] * phi.val[:, :, 1:] phi.val[:,:,:] = (1.0 - alfa) * phi.val[:,:,:] \ + alfa * sum[:,:,:] / a.C[:,:,:] phi.exchange() # r = b - A * x r[:, :, :] = b[:, :, :] - mat_vec_bnd(a, phi) # Compute residual res = norm(r) if verbose is True: print("%12.5e" % res) # If tolerance has been reached, get out of here if res < tol: return phi.val return phi.val # end of function
def bicgstab(a, phi, b, tol, ver): # ----------------------------------------------------------------------------- """ Args: a: System matrix in PyNS format (which ssentially means storing a bundle of non-zero diagonals in compas directions) phi: Unknown to be solved (from "create_unknown" function) b: Three-dimensional matrix holding the source term. tol: Absolute solver tolerance ver: Logical variable setting if solver will be verbatim (print info on Python console) or not. Returns: x: Three-dimensional matrix with solution. Note: One should also consider implementing periodic boundary conditions in this version of the solver. """ if ver: print("Solver: BiCGStab") # Helping variables x = phi.val n = prod(x.shape) # Intitilize arrays p = zeros(x.shape) p_hat = zeros(x.shape) r = zeros(x.shape) r_tilda = zeros(x.shape) s = zeros(x.shape) s_hat = zeros(x.shape) v = zeros(x.shape) # r = b - A * x r[:,:,:] = b[:,:,:] - mat_vec_bnd(a, phi) # Chose r~ r_tilda[:,:,:] = r[:,:,:] # --------------- # Iteration loop # --------------- for i in range(1,n): if ver: print(" iteration: %3d:" % (i), end = "" ) # rho = r~ * r rho = vec_vec(r_tilda, r) # If rho == 0 method fails if abs(rho) < TINY * TINY: print("bicgstab fails becuase rho = %12.5e" % rho) return x if i == 1: # p = r p[:,:,:] = r[:,:,:] else: # beta = (rho / rho_old)(alfa/omega) beta = rho / rho_old * alfa / omega # p = r + beta (p - omega v) p[:,:,:] = r[:,:,:] + beta * (p[:,:,:] - omega * v[:,:,:]) # Solve M p_hat = p p_hat[:,:,:] = p[:,:,:] / a.P[:,:,:] # v = A * p^ v[:,:,:] = mat_vec(a, p_hat) # alfa = rho / (r~ * v) alfa = rho / vec_vec(r_tilda, v) # s = r - alfa v s[:,:,:] = r[:,:,:] - alfa * v[:,:,:] # Check norm of s, if small enough set x = x + alfa p_hat and stop res = norm(s) if res < tol: if ver: print("%12.5e" %res) x[:,:,:] += alfa * p_hat[:,:,:] return x # Solve M s^ = s s_hat[:,:,:] = s[:,:,:] / a.P[:,:,:] # t = A s^ t = mat_vec(a, s_hat) # omega = (t * s) / (t * t) omega = vec_vec(t, s) / vec_vec(t, t) # x = x + alfa p^ + omega * s^ x[:,:,:] += alfa * p_hat[:,:,:] + omega * s_hat[:,:,:] # r = s - omega q^ r[:,:,:] = s[:,:,:] - omega * t[:,:,:] # Compute residual res = norm(r) if ver: print("%12.5e" %res) # If tolerance has been reached, get out of here if res < tol: return x # Prepare for next iteration rho_old = rho return x # end of function
def cgs(a, phi, b, tol, ver): # ----------------------------------------------------------------------------- """ Args: a: System matrix in PyNS format (which ssentially means storing a bundle of non-zero diagonals in compas directions) phi: Unknown to be solved (from "create_unknown" function) b: Three-dimensional matrix holding the source term. tol: Absolute solver tolerance ver: Logical variable setting if solver will be verbatim (print info on Python console) or not. Returns: x: Three-dimensional matrix with solution. Note: One should also consider implementing periodic boundary conditions in this version of the solver. """ if ver: print("Solver: CGS") # Helping variables x = phi.val n = prod(x.shape) # Intitilize arrays p = zeros(x.shape) p_hat = zeros(x.shape) q = zeros(x.shape) r = zeros(x.shape) r_tilda = zeros(x.shape) u = zeros(x.shape) u_hat = zeros(x.shape) v_hat = zeros(x.shape) # r = b - A * x r[:, :, :] = b[:, :, :] - mat_vec_bnd(a, phi) # Chose r~ r_tilda[:, :, :] = r[:, :, :] # --------------- # Iteration loop # --------------- for i in range(1, n): if ver: print(" iteration: %3d:" % (i), end="") # rho = r~ * r rho = vec_vec(r_tilda, r) # If rho == 0 method fails if abs(rho) < TINY * TINY: print("cgs fails becuase rho = %12.5e" % rho) return x if i == 1: # u = r u[:, :, :] = r[:, :, :] # p = u p[:, :, :] = u[:, :, :] else: # beta = rho / rho_old beta = rho / rho_old # u = r + beta q u[:, :, :] = r[:, :, :] + beta * q[:, :, :] # p = u + beta (q + beta p) p[:, :, :] = u[:, :, :] + beta * (q[:, :, :] + beta * p[:, :, :]) # Solve M p_hat = p p_hat[:, :, :] = p[:, :, :] / a.P[:, :, :] # v^ = A * p^ v_hat[:, :, :] = mat_vec(a, p_hat) # alfa = rho / (r~ * v^) alfa = rho / vec_vec(r_tilda, v_hat) # q = u - alfa v^ q[:, :, :] = u[:, :, :] - alfa * v_hat[:, :, :] # Solve M u^ = u + q u_hat[:, :, :] = (u[:, :, :] + q[:, :, :]) / a.P[:, :, :] # x = x + alfa u^ x[:, :, :] += alfa * u_hat[:, :, :] # q^ = A u^ q_hat = mat_vec(a, u_hat) # r = r - alfa q^ r[:, :, :] -= alfa * q_hat[:, :, :] # Compute residual res = norm(r) if ver: print("%12.5e" % res) # If tolerance has been reached, get out of here if res < tol: return x # Prepare for next iteration rho_old = rho return x # end of function
def bicgstab(a, phi, b, tol, verbose=False, max_iter=-1): # ----------------------------------------------------------------------------- """ Args: a: ...... Object of the type "Matrix", holding the system matrix. phi: .... Object of the type "Unknown" to be solved. b: ...... Three-dimensional array holding the source term. tol: .... Absolute solver tolerance verbose: Logical variable setting if solver will be verbose (print info on Python console) or not. max_iter: Maxiumum number of iterations. Returns: x: Three-dimensional array with solution. """ if verbose is True: write.at(__name__) # Helping variable x = phi.val # Intitilize arrays p = zeros(x.shape) p_hat = Unknown("vec_p_hat", phi.pos, x.shape, -1, per=phi.per, verbose=False) r = zeros(x.shape) r_tilda = zeros(x.shape) s = zeros(x.shape) s_hat = Unknown("vec_s_hat", phi.pos, x.shape, -1, per=phi.per, verbose=False) v = zeros(x.shape) # r = b - A * x r[:, :, :] = b[:, :, :] - mat_vec_bnd(a, phi) # Chose r~ r_tilda[:, :, :] = r[:, :, :] # --------------- # Iteration loop # --------------- if max_iter == -1: max_iter = prod(phi.val.shape) for i in range(1, max_iter): if verbose is True: print(" iteration: %3d:" % (i), end="") # rho = r~ * r rho = vec_vec(r_tilda, r) # If rho == 0 method fails if abs(rho) < TINY * TINY: write.at(__name__) print(" Fails becuase rho = %12.5e" % rho) return x if i == 1: # p = r p[:, :, :] = r[:, :, :] else: # beta = (rho / rho_old)(alfa/omega) beta = rho / rho_old * alfa / omega # p = r + beta (p - omega v) p[:, :, :] = r[:, :, :] + beta * (p[:, :, :] - omega * v[:, :, :]) # Solve M p_hat = p p_hat.val[:, :, :] = p[:, :, :] / a.C[:, :, :] # v = A * p^ v[:, :, :] = mat_vec_bnd(a, p_hat) # alfa = rho / (r~ * v) alfa = rho / vec_vec(r_tilda, v) # s = r - alfa v s[:, :, :] = r[:, :, :] - alfa * v[:, :, :] # Check norm of s, if small enough set x = x + alfa p_hat and stop res = norm(s) if res < tol: if verbose is True == True: write.at(__name__) print(" Fails becuase rho = %12.5e" % rho) x[:, :, :] += alfa * p_hat.val[:, :, :] return x # Solve M s^ = s s_hat.val[:, :, :] = s[:, :, :] / a.C[:, :, :] # t = A s^ t = mat_vec_bnd(a, s_hat) # omega = (t * s) / (t * t) omega = vec_vec(t, s) / vec_vec(t, t) # x = x + alfa p^ + omega * s^ x[:, :, :] += alfa * p_hat.val[:, :, :] + omega * s_hat.val[:, :, :] # r = s - omega q^ r[:, :, :] = s[:, :, :] - omega * t[:, :, :] # Compute residual res = norm(r) if verbose is True: print("%12.5e" % res) # If tolerance has been reached, get out of here if res < tol: return x # Prepare for next iteration rho_old = rho return x # end of function
def cg(a, phi, b, tol, ver): # ----------------------------------------------------------------------------- """ Args: a: System matrix in PyNS format (which ssentially means storing a bundle of non-zero diagonals in compas directions) phi: Unknown to be solved (from "create_unknown" function) b: Three-dimensional matrix holding the source term. tol: Absolute solver tolerance ver: Logical variable setting if solver will be verbatim (print info on Python console) or not. Returns: x: Three-dimensional matrix with solution. Note: One should also consider implementing periodic boundary conditions in this version of the solver. """ if ver: print("Solver: CG") # Helping variables x = phi.val n = prod(x.shape) # Intitilize arrays p = zeros(x.shape) q = zeros(x.shape) r = zeros(x.shape) z = zeros(x.shape) # r = b - A * x r[:, :, :] = b[:, :, :] - mat_vec_bnd(a, phi) # --------------- # Iteration loop # --------------- for i in range(1, n): if ver: print(" iteration: %3d:" % (i), end="") # Solve M z = r z[:, :, :] = r[:, :, :] / a.P[:, :, :] # rho = r * z rho = vec_vec(r, z) if i == 1: # p = z p[:, :, :] = z[:, :, :] else: # beta = rho / rho_old beta = rho / rho_old # p = z + beta p p[:, :, :] = z[:, :, :] + beta * p[:, :, :] # q = A * p q[:, :, :] = mat_vec(a, p) # alfa = rho / (p * q) alfa = rho / vec_vec(p, q) # x = x + alfa p x[:, :, :] += alfa * p[:, :, :] # r = r - alfa q r[:, :, :] -= alfa * q[:, :, :] # Compute residual res = norm(r) if ver: print("%12.5e" % res) # If tolerance has been reached, get out of here if res < tol: return x # Prepare for next iteration rho_old = rho return x # end of function
def gamg_v_cycle(a, phi, b, tol, verbose=False, max_cycles=8, max_smooth=4): # ----------------------------------------------------------------------------- """ Args: a: ..... Object of the type "Matrix", holding the system matrix. phi: ... Object of the type "Unknown" to be solved. b: ..... Three-dimensional array holding the source term. tol: ... Absolute solver tolerance verbose: Logical variable setting if solver will be verbose (print info on Python console) or not. Returns: x: Three-dimensional array with solution. """ if verbose is True: write.at(__name__) # ------------------ # # Get system levels # # ------------------ n_, shape_, a_, i_, d_, phi_, b_, r_ = gamg_coarsen_system(a, phi, b) # Set a couple of parameters for the solver n_steps = n_ - 1 # number of steps down the "V" cycle # ----------------------------------------------------- # # Solve a bit on the finest level and compute residual # # ----------------------------------------------------- grid = 0 # finest level phi_[grid].val = jacobi(a_[grid], phi_[grid], b_[grid], TOL, verbose=True, max_iter=4) # r = b - A * x r_[grid].val[:] = b_[grid][:] - mat_vec_bnd(a_[grid], phi_[grid]) if verbose is True: print(" residual at level %d" % grid, norm(r_[grid].val)) # ========================================================================= # # Start the V-cycle # # ========================================================================= for cycle in range(0, max_cycles): if verbose is True: write.cycle(cycle) # -------------------- # # Go down a few steps # # -------------------- for level in range(1, n_steps + 1): grid = grid + 1 # Compute ratio between grid levels rx = shape_[grid - 1][X] // shape_[grid][X] ry = shape_[grid - 1][Y] // shape_[grid][Y] rz = shape_[grid - 1][Z] // shape_[grid][Z] # Lower bounds for browsing through grid levels wl = 0 el = 1 sl = 0 nl = 1 bl = 0 tl = 1 if rx < 2: el = 0 if ry < 2: nl = 0 if rz < 2: tl = 0 # ------------------------------------- # Restrict # # Computes r.h.s. on the coarser level # from residual on the finer level. # ------------------------------------- b_[grid][:] = r_[grid - 1].val[wl::rx, sl::ry, bl::rz] b_[grid][:] += r_[grid - 1].val[wl::rx, nl::ry, bl::rz] b_[grid][:] += r_[grid - 1].val[wl::rx, sl::ry, tl::rz] b_[grid][:] += r_[grid - 1].val[wl::rx, nl::ry, tl::rz] b_[grid][:] += r_[grid - 1].val[el::rx, sl::ry, bl::rz] b_[grid][:] += r_[grid - 1].val[el::rx, nl::ry, bl::rz] b_[grid][:] += r_[grid - 1].val[el::rx, sl::ry, tl::rz] b_[grid][:] += r_[grid - 1].val[el::rx, nl::ry, tl::rz] b_[grid][:] = b_[grid][:] / ((3 - rx) * (3 - ry) * (3 - rz)) # ------------------------------------------------ # Solve on the coarser level and compute residual # ------------------------------------------------ phi_[grid].val[:] = 0 # nulify to forget previous corrections phi_[grid].val = jacobi(a_[grid], phi_[grid], b_[grid], TOL, verbose=False, max_iter=max_smooth) # r = b - A * x r_[grid].val[:] = b_[grid][:] - mat_vec_bnd(a_[grid], phi_[grid]) if verbose is True: print(" residual at level %d" % grid, norm(r_[grid].val)) # ================================== # # This is the bottom of the V-cycle # # ================================== # ------------------ # # Go up a few steps # # ------------------ for level in range(1, n_steps + 1): grid = grid - 1 # Compute ratio between grid levels rx = shape_[grid][X] // shape_[grid + 1][X] ry = shape_[grid][Y] // shape_[grid + 1][Y] rz = shape_[grid][Z] // shape_[grid + 1][Z] # Lower bounds for browsing through grid levels wl = 0 el = 1 sl = 0 nl = 1 bl = 0 tl = 1 if rx < 2: el = 0 if ry < 2: nl = 0 if rz < 2: tl = 0 # ------------------------------------------- # Prolongation # # Interpolates the solution from the coarser # level as the correction to the current. # It also smoooths it out a little bit. # ------------------------------------------- r_[grid].val[:] = 0 # First copy in each available cell on fine level r_[grid].val[wl::rx, sl::ry, bl::rz] = phi_[grid + 1].val[:] # Then spread arond r_[grid].val[el::rx, sl::ry, bl::rz] = r_[grid].val[wl::rx, sl::ry, bl::rz] r_[grid].val[wl::rx, nl::ry, bl::rz] = r_[grid].val[wl::rx, sl::ry, bl::rz] r_[grid].val[el::rx, nl::ry, bl::rz] = r_[grid].val[wl::rx, sl::ry, bl::rz] r_[grid].val[wl::rx, sl::ry, tl::rz] = r_[grid].val[wl::rx, sl::ry, bl::rz] r_[grid].val[el::rx, sl::ry, tl::rz] = r_[grid].val[wl::rx, sl::ry, bl::rz] r_[grid].val[wl::rx, nl::ry, tl::rz] = r_[grid].val[wl::rx, sl::ry, bl::rz] r_[grid].val[el::rx, nl::ry, tl::rz] = r_[grid].val[wl::rx, sl::ry, bl::rz] # Then smooth them out a little bit for smooth in range(0, max_smooth): r_[grid].exchange() summ = zeros((shape_[grid])) summ[:] += cat_x((r_[grid].bnd[W].val, r_[grid].val[:-1, :, :])) * a_[grid].W summ[:] += cat_x( (r_[grid].val[1:, :, :], r_[grid].bnd[E].val)) * a_[grid].E summ[:] += cat_y((r_[grid].bnd[S].val, r_[grid].val[:, :-1, :])) * a_[grid].S summ[:] += cat_y( (r_[grid].val[:, 1:, :], r_[grid].bnd[N].val)) * a_[grid].N summ[:] += cat_z((r_[grid].bnd[B].val, r_[grid].val[:, :, :-1])) * a_[grid].B summ[:] += cat_z( (r_[grid].val[:, :, 1:], r_[grid].bnd[T].val)) * a_[grid].T r_[grid].val[:] = summ[:] / d_[grid][:] # ----------------------------------------------- # Correction on the finer level, followed by a # bit of smoothing and computation of residuals. # ----------------------------------------------- phi_[grid].val[:] += r_[grid].val[:] phi_[grid].val = jacobi(a_[grid], phi_[grid], b_[grid], TOL, verbose=False, max_iter=max_smooth) # r = b - A * x r_[grid].val[:] = b_[grid][:] \ - mat_vec_bnd(a_[grid], phi_[grid]) print(" residual at level %d" % grid, norm(r_[grid].val)) return phi_[0].val # end of function
def cg(a, phi, b, tol, verbose=False, max_iter=-1): # ----------------------------------------------------------------------------- """ Args: a: ...... Object of the type "Matrix", holding the system matrix. phi: .... Object of the type "Unknown" to be solved. b: ...... Three-dimensional array holding the source term. tol: .... Absolute solver tolerance verbose: Logical variable setting if solver will be verbose (print info on Python console) or not. max_iter: Maxiumum number of iterations. Returns: x: Three-dimensional array with solution. """ if verbose is True: write.at(__name__) # Helping variable x = phi.val # Intitilize arrays p = Unknown("vec_p", phi.pos, x.shape, -1, per=phi.per, verbose=False) q = zeros(x.shape) r = zeros(x.shape) z = zeros(x.shape) # r = b - A * x r[:, :, :] = b[:, :, :] - mat_vec_bnd(a, phi) # --------------- # Iteration loop # --------------- if max_iter == -1: max_iter = prod(phi.val.shape) for i in range(1, max_iter): if verbose is True: print(" iteration: %3d:" % (i), end="") # Solve M z = r z[:, :, :] = r[:, :, :] / a.C[:, :, :] # rho = r * z rho = vec_vec(r, z) if i == 1: # p = z p.val[:, :, :] = z[:, :, :] else: # beta = rho / rho_old beta = rho / rho_old # p = z + beta p p.val[:, :, :] = z[:, :, :] + beta * p.val[:, :, :] # q = A * p q[:, :, :] = mat_vec_bnd(a, p) # alfa = rho / (p * q) alfa = rho / vec_vec(p.val, q) # x = x + alfa p x[:, :, :] += alfa * p.val[:, :, :] # r = r - alfa q r[:, :, :] -= alfa * q[:, :, :] # Compute residual res = norm(r) if verbose is True: print("%12.5e" % res) # If tolerance has been reached, get out of here if res < tol: return x # Prepare for next iteration rho_old = rho return x # end of function