def shear_stress(self, velocity): if self.geometric_dimension == 1: return dolf.Constant(4.0 / 3.0) * velocity.dx(0) / self.dolf_constants.Re i, j = ufl.indices(2) shear_stress = ( velocity[i].dx(j) + dolf.Constant(1.0 / 3.0) * self.identity_tensor[i, j] * dolf.div(velocity) ) / self.dolf_constants.Re # shear_stress = ( # velocity[i].dx(j) # + velocity[j].dx(i) # - dolf.Constant(2.0 / 3.0) * self.identity_tensor[i, j] * dolf.div(velocity) # ) / self.dolf_constants.Re return dolf.as_tensor(shear_stress, (i, j))
def strain_rate_tensor(self, u): r"""Define the symmetric strain-rate tensor :param u: The velocity field (2D). :return: The strain rate tensor. """ r = dolfin.SpatialCoordinate(self._mesh)[0] ur = u[0] uz = u[1] ur_r = ur.dx(0) ur_z = ur.dx(1) uz_r = uz.dx(0) uz_z = uz.dx(1) return dolfin.sym( dolfin.as_tensor([[ur_r, 0, 0.5 * (uz_r + ur_z)], [0, ur / r, 0], [0.5 * (uz_r + ur_z), 0, uz_z]]))
def gen3d2(rank2_2d): r""" Generate a 3D 2-tensor from a 2D 2-tensor (add zeros to last dimensions). Returns the synthetic 3D version :math:`A \in \mathbb{R}^{3 \times 3}` of a 2D rank-2 tensor :math:`B \in \mathbb{R}^{2 \times 2}`. The 3D-components are set to zero. .. math:: B &= \begin{pmatrix} b_{xx} & b_{xy} \\ b_{yx} & b_{yy} \end{pmatrix} \\ A &= \begin{pmatrix} b_{xx} & b_{xy} & 0 \\ b_{yx} & b_{yy} & 0 \\ 0 & 0 & 0 \end{pmatrix} Example ------- >>> t2d = df.Expression((("1","2"),("3","4")), degree=1) >>> t3d = gen3d2(t2d) >>> print( ... t3d[0,0]==t2d[0,0] and ... t3d[0,1]==t2d[0,1] and ... t3d[0,2]==0 and ... t3d[1,0]==t2d[1,0] and ... t3d[1,1]==t2d[1,1] and ... t3d[1,2]==0 and ... t3d[2,0]==0 and ... t3d[2,1]==0 and ... t3d[2,2]==0 ... ) True """ return df.as_tensor([[rank2_2d[0, 0], rank2_2d[0, 1], 0], [rank2_2d[1, 0], rank2_2d[1, 1], 0], [0, 0, 0]])
def gen3dTF2(rank2_2d): r""" Generate a 3D tracefree 2-tensor from a 2D 2-tensor. Returns the synthetic 3D version :math:`A \in \mathbb{R}^{3 \times 3}` of a 2D rank-2 tensor :math:`B \in \mathbb{R}^{2 \times 2}`. .. math:: B &= \begin{pmatrix} b_{xx} & b_{xy} \\ b_{yx} & b_{yy} \end{pmatrix} \\ A &= \begin{pmatrix} b_{xx} & b_{xy} & 0 \\ b_{yx} & b_{yy} & 0 \\ 0 & 0 & -(b_{yx}+b_{yy}) \end{pmatrix} Example ------- >>> t2d = df.Expression((("1","2"),("3","4")), degree=1) >>> t3d = gen3dTF2(t2d) >>> print( ... t3d[0,0]==t2d[0,0] and ... t3d[0,1]==t2d[0,1] and ... t3d[0,2]==0 and ... t3d[1,0]==t2d[1,0] and ... t3d[1,1]==t2d[1,1] and ... t3d[1,2]==0 and ... t3d[2,0]==0 and ... t3d[2,1]==0 and ... t3d[2,2]==-t2d[0,0]-t2d[1,1] ... ) True """ return df.as_tensor([[rank2_2d[0, 0], rank2_2d[0, 1], 0], [rank2_2d[1, 0], rank2_2d[1, 1], 0], [0, 0, -rank2_2d[0, 0] - rank2_2d[1, 1]]])
def _spatial_component(self, trial, test): pressure, velocity, temperature = trial test_pressure, test_velocity, test_temperature = test i, j = ufl.indices(2) if self.geometric_dimension == 1: continuity_component = test_pressure * velocity.dx(0) momentum_component = test_velocity.dx(0) * self.stress(pressure, velocity) else: continuity_component = test_pressure * dolf.div(velocity) momentum_component = dolf.inner( dolf.as_tensor(test_velocity[i].dx(j), (i, j)), self.stress(pressure, velocity), ) energy_component = dolf.inner( dolf.grad(test_temperature), self.heat_flux(temperature) ) return continuity_component + momentum_component + energy_component
def define_coupled_equation(self): """ Setup the coupled Navier-Stokes equation This implementation assembles the full LHS and RHS each time they are needed """ sim = self.simulation mpm = sim.multi_phase_model mesh = sim.data['mesh'] Vcoupled = sim.data['Vcoupled'] u_conv = sim.data['u_conv'] # Unpack the coupled trial and test functions uc = dolfin.TrialFunction(Vcoupled) vc = dolfin.TestFunction(Vcoupled) ulist = [] vlist = [] sigmas, taus = [], [] for d in range(sim.ndim): ulist.append(uc[d]) vlist.append(vc[d]) indices = list( range(1 + sim.ndim * (d + 1), 1 + sim.ndim * (d + 2))) sigmas.append([uc[i] for i in indices]) taus.append([vc[i] for i in indices]) u = dolfin.as_vector(ulist) v = dolfin.as_vector(vlist) p = uc[sim.ndim] q = vc[sim.ndim] sigma = dolfin.as_tensor(sigmas) tau = dolfin.as_tensor(taus) c1, c2, c3 = sim.data['time_coeffs'] dt = sim.data['dt'] g = sim.data['g'] n = dolfin.FacetNormal(mesh) h = dolfin.FacetArea(mesh) # Fluid properties rho = mpm.get_density(0) mu = mpm.get_laminar_dynamic_viscosity(0) # Upwind and downwind velocities w_nU = (dot(u_conv, n) + abs(dot(u_conv, n))) / 2.0 w_nD = (dot(u_conv, n) - abs(dot(u_conv, n))) / 2.0 u_uw_s = dolfin.conditional(dolfin.gt(dot(u_conv, n), 0.0), 1.0, 0.0)('+') u_uw = u_uw_s * u('+') + (1 - u_uw_s) * u('-') # LDG penalties # kappa_0 = Constant(4.0) # kappa = mu*kappa_0/h C11 = avg(mu / h) D11 = avg(h / mu) C12 = 0.2 * n('+') D12 = 0.2 * n('+') def ojump(v, n): return outer(v, n)('+') + outer(v, n)('-') # Interior facet fluxes # u_hat_dS = avg(u) # sigma_hat_dS = avg(sigma) - avg(kappa)*ojump(u, n) # p_hat_dS = avg(p) u_hat_s_dS = avg(u) + dot(ojump(u, n), C12) u_hat_p_dS = avg(u) + D11 * jump(p, n) + D12 * jump(u, n) sigma_hat_dS = avg(sigma) - C11 * ojump(u, n) - outer( jump(sigma, n), C12) p_hat_dS = avg(p) - dot(D12, jump(p, n)) # Time derivative up = sim.data['up'] upp = sim.data['upp'] eq = rho * dot(c1 * u + c2 * up + c3 * upp, v) / dt * dx # LDG equation 1 eq += inner(sigma, tau) * dx eq += dot(u, div(mu * tau)) * dx eq -= dot(u_hat_s_dS, jump(mu * tau, n)) * dS # LDG equation 2 eq += (inner(sigma, grad(v)) - p * div(v)) * dx eq -= (inner(sigma_hat_dS, ojump(v, n)) - p_hat_dS * jump(v, n)) * dS eq -= dot(u, div(outer(v, rho * u_conv))) * dx eq += rho('+') * dot(u_conv('+'), n('+')) * dot(u_uw, v('+')) * dS eq += rho('-') * dot(u_conv('-'), n('-')) * dot(u_uw, v('-')) * dS momentum_sources = sim.data['momentum_sources'] + [rho * g] eq -= dot(sum(momentum_sources), v) * dx # LDG equation 3 eq -= dot(u, grad(q)) * dx eq += dot(u_hat_p_dS, jump(q, n)) * dS # Dirichlet boundary dirichlet_bcs = get_collected_velocity_bcs(sim, 'dirichlet_bcs') for ds, u_bc in dirichlet_bcs.items(): # sigma_hat_ds = sigma - kappa*outer(u, n) sigma_hat_ds = sigma - C11 * outer(u - u_bc, n) u_hat_ds = u_bc p_hat_ds = p # LDG equation 1 eq -= dot(u_hat_ds, dot(mu * tau, n)) * ds # LDG equation 2 eq -= (inner(sigma_hat_ds, outer(v, n)) - p_hat_ds * dot(v, n)) * ds eq += rho * w_nU * dot(u, v) * ds eq += rho * w_nD * dot(u_bc, v) * ds # LDG equation 3 eq += dot(u_hat_ds, q * n) * ds # Neumann boundary neumann_bcs = get_collected_velocity_bcs(sim, 'neumann_bcs') assert not neumann_bcs for ds, du_bc in neumann_bcs.items(): # Divergence free criterion if self.use_grad_q_form: eq += q * dot(u, n) * ds else: eq -= q * dot(u, n) * ds # Convection eq += rho * w_nU * dot(u, v) * ds # Diffusion u_hat_ds = u sigma_hat_ds = outer(du_bc, n) / mu eq -= dot(u_hat_ds, dot(mu * tau, n)) * ds eq -= inner(sigma_hat_ds, outer(v, n)) * ds # Pressure if not self.use_grad_p_form: eq += p * dot(v, n) * ds a, L = dolfin.system(eq) self.form_lhs = a self.form_rhs = L self.tensor_lhs = None self.tensor_rhs = None
def solve(mesh, Eps, degree): V = FunctionSpace(mesh, "CG", degree) u = TrialFunction(V) v = TestFunction(V) n = FacetNormal(mesh) gdim = mesh.geometry().dim() A = [ _assemble_eigen( Constant(Eps[i, j]) * (u.dx(i) * v.dx(j) * dx - u.dx(i) * n[j] * v * ds) ).sparray() for j in range(gdim) for i in range(gdim) ] assert_equality = False if assert_equality: # The sum of the `A`s is exactly that: n = FacetNormal(V.mesh()) AA = _assemble_eigen( +dot(dot(as_tensor(Eps), grad(u)), grad(v)) * dx - dot(dot(as_tensor(Eps), grad(u)), n) * v * ds ).sparray() diff = AA - sum(A) assert numpy.all(abs(diff.data) < 1.0e-14) # # ATAsum = sum(a.T.dot(a) for a in A) # diff = AA.T.dot(AA) - ATAsum # # import betterspy # # betterspy.show(ATAsum) # # betterspy.show(AA.T.dot(AA)) # # betterspy.show(ATAsum - AA.T.dot(AA)) # print(diff.data) # assert numpy.all(abs(diff.data) < 1.0e-14) tol = 1.0e-10 def lower(x, on_boundary): return on_boundary and x[1] < -1.0 + tol def upper(x, on_boundary): return on_boundary and x[1] > 1.0 - tol def left(x, on_boundary): return on_boundary and abs(x[0] + 1.0) < tol def right(x, on_boundary): return on_boundary and abs(x[0] - 1.0) < tol def upper_left(x, on_boundary): return on_boundary and x[1] > +1.0 - tol and x[0] < -0.8 def lower_right(x, on_boundary): return on_boundary and x[1] < -1.0 + tol and x[0] > 0.8 bcs = [ # DirichletBC(V, Constant(0.0), lower_right), # DirichletBC(V, Constant(0.0), upper_left), DirichletBC(V, Constant(0.0), lower), DirichletBC(V, Constant(0.0), upper), # DirichletBC(V, Constant(0.0), upper_left, method='pointwise'), # DirichletBC(V, Constant(0.0), lower_left, method='pointwise'), # DirichletBC(V, Constant(0.0), lower_right, method='pointwise'), ] M = _assemble_eigen(u * v * dx).sparray() ATMinvAsum = sum( numpy.dot(a.toarray().T, numpy.linalg.solve(M.toarray(), a.toarray())) for a in A ) AA2 = _assemble_eigen( +dot(dot(as_tensor(Eps), grad(u)), grad(v)) * dx - dot(dot(as_tensor(Eps), grad(u)), n) * v * ds, # bcs=[DirichletBC(V, Constant(0.0), 'on_boundary')] # bcs=bcs # bcs=[ # DirichletBC(V, Constant(0.0), lower), # DirichletBC(V, Constant(0.0), right), # ] ).sparray() ATA2 = numpy.dot(AA2.toarray().T, numpy.linalg.solve(M.toarray(), AA2.toarray())) # Find combination of Dirichlet points: if False: # min_val = 1.0 max_val = 0.0 # min_combi = [] max_combi = [] is_updated = False it = 0 # get boundary indices d = DirichletBC(V, Constant(0.0), "on_boundary") boundary_idx = numpy.sort(list(d.get_boundary_values().keys())) # boundary_idx = numpy.arange(V.dim()) # print(boundary_idx) # pick some at random # idx = numpy.sort(numpy.random.choice(boundary_idx, size=3, replace=False)) for idx in itertools.combinations(boundary_idx, 3): it += 1 print() print(it) # Replace the rows corresponding to test functions living in one cell # (deliberately chosen as 0) by Dirichlet rows. AA3 = AA2.tolil() for k in idx: AA3[k] = 0 AA3[k, k] = 1 n = AA3.shape[0] AA3 = AA3.tocsr() ATA2 = numpy.dot( AA3.toarray().T, numpy.linalg.solve(M.toarray(), AA3.toarray()) ) vals = numpy.sort(numpy.linalg.eigvalsh(ATA2)) if vals[0] < 0.0: continue # op = sparse.linalg.LinearOperator( # (n, n), # matvec=lambda x: _spsolve(AA3, M.dot(_spsolve(AA3.T.tocsr(), x))) # ) # vals, _ = scipy.sparse.linalg.eigsh(op, k=3, which='LM') # vals = numpy.sort(1/vals[::-1]) # print(vals) print(idx) # if min_val > vals[0]: # min_val = vals[0] # min_combi = idx # is_updated = True if max_val < vals[0]: max_val = vals[0] max_combi = idx is_updated = True if is_updated: # vals, _ = scipy.sparse.linalg.eigsh(op, k=10, which='LM') # vals = numpy.sort(1/vals[::-1]) # print(vals) is_updated = False # print(min_val, min_combi) print(max_val, max_combi) # plt.plot(dofs_x[:, 0], dofs_x[:, 1], 'x') meshzoo.plot2d(mesh.coordinates(), mesh.cells()) dofs_x = V.tabulate_dof_coordinates().reshape((-1, gdim)) # plt.plot(dofs_x[min_combi, 0], dofs_x[min_combi, 1], 'or') plt.plot(dofs_x[max_combi, 0], dofs_x[max_combi, 1], "ob") plt.gca().set_aspect("equal") plt.title(f"smallest eigenvalue: {max_val}") plt.show() # # if True: # if abs(vals[0]) < 1.0e-8: # gdim = mesh.geometry().dim() # # plt.plot(dofs_x[:, 0], dofs_x[:, 1], 'x') # X = mesh.coordinates() # meshzoo.plot2d(mesh.coordinates(), mesh.cells()) # dofs_x = V.tabulate_dof_coordinates().reshape((-1, gdim)) # plt.plot(dofs_x[idx, 0], dofs_x[idx, 1], 'or') # plt.gca().set_aspect('equal') # plt.show() meshzoo.plot2d(mesh.coordinates(), mesh.cells()) dofs_x = V.tabulate_dof_coordinates().reshape((-1, gdim)) # plt.plot(dofs_x[min_combi, 0], dofs_x[min_combi, 1], 'or') plt.plot(dofs_x[max_combi, 0], dofs_x[max_combi, 1], "ob") plt.gca().set_aspect("equal") plt.title(f"final smallest eigenvalue: {max_val}") plt.show() exit(1) # Eigenvalues of the operators if True: # import betterspy # betterspy.show(sum(A), colormap="viridis") AA = _assemble_eigen( +dot(grad(u), grad(v)) * dx - dot(grad(u), n) * v * ds ).sparray() eigvals, eigvecs = scipy.sparse.linalg.eigs(AA, k=5, which="SM") assert numpy.all(numpy.abs(eigvals.imag) < 1.0e-12) eigvals = eigvals.real assert numpy.all(numpy.abs(eigvecs.imag) < 1.0e-12) eigvecs = eigvecs.real i = numpy.argsort(eigvals) print(eigvals[i]) import meshio for k in range(3): meshio.write_points_cells( f"eigval{k}.vtk", points, {"triangle": cells}, point_data={"ev": eigvecs[:, i][:, k]}, ) exit(1) # import betterspy # betterspy.show(AA, colormap="viridis") # print(numpy.sort(numpy.linalg.eigvals(AA.todense()))) exit(1) Asum = sum(A).todense() AsumT_Minv_Asum = numpy.dot(Asum.T, numpy.linalg.solve(M.toarray(), Asum)) # print(numpy.sort(numpy.linalg.eigvalsh(Asum))) print(numpy.sort(numpy.linalg.eigvalsh(AsumT_Minv_Asum))) exit(1) # eigvals, eigvecs = numpy.linalg.eigh(Asum) # i = numpy.argsort(eigvals) # print(eigvals[i]) # exit(1) # print(eigvals[:20]) # eigvals[eigvals < 1.0e-15] = 1.0e-15 # # eigvals = numpy.sort(numpy.linalg.eigvalsh(sum(A).todense())) # print(eigvals[:20]) # plt.semilogy(eigvals, ".", label="Asum") # plt.legend() # plt.grid() # plt.show() # exit(1) ATMinvAsum_eigs = numpy.sort(numpy.linalg.eigvalsh(ATMinvAsum)) print(ATMinvAsum_eigs[:20]) ATMinvAsum_eigs[ATMinvAsum_eigs < 0.0] = 1.0e-12 # ATA2_eigs = numpy.sort(numpy.linalg.eigvalsh(ATA2)) # print(ATA2_eigs[:20]) plt.semilogy(ATMinvAsum_eigs, ".", label="ATMinvAsum") # plt.semilogy(ATA2_eigs, ".", label="ATA2") plt.legend() plt.grid() plt.show() # # Preconditioned eigenvalues # # IATA_eigs = numpy.sort(scipy.linalg.eigvalsh(ATMinvAsum, ATA2)) # # plt.semilogy(IATA_eigs, ".", label="precond eigenvalues") # # plt.legend() # # plt.show() exit(1) # # Test with A only # numpy.random.seed(123) # b = numpy.random.rand(sum(a.shape[0] for a in A)) # MTM = M.T.dot(M) # MTb = M.T.dot(b) # sol = _gmres( # MTM, # # TODO linear operator # # lambda x: M.T.dot(M.dot(x)), # MTb, # M=prec # ) # plt.semilogy(sol.resnorms) # plt.show() # exit(1) n = AA2.shape[0] # define the operator def matvec(x): # M^{-1} can be computed in O(n) with CG + diagonal preconditioning # or algebraic multigrid. # return sum([a.T.dot(a.dot(x)) for a in A]) return numpy.sum([a.T.dot(_spsolve(M, a.dot(x))) for a in A], axis=0) op = sparse.linalg.LinearOperator((n, n), matvec=matvec) # pick a random solution and a consistent rhs x = numpy.random.rand(n) b = op.dot(x) linear_system = krypy.linsys.LinearSystem(op, b) print("unpreconditioned solve...") t = time.time() out = krypy.linsys.Gmres(linear_system, tol=1.0e-12, explicit_residual=True) out.xk = out.xk.reshape(b.shape) print("done.") print(" res: {}".format(out.resnorms[-1])) print( " unprec res: {}".format( numpy.linalg.norm(b - op.dot(out.xk)) / numpy.linalg.norm(b) ) ) # The error isn't useful here; only with the nullspace removed # print(' error: {}'.format(numpy.linalg.norm(out.xk - x))) print(" its: {}".format(len(out.resnorms))) print(" duration: {}s".format(time.time() - t)) # preconditioned solver ml = pyamg.smoothed_aggregation_solver(AA2) # res = [] # b = numpy.random.rand(AA2.shape[0]) # x0 = numpy.zeros(AA2.shape[1]) # x = ml.solve(b, x0, residuals=res, tol=1.0e-12) # print(res) # plt.semilogy(res) # plt.show() mlT = pyamg.smoothed_aggregation_solver(AA2.T.tocsr()) # res = [] # b = numpy.random.rand(AA2.shape[0]) # x0 = numpy.zeros(AA2.shape[1]) # x = mlT.solve(b, x0, residuals=res, tol=1.0e-12) # print(res) def prec_matvec(b): x0 = numpy.zeros(n) b1 = mlT.solve(b, x0, tol=1.0e-12) b2 = M.dot(b1) x = ml.solve(b2, x0, tol=1.0e-12) return x prec = LinearOperator((n, n), matvec=prec_matvec) # TODO assert this in a test # x = prec_matvec(b) # print(b - AA2.T.dot(AA2.dot(x))) linear_system = krypy.linsys.LinearSystem(op, b, Ml=prec) print() print("preconditioned solve...") t = time.time() try: out_prec = krypy.linsys.Gmres( linear_system, tol=1.0e-14, maxiter=1000, explicit_residual=True ) except krypy.utils.ConvergenceError: print("prec not converged!") pass out_prec.xk = out_prec.xk.reshape(b.shape) print("done.") print(" res: {}".format(out_prec.resnorms[-1])) print( " unprec res: {}".format( numpy.linalg.norm(b - op.dot(out_prec.xk)) / numpy.linalg.norm(b) ) ) print(" its: {}".format(len(out_prec.resnorms))) print(" duration: {}s".format(time.time() - t)) plt.semilogy(out.resnorms, label="original") plt.semilogy(out_prec.resnorms, label="preconditioned") plt.legend() plt.show() return out.xk
def grad3dOf2(rank2_3d): r""" Return 3D gradient of 3D 2-tensor. Returns the 3D gradient (w.r.t. :math:`x,y,z`) :math:`\frac{\partial A_{ij}}{\partial x_{k}}` of a 3D :math:`z`-independent rank-2 tensor :math:`A(x,y) \in \mathbb{R}^{3 \times 3}` where .. math:: A_{ij} = \begin{pmatrix} a_{xx}(x,y) & a_{xy}(x,y) & a_{xz}(x,y) \\ a_{yx}(x,y) & a_{yy}(x,y) & a_{yz}(x,y) \\ a_{zx}(x,y) & a_{zy}(x,y) & a_{zz}(x,y) \end{pmatrix} The function then returns the 3-tensor with components :math:`\frac{\partial A_{ij}}{\partial x_{k}}` where .. math:: \frac{\partial A_{ij}}{\partial x_{1}} = \frac{\partial A_{ij}}{\partial x} &= \begin{pmatrix} \partial_x a_{xx}(x,y) & \partial_x a_{xy}(x,y) & \partial_x a_{xz}(x,y) \\ \partial_x a_{yx}(x,y) & \partial_x a_{yy}(x,y) & \partial_x a_{yz}(x,y) \\ \partial_x a_{zx}(x,y) & \partial_x a_{zy}(x,y) & \partial_x a_{zz}(x,y) \end{pmatrix} , \\ \frac{\partial A_{ij}}{\partial x_{2}} = \frac{\partial A_{ij}}{\partial y} &= \begin{pmatrix} \partial_y a_{xx}(x,y) & \partial_y a_{xy}(x,y) & \partial_y a_{xz}(x,y) \\ \partial_y a_{yx}(x,y) & \partial_y a_{yy}(x,y) & \partial_y a_{yz}(x,y) \\ \partial_y a_{zx}(x,y) & \partial_y a_{zy}(x,y) & \partial_y a_{zz}(x,y) \end{pmatrix} , \\ \frac{\partial A_{ij}}{\partial x_{3}} = 0 &= \begin{pmatrix} 0 & 0 & 0 \\ 0 & 0 & 0 \\ 0 & 0 & 0 \end{pmatrix} """ grad2d = df.grad(rank2_3d) dim3 = df.as_tensor([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) grad3d = df.as_tensor([grad2d[:, :, 0], grad2d[:, :, 1], dim3[:, :]]) return grad3d
def solve(M, b, mesh, Eps): V = FunctionSpace(mesh, 'CG', 1) u = TrialFunction(V) v = TestFunction(V) n = FacetNormal(mesh) dim = mesh.geometry().dim() A = [ [ _assemble_eigen(+Constant(Eps[i, j]) * u.dx(i) * v.dx(j) * dx # pylint: disable=unsubscriptable-object - Constant(Eps[i, j]) * u.dx(i) * n[j] * v * ds).sparray() for j in range(dim) ] for i in range(dim) ] Aflat = [item for sublist in A for item in sublist] assert_equality = False if assert_equality: # The sum of the `A`s is exactly that: n = FacetNormal(V.mesh()) AA = _assemble_eigen(+dot(dot(as_tensor(Eps), grad(u)), grad(v)) * dx - dot(dot(as_tensor(Eps), grad(u)), n) * v * ds).sparray() diff = AA - sum(Aflat) assert numpy.all(abs(diff.data) < 1.0e-14) # # ATAsum = sum(a.T.dot(a) for a in Aflat) # diff = AA.T.dot(AA) - ATAsum # # import betterspy # # betterspy.show(ATAsum) # # betterspy.show(AA.T.dot(AA)) # # betterspy.show(ATAsum - AA.T.dot(AA)) # print(diff.data) # assert numpy.all(abs(diff.data) < 1.0e-14) tol = 1.0e-13 def lower(x, on_boundary): return on_boundary and abs(x[1] + 1.0) < tol def right(x, on_boundary): return on_boundary and abs(x[0] - 1.0) < tol def upper_left(x, on_boundary): return on_boundary and (abs(x[0] + 1.0) < tol) and (abs(x[1] - 1.0) < tol) def lower_left(x, on_boundary): return on_boundary and (abs(x[0] + 1.0) < tol) and (abs(x[1] + 1.0) < tol) def lower_right(x, on_boundary): return on_boundary and (abs(x[0] - 1.0) < tol) and (abs(x[1] + 1.0) < tol) bcs = [ DirichletBC(V, Constant(0.0), upper_left, method='pointwise'), DirichletBC(V, Constant(0.0), lower_left, method='pointwise'), DirichletBC(V, Constant(0.0), lower_right, method='pointwise'), ] # TODO THIS IS IT AA2 = _assemble_eigen( +dot(dot(as_tensor(Eps), grad(u)), grad(v)) * dx - dot(dot(as_tensor(Eps), grad(u)), n) * v * ds, # bcs=[DirichletBC(V, Constant(0.0), 'on_boundary')] # bcs=bcs bcs=[ DirichletBC(V, Constant(0.0), lower), DirichletBC(V, Constant(0.0), right), ]).sparray() ATA2 = AA2.dot(AA2) # ATAsum = sum(a.T.dot(a) for a in Aflat) # ATAsum_eigs = numpy.sort(numpy.linalg.eigvalsh(ATAsum.todense())) # print(ATAsum_eigs) # print() ATA2_eigs = numpy.sort(numpy.linalg.eigvalsh(ATA2.todense())) print(ATA2_eigs) exit(1) # plt.semilogy(range(len(ATAsum_eigs)), ATAsum_eigs, '.', label='ATAsum') # plt.semilogy(range(len(ATA2_eigs)), ATA2_eigs, '.', label='ATA2') # plt.legend() # plt.show() # # invsqrtATA2 = numpy.linalg.inv(scipy.linalg.sqrtm(ATA2.todense())) # # IATA = numpy.dot(numpy.dot(invsqrtATA2, ATAsum), invsqrtATA2) # # IATA_eigs = numpy.sort(numpy.linalg.eigvals(IATA)) # IATA_eigs = numpy.sort(scipy.linalg.eigvals(ATAsum.todense(), ATA2.todense())) # plt.semilogy(range(len(IATA_eigs)), IATA_eigs, '.', label='IATA') # # plt.plot(IATA_eigs, numpy.zeros(len(IATA_eigs)), 'x', label='IATA') # plt.legend() # plt.show() # # exit(1) # # Test with A only # M = sparse.vstack(Aflat) # numpy.random.seed(123) # b = numpy.random.rand(sum(a.shape[0] for a in Aflat)) # MTM = M.T.dot(M) # MTb = M.T.dot(b) # sol = _gmres( # MTM, # # TODO linear operator # # lambda x: M.T.dot(M.dot(x)), # MTb, # M=prec # ) # plt.semilogy(sol.resnorms) # plt.show() # exit(1) ml = pyamg.smoothed_aggregation_solver(AA2) # res = [] # b = numpy.random.rand(AA2.shape[0]) # x0 = numpy.zeros(AA2.shape[1]) # x = ml.solve(b, x0, residuals=res, tol=1.0e-12) # print(res) # plt.semilogy(res) # plt.show() mlT = pyamg.smoothed_aggregation_solver(AA2.T.tocsr()) # res = [] # b = numpy.random.rand(AA2.shape[0]) # x0 = numpy.zeros(AA2.shape[1]) # x = mlT.solve(b, x0, residuals=res, tol=1.0e-12) # print(res) def prec_matvec(b): n = len(b) x0 = numpy.zeros(n) b1 = mlT.solve(b, x0, tol=1.0e-12) x = ml.solve(b1, x0, tol=1.0e-12) return x n = AA2.shape[0] prec = LinearOperator((n, n), matvec=prec_matvec) # TODO assert this in a test # x = prec_matvec(b) # print(b - AA2.T.dot(AA2.dot(x))) MTM = sparse.linalg.LinearOperator((M.shape[1], M.shape[1]), matvec=lambda x: M.T.dot(M.dot(x))) linear_system = krypy.linsys.LinearSystem(MTM, M.T.dot(b), M=prec) out = krypy.linsys.Gmres(linear_system, tol=1.0e-12) # plt.semilogy(out.resnorms) # plt.show() return out.xk