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 main(show_plot=True, time_steps=12, plot_freq=1): # ============================================================================= # # Define problem # # ============================================================================= xn = nodes(0, 1, 64, 1.0 / 256, 1.0 / 256) yn = nodes(0, 1, 64, 1.0 / 256, 1.0 / 256) zn = nodes(0, 0.1, 5) # Cell dimensions nx, ny, nz, dx, dy, dz, rc, ru, rv, rw = cartesian_grid(xn, yn, zn) # Set physical properties grashof = 1.4105E+06 prandtl = 0.7058 rho = zeros(rc) mu = zeros(rc) kappa = zeros(rc) cap = zeros(rc) rho[:, :, :] = 1.0 mu[:, :, :] = 1.0 / sqrt(grashof) kappa[:, :, :] = 1.0 / (prandtl * sqrt(grashof)) cap[:, :, :] = 1.0 # Time-stepping parameters dt = 2 # time step ndt = time_steps # number of time steps # Create unknowns; names, positions and sizes uf = Unknown("face-u-vel", X, ru, DIRICHLET) vf = Unknown("face-v-vel", Y, rv, DIRICHLET) wf = Unknown("face-w-vel", Z, rw, DIRICHLET) t = Unknown("temperature", C, rc, NEUMANN) p = Unknown("pressure", C, rc, NEUMANN) p_tot = Unknown("total-pressure", C, rc, NEUMANN) # This is a new test t.bnd[W].typ[:] = DIRICHLET t.bnd[W].val[:] = -0.5 t.bnd[E].typ[:] = DIRICHLET t.bnd[E].val[:] = +0.5 for j in (B, T): uf.bnd[j].typ[:] = NEUMANN vf.bnd[j].typ[:] = NEUMANN wf.bnd[j].typ[:] = NEUMANN # ============================================================================= # # Solution algorithm # # ============================================================================= # ---------- # # Time loop # # ---------- for ts in range(1, ndt + 1): write.time_step(ts) # ----------------- # Store old values # ----------------- t.old[:] = t.val[:] uf.old[:] = uf.val[:] vf.old[:] = vf.val[:] wf.old[:] = wf.val[:] # --------------------------- # Start inner iteration loop # --------------------------- # Allocate space for results from previous iteration t_prev = zeros(rc) u_prev = zeros(ru) v_prev = zeros(rv) w_prev = zeros(rw) for inner in range(1, 33): write.iteration(inner) # Store results from previous iteration t_prev[:] = t.val[:] u_prev[:] = uf.val[:] v_prev[:] = vf.val[:] w_prev[:] = wf.val[:] # Temperature (enthalpy) calc_t(t, (uf, vf, wf), (rho * cap), kappa, dt, (dx, dy, dz), advection_scheme="upwind", under_relaxation=0.75) # Momentum conservation ext_f = zeros(ru), avg(Y, t.val), zeros(rw) calc_uvw((uf, vf, wf), (uf, vf, wf), rho, mu, dt, (dx, dy, dz), pressure=p_tot, force=ext_f, advection_scheme="upwind", under_relaxation=0.75) # Pressure calc_p(p, (uf, vf, wf), rho, dt, (dx, dy, dz), verbose=False) p_tot.val += 0.25 * p.val # Velocity correction corr_uvw((uf, vf, wf), p, rho, dt, (dx, dy, dz), verbose=False) # Print differences in results between two iterations t_diff = abs(t.val[:] - t_prev) u_diff = abs(uf.val[:] - u_prev) v_diff = abs(vf.val[:] - v_prev) w_diff = abs(wf.val[:] - w_prev) print("t_diff = ", norm(t_diff)) print("u_diff = ", norm(u_diff)) print("v_diff = ", norm(v_diff)) print("w_diff = ", norm(w_diff)) # -------------------------------------------------- # Check the CFL number at the end of iteration loop # -------------------------------------------------- cfl = cfl_max((uf, vf, wf), dt, (dx, dy, dz)) # ============================================================================= # # Visualisation # # ============================================================================= if show_plot: if ts % plot_freq == 0: plot.isolines(t.val, (uf, vf, wf), (xn, yn, zn), Z) plot.gmv("tdc-staggered-%6.6d" % ts, (xn, yn, zn), (uf, vf, wf, t))
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