Esempio n. 1
0
    def assemble_RHS(self, t=None):
        """Assemble right hand side of the FBVP
        """
        print('Assembling RHS')
        self.forcing_terms = np.empty([self.control_set_size, self.dim])
        for i, alpha in enumerate(self.control_set):
            rhs = self.parameters.RHSt(alpha)
            if t is not None:
                rhs.t = t
            # Initialise forcing term
            F = np.array(assemble(rhs * self.u * dx)[:])

            for j in self.parameters.regions['RobinTime']:
                rhs = self.parameters.RHS_bound[j](alpha)
                if t is not None:
                    rhs.t = t
                bc = DirichletBC(self.V, rhs, self.boundary_markers, j)
                vals = bc.get_boundary_values()
                F[list(vals.keys())] = list(vals.values())

            for j in self.parameters.regions['Robin']:
                rhs = self.parameters.RHS_bound[j](alpha)
                if t is not None:
                    rhs.t = t
                bc = DirichletBC(self.V, rhs, self.boundary_markers, j)
                vals = bc.get_boundary_values()
                F[list(vals.keys())] = list(vals.values())

            self.forcing_terms[i] = self.timestep_size * F
Esempio n. 2
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
def solverBHWreduced(P, opt):
    ''' Function to solve the second-order pde in
    nonvariational formulation using gmres '''

    if P.hasDrift:
        raise ValueError('Method currently does not support non-zero drift terms.')
    if P.isTimeDependant:
        raise ValueError('Method currently does not support parabolic problems.')
    if P.hasPotential:
        raise ValueError('Method currently does not support non-zero potential terms.')

    gamma = P.normalizeSystem(opt)

    # Extract local space of tensor space W_h
    W_H_loc = P.mixedSpace.sub(1).extract_sub_space(np.array([0])).collapse()

    trial_u = TrialFunction(P.V)
    test_u = TestFunction(P.V)

    trial_p = TrialFunction(W_H_loc)
    test_p = TestFunction(W_H_loc)

    # Get number of dofs in V
    N = P.V.dim()
    NW = W_H_loc.dim()

    # Get indices of inner and boundary nodes
    # Calling DirichletBC with actual P.g calls project which is expensive
    bc_V = DirichletBC(P.V, Constant(1), 'on_boundary')
    idx_bnd = list(bc_V.get_boundary_values().keys())
    N_bnd = len(idx_bnd)
    N_in = N - N_bnd

    # Get indices of inner nodes
    idx_inner = np.setdiff1d(range(N), idx_bnd)

    def _i2a(S):
        return S[:, idx_inner]

    def _i2i(S):
        return S[idx_inner, :][:, idx_inner]

    def _b2a(S):
        return S[:, idx_bnd]

    def _b2i(S):
        return S[idx_inner, :][:, idx_bnd]

    # Assemble mass matrix and store LU decomposition
    M_W = spmat(assemble(trial_p * test_p * dx))
    # spy(M_W)

    if opt['time_check']:
        t1 = time()

    # M_LU = la.splu(M_W)
    M_LU = cgMat(M_W)

    if opt['time_check']:
        print("Compute LU decomposition of M_W ... %.2fs" % (time() - t1))
        sys.stdout.flush()

    # Check for constant zero entries in diffusion matrix

    # The diagonal entries are set up everytime
    nzdiags = [(i, i) for i in range(P.dim())]

    # The off-diagonal entries
    nzs = []
    Asym = True
    for (i, j) in itertools.product(range(P.dim()), range(P.dim())):
        if i == j:
            nzs.append((i, j))
        else:
            is_zero = checkForZero(P.a[i, j])
            if not is_zero:
                Asym = False
                print('Use value ({},{})'.format(i, j))
                nzs.append((i, j))
            else:
                print('Ignore value ({},{})'.format(i, j))

    def emptyMat(d=P.dim()):
        return [[-1e15] * d for i in range(d)]
        # return [[0] * d for i in range(d)]

    # Assemble weighted mass matrices
    B = emptyMat()
    for (i, j) in nzs:
        # ipdb.set_trace()
        this_form = gamma * P.a[i, j] * trial_p * test_p * dx
        B[i][j] = spmat(assemble(this_form))

    # Init array for partial stiffness matrices
    C = emptyMat()

    # Set up the form for partial stiffness matrices
    def C_form(i, j):
        this_form = -trial_u.dx(i) * test_p.dx(j) * \
            dx + trial_u.dx(i) * test_p * P.nE[j] * ds
        if opt["HessianSpace"] == 'DG':
            this_form += avg(trial_u.dx(i)) \
                * (test_p('+') * P.nE[j]('+') + test_p('-') * P.nE[j]('-')) * dS
        return this_form

    # Ensure the diagonal is set up, necessary for the FE Laplacian
    for i in range(P.dim()):
        C[i][i] = spmat(assemble(C_form(i, i)))

    # Assemble the partial stiffness matrices for off-diagonal entries
    # only if a_i,j is non-zero
    for i, j in nzs:
        if i != j:
            C[i][j] = spmat(assemble(C_form(i, j)))

    C_lapl = sum([C[i][j] for i, j in nzdiags])

    # Set up the form for stabilization term
    if opt["stabilizationFlag"] > 0:

        this_form = 0

        # First stabilization term
        if opt["stabilityConstant1"] > 0:
            this_form += opt["stabilityConstant1"] * avg(P.hE)**(-1) * \
                inner(vj(grad(trial_u), P.nE), vj(grad(test_u), P.nE)) * dS

        # Second stabilization term
        if opt["stabilityConstant2"] > 0:
            this_form += opt["stabilityConstant2"] * avg(P.hE)**(+1) * \
                inner(mj(grad(grad(trial_u)), P.nE),
                      mj(grad(grad(test_u)), P.nE)) * dS

        # Assemble stabilization term
        S = spmat(assemble(this_form))

    else:

        # If no stabilization is used, S is zero
        S = sp.csc_matrix((N, N))

    # Set up matrix-vector product for inner nodes
    def S_II_times_u(x):
        Dv = [B[i][j] * M_LU.solve(_i2a(C[i][j]) * x) for i, j in nzs]
        w = M_LU.solve(sum(Dv))
        return (_i2a(C_lapl)).transpose() * w + _i2i(S) * x

    # Set up matrix-vector product for boundary nodes
    def S_IB_times_u(x):
        Dv = [B[i][j] * M_LU.solve(_b2a(C[i][j]) * x) for i, j in nzs]
        w = M_LU.solve(sum(Dv))
        return (_i2a(C_lapl)).transpose() * w + _b2i(S) * x

    # Assemble f_W
    f_W = assemble(gamma * P.f * test_p * dx)

    M_in = la.LinearOperator((N_in, N_in), matvec=lambda x: S_II_times_u(x))
    M_bnd = la.LinearOperator((N_in, N_bnd), matvec=lambda x: S_IB_times_u(x))

    # Set up right-hand side
    try:
        print('Project boundary data with LU')
        G = project(P.g, P.V, solver_type="lu")
    except RuntimeError:
        print('Out of memory error: Switch to projection with CG')
        G = project(P.g, P.V, solver_type="cg")

    # Compute right-hand side
    rhs = (_i2a(C_lapl)).transpose() * M_LU.solve(f_W.get_local())

    Gvec = G.vector()
    g_bc = Gvec.get_local().take(idx_bnd)
    rhs -= M_bnd * g_bc

    M_W_DiagInv = sp.spdiags(1. / M_W.diagonal(), np.array([0]), NW, NW, format='csc')
    D = sum([sp.spdiags(B[i][j].diagonal(), np.array([0]), NW, NW, format='csc')
             * M_W_DiagInv * _i2a(C[i][j]) for i, j in nzs])
    Prec = (_i2a(C_lapl)).transpose().tocsc() * M_W_DiagInv * D + _i2i(S)

    if opt['time_check']:
        t1 = time()

    # Determine approximate size of LU decomposition in GB
    LU_size = NW**2 / (1024.**3)
    MEM_size = os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES') / (1024.**3)

    if LU_size / MEM_size > 0.8:
        if Asym:
            print('Use CG for preconditioning')
            Prec_LU = cgMat(Prec)
        else:
            print('Use GMRES for preconditioning')
            Prec_LU = gmresMat(Prec)
    else:
        try:
            print('Use LU for preconditioning')
            Prec_LU = la.splu(Prec)
        except MemoryError:
            if Asym:
                print('Use CG for preconditioning')
                Prec_LU = cgMat(Prec)
            else:
                print('Use GMRES for preconditioning')
                Prec_LU = gmresMat(Prec)

    PrecLinOp = la.LinearOperator(
        (N_in, N_in), matvec=lambda x: Prec_LU.solve(x))

    # import ipdb
    # ipdb.set_trace()
    # gmres_mode = 1  # LU decomposition of Prec
    # # gmres_mode = 3  # incomplete LU decomposition of Prec
    # # gmres_mode = 4  # aslinearop
    # # Findings during experiments
    # # - LU factorization of prec is fast, high memory demand
    # # - Using only the diag of prec is not suitable
    # # - Solve routine from scipy is slow

    # # 1st variant: determine LU factorization of preconditioner
    # if gmres_mode == 1:
    #     Prec_LU = la.splu(Prec)
    #     PrecLinOp = la.LinearOperator(
    #         (N_in, N_in), matvec=lambda x: Prec_LU.solve(x))

    # # 3rd variant: determine incomplete LU factorization of preconditioner
    # if gmres_mode == 3:
    #     if P.solDofs(opt) < MEM_THRESHOLD:
    #         fill_factor = 20
    #         fill_factor = 30
    #         print('Use incomplete LU with fill factor {} for preconditioning'.format(fill_factor))
    #         Prec_LU = la.spilu(Prec,
    #                            fill_factor=fill_factor,
    #                            drop_tol=1e-4)
    #     else:
    #         print('Use gmres for preconditioning')
    #         Prec_LU = gmresMat(Prec, tol=1e-8)
    #         # print('Use cg for preconditioning')
    #         # Prec_LU = cgMat(Prec)
    #     PrecLinOp = la.LinearOperator(
    #         (N_in, N_in), matvec=lambda x: Prec_LU.solve(x))

    # if gmres_mode == 4:

    #     if P.solDofs(opt) < MEM_THRESHOLD:
    #         Prec_LU = la.splu(Prec)
    #     else:
    #         Prec_LU = gmresMat(Prec)

    #     PrecLinOp = la.LinearOperator(
    #         (N_in, N_in), matvec=lambda x: Prec_LU.solve(x))

    if opt['time_check']:
        t2 = time()
        print("Prepare GMRES (e.g. LU decomp of Prec) ... %.2fs" % (t2 - t1))
        sys.stdout.flush()

    do_savemat = 0
    if do_savemat:
        from scipy.io import savemat
        savemat('M_{}.mat'.format(P.meshLevel),
                mdict={'Prec': Prec,
                       'B': B,
                       'C': C,
                       'S': S,
                       'M': M_W,
                       'f': f_W.get_local(),
                       'g': Gvec.get_local(),
                       'idx_inner': idx_inner,
                       'idx_bnd': idx_bnd,
                       })

    if P.meshLevel == 1 or not opt["gmresWarmStart"]:
        x0 = np.zeros(N_in)
    else:
        tmp = interpolate(P.uold, P.V)
        x0 = tmp.vector().get_local()[idx_inner]

    # Initialize counter for GMRES
    counter = gmres_counter(disp=True)

    # System solve
    (x, gmres_flag) = la.gmres(A=M_in,
                               b=rhs,
                               M=PrecLinOp,
                               x0=x0,
                               maxiter=2000,
                               tol=opt["gmresTolRes"],
                               atol=opt["gmresTolRes"],
                               restart=20,
                               callback=counter)

    if opt['time_check']:
        print("Time for GMRES ... %.2fs" % (time() - t2))
        sys.stdout.flush()

    print('GMRES output flag: {}'.format(gmres_flag))

    N_iter = counter.niter

    u_loc = Function(P.V)
    u_loc.vector()[idx_bnd] = g_bc
    u_loc.vector()[idx_inner] = x

    # Set solution to problem structure
    assign(P.u, u_loc)

    # Compute FE Hessians
    # import ipdb
    # ipdb.set_trace()

    for (i, j) in itertools.product(range(P.dim()), range(P.dim())):
        if (i, j) in nzs:
            Hij = Function(P.W_H.sub(i*P.dim() + j).collapse())
            hij = M_LU.solve(C[i][j] * u_loc.vector())
            Hij.vector()[:] = hij
            assign(P.H.sub(i*P.dim() + j), Hij)

    return N_iter
Esempio n. 4
0
    def __init__(self, mesh_name, parameters, alpha_range=None):
        # LOAD MESH AND PARAMETERS
        self.parameters = parameters
        self.mesh_name = mesh_name
        if not alpha_range:
            self.alpha_range = parameters.alpha_range
        else:
            self.alpha_range = alpha_range
        mesh_path = self.parameters.get_mesh_path()

        self.mesh = Mesh()
        with XDMFFile(mesh_path) as f:
            f.read(self.mesh)
        print(f'Mesh size= {self.mesh.hmax()}')
        # dimension of approximation space
        self.dim = len(self.mesh.coordinates())
        print(f'Dimension of solution space is {self.dim}')
        self.V = FunctionSpace(self.mesh, 'CG', 1)  # CG =  P1
        self.coords = self.mesh.coordinates()[dof_to_vertex_map(self.V)]
        self.T = self.parameters.T  # final time
        self.w = TrialFunction(self.V)
        self.u = TestFunction(self.V)
        #######################################################################
        # CONTROL SET CREATION
        self.control_set = np.linspace(self.alpha_range[0],
                                       self.alpha_range[1],
                                       self.parameters.control_set_size)
        self.control_set_size = len(self.control_set)
        print(f'Discretized control set has size {self.control_set_size}')
        #######################################################################
        # BOUNDARY CONDITIONS
        parameters.set_boundary_conditions(self.mesh)
        self.boundary_markers = MeshFunction('size_t', self.mesh, 1)
        self.boundary_markers.set_all(4)  # pylint: disable=no-member

        for i, omega in self.parameters.omegas.items():
            omega.mark(self.boundary_markers, i)

        self.ds = Measure('ds',
                          domain=self.mesh,
                          subdomain_data=self.boundary_markers)

        self.dirichlet_bcs = [
            DirichletBC(self.V, parameters.RHS_bound[j], self.boundary_markers,
                        j) for j in self.parameters.regions["Dirichlet"]
        ]

        # Get indices of dirichlet and robin dofs
        self.dirichlet_nodes_list = set()
        self.dirichlet_nodes_dict = {}
        for j in self.parameters.regions["Dirichlet"]:
            bc = DirichletBC(self.V, Constant(0), self.boundary_markers, j)
            self.dirichlet_nodes_list |= set(bc.get_boundary_values().keys())
            self.dirichlet_nodes_dict[j] = list(
                bc.get_boundary_values().keys())

        self.robin_nodes_list = set()
        self.robin_nodes_dict = {}
        for j in self.parameters.regions["Robin"]:
            bc = DirichletBC(self.V, Constant(0), self.boundary_markers, j)
            self.robin_nodes_list |= set(bc.get_boundary_values().keys())
            self.robin_nodes_dict[j] = list(bc.get_boundary_values().keys())

        bc = DirichletBC(self.V, Constant(0), 'on_boundary')
        self.boundary_nodes_list = bc.get_boundary_values().keys()

        self.robint_nodes_list = set()
        self.robint_nodes_dict = {}
        for j in self.parameters.regions["RobinTime"]:
            bc = DirichletBC(self.V, Constant(0), self.boundary_markers, j)
            self.robint_nodes_list |= set(bc.get_boundary_values().keys())
            self.robint_nodes_dict[j] = list(bc.get_boundary_values().keys())
        #######################################################################
        # ASSEMBLY
        time_start = time.process_time()
        self.assemble_diagonal_matrix()  # auxilliary generic diagonal matrix
        # used for vector*matrix multiplication of dolfin matrices
        self.assemble_lumpedmm()  # lumped mass matrix
        # which serves the role of identity operator
        self.assemble_laplacian()  # discrete laplacian

        self.ad_data_path = f'out/{self.parameters.experiment}'
        Path(self.ad_data_path).mkdir(parents=True, exist_ok=True)

        self.timesteps = self.parameters.get_number_of_timesteps()
        self.assemble_HJBe()  # assembly of explicit operators
        self.assemble_HJBi()  # assembly of implicit operators
        self.assemble_RHS()  # assembly of forcing term
        print('Final time assembly complete')
        print(f'Assembly took {time.process_time() - time_start} seconds')

        print('===========================================================')