Exemple #1
0
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()
Exemple #2
0
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
Exemple #3
0
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
Exemple #4
0
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")
Exemple #6
0
    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))
Exemple #7
0
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)
Exemple #8
0
    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))
Exemple #9
0
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)
Exemple #10
0
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)
Exemple #11
0
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)
Exemple #13
0
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
Exemple #14
0
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