def _test_reduced_mesh_elliptic_matrix(V, reduced_mesh): reduced_V = reduced_mesh.get_reduced_function_spaces() dofs = reduced_mesh.get_dofs_list() reduced_dofs = reduced_mesh.get_reduced_dofs_list() u = TrialFunction(V) v = TestFunction(V) trial = 1 test = 0 u_N = TrialFunction(reduced_V[trial]) v_N = TestFunction(reduced_V[test]) A = assemble((u.dx(0) * v + u * v) * dx) A_N = assemble((u_N.dx(0) * v_N + u_N * v_N) * dx) A_dofs = evaluate_and_vectorize_sparse_matrix_at_dofs(A, dofs) A_N_reduced_dofs = evaluate_and_vectorize_sparse_matrix_at_dofs(A_N, reduced_dofs) test_logger.log(DEBUG, "A at dofs:") test_logger.log(DEBUG, str(A_dofs)) test_logger.log(DEBUG, "A_N at reduced dofs:") test_logger.log(DEBUG, str(A_N_reduced_dofs)) test_logger.log(DEBUG, "Error:") test_logger.log(DEBUG, str(A_dofs - A_N_reduced_dofs)) assert isclose(A_dofs, A_N_reduced_dofs).all()
def mpi1d_weak_solution(V: FunctionSpace, f: Function, ft: Function, fx: Function) -> (Function, Function): # Define trial and test functions. v = TrialFunction(V) w = TestFunction(V) # Define weak formulation. A = (v.dx(1) * w.dx(1) + v * w + (fx * v + f * v.dx(1)) * (fx * w + f * w.dx(1))) * dx b = -ft * (fx * w + f * w.dx(1)) * dx # F = (v.dx(1) * w.dx(1) + v * w # + (fx * v + f * v.dx(1) + ft) * (fx * w + f * w.dx(1))) * dx # A = lhs(F) # b = rhs(F) # Compute solution. v = Function(V) solve(A == b, v) # Compute k. k = project(fx * v + f * v.dx(1) + ft, V) return v, k
def cm1dvelocity(img: np.array, vel: np.array, alpha0: float, alpha1: float) -> np.array: """Computes the source for a L2-H1 mass conserving flow for a 1D image sequence and a given velocity. Takes a one-dimensional image sequence and a velocity, and returns a minimiser of the L2-H1 mass conservation functional with spatio-temporal regularisation. Args: img (np.array): A 1D image sequence of shape (m, n), where m is the number of time steps and n is the number of pixels. vel (np.array): A 1D image sequence of shape (m, n). alpha0 (float): The spatial regularisation parameter. alpha1 (float): The temporal regularisation parameter. Returns: k: A source array of shape (m, n). """ # Create mesh. [m, n] = img.shape mesh = UnitSquareMesh(m - 1, n - 1) # Define function space and functions. V = FunctionSpace(mesh, 'CG', 1) k = TrialFunction(V) w = TestFunction(V) # Convert image to function. f = Function(V) f.vector()[:] = dh.img2funvec(img) # Convert velocity to function. v = Function(V) v.vector()[:] = dh.img2funvec(vel) # Define derivatives of data. ft = Function(V) ftv = np.diff(img, axis=0) * (m - 1) ftv = np.concatenate((ftv, ftv[-1, :].reshape(1, n)), axis=0) ft.vector()[:] = dh.img2funvec(ftv) fx = Function(V) fxv = np.gradient(img, 1 / (n - 1), axis=1) fx.vector()[:] = dh.img2funvec(fxv) # Define weak formulation. A = k * w * dx + alpha0 * k.dx(1) * w.dx(1) * dx + alpha1 * k.dx(0) * w.dx( 0) * dx b = (ft + v.dx(1) * f + v * fx) * w * dx # Compute solution. k = Function(V) solve(A == b, k) # Convert back to array. k = dh.funvec2img(k.vector().get_local(), m, n) return k
def fit(x0, y0, mesh, Eps, degree=1, verbose=False, solver='spsolve'): V = FunctionSpace(mesh, 'CG', degree) 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 i in range(dim) for j in range(dim) ] E = _build_eval_matrix(V, x0) M = sparse.vstack(A + [E]) b = numpy.concatenate([numpy.zeros(sum(a.shape[0] for a in A)), y0]) if solver == 'spsolve': MTM = M.T.dot(M) x = sparse.linalg.spsolve(MTM, M.T.dot(b)) elif solver == 'lsqr': x, istop, *_ = sparse.linalg.lsqr( M, b, show=verbose, atol=1.0e-10, btol=1.0e-10, ) assert istop == 2, \ 'sparse.linalg.lsqr not successful (error code {})'.format(istop) elif solver == 'lsmr': x, istop, *_ = sparse.linalg.lsmr( M, b, show=verbose, atol=1.0e-10, btol=1.0e-10, # min(M.shape) is the default maxiter=max(min(M.shape), 10000)) assert istop == 2, \ 'sparse.linalg.lsmr not successful (error code {})'.format(istop) else: assert solver == 'gmres', 'Unknown solver \'{}\'.'.format(solver) A = sparse.linalg.LinearOperator((M.shape[1], M.shape[1]), matvec=lambda x: M.T.dot(M.dot(x))) x, info = sparse.linalg.gmres(A, M.T.dot(b), tol=1.0e-12) assert info == 0, \ 'sparse.linalg.gmres not successful (error code {})'.format(info) u = Function(V) u.vector().set_local(x) return u
def __init__(self, truth_problem, expression_type, basis_generation): self.V = truth_problem.V1 (f0, _) = split(truth_problem._solution) # folder_prefix = os.path.join("test_eim_approximation_14_tempdir", expression_type, basis_generation) assert expression_type in ("Function", "Vector", "Matrix") if expression_type == "Function": # Call Parent constructor EIMApproximation.__init__(self, truth_problem, ParametrizedExpressionFactory(f0), folder_prefix, basis_generation) elif expression_type == "Vector": v = TestFunction(self.V) form = f0[0] * v * dx + f0[1] * v.dx(0) * dx # Call Parent constructor EIMApproximation.__init__(self, truth_problem, ParametrizedTensorFactory(form), folder_prefix, basis_generation) elif expression_type == "Matrix": u = TrialFunction(self.V) v = TestFunction(self.V) form = f0[0] * u * v * dx + f0[1] * u.dx(0) * v * dx # Call Parent constructor EIMApproximation.__init__(self, truth_problem, ParametrizedTensorFactory(form), folder_prefix, basis_generation) else: # impossible to arrive here anyway thanks to the assert raise AssertionError("Invalid expression_type")
def __init__(self, u_, Space, bcs=[], name="div", method={}): solver_type = method.get('solver_type', 'cg') preconditioner_type = method.get('preconditioner_type', 'default') solver_method = method.get('method', 'default') low_memory_version = method.get('low_memory_version', False) OasisFunction.__init__(self, div(u_), Space, bcs=bcs, name=name, method=solver_method, solver_type=solver_type, preconditioner_type=preconditioner_type) Source = u_[0].function_space() if not low_memory_version: self.matvec = [[A_cache[(self.test * TrialFunction(Source).dx(i) * dx, ())], u_[i]] for i in range(Space.mesh().geometry().dim())] if solver_method.lower() == "gradient_matrix": from fenicstools import compiled_gradient_module DG = FunctionSpace(Space.mesh(), 'DG', 0) G = assemble(TrialFunction(DG) * self.test * dx()) dg = Function(DG) self.WGM = [] st = TrialFunction(Source) for i in range(Space.mesh().geometry().dim()): dP = assemble(st.dx(i) * TestFunction(DG) * dx) A = Matrix(G) self.WGM.append(compiled_gradient_module.compute_weighted_gradient_matrix(A, dP, dg))
def of1d_weak_solution(V: FunctionSpace, f: Function, ft: Function, fx: Function, alpha0: float, alpha1: float) \ -> (Function, float, float): """Solves the weak formulation of the Euler-Lagrange equations of the L2-H1 Horn-Schunck optical flow functional with spatio-temporal regularisation for a 1D image sequence, i.e. f_x * (f_t + f_x * v) - alpha0 * v_xx - alpha1 * v_tt = 0 with zero Neumann boundary conditions v_x = 0 and v_t = 0. Takes a function space, a one-dimensional image sequence f and its partial derivatives with respect to time and space, and returns a solution. Args: f (Function): A 1D image sequence. ft (Function): Partial derivative of f wrt. time. fx (Function): Partial derivative of f wrt. space. alpha0 (float): The spatial regularisation parameter. alpha1 (float): The temporal regularisation parameter. Returns: v (Function): The velocity. res (float): The residual. fun (float): The function value. """ # Define trial and test functions. v = TrialFunction(V) w = TestFunction(V) # Define weak formulation. A = (fx * fx * v * w + alpha0 * v.dx(1) * w.dx(1) + alpha1 * v.dx(0) * w.dx(0)) * dx b = -fx * ft * w * dx # Compute and return solution. v = Function(V) solve(A == b, v) # Evaluate and print residual and functional value. res = abs(ft + fx*v) fun = 0.5 * (res ** 2 + alpha0 * v.dx(1) ** 2 + alpha1 * v.dx(0) ** 2) print('Res={0}, Func={1}'.format(assemble(res * dx), assemble(fun * dx))) return v, assemble(res * dx), assemble(fun * dx)
def __init__(self, u_, Space, bcs=[], name="div", method={}): solver_type = method.get('solver_type', 'cg') preconditioner_type = method.get('preconditioner_type', 'default') solver_method = method.get('method', 'default') low_memory_version = method.get('low_memory_version', False) OasisFunction.__init__(self, div(u_), Space, bcs=bcs, name=name, method=solver_method, solver_type=solver_type, preconditioner_type=preconditioner_type) Source = u_[0].function_space() if not low_memory_version: self.matvec = [[ A_cache[(self.test * TrialFunction(Source).dx(i) * dx, ())], u_[i] ] for i in range(Space.mesh().geometry().dim())] if solver_method.lower() == "gradient_matrix": from fenicstools import compiled_gradient_module DG = FunctionSpace(Space.mesh(), 'DG', 0) G = assemble(TrialFunction(DG) * self.test * dx()) dg = Function(DG) self.WGM = [] st = TrialFunction(Source) for i in range(Space.mesh().geometry().dim()): dP = assemble(st.dx(i) * TestFunction(DG) * dx) A = Matrix(G) self.WGM.append( compiled_gradient_module.compute_weighted_gradient_matrix( A, dP, dg))
def les_setup(u_, mesh, assemble_matrix, CG1Function, nut_krylov_solver, bcs, **NS_namespace): """ Set up for solving the Germano Dynamic LES model applying Lagrangian Averaging. """ # Create function spaces CG1 = FunctionSpace(mesh, "CG", 1) p, q = TrialFunction(CG1), TestFunction(CG1) dim = mesh.geometry().dim() # Define delta and project delta**2 to CG1 delta = pow(CellVolume(mesh), 1. / dim) delta_CG1_sq = project(delta, CG1) delta_CG1_sq.vector().set_local(delta_CG1_sq.vector().array()**2) delta_CG1_sq.vector().apply("insert") # Define nut_ Sij = sym(grad(u_)) magS = sqrt(2 * inner(Sij, Sij)) Cs = Function(CG1) nut_form = Cs**2 * delta**2 * magS # Create nut_ BCs ff = FacetFunction("size_t", mesh, 0) bcs_nut = [] for i, bc in enumerate(bcs['u0']): bc.apply(u_[0].vector()) # Need to initialize bc m = bc.markers() # Get facet indices of boundary ff.array()[m] = i + 1 bcs_nut.append(DirichletBC(CG1, Constant(0), ff, i + 1)) nut_ = CG1Function(nut_form, mesh, method=nut_krylov_solver, bcs=bcs_nut, bounded=True, name="nut") # Create functions for holding the different velocities u_CG1 = as_vector([Function(CG1) for i in range(dim)]) u_filtered = as_vector([Function(CG1) for i in range(dim)]) dummy = Function(CG1) ll = LagrangeInterpolator() # Assemble required filter matrices and functions G_under = Function(CG1, assemble(TestFunction(CG1) * dx)) G_under.vector().set_local(1. / G_under.vector().array()) G_under.vector().apply("insert") G_matr = assemble(inner(p, q) * dx) # Set up functions for Lij and Mij Lij = [Function(CG1) for i in range(dim * dim)] Mij = [Function(CG1) for i in range(dim * dim)] # Check if case is 2D or 3D and set up uiuj product pairs and # Sij forms, assemble required matrices Sijcomps = [Function(CG1) for i in range(dim * dim)] Sijfcomps = [Function(CG1) for i in range(dim * dim)] # Assemble some required matrices for solving for rate of strain terms Sijmats = [assemble_matrix(p.dx(i) * q * dx) for i in range(dim)] if dim == 3: tensdim = 6 uiuj_pairs = ((0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)) else: tensdim = 3 uiuj_pairs = ((0, 0), (0, 1), (1, 1)) # Set up Lagrange functions JLM = Function(CG1) JLM.vector()[:] += 1E-32 JMM = Function(CG1) JMM.vector()[:] += 1 return dict(Sij=Sij, nut_form=nut_form, nut_=nut_, delta=delta, bcs_nut=bcs_nut, delta_CG1_sq=delta_CG1_sq, CG1=CG1, Cs=Cs, u_CG1=u_CG1, u_filtered=u_filtered, ll=ll, Lij=Lij, Mij=Mij, Sijcomps=Sijcomps, Sijfcomps=Sijfcomps, Sijmats=Sijmats, JLM=JLM, JMM=JMM, dim=dim, tensdim=tensdim, G_matr=G_matr, G_under=G_under, dummy=dummy, uiuj_pairs=uiuj_pairs)
def les_setup(u_, mesh, assemble_matrix, CG1Function, nut_krylov_solver, bcs, **NS_namespace): """ Set up for solving the Germano Dynamic LES model applying Lagrangian Averaging. """ # Create function spaces CG1 = FunctionSpace(mesh, "CG", 1) p, q = TrialFunction(CG1), TestFunction(CG1) dim = mesh.geometry().dim() # Define delta and project delta**2 to CG1 delta = pow(CellVolume(mesh), 1. / dim) delta_CG1_sq = project(delta, CG1) delta_CG1_sq.vector().set_local(delta_CG1_sq.vector().array()**2) delta_CG1_sq.vector().apply("insert") # Define nut_ Sij = sym(grad(u_)) magS = sqrt(2 * inner(Sij, Sij)) Cs = Function(CG1) nut_form = Cs**2 * delta**2 * magS # Create nut_ BCs ff = MeshFunction("size_t", mesh, mesh.topology().dim() - 1, 0) bcs_nut = [] for i, bc in enumerate(bcs['u0']): bc.apply(u_[0].vector()) # Need to initialize bc m = bc.markers() # Get facet indices of boundary ff.array()[m] = i + 1 bcs_nut.append(DirichletBC(CG1, Constant(0), ff, i + 1)) nut_ = CG1Function(nut_form, mesh, method=nut_krylov_solver, bcs=bcs_nut, bounded=True, name="nut") # Create functions for holding the different velocities u_CG1 = as_vector([Function(CG1) for i in range(dim)]) u_filtered = as_vector([Function(CG1) for i in range(dim)]) dummy = Function(CG1) ll = LagrangeInterpolator() # Assemble required filter matrices and functions G_under = Function(CG1, assemble(TestFunction(CG1) * dx)) G_under.vector().set_local(1. / G_under.vector().array()) G_under.vector().apply("insert") G_matr = assemble(inner(p, q) * dx) # Set up functions for Lij and Mij Lij = [Function(CG1) for i in range(dim * dim)] Mij = [Function(CG1) for i in range(dim * dim)] # Check if case is 2D or 3D and set up uiuj product pairs and # Sij forms, assemble required matrices Sijcomps = [Function(CG1) for i in range(dim * dim)] Sijfcomps = [Function(CG1) for i in range(dim * dim)] # Assemble some required matrices for solving for rate of strain terms Sijmats = [assemble_matrix(p.dx(i) * q * dx) for i in range(dim)] if dim == 3: tensdim = 6 uiuj_pairs = ((0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)) else: tensdim = 3 uiuj_pairs = ((0, 0), (0, 1), (1, 1)) # Set up Lagrange functions JLM = Function(CG1) JLM.vector()[:] += 1E-32 JMM = Function(CG1) JMM.vector()[:] += 1 return dict(Sij=Sij, nut_form=nut_form, nut_=nut_, delta=delta, bcs_nut=bcs_nut, delta_CG1_sq=delta_CG1_sq, CG1=CG1, Cs=Cs, u_CG1=u_CG1, u_filtered=u_filtered, ll=ll, Lij=Lij, Mij=Mij, Sijcomps=Sijcomps, Sijfcomps=Sijfcomps, Sijmats=Sijmats, JLM=JLM, JMM=JMM, dim=dim, tensdim=tensdim, G_matr=G_matr, G_under=G_under, dummy=dummy, uiuj_pairs=uiuj_pairs)
def cm1dsource(img: np.array, k: np.array, alpha0: float, alpha1: float) -> np.array: """Computes the L2-H1 mass conserving flow for a 1D image sequence and a given source. Takes a one-dimensional image sequence and a source, and returns a minimiser of the L2-H1 mass conservation functional with spatio-temporal regularisation. Args: img (np.array): A 1D image sequence of shape (m, n), where m is the number of time steps and n is the number of pixels. k (np.array): A 1D image sequence of shape (m, n). alpha0 (float): The spatial regularisation parameter. alpha1 (float): The temporal regularisation parameter. Returns: v: A velocity array of shape (m, n). """ # Create mesh. [m, n] = img.shape mesh = UnitSquareMesh(m - 1, n - 1) # Define function space and functions. V = FunctionSpace(mesh, 'CG', 1) v = TrialFunction(V) w = TestFunction(V) # Convert image to function. f = Function(V) f.vector()[:] = dh.img2funvec(img) # Convert source to function. g = Function(V) g.vector()[:] = dh.img2funvec(k) # Define derivatives of data. ft = Function(V) ftv = np.diff(img, axis=0) * (m - 1) ftv = np.concatenate((ftv, ftv[-1, :].reshape(1, n)), axis=0) ft.vector()[:] = dh.img2funvec(ftv) fx = Function(V) fxv = np.gradient(img, 1 / (n - 1), axis=1) fx.vector()[:] = dh.img2funvec(fxv) ft = f.dx(0) fx = f.dx(1) # Define weak formulation. A = - (fx*v + f*v.dx(1)) * (fx*w + f*w.dx(1))*dx \ - alpha0*v.dx(1)*w.dx(1)*dx - alpha1*v.dx(0)*w.dx(0)*dx b = ft * (fx * w + f * w.dx(1)) * dx - g * (fx * w + f * w.dx(1)) * dx # Compute solution. v = Function(V) solve(A == b, v) # Convert back to array. vel = dh.funvec2img(v.vector().get_local(), m, n) return vel
def __init__(self, parameters): """ TV regularization in primal-dual format Input parameters: * k = regularization parameter * eps = regularization constant (see above) * rescaledradiusdual = radius of dual set * exact = use full TV (bool) * PCGN = use GN Hessian to precondition (bool); not recommended for performance but can help avoid num.instability * print (bool) """ self.parameters = {} self.parameters['k'] = 1.0 self.parameters['eps'] = 1e-2 self.parameters['rescaledradiusdual'] = 1.0 self.parameters['exact'] = False self.parameters['PCGN'] = False self.parameters['print'] = False self.parameters['correctcost'] = True self.parameters['amg'] = 'default' assert parameters.has_key('Vm') self.parameters.update(parameters) self.Vm = self.parameters['Vm'] k = self.parameters['k'] eps = self.parameters['eps'] exact = self.parameters['exact'] amg = self.parameters['amg'] self.m = Function(self.Vm) testm = TestFunction(self.Vm) trialm = TrialFunction(self.Vm) # WARNING: should not be changed. # As it is, code only works with DG0 if self.parameters.has_key('Vw'): Vw = self.parameters['Vw'] else: Vw = FunctionSpace(self.Vm.mesh(), 'DG', 0) self.wx = Function(Vw) self.wxrs = Function(Vw) # re-scaled dual variable self.wxhat = Function(Vw) self.gwx = Function(Vw) self.wy = Function(Vw) self.wyrs = Function(Vw) # re-scaled dual variable self.wyhat = Function(Vw) self.gwy = Function(Vw) self.wxsq = Vector() self.wysq = Vector() self.normw = Vector() self.factorw = Vector() testw = TestFunction(Vw) trialw = TrialFunction(Vw) normm = inner(nabla_grad(self.m), nabla_grad(self.m)) TVnormsq = normm + Constant(eps) TVnorm = sqrt(TVnormsq) if self.parameters['correctcost']: meshtmp = UnitSquareMesh(self.Vm.mesh().mpi_comm(), 10, 10) Vtmp = FunctionSpace(meshtmp, 'CG', 1) x = SpatialCoordinate(meshtmp) correctioncost = 1. / assemble(sqrt(4.0 * x[0] * x[0]) * dx) else: correctioncost = 1.0 self.wkformcost = Constant(k * correctioncost) * TVnorm * dx if exact: sys.exit(1) # self.w = nabla_grad(self.m)/TVnorm # full Hessian # self.Htvw = inner(Constant(k) * nabla_grad(testm), self.w) * dx self.misfitwx = inner(testw, self.wx * TVnorm - self.m.dx(0)) * dx self.misfitwy = inner(testw, self.wy * TVnorm - self.m.dx(1)) * dx self.Htvx = assemble(inner(Constant(k) * testm.dx(0), trialw) * dx) self.Htvy = assemble(inner(Constant(k) * testm.dx(1), trialw) * dx) self.massw = inner(TVnorm * testw, trialw) * dx mpicomm = self.Vm.mesh().mpi_comm() invMwMat, VDM, VDM = setupPETScmatrix(Vw, Vw, 'aij', mpicomm) for ii in VDM.dofs(): invMwMat[ii, ii] = 1.0 invMwMat.assemblyBegin() invMwMat.assemblyEnd() self.invMwMat = PETScMatrix(invMwMat) self.invMwd = Vector() self.invMwMat.init_vector(self.invMwd, 0) self.invMwMat.init_vector(self.wxsq, 0) self.invMwMat.init_vector(self.wysq, 0) self.invMwMat.init_vector(self.normw, 0) self.invMwMat.init_vector(self.factorw, 0) u = Function(Vw) uflrank = len(u.ufl_shape) if uflrank == 0: ones = ("1.0") elif uflrank == 1: ones = (("1.0", "1.0")) else: sys.exit(1) u = interpolate(Constant(ones), Vw) self.one = u.vector() self.wkformAx = inner(testw, trialm.dx(0) - \ self.wx * inner(nabla_grad(self.m), nabla_grad(trialm)) / TVnorm) * dx self.wkformAxrs = inner(testw, trialm.dx(0) - \ self.wxrs * inner(nabla_grad(self.m), nabla_grad(trialm)) / TVnorm) * dx self.wkformAy = inner(testw, trialm.dx(1) - \ self.wy * inner(nabla_grad(self.m), nabla_grad(trialm)) / TVnorm) * dx self.wkformAyrs = inner(testw, trialm.dx(1) - \ self.wyrs * inner(nabla_grad(self.m), nabla_grad(trialm)) / TVnorm) * dx kovsq = Constant(k) / TVnorm self.wkformGNhess = kovsq * inner(nabla_grad(trialm), nabla_grad(testm)) * dx factM = 1e-2 * k M = assemble(inner(testm, trialm) * dx) self.sMass = M * factM self.Msolver = PETScKrylovSolver('cg', 'jacobi') self.Msolver.parameters["maximum_iterations"] = 2000 self.Msolver.parameters["relative_tolerance"] = 1e-24 self.Msolver.parameters["absolute_tolerance"] = 1e-24 self.Msolver.parameters["error_on_nonconvergence"] = True self.Msolver.parameters["nonzero_initial_guess"] = False self.Msolver.set_operator(M) if amg == 'default': self.amgprecond = amg_solver() else: self.amgprecond = amg if self.parameters['print']: print '[TVPD] TV regularization -- primal-dual method', if self.parameters['PCGN']: print ' -- PCGN', print ' -- k={}, eps={}'.format(k, eps) print '[TVPD] preconditioner = {}'.format(self.amgprecond) print '[TVPD] correction cost with factor={}'.format( correctioncost)
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 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