Exemple #1
0
    def solve(self, **arguments):

        t_start = time.clock()

        # definig Function space on this mesh using Lagrange
        #polynoimals of degree 1.
        H = FunctionSpace(self.mesh, "CG", 1)

        # Setting up the variational problem
        v = TrialFunction(H)
        w = TestFunction(H)

        epsilon = Constant(arguments[Components().Diffusion])
        f = Constant(0)

        a = (epsilon * inner(grad(v), grad(w)) + inner(v, w)) * dx
        #Still have to figure it how to use a Neumann Condition here
        L = f * w * dx

        # solving the variational problem.
        v = Function(H)
        solve(a == L, v)

        self.solution.extend(v.vector().array())

        return [self.solution, time.clock() - t_start]
Exemple #2
0
def project_gradient_neumann(
        f0,
        degree=None,
        mesh=None,
        solver_type='gmres',
        preconditioner_type='default'
    ):
    """Find an approximation to f0 that has the same gradient

    The resulting function also satisfies homogeneous Neumann boundary
    conditions.

    Parameters:    
    f0: the function to approximate
    mesh=None: the mesh on which to approximate it If not provided, the
        mesh is extracted from f0.
    degree=None: degree of the polynomial approximation. extracted
        from f0 if not provided. 
    solver_type='gmres': The linear solver type to use.
    preconditioner_type='default': Preconditioner type to use
    """
    if not mesh: mesh = f0.function_space().mesh()
    element = f0.ufl_element()
    if not degree:
        degree = element.degree()
    CE = FiniteElement('CG', mesh.ufl_cell(), degree)
    CS = FunctionSpace(mesh, CE)
    DE = FiniteElement('DG', mesh.ufl_cell(), degree)
    DS = FunctionSpace(mesh, DE)
    CVE = VectorElement('CG', mesh.ufl_cell(), degree - 1)
    CV = FunctionSpace(mesh, CVE)
    RE = FiniteElement('R', mesh.ufl_cell(), 0)
    R = FunctionSpace(mesh, RE)
    CRE = MixedElement([CE, RE])
    CR = FunctionSpace(mesh, CRE)
    f = fe.project(f0, CS,
                   solver_type=solver_type,
                   preconditioner_type=preconditioner_type)
    g = fe.project(fe.grad(f), CV,
                   solver_type=solver_type,
                   preconditioner_type=preconditioner_type)
    lf = fe.project(fe.nabla_div(g), CS,
                    solver_type=solver_type,
                    preconditioner_type=preconditioner_type)
    tf, tc = TrialFunction(CR)
    wf, wc = TestFunctions(CR)
    dx = Measure('dx', domain=mesh,
                 metadata={'quadrature_degree': min(degree, 10)})
    a = (fe.dot(fe.grad(tf), fe.grad(wf)) + tc * wf + tf * wc) * dx
    L = (f * wc - lf * wf) * dx
    igc = Function(CR)
    fe.solve(a == L, igc,
             solver_parameters={'linear_solver': solver_type,
                                 'preconditioner': preconditioner_type}
    )
    ig, c = igc.sub(0), igc.sub(1)
    igd = fe.project(ig, DS,
                     solver_type=solver_type,
                     preconditioner_type=preconditioner_type)
    return igd
Exemple #3
0
    def solve(self, **arguments):

        t_start = time.clock()

        # definig Function space on this mesh using Lagrange
        #polynoimals of degree 1.
        H = FunctionSpace(self.mesh, "CG", 1)

        # Setting up the variational problem
        v = TrialFunction(H)
        w = TestFunction(H)

        epsilon = Constant(arguments[Components().Diffusion])
        f = Expression("(1 - epsilon*4*pow(pi,2))*cos(2*pi*x[0])",\
                       epsilon=epsilon, degree=1)

        a = (epsilon * inner(grad(v), grad(w)) + inner(v, w)) * dx
        L = f * w * dx

        # solving the variational problem.
        v = Function(H)
        solve(a == L, v)

        self.solution.extend(v.vector().array())

        return [self.solution, time.clock() - t_start]
def run_fokker_planck(nx, num_steps, t_0 = 0, t_final=10):

    # define mesh
    mesh = IntervalMesh(nx, -200, 200)
    # define function space. 
    V = FunctionSpace(mesh, "Lagrange", 1)

    # Homogenous Neumann BCs don't have to be defined as they are the default in dolfin
    # define parameters.
    dt = (t_final-t_0) / num_steps

    # set mu and sigma 
    mu = Constant(-1)
    D = Constant(1)

    # define initial conditions u_0
    u_0 = Expression('x[0]', degree=1)

    # set U_n to be the interpolant of u_0 over the function space V. Note that 
    # u_n is the value of u at the previous timestep, while u is the current value. 
    u_n = interpolate(u_0, V)

    # Define variational problem
    u = TrialFunction(V)
    v = TestFunction(V)
    F = u*v*dx + dt*inner(D*grad(u), grad(v))*dx + dt*mu*grad(u)[0]*v*dx - inner(u_n, v)*dx

    # isolate the bilinear and linear forms. 
    a, L = lhs(F), rhs(F)

    # initialize function to capture solution. 
    t = 0 
    u_h = Function(V)

    plt.figure(figsize=(15, 15))

    # time-stepping section
    for n in range(num_steps):
        t += dt 

        # compute solution 
        solve(a == L, u_h)
        u_n.assign(u_h)

        # Plot solutions intermittently
        if n % (num_steps // 10) == 0 and num_steps > 0:

            plot(u_h, label='t = %s' % t)
    
    plt.legend() 
    plt.grid()
    plt.title("Finite Element Solutions to Fokker-Planck Equation with $\mu(x, t) = -(x+1)$ , $D(x, t) = e^t x^2$, $t_n$ = %s" % t_final)
    plt.ylabel("$u(x, t)$")
    plt.xlabel("x")
    plt.savefig("fpe/fokker-planck-solutions-mu.png")
    plt.clf() 

    # return the approximate solution evaluated on the coordinates, and the actual coordinates. 
    return u_n.compute_vertex_values(), mesh.coordinates() 
Exemple #5
0
def dual_error_estimates(resolution):
    mesh = UnitSquareMesh(resolution, resolution)

    def all_boundary(_, on_boundary):
        return on_boundary

    zero = Constant(0.0)

    def a(u, v):
        return inner(grad(u), grad(v)) * dx

    def L(f, v):
        return f * v * dx

    # Primal problem
    f = Expression("32.*x[0]*(1. - x[0])+32.*x[1]*(1. - x[1])",
                   domain=mesh,
                   degree=5)
    ue = Expression("16.*x[0]*(1. - x[0])*x[1]*(1. - x[1])",
                    domain=mesh,
                    degree=5)

    Qp = FunctionSpace(mesh, 'CG', 1)
    bcp = DirichletBC(Qp, zero, all_boundary)

    u = TrialFunction(Qp)
    v = TestFunction(Qp)

    U = Function(Qp)
    solve(a(u, v) == L(f, v), U, bcp)

    # Dual problem
    Qd = FunctionSpace(mesh, 'CG', 2)
    psi = Constant(1.0)
    bcd = DirichletBC(Qd, zero, all_boundary)

    w = TestFunction(Qd)
    phi = TrialFunction(Qd)
    Phi = Function(Qd)
    solve(a(w, phi) == L(psi, w), Phi, bcd)

    # Compute errors
    e1 = compute_error(ue, U)
    e2 = assemble((inner(grad(U), grad(Phi)) - f * Phi) * dx)
    print("e1 = {}".format(e1))
    print("e2 = {}".format(e2))
Exemple #6
0
    def test_multiplication(self):
        print(
            '\n== testing multiplication of system matrix for problem of weighted projection ===='
        )
        for dim, pol_order in itertools.product([2, 3], [1, 2]):
            N = 2  # no. of elements

            print('dim={0}, pol_order={1}, N={2}'.format(dim, pol_order, N))

            # creating MESH and defining MATERIAL
            if dim == 2:
                mesh = UnitSquareMesh(N, N)
                m = Expression("1+10*16*x[0]*(1-x[0])*x[1]*(1-x[1])",
                               degree=2)  # material coefficients
            elif dim == 3:
                mesh = UnitCubeMesh(N, N, N)
                m = Expression("1+10*16*x[0]*(1-x[0])*(1-x[1])*x[2]",
                               degree=2)  # material coefficients

            mesh.coordinates()[:] += 0.1 * np.random.random(
                mesh.coordinates().shape)  # mesh perturbation

            V = FunctionSpace(mesh, "CG", pol_order)  # original FEM space
            W = FunctionSpace(mesh, "CG", 2 * pol_order)  # double-grid space

            print('assembling local matrices for DoGIP...')
            Bhat = get_Bhat(
                dim, pol_order,
                problem=0)  # projection between V on W on a reference element
            AT_dogip = get_A_T(m, V, W, problem=0)

            dofmapV = V.dofmap()

            def system_multiplication_DoGIP(AT_dogip, Bhat, u_vec):
                # mutliplication with DoGIP decomposition
                Au = np.zeros_like(u_vec)
                for ii, cell in enumerate(cells(mesh)):
                    ind = dofmapV.cell_dofs(ii)  # local to global map
                    Au[ind] += Bhat.T.dot(AT_dogip[ii] * Bhat.dot(u_vec[ind]))
                return Au

            print('assembling FEM sparse matrix')
            u, v = TrialFunction(V), TestFunction(V)
            Asp = assemble(m * u * v * dx, tensor=EigenMatrix())  #
            Asp = Asp.sparray()

            print('multiplication...')
            ur = Function(V)  # creating random vector
            ur_vec = 5 * np.random.random(V.dim())
            ur.vector().set_local(ur_vec)

            Au_DoGIP = system_multiplication_DoGIP(
                AT_dogip, Bhat, ur_vec)  # DoGIP multiplication
            Auex = Asp.dot(ur_vec)  # FEM multiplication with sparse matrix

            # testing the difference between DoGIP and FEniCS
            self.assertAlmostEqual(0, np.linalg.norm(Auex - Au_DoGIP))
            print('...ok')
Exemple #7
0
def problem_mix(T, dt, E, coupling, VV, boundaries, rho_s, lambda_, mu_s, f,
                bcs, **Solid_namespace):
    # Temporal parameters
    t = 0
    k = Constant(dt)

    # Split problem to two 1.order differential equations
    psi, phi = TestFunctions(VV)

    # Functions, wd is for holding the solution
    d_ = {}
    w_ = {}
    wd_ = {}
    for time in ["n", "n-1", "n-2", "n-3"]:
        if time == "n" and E not in [None, reference]:
            tmp_wd = Function(VV)
            wd_[time] = tmp_wd
            wd = TrialFunction(VV)
            w, d = split(wd)
        else:
            wd = Function(VV)
            wd_[time] = wd
            w, d = split(wd)

        d_[time] = d
        w_[time] = w

    # Time derivative
    if coupling == "center":
        G = rho_s / (2 * k) * inner(w_["n"] - w_["n-2"], psi) * dx
    else:
        G = rho_s / k * inner(w_["n"] - w_["n-1"], psi) * dx

    # Stress tensor
    G += inner(Piola2(d_, w_, k, lambda_, mu_s, E_func=E), grad(psi)) * dx

    # External forces, like gravity
    G -= rho_s * inner(f, psi) * dx

    # d-w coupling
    if coupling == "CN":
        G += inner(d_["n"] - d_["n-1"] - k * 0.5 *
                   (w_["n"] + w_["n-1"]), phi) * dx
    elif coupling == "imp":
        G += inner(d_["n"] - d_["n-1"] - k * w_["n"], phi) * dx
    elif coupling == "exp":
        G += inner(d_["n"] - d_["n-1"] - k * w_["n-1"], phi) * dx
    elif coupling == "center":
        G += innter(d_["n"] - d_["n-2"] - 2 * k * w["n-1"], phi) * dx
    else:
        print "The coupling %s is not implemented, 'CN', 'imp', and 'exp' are the only valid choices."
        sys.exit(0)

    # Solve
    if E in [None, reference]:
        solver_nonlinear(G, d_, w_, wd_, bcs, T, dt, **Solid_namespace)
    else:
        solver_linear(G, d_, w_, wd_, bcs, T, dt, **Solid_namespace)
Exemple #8
0
    def test_DoGIP_vs_FEniCS(self):
        print(
            '\n== testing DoGIP vs. FEniCS for problem of weighted projection ===='
        )

        for dim, pol_order in itertools.product([2, 3], [1, 2]):
            print('dim={}; pol_order={}'.format(dim, pol_order))
            N = 2
            # creating MESH, defining MATERIAL and SOURCE
            if dim == 2:
                mesh = UnitSquareMesh(N, N)
                m = Expression("1+10*16*x[0]*(1-x[0])*x[1]*(1-x[1])",
                               degree=3)  # material coefficients
                f = Expression("x[0]*x[0]*x[1]", degree=2)
            elif dim == 3:
                mesh = UnitCubeMesh(N, N, N)
                m = Expression("1+100*x[0]*(1-x[0])*x[1]*x[2]",
                               degree=2)  # material coefficients
                f = Expression("(1-x[0])*x[1]*x[2]", degree=2)

            mesh.coordinates()[:] += 0.1 * np.random.random(
                mesh.coordinates().shape)  # mesh perturbation

            ## standard approach with FEniCS #############################################
            V = FunctionSpace(mesh, "CG", pol_order)  # original FEM space
            u, v = TrialFunction(V), TestFunction(V)
            u_fenics = Function(V)
            solve(m * u * v * dx == m * f * v * dx, u_fenics)

            ## DoGIP - double-grid integration with interpolation-projection #############
            W = FunctionSpace(mesh, "CG", 2 * pol_order)  # double-grid space
            w = TestFunction(W)
            A_dogip = assemble(
                m * w *
                dx).get_local()  # diagonal matrix of material coefficients
            b = assemble(m * f * v * dx)  # vector of right-hand side

            # assembling interpolation-projection matrix B
            B = get_B(V, W, problem=0)

            # # linear solver on double grid, standard
            Afun = lambda x: B.T.dot(A_dogip * B.dot(x))

            Alinoper = linalg.LinearOperator((V.dim(), V.dim()),
                                             matvec=Afun,
                                             dtype=np.float)
            x, info = linalg.cg(Alinoper,
                                b.get_local(),
                                x0=np.zeros(V.dim()),
                                tol=1e-10,
                                maxiter=1e3,
                                callback=None)

            # testing the difference between DoGIP and FEniCS
            self.assertAlmostEqual(
                0, np.linalg.norm(u_fenics.vector().get_local() - x))
            print('...ok')
Exemple #9
0
    def solve(self, **arguments):

        t_start = time.clock()

        # definig Function space on this mesh using Lagrange
        #polynoimals of degree 1.
        H = FunctionSpace(self.mesh, "CG", 1)

        # Setting up the variational problem
        v = TrialFunction(H)
        w = TestFunction(H)

        coeff_dx2 = Constant(1)
        coeff_v = Constant(1)

        f = Expression("(4*pow(pi,2))*exp(-(1/coeff_v)*t)*sin(2*pi*x[0])",
                       {'coeff_v': coeff_v},
                       degree=2)

        v0 = Expression("sin(2*pi*x[0])", degree=2)

        f.t = 0

        def boundary(x, on_boundary):
            return on_boundary

        bc = DirichletBC(H, v0, boundary)

        v1 = interpolate(v0, H)
        dt = self.steps.time

        a = (dt * inner(grad(v), grad(w)) + dt * coeff_v * inner(v, w)) * dx
        L = (f * dt - coeff_v * v1) * w * dx

        A = assemble(a)
        v = Function(H)

        T = self.domain.time[-1]
        t = dt

        # solving the variational problem.
        while t <= T:
            b = assemble(L, tensor=b)
            vo.t = t
            bc.apply(A, b)

            solve(A, v.vector(), b)
            t += dt

            v1.assign(v)

        self.solution.extend(v.vector().array())

        return [self.solution, time.clock() - t_start]
Exemple #10
0
 def __init__(self, *, V: Optional[FunctionSpace], mesh: Mesh,
              dt: float) -> None:
     V = V or FunctionSpace(mesh, "Lagrange", 1)
     self.V = V
     self.T = TrialFunction(V)
     self.v = TestFunction(V)
     self.T_prev = Function(V)
     self.P_s = Constant(1.0)
     self.c_s = Constant(1.0)
     self.k_e = Constant(1.0)
     self.Q_pc = Constant(1.0)
     self.Q_sw = Constant(1.0)
     self.Q_mm = Constant(1.0)
     self.dt = Constant(dt)
Exemple #11
0
def determine_gradient(V_g, u, flux):
    """
    compute flux following http://hplgit.github.io/INF5620/doc/pub/fenics_tutorial1.1/tu2.html#tut-poisson-gradu
    :param mesh
    :param u: solution where gradient is to be determined
    :return:
    """

    w = TrialFunction(V_g)
    v = TestFunction(V_g)

    a = inner(w, v) * dx
    L = inner(grad(u), v) * dx
    solve(a == L, flux)
Exemple #12
0
def determine_gradient(V_g, u, flux):
    """
    compute flux following http://hplgit.github.io/INF5620/doc/pub/fenics_tutorial1.1/tu2.html#tut-poisson-gradu
    :param V_g: Vector function space
    :param u: solution where gradient is to be determined
    :param flux: returns calculated flux into this value
    """

    w = TrialFunction(V_g)
    v = TestFunction(V_g)

    a = inner(w, v) * dx
    L = inner(grad(u), v) * dx
    solve(a == L, flux)
    def _solve(self, z, x=None):
        # problem variables
        du = TrialFunction(self.V)                          # incremental displacement
        v = TestFunction(self.V)                            # test function
        u = Function(self.V)                                # displacement from previous iteration

        # kinematics
        ii = Identity(3)                                    # identity tensor dimension 3
        f = ii + grad(u)                                    # deformation gradient
        c = f.T * f                                         # right Cauchy-Green tensor

        # invariants of deformation tensors
        ic = tr(c)
        j = det(f)

        # elasticity parameters
        if type(z) in [list, np.ndarray]:
            param = self.param_remapper(z[0]) if self.param_remapper is not None else z[0]
        else:
            param = self.param_remapper(z) if self.param_remapper is not None else z

        e_var = variable(Constant(param))                   # Young's modulus
        nu = Constant(.3)                                   # Shear modulus (Lamè's second parameter)
        mu, lmbda = e_var / (2 * (1 + nu)), e_var * nu / ((1 + nu) * (1 - 2 * nu))

        # strain energy density, total potential energy
        psi = (mu / 2) * (ic - 3) - mu * ln(j) + (lmbda / 2) * (ln(j)) ** 2
        pi = psi * dx - self.time * dot(self.f, u) * self.ds(3)

        ff = derivative(pi, u, v)                           # compute first variation of pi
        jj = derivative(ff, u, du)                          # compute jacobian of f

        # solving
        if x is not None:
            numeric_evals = np.zeros(shape=(x.shape[1], len(self.times)))
            evals = np.zeros(shape=(x.shape[1], len(self.eval_times)))
        else:
            numeric_evals = None
            evals = None
        for it, t in enumerate(self.times):
            self.time.t = t
            self.solver(ff == 0, u, self.bcs, J=jj, bcs=self.bcs, solver_parameters=self.solver_parameters)
            if x is not None:
                numeric_evals[:, it] = np.log(np.array([-u(x_)[2] for x_ in x.T]).T)

        # time-interpolation
        if x is not None:
            for i in range(evals.shape[0]):
                evals[i, :] = np.interp(self.eval_times, self.times, numeric_evals[i, :])
        return (evals, u) if x is not None else u
Exemple #14
0
    def __init__(self,
                 grid_shape,
                 f,
                 init_z,
                 dirichlet,
                 degree=1,
                 polynomial_type='P',
                 reparam=True):
        """Parameters
        ----------
        grid_shape : numpy.array or list
            Defines the grid dimensions of the mesh used to solve the problem.
        f : str
            Source term of the Poisson equation in a form accepted by FEniCS (C++ style string)
        init_z : numpy.ndarray
            Placeholder value(s) for parameters of the model.
        dirichlet : str
            Dirichlet boundary conditions in string form accepted by FEniCS.
        degree : int, default 1
            Polynomial degree for the functional space.
        polynomial_type : str, default 'P'
            String encoding the type of polynomials in the functional space, according to FEniCS conventions
            (defaults to Lagrange polynomials).
        reparam: bool, default True
            Boolean indicating whether input parameters are to be reparametrized according to
            an inverse-logit transform.
        """
        def boundary(x, on_boundary):
            return on_boundary

        self.grid_shape = grid_shape
        self.mesh = UnitSquareMesh(*grid_shape)

        self.V = FunctionSpace(self.mesh, polynomial_type, degree)
        self.dirichlet = DirichletBC(self.V,
                                     Expression(dirichlet, degree=degree + 3),
                                     boundary)
        self._paramnames = ['param{}'.format(i) for i in range(len(init_z))]
        self.f = Expression(f,
                            degree=degree,
                            **dict(zip(self._paramnames, init_z)))
        u = TrialFunction(self.V)
        v = TestFunction(self.V)

        self.a = dot(grad(u), grad(v)) * dx
        self.L = self.f * v * dx
        self.u = Function(self.V)
        self.reparam = reparam
        self.solver = CountIt(solve)
Exemple #15
0
def local_project(v, V, u=None):
    """Element-wise projection using LocalSolver"""
    dv = TrialFunction(V)
    v_ = TestFunction(V)
    a_proj = inner(dv, v_) * dx
    b_proj = inner(v, v_) * dx
    solver = LocalSolver(a_proj, b_proj)
    solver.factorize()
    if u is None:
        u = Function(V)
        solver.solve_local_rhs(u)
        return u
    else:
        solver.solve_local_rhs(u)
        return
    def compute_steady_state(self):

        names = {'Cl', 'Na', 'K'}

        P1 = FiniteElement('P', fe.triangle, 1)
        element = MixedElement([P1, P1, P1])
        V = FunctionSpace(self.mesh, element)
        self.V_conc = V

        (u_cl, u_na, u_k) = TrialFunction(V)
        (v_cl, v_na, v_k) = TestFunction(V)

        assert (self.flow is not None)

        n = fe.FacetNormal(self.mesh)

        # F = ( self.F_diff_conv(u_cl, v_cl, n, grad(self.phi), 1. ,1., 0.)
        #    + self.F_diff_conv(u_na, v_na, n, grad(self.phi), 1. ,1., 0.)
        #    + self.F_diff_conv(u_k , v_k , n, grad(self.phi), 1. ,1., 0.) )

        dx, ds = self.dx, self.ds
        flow = self.flow
        F = inner(grad(u_cl), grad(v_cl)) * dx \
            + inner(flow, grad(u_cl)) * v_cl * dx \
            + inner(grad(u_na), grad(v_na)) * dx \
            + inner(flow, grad(u_na)) * v_na * dx \
            + inner(grad(u_k), grad(v_k)) * dx \
            + inner(flow, grad(u_k)) * v_k * dx

        a, L = fe.lhs(F), fe.rhs(F)
        a_mat = fe.assemble(a)
        L_vec = fe.assemble(L)
        # solve
        u = Function(V)
        fe.solve(a_mat, u.vector(), L_vec)

        u_cl, u_na, u_k = u.split()

        output1 = fe.File('/tmp/steady_state_cl.pvd')
        output1 << u_cl
        output2 = fe.File('/tmp/steady_state_na.pvd')
        output2 << u_na
        output3 = fe.File('/tmp/steady_state_k.pvd')
        output3 << u_k

        self.u_cl = u_cl
        self.u_na = u_na
        self.u_k = u_k
 def __init__(self, *, V: Optional[FunctionSpace], mesh: Mesh, dt: float):
     V = V or FunctionSpace(mesh, "Lagrange", 1)
     self.V = V
     self.u = TrialFunction(V)
     self.v = TestFunction(V)
     self.P_prev = Function(V)
     self.theta_a = Constant(1.0)
     self.D_e = Constant(1.0)
     self.P_d = Constant(1.0)
     self.my_v = Constant(1.0)
     self.my_d = Constant(1.0)
     self.alpha_th = Constant(1.0)
     self.M_mm = Constant(1.0)
     self.q_h = Constant(1.0)
     self.T_s = project(Constant(-5.0), V)
     self.dt = Constant(dt)
     self.mesh = mesh
Exemple #18
0
    def __init__(self, V):
        u = TrialFunction(V)
        v = TestFunction(V)
        A = assemble(inner(u, v) * dx, tensor=EigenMatrix())
        self.V = V
        self.v = v

        try:
            import sksparse
            from sksparse.cholmod import cholesky  # sparse Cholesky decomposition
            print('...projection with cholesky of version {}'.format(
                sksparse.__version__))
            self.solve = cholesky(A.sparray().tocsc())
        except:
            print('...projection with LU decomposition')
            invA = scipy.sparse.linalg.splu(
                A.sparray().tocsc())  # sparse LU decomposition
            self.solve = invA.solve
def solve_wave_equation(u0, u1, u_boundary, f, domain, mesh, degree):
    """Solving the wave equation using CG-CG method.

    Args:
        u0: Initial data.
        u1: Initial velocity.
        u_boundary: Dirichlet boundary condition.
        f: Right-hand side.
        domain: Space-time domain.
        mesh: Computational mesh.
        degree: CG(degree) will be used as the finite element.
    Outputs:
        uh: Numerical solution.
    """
    # Element
    V = FunctionSpace(mesh, "CG", degree)
    # Measures on the initial and terminal slice
    mask = MeshFunction("size_t", mesh, mesh.topology().dim() - 1, 0)
    domain.get_initial_slice().mark(mask, 1)
    ends = ds(subdomain_data=mask)
    # Form
    g = Constant(((-1.0, 0.0), (0.0, 1.0)))
    u = TrialFunction(V)
    v = TestFunction(V)
    a = dot(grad(v), dot(g, grad(u))) * dx
    L = f * v * dx + u1 * v * ends(1)
    # Assembled matrices
    A = assemble(a, keep_diagonal=True)
    b = assemble(L, keep_diagonal=True)
    # Spatial boundary condition
    bc = DirichletBC(V, u_boundary, domain.get_spatial_boundary())
    bc.apply(A, b)
    # Temporal boundary conditions (by hand)
    (A, b) = apply_time_boundary_conditions(domain, V, u0, A, b)
    # Solve
    solver = LUSolver()
    solver.set_operator(A)
    uh = Function(V)
    solver.solve(uh.vector(), b)
    return uh
Exemple #20
0
                                    mesh=mesh,
                                    read_field=u_D_function,
                                    write_field=f_N_function,
                                    u_n=u_n)
elif problem is ProblemType.NEUMANN:
    precice_dt = precice.initialize(coupling_subdomain=coupling_boundary,
                                    mesh=mesh,
                                    read_field=f_N_function,
                                    write_field=u_D_function,
                                    u_n=u_n)

dt = Constant(0)
dt.assign(np.min([fenics_dt, precice_dt]))

# Define variational problem
u = TrialFunction(V)
v = TestFunction(V)
f = Expression(
    'beta + gamma * x[0] * x[0] - 2 * gamma * t - 2 * (1-gamma) - 2 * alpha',
    degree=2,
    alpha=alpha,
    beta=beta,
    gamma=gamma,
    t=0)
F = u * v / dt * dx + dot(grad(u), grad(v)) * dx - (u_n / dt + f) * v * dx

if problem is ProblemType.DIRICHLET:
    # apply Dirichlet boundary condition on coupling interface
    bcs.append(precice.create_coupling_dirichlet_boundary_condition(V))
if problem is ProblemType.NEUMANN:
    # apply Neumann boundary condition on coupling interface, modify weak form correspondingly
Exemple #21
0
def theta_method(A, f, ah, bh, θ, k, T):
    """θ-method time-stepper.

    Abstract problem:

        u'' + Au = f,  u(0) = ah, u'(0) = bh

    is formulated as a first-order system:

        u' - v = 0,
        v' + Au = f,
        u(0) = ah, v(0) = bh.

    Args:
        A (Function -> Function -> Form): Possibly nonlinear functional A(u, v)
        f (float -> Function): Right-hand side
        ah (Function): Initial value
        bh (Function): Initial velocity
        k (float): Time step
        T (float): Max time

    Returns:
        list(float): Times
        list(Function): Solution at each time
    """
    # pylint: disable=invalid-name, too-many-arguments, too-many-locals
    # Basic setup
    V = ah.function_space()
    u = TrialFunction(V)
    w = TestFunction(V)
    v = TrialFunction(V)
    y = TestFunction(V)
    α = k * θ
    β = k * (1.0 - θ)
    # Prepare initial condition
    u0 = Function(V)
    u0.vector()[:] = ah.vector()
    v0 = Function(V)
    v0.vector()[:] = bh.vector()
    # Initialize time stepper
    t = k
    u1 = Function(V)
    u1.vector()[:] = u0.vector()
    v1 = Function(V)
    v1.vector()[:] = v0.vector()
    ts = [0]
    uh = [interpolate(u0, V)]
    progress = -1
    print("Progress: ", end="")
    while t < T:
        # Print progress
        pct = int(t / T * 100) // 10 * 10
        if pct > progress:
            print("{}%..".format(pct), end="")
            progress = pct
        # Solve for the next u (nonlinear)
        lhs = (dot(u, w) + α**2 * A(u, w)) * dx
        rhs = (dot(u0, w) - α * β * A(u0, w) + k * dot(v0, w) +
               α**2 * f(t + k, w) + α * β * f(t, w)) * dx
        act = action(lhs - rhs, u1)
        J = derivative(act, u1)
        problem = NonlinearVariationalProblem(act, u1, [], J)
        solver = NonlinearVariationalSolver(problem)
        solver.parameters["newton_solver"]["linear_solver"] = "gmres"
        solver.parameters["newton_solver"]["preconditioner"] = "ilu"
        try:
            solver.solve()
        except RuntimeError:
            print("blowup at t={}.".format(t))
            return (ts, uh)
        # Solve for the next v (linear)
        lhs = dot(v, y) * dx
        rhs = (dot(u1 - u0, y) - β * dot(v0, w)) / α * dx
        problem = LinearVariationalProblem(lhs, rhs, v1)
        solver = LinearVariationalSolver(problem)
        solver.parameters["linear_solver"] = "cg"
        solver.parameters["preconditioner"] = "hypre_amg"
        solver.solve()
        # Update
        t += k
        u0.vector()[:] = u1.vector()
        v0.vector()[:] = v1.vector()
        # Record result
        ts.append(t)
        uh.append(interpolate(u1, V))
    print("done")
    return (ts, uh)
Exemple #22
0
def solve_flem(model_space, physical_space, flow, u_n, mesh, V, bc, dt,
               num_steps, out_time, plot, statistics, name):
    """
    Solve for landscape evolution

    This function does hte hard work. First the model domain is created. Then we loop through time and solve the
    diffusion equation to solve for landscape evolution. Output can be saved as vtk files at every "out_time" specified.
    Plots using fenics inbuilt library can be visualised at every "plot_time"

    This function returns a 1d numpy array of time, sediment flux and if statistics is turned on a 2d numpy array of
    the final wavelength of the landscape.

    :param model_space: list of domain variables, [lx,ly,res]
    :param physical_space: list of physical parameters, [kappa, c, nexp, alpha, U]
    :param flow: 0 = MFD node-to-node; 1 = MFD cell-to-cell; 2 = SD node-to-node; 3 = SD cell-to-cell
    :param u_n: elevation function
    :param mesh: dolphyn mesh
    :param V: fenics functionspace
    :param bc: boundary conditions
    :param dt: time step size in years
    :param num_steps: number of time steps
    :param out_time: time steps to output vtk files (0=none)
    :param plot: plot sediment flux (0=off,1=on)
    :param statistics: output statistics of landscape (0=off,1=on)
    :param name: directory name for output vtk files
    :return: sed_flux, time, wavelength
    """

    # Domain dimensions
    lx = model_space[0]
    ly = model_space[1]

    # Physical parameters
    kappa = physical_space[0]  # diffusion coefficient
    c = physical_space[1]  # discharge transport coefficient
    nexp = physical_space[2]  # discharge exponent
    alpha = physical_space[3]  # precipitation rate
    De = c * pow(alpha * ly, nexp) / kappa
    uamp = physical_space[4] * ly / kappa  # uplift

    dt = dt * kappa / (ly * ly)  # time step size

    sed_flux = np.zeros(num_steps)  # array to store sediment flux
    time = np.zeros(num_steps)

    # Define variational problem
    u = TrialFunction(V)
    v = TestFunction(V)
    f = Constant(uamp)

    # 0 = MFD node-to-node; 1 = MFD cell-to-cell; 2 = SD node-to-node; 3 = SD cell-to-cell
    if flow == 0:
        q_n = mfd_nodenode(mesh, V, u_n, De, nexp)
    if flow == 1:
        q_n = mfd_cellcell(mesh, V, u_n, De, nexp)
    if flow == 2:
        q_n = sd_nodenode(mesh, V, u_n, De, nexp)
    if flow == 3:
        q_n = sd_cellcell(mesh, V, u_n, De, nexp)

    F = u * v * dx + dt * q_n * dot(grad(u),
                                    grad(v)) * dx - (u_n + dt * f) * v * dx
    a, L = lhs(F), rhs(F)

    # Solution and sediment flux
    u = Function(V)
    q_s = Expression('u0 + displ - u1',
                     u0=u_n,
                     displ=Constant(uamp * dt),
                     u1=u,
                     degree=2)

    # Iterate
    t = 0
    i = 0
    for n in range(num_steps):

        # This needs to become an option!
        # Double rain fall
        # if n == 501:
        #   alpha = 2
        #   De    = c*pow(alpha*ly,nexp)/kappa

        # Update current time
        t += dt

        # Compute solution
        solve(a == L, u, bc)

        # Calculate sediment flux
        sed_flux[i] = assemble(q_s * dx(mesh))
        time[i] = t
        i += 1

        # Update previous solution
        u_n.assign(u)

        # Update flux
        # 0 = MFD node-to-node; 1 = MFD cell-to-cell; 2 = SD node-to-node; 3 = SD cell-to-cell
        if flow == 0:
            q = mfd_nodenode(mesh, V, u_n, De, nexp)
        if flow == 1:
            q = mfd_cellcell(mesh, V, u_n, De, nexp)
        if flow == 2:
            q = sd_nodenode(mesh, V, u_n, De, nexp)
        if flow == 3:
            q = sd_cellcell(mesh, V, u_n, De, nexp)
        q_n.assign(q)

        # Output solutions
        if out_time != 0:
            if np.mod(n, out_time) == 0:
                filename = '%s/u_solution_%d.pvd' % (name, n)
                vtkfile = File(filename)
                vtkfile << u
                filename = '%s/q_solution_%d.pvd' % (name, n)
                vtkfile = File(filename)
                vtkfile << q

    # Post processing
    if plot != 0:
        plt.plot(time * 1e-6 * ly * ly / kappa,
                 sed_flux / dt * kappa,
                 'k',
                 linewidth=2)
        plt.xlabel('Time (Myr)')
        plt.ylabel('Sediment Flux (m^2/yr)')
        sedname = '%s/sed_flux_%d.svg' % (name, model_space[2])
        plt.savefig(sedname, format='svg')
        plt.clf()

    if out_time != 0:
        # Output last elevation
        filename = '%s/u_solution_%d_%d.pvd' % (name, model_space[2], n)
        vtkfile = File(filename)
        u.rename("elv", "elevation")
        vtkfile << u

        # Output last water flux
        filename = '%s/q_solution_%d_%d.pvd' % (name, model_space[2], n)
        vtkfile = File(filename)
        q.rename("flx", "flux")
        vtkfile << q

    # Calculate valley spacing from peak to peak in water flux
    tol = 0.001  # avoid hitting points outside the domain
    y = np.linspace(0 + tol, 1 - tol, 100)
    x = np.linspace(0.01, lx / ly - 0.01, 20)
    wavelength = np.zeros(len(x))
    if statistics != 0:
        i = 0
        for ix in x:
            points = [(ix, y_) for y_ in y]  # 2D points
            q_line = np.array([q(point) for point in points])

            indexes = peakutils.indexes(q_line, thres=0.05, min_dist=5)
            if len(indexes) > 1:
                wavelength[i] = sum(np.diff(y[indexes])) / (len(indexes) - 1)
            else:
                wavelength[i] = 0
        i += 1

        if plot != 0:
            plt.plot(y * 1e-3 * ly, q_line * kappa / ly, 'k', linewidth=2)
            plt.plot(y[indexes] * 1e-3 * ly, q_line[indexes] * kappa / ly,
                     '+r')
            plt.xlabel('Distance (km)')
            plt.ylabel('Water Flux (m/yr)')
            watername = '%s/water_flux_spacing_%d.svg' % (name, model_space[2])
            plt.savefig(watername, format='svg')
            plt.clf()

    return sed_flux, time, wavelength
Exemple #23
0
    def __init__(self,
                 mesh=None,
                 width=1.0,
                 dim=1,
                 nelements=8,
                 degree=2,
                 parameters={},
                 V=(lambda U: U),
                 U0=None,
                 rho0=None,
                 t0=0.0,
                 debug=False,
                 solver_type='gmres',
                 preconditioner_type='default',
                 periodic=False,
                 ligands=None):
        """Discontinuous Galerkin solver for the Keller-Segel PDE system

        Keyword parameters:
        mesh=None: the mesh on which to solve the problem
        width=1.0: the width of the domain
        dim=1: # of spatial dimensions.
        nelements=8: If mesh is not supplied, one will be
        contructed using UnitIntervalMesh, UnitSquareMesh, or
        UnitCubeMesh (depending on dim). dim and nelements are not
        needed if mesh is supplied.
        degree=2: degree of the polynomial approximation
        parameters={}: a dict giving the values of scalar parameters of
            .V, U0, and rho0 Expressions. This dict needs to also
            define numerical parameters that appear in the PDE. Some
            of these have defaults:
            dim = dim: # of spatial dimensions
            sigma: organism movement rate
            s: attractant secretion rate
            gamma: attractant decay rate
            D: attractant diffusion constant
            rho_min=10.0**-7: minimum feasible worm density
            U_min=10.0**-7: minimum feasible attractant concentration
            rhopen=10: penalty for discontinuities in rho
            Upen=1: penalty for discontinuities in U
            grhopen=1, gUpen=1: penalties for discontinuities in gradients
        V=(lambda U: U): a callable taking two numerical arguments, U
            and rho, or a single argument, U, and returning a single
            number, V, the potential corresponding to U. Use fenics
            versions of mathematical functions, e.g. ufl.ln, abs,
            ufl.exp.
        U0, rho0: Expressions, Functions, or strs specifying the
            initial condition.
        t0=0.0: initial time
        solver_type='gmres'
        preconditioner_type='default'
        periodic, ligands: ignored for caompatibility
        """
        logSOLVER('creating KSDGSolver')
        self.args = dict(mesh=mesh,
                         width=width,
                         dim=dim,
                         nelements=nelements,
                         degree=degree,
                         parameters=parameters,
                         V=V,
                         U0=U0,
                         rho0=rho0,
                         t0=t0,
                         debug=debug,
                         solver_type=solver_type,
                         preconditioner_type=preconditioner_type,
                         periodic=periodic,
                         ligands=ligands)
        self.debug = debug
        self.solver_type = solver_type
        self.preconditioner_type = preconditioner_type
        self.periodic = False
        self.ligands = ligands
        self.params = self.default_params.copy()
        if (mesh):
            self.omesh = self.mesh = mesh
        else:
            self.omesh = self.mesh = box_mesh(width=width,
                                              dim=dim,
                                              nelements=nelements)
            self.nelements = nelements
        logSOLVER('self.mesh', self.mesh)
        logSOLVER('self.mesh.mpi_comm().size', self.mesh.mpi_comm().size)
        self.nelements = nelements
        self.degree = degree
        self.dim = self.mesh.geometry().dim()
        self.params['dim'] = self.dim
        self.params.update(parameters)
        #
        # Solution spaces and Functions
        #
        fss = self.make_function_space()
        (self.SE, self.SS, self.VE,
         self.VS) = [fss[fs] for fs in ('SE', 'SS', 'VE', 'VS')]
        logSOLVER('self.VS', self.VS)
        self.sol = Function(self.VS)  # sol, current soln
        logSOLVER('self.sol', self.sol)
        self.srho, self.sU = self.sol.sub(0), self.sol.sub(1)
        self.irho, self.iU = fe.split(self.sol)
        self.wrho, self.wU = TestFunctions(self.VS)
        self.tdsol = TrialFunction(self.VS)
        self.tdrho, self.tdU = fe.split(self.tdsol)
        self.n = FacetNormal(self.mesh)
        self.h = CellDiameter(self.mesh)
        self.havg = fe.avg(self.h)
        self.dx = fe.dx
        #        self.dx = fe.dx(metadata={'quadrature_degree': min(degree, 10)})
        self.dS = fe.dS
        #        self.dS = fe.dS(metadata={'quadrature_degree': min(degree, 10)})
        #
        # record initial state
        #
        try:
            V(self.iU, self.irho)

            def realV(U, rho):
                return V(U, rho)
        except TypeError:

            def realV(U, rho):
                return V(U)

        self.V = realV
        if not U0:
            U0 = Constant(0.0)
        if isinstance(U0, ufl.coefficient.Coefficient):
            self.U0 = U0
        else:
            self.U0 = Expression(U0,
                                 **self.params,
                                 degree=self.degree,
                                 domain=self.mesh)
        if not rho0:
            rho0 = Constant(0.0)
        if isinstance(rho0, ufl.coefficient.Coefficient):
            self.rho0 = rho0
        else:
            self.rho0 = Expression(rho0,
                                   **self.params,
                                   degree=self.degree,
                                   domain=self.mesh)
        self.t0 = t0
        #
        # initialize state
        #
        # cache assigners
        logSOLVER('restarting')
        self.restart()
        logSOLVER('restart returned')
        return (None)
Exemple #24
0
def solid_problem(u_f, v_f, u_s, v_s,
                  fluid, solid, param, save = False):

    # Store old solutions
    u_s_n_K = Function(solid.V_split[0])
    v_s_n_K = Function(solid.V_split[1])
    u_s_n_K.assign(u_s.old)
    v_s_n_K.assign(v_s.old)
        
    # Store old boundary values
    v_s_n_i_K = Function(solid.V_split[1])
    v_s_n_i_K.assign(v_s.i_old)
    
    # Initialize interface values
    v_s_i = Function(solid.V_split[1])
    
    # Define Dirichlet boundary conditions
    bc_u_s_0 = DirichletBC(solid.V.sub(0), Constant(0.0), boundary)
    bc_v_s_0 = DirichletBC(solid.V.sub(1), Constant(0.0), boundary)
    bcs_s = [bc_u_s_0, bc_v_s_0]
            
    # Compute fractional steps for solid problem
    for k in range(param.K):
            
        # Update boundary values
        v_s_i.assign(project((param.K - k - 1.0)/param.K*v_s.i_old +
              + (k + 1.0)/param.K*fluid_to_solid(v_f.new,
              fluid, solid, param, 1), solid.V_split[1]))
                
        # Define trial and test functions
        U_s_new = TrialFunction(solid.V)
        (u_s_new, v_s_new) = split(U_s_new)
        Phi_s = TestFunction(solid.V)
        (phi_s, psi_s) = split(Phi_s)
                
        # Define scheme
        A_s = (v_s_new*phi_s*solid.dx
            + u_s_new*psi_s*solid.dx
            + 0.5*param.dt/param.K*a_s(u_s_new, v_s_new, phi_s, psi_s,
                                       solid, param))
        L_s = (v_s_n_K*phi_s*solid.dx 
            + u_s_n_K*psi_s*solid.dx 
            - 0.5*param.dt/param.K*a_s(u_s_n_K, v_s_n_K, phi_s, psi_s, 
                                       solid, param) 
            + 0.5*param.dt/param.K*param.nu*dot(grad(v_s_i), 
                                                solid.n)*phi_s*solid.ds 
            + 0.5*param.dt/param.K*param.nu*dot(grad(v_s_n_i_K),
                                                solid.n)*phi_s*solid.ds) 
                
        # Solve solid problem
        U_s_new = Function(solid.V)
        solve(A_s == L_s, U_s_new, bcs_s)
        (u_s_new, v_s_new) = U_s_new.split(U_s_new)
        
        # Append solutions to the arrays
        if save:
            
            u_s.array.append(u_s_new.copy(deepcopy = True))
            v_s.array.append(v_s_new.copy(deepcopy = True))
            
        # Update solid solution
        u_s_n_K.assign(u_s_new)
        v_s_n_K.assign(v_s_new)
                
        # Update boundary condition
        v_s_n_i_K.assign(project(v_s_i, solid.V_split[1]))
        
    # Save final values
    u_s.new.assign(u_s_new)
    v_s.new.assign(v_s_new)
    v_s.i_new.assign(v_s_i)
    
    return 
Exemple #25
0
def solve_linear_pde(
    u_D_array,
    T,
    D=1,
    C1=0,
    num_r=100,
    min_r=0.001,
    tol=1e-14,
    degree=1,
):
    # disable logging
    set_log_active(False)

    num_t = len(u_D_array)
    dt = T / num_t  # time step size

    mesh = IntervalMesh(num_r, min_r, 1)
    r = mesh.coordinates().flatten()
    r_args = np.argsort(r)
    V = FunctionSpace(mesh, "P", 1)

    # Define boundary conditions
    # Dirichlet condition at R
    def boundary_at_R(x, on_boundary):
        return on_boundary and near(x[0], 1, tol)

    D = Constant(D)
    u_D = Constant(u_D_array[0])
    bc_at_R = DirichletBC(V, u_D, boundary_at_R)

    # Define initial values for free c
    c_0 = Expression("C1", C1=C1, degree=degree)
    c_n = interpolate(c_0, V)

    # Define variational problem
    c = TrialFunction(V)
    v = TestFunction(V)

    # define Constants
    r_squ = Expression("4*pi*pow(x[0],2)", degree=degree)

    F_tmp = (D * dt * inner(grad(c), grad(v)) * r_squ * dx +
             c * v * r_squ * dx - c_n * v * r_squ * dx)
    a, L = lhs(F_tmp), rhs(F_tmp)
    u = Function(V)

    data_c = np.zeros((num_t, len(r)), dtype=np.double)

    for n in range(num_t):
        u_D.assign(u_D_array[n])

        # Compute solution
        solve(a == L, u, bc_at_R)
        data_c[n, :] = u.vector().vec().array

        c_n.assign(u)

    data_c = data_c[:, r_args[::-1]]
    r = r[r_args]

    return data_c, r
Exemple #26
0
    def __init__(
            self,
            mesh=None,
            width=1.0,
            dim=1,
            nelements=8,
            degree=2,
            parameters={},
            V=(lambda U: U),
            U0=None,
            rho0=None,
            t0=0.0,
            debug=False,
            solver_type = 'lu',
            preconditioner_type = 'default',
            periodic=True,
            ligands=None
            ):
        """DG solver for the periodic Keller-Segel PDE system

        Keyword parameters:
        mesh=None: the mesh on which to solve the problem
        width=1.0: the width of the domain
        dim=1: # of spatial dimensions.
        nelements=8: If mesh is not supplied, one will be
        contructed using UnitIntervalMesh, UnitSquareMesh, or
        UnitCubeMesh (depending on dim). dim and nelements are not
        needed if mesh is supplied.
        degree=2: degree of the polynomial approximation
        parameters={}: a dict giving the values of scalar parameters of
            .V, U0, and rho0 Expressions. This dict needs to also
            define numerical parameters that appear in the PDE. Some
            of these have defaults:
            dim = dim: # of spatial dimensions
            sigma: organism movement rate
            s: attractant secretion rate
            gamma: attractant decay rate
            D: attractant diffusion constant
            rho_min=10.0**-7: minimum feasible worm density
            U_min=10.0**-7: minimum feasible attractant concentration
            rhopen=10: penalty for discontinuities in rho
            Upen=1: penalty for discontinuities in U
            grhopen=1, gUpen=1: penalties for discontinuities in gradients
        V=(lambda U: U): a callable taking two numerical arguments, U
            and rho, or a single argument, U, and returning a single
            number, V, the potential corresponding to U. Use fenics
            versions of mathematical functions, e.g. fe.ln, abs,
            fe.exp.
        U0, rho0: Expressions, Functions, or strs specifying the
            initial condition.
        t0=0.0: initial time
        solver_type='lu'
        preconditioner_type='default'
        periodic=True: Allowed for compatibility, but ignored
        ligands=None: ignored for compatibility
        """
        logPERIODIC('creating KSDGSolverPeriodic')
        self.args = dict(
            mesh=mesh,
            width=width,
            dim=dim,
            nelements=nelements,
            degree=degree,
            parameters=parameters,
            V=V,
            U0=U0,
            rho0=rho0,
            t0=t0,
            debug=debug,
            solver_type = solver_type,
            preconditioner_type = preconditioner_type,
            periodic=True,
            ligands=ligands
        )
        self.debug = debug
        self.solver_type = solver_type
        self.preconditioner_type = preconditioner_type
        self.periodic = True
        self.params = self.default_params.copy()
        #
        # Store the original mesh in self.omesh. self.mesh will be the
        # corner mesh.
        #
        if (mesh):
            self.omesh = mesh
        else:
            self.omesh = box_mesh(width=width, dim=dim, nelements=nelements)
            self.nelements = nelements
        try:
            comm = self.omesh.mpi_comm().tompi4py()
        except AttributeError:
            comm = self.omesh.mpi_comm()
        self.lmesh = gather_mesh(self.omesh)
        omeshstats = mesh_stats(self.omesh)
        logPERIODIC('omeshstats', omeshstats)
        self.xmin = omeshstats['xmin']
        self.xmax = omeshstats['xmax']
        self.xmid = omeshstats['xmid']
        self.delta_ = omeshstats['dx']
        self.mesh = corner_submesh(self.lmesh)
        meshstats = mesh_stats(self.mesh)
        logPERIODIC('meshstats', meshstats)
        logPERIODIC('self.omesh', self.omesh)
        logPERIODIC('self.mesh', self.mesh)
        logPERIODIC('self.mesh.mpi_comm().size', self.mesh.mpi_comm().size)
        self.nelements = nelements
        self.degree = degree
        self.dim = self.mesh.geometry().dim()
        self.params['dim'] = self.dim
        self.params.update(parameters)
        # 
        # Solution spaces and Functions
        #
        # The solution function space is a vector space with
        # 2*(2**dim) elements. The first 2**dim components are even
        # and odd parts of rho; These are followed by even and
        # odd parts of U. The array self.evenodd identifies even
        # and odd components. Each row is a length dim sequence 0s and
        # 1s and represnts one component. For instance, if evenodd[i]
        # is [0, 1, 0], then component i of the vector space is even
        # in dimensions 0 and 2 (x and z conventionally) and off in
        # dimension 1 (y).
        #
        self.symmetries = evenodd_symmetries(self.dim)
        self.signs = [fe.as_matrix(np.diagflat(1.0 - 2.0*eo))
                      for eo in self.symmetries]
        self.eomat = evenodd_matrix(self.symmetries)
        fss = self.make_function_space()
        (self.SE, self.SS, self.VE, self.VS) = [
            fss[fs] for fs in ('SE', 'SS', 'VE', 'VS')
        ]
        (self.SE, self.SS, self.VE, self.VS) = self.make_function_space()
        self.sol = Function(self.VS)                  # sol, current soln
        logPERIODIC('self.sol', self.sol)
        # srhos and sUs are fcuntions defiend on subspaces
        self.srhos = self.sol.split()[:2**self.dim]
        self.sUs = self.sol.split()[2**self.dim:]
        # irhos and iUs are Indexed UFL expressions
        self.irhos = fe.split(self.sol)[:2**self.dim]
        self.iUs = fe.split(self.sol)[2**self.dim:]
        self.wrhos = TestFunctions(self.VS)[: 2**self.dim]
        self.wUs = TestFunctions(self.VS)[2**self.dim :]
        self.tdsol = TrialFunction(self.VS) # time derivatives
        self.tdrhos = fe.split(self.tdsol)[: 2**self.dim]
        self.tdUs = fe.split(self.tdsol)[2**self.dim :]
        bc_method = 'geometric' if self.dim > 1 else 'pointwise'
        rhobcs = [DirichletBC(
            self.VS.sub(i),
            Constant(0),
            FacesDomain(self.mesh, self.symmetries[i]),
            method=bc_method
        ) for i in range(2**self.dim) if np.any(self.symmetries[i] != 0.0)]
        Ubcs = [DirichletBC(
            self.VS.sub(i + 2**self.dim),
            Constant(0),
            FacesDomain(self.mesh, self.symmetries[i]),
            method=bc_method
        ) for i in range(2**self.dim)  if np.any(self.symmetries[i] != 0.0)]
        self.bcs = rhobcs + Ubcs
        self.n = FacetNormal(self.mesh)
        self.h = CellDiameter(self.mesh)
        self.havg = fe.avg(self.h)
        self.dx = fe.dx
        self.dS = fe.dS
        #
        # record initial state
        #
        if not U0:
            U0 = Constant(0.0)
        if isinstance(U0, ufl.coefficient.Coefficient):
            self.U0 = U0
        else:
            self.U0 = Expression(U0, **self.params,
                                 degree=self.degree, domain=self.mesh)
        if not rho0:
            rho0 = Constant(0.0)
        if isinstance(rho0, ufl.coefficient.Coefficient):
            self.rho0 = rho0
        else:
            self.rho0 = Expression(rho0, **self.params,
                                   degree=self.degree, domain=self.mesh)
        try:
            V(self.U0, self.rho0)
            def realV(U, rho):
                return V(U, rho)
        except TypeError:
            def realV(U, rho):
                return V(U)
        self.V = realV
        self.t0 = t0
        #
        # initialize state
        #
        # cache assigners
        logPERIODIC('restarting')
        self.restart()
        logPERIODIC('restart returned')
        return(None)
    def compute_potential_flow(self):

        class Hole(SubDomain):
            def inside(s, x, on_boundary):
                return on_boundary and self.boundary_fnc(x)

        #class ActiveArea(SubDomain):
        #    def inside(self, x, on_boundary):
        #        return between(x[0], (0., 0.1)) and between(x[1], (0, 0.2))

        # Initialize sub-domain instances
        hole = Hole()
        # self.activate = ActiveArea()

        # Initialize mesh function for interior domains
        self.domains = MeshFunction("size_t", self.mesh, 2)
        self.domains.set_all(0)
        # self.activate.mark(self.domains, 1)

        # Initialize mesh function for boundary domains
        self.boundaries = MeshFunction("size_t", self.mesh, 1)
        self.boundaries.set_all(0)
        hole.mark(self.boundaries, 1)

        # Define new measures associated with the interior domains and
        # exterior boundaries

        self.dx = Measure('dx', domain=self.mesh, subdomain_data=self.domains)
        self.ds = Measure('ds', domain=self.mesh, subdomain_data=self.boundaries)

        dx, ds = self.dx, self.ds

        # Define function space and basis functions
        V = FunctionSpace(self.mesh, "P", 1)
        self.V_vel = V
        phi = TrialFunction(V)  # potential
        v = TestFunction(V)

        # Define Dirichlet boundary conditions at top and bottom boundaries
        bcs = [fe.DirichletBC(V, 0.0, self.boundaries, 1)]

        # Define input data
        a0 = fe.Constant(1.0)
        a1 = fe.Constant(0.01)
        f_water = fe.Constant(self.water_in_flux)

        # Define the reaction equation

        # Define variational form
        F_pot = inner(a0 * grad(phi), grad(v)) * dx - f_water * v * dx

        # Separate left and right hand sides of equation
        a, L = fe.lhs(F_pot), fe.rhs(F_pot)

        # Solve problem
        phi = fe.Function(V)
        fe.solve(a == L, phi, bcs)

        # Evaluate integral of normal gradient over top boundary
        n = fe.FacetNormal(self.mesh)
        result_flux = fe.assemble(dot(grad(phi), n) * ds(1))

        # test conservation of water
        expected_flux = -self.water_in_flux * fe.assemble(1 * dx)

        print("relative error of conservation of water %f" % ((result_flux - expected_flux) / expected_flux))

        self.phi = phi
        self.flow = -grad(phi)

        # Save result
        output = fe.File("/tmp/potential.pvd")
        output << self.phi
Exemple #28
0
def fluid_problem(u_f, v_f, u_s, v_s, fluid, solid, param, t, save=False):

    # Store old solutions
    u_f_n_M = Function(fluid.V_split[0])
    v_f_n_M = Function(fluid.V_split[1])
    u_f_n_M.assign(u_f.old)
    v_f_n_M.assign(v_f.old)

    # Store old boundary values
    u_f_n_i_M = Function(fluid.V_split[0])
    v_f_n_i_M = Function(fluid.V_split[1])
    u_f_n_i_M.assign(u_f.i_old)
    v_f_n_i_M.assign(v_f.i_old)

    # Initialize interface values
    u_f_i = Function(fluid.V_split[0])
    v_f_i = Function(fluid.V_split[1])

    # Define Dirichlet boundary conditions
    bc_u_f_0 = DirichletBC(fluid.V.sub(0), Constant(0.0), boundary)
    bc_v_f_0 = DirichletBC(fluid.V.sub(1), Constant(0.0), boundary)
    bcs_f = [bc_u_f_0, bc_v_f_0]

    # Compute fractional steps for fluid problem
    for m in range(param.M):

        # Update boundary values
        u_f_i.assign(
            project((param.M - m - 1.0) / param.M * u_f.i_old + (m + 1.0) /
                    param.M * solid_to_fluid(u_s.new, fluid, solid, param, 0),
                    fluid.V_split[0]))
        v_f_i.assign(
            project((param.M - m - 1.0) / param.M * v_f.i_old + (m + 1.0) /
                    param.M * solid_to_fluid(v_s.new, fluid, solid, param, 1),
                    fluid.V_split[1]))

        # Define trial and test functions
        U_f_new = TrialFunction(fluid.V)
        (u_f_new, v_f_new) = split(U_f_new)
        Phi_f = TestFunction(fluid.V)
        (phi_f, psi_f) = split(Phi_f)

        # Define scheme
        A_f = (v_f_new * phi_f * fluid.dx + 0.5 * param.dt / param.M *
               a_f(u_f_new, v_f_new, phi_f, psi_f, fluid, param))
        L_f = (v_f_n_M * phi_f * fluid.dx - 0.5 * param.dt / param.M *
               a_f(u_f_n_M, v_f_n_M, phi_f, psi_f, fluid, param) +
               0.5 * param.dt / param.M * param.gamma / fluid.h * u_f_i *
               psi_f * fluid.ds + 0.5 * param.dt / param.M * param.gamma /
               fluid.h * v_f_i * phi_f * fluid.ds + 0.5 * param.dt / param.M *
               param.gamma / fluid.h * u_f_n_i_M * psi_f * fluid.ds +
               0.5 * param.dt / param.M * param.gamma / fluid.h * v_f_n_i_M *
               phi_f * fluid.ds + param.dt / param.M * f(t) * phi_f * fluid.dx)

        # Solve fluid problem
        U_f_new = Function(fluid.V)
        solve(A_f == L_f, U_f_new, bcs_f)
        (u_f_new, v_f_new) = U_f_new.split(U_f_new)

        # Append solutions to the arrays
        if save:

            u_f.array.append(u_f_new.copy(deepcopy=True))
            v_f.array.append(v_f_new.copy(deepcopy=True))

        # Update fluid solution
        u_f_n_M.assign(u_f_new)
        v_f_n_M.assign(v_f_new)

        # Update boundary conditions
        u_f_n_i_M.assign(project(u_f_i, fluid.V_split[0]))
        v_f_n_i_M.assign(project(v_f_i, fluid.V_split[1]))

    # Save final values
    u_f.new.assign(u_f_new)
    v_f.new.assign(v_f_new)
    u_f.i_new.assign(u_f_i)
    v_f.i_new.assign(v_f_i)

    return
Exemple #29
0
def leapfrog(A, f, ah, bh, k, T):
    """Leapfrog time-stepper.

    Abstract problem:

        u'' + Au = f,  u(0) = ah, u'(0) = bh

    Args:
        A (Function -> Function -> Form): Possibly nonlinear functional A(u, v)
        f (float -> Function): Right-hand side
        ah (Function): Initial value
        bh (Function): Initial velocity
        k (float): Time step
        T (float): Max time

    Returns:
        list(float): Times
        list(Function): Solution at each time
    """
    # pylint: disable=invalid-name, too-many-arguments, too-many-locals
    # Basic setup
    V = ah.function_space()
    u = TrialFunction(V)
    v = TestFunction(V)
    # Prepare initial condition
    u0 = Function(V)
    u0.vector()[:] = ah.vector()
    u1 = Function(V)
    u1.vector()[:] = ah.vector() + k * bh.vector()
    # Initialize time stepper
    t = k
    u2 = Function(V)
    u2.vector()[:] = u1.vector()
    ts = [0, t]
    uh = [interpolate(u0, V), interpolate(u1, V)]
    progress = -1
    print("Progress: ", end="")
    while t < T:
        # Print progress
        pct = int(t / T * 100) // 10 * 10
        if pct > progress:
            print("{}%..".format(pct), end="")
            progress = pct
        # Solve
        lhs = dot(u, v) * dx
        rhs = (dot(2 * u1 - u0, v) + k * k * (f(t, v) - A(u1, v))) * dx
        problem = LinearVariationalProblem(lhs, rhs, u2)
        solver = LinearVariationalSolver(problem)
        solver.parameters["linear_solver"] = "cg"
        solver.parameters["preconditioner"] = "hypre_amg"
        try:
            solver.solve()
        except RuntimeError:
            print("blowup at t={}.".format(t))
            return (ts, uh)
        # Update
        t += k
        u0.vector()[:] = u1.vector()
        u1.vector()[:] = u2.vector()
        # Record result
        ts.append(t)
        uh.append(interpolate(u1, V))
    print("done")
    return (ts, uh)
    def compute_static_deformation(self):

        assert self.mesh is not None

        # now we define subdomains on the mesh

        bottom = fe.CompiledSubDomain('near(x[2], 0) && on_boundary')
        top = fe.CompiledSubDomain('near(x[2], 1) && on_boundary')
        # middle = fe.CompiledSubDomain('x[2] > 0.3 && x[2] < 0.7')

        # Initialize mesh function for interior domains
        self.domains = fe.MeshFunction('size_t', self.mesh, 3)
        self.domains.set_all(0)
        # middle.mark(self.domains, 1)

        # Initialize mesh function for boundary domains
        self.boundaries = fe.MeshFunction('size_t', self.mesh, 2)
        self.boundaries.set_all(0)
        bottom.mark(self.boundaries, 1)
        top.mark(self.boundaries, 2)

        # Define new measures associated with the interior domains and
        # exterior boundaries

        self.dx = fe.Measure('dx',
                             domain=self.mesh,
                             subdomain_data=self.domains)
        self.ds = fe.Measure('ds',
                             domain=self.mesh,
                             subdomain_data=self.boundaries)

        # define function spaces
        V = fe.VectorFunctionSpace(self.mesh, "Lagrange", 1)
        # now we define subdomains on the mesh

        bottom = fe.CompiledSubDomain('near(x[2], 0) && on_boundary')
        top = fe.CompiledSubDomain('near(x[2], 1) && on_boundary')
        # middle = fe.CompiledSubDomain('x[2] > 0.3 && x[2] < 0.7')

        d = self.mesh.geometry().dim()

        # Initialize mesh function for interior domains
        self.domains = fe.MeshFunction('size_t', self.mesh, d)
        self.domains.set_all(0)
        # middle.mark(self.domains, 1)

        # Initialize mesh function for boundary domains
        self.boundaries = fe.MeshFunction('size_t', self.mesh, d - 1)
        self.boundaries.set_all(0)
        bottom.mark(self.boundaries, 1)
        top.mark(self.boundaries, 2)

        # Define new measures associated with the interior domains and
        # exterior boundaries

        self.dx = fe.Measure('dx',
                             domain=self.mesh,
                             subdomain_data=self.domains)
        self.ds = fe.Measure('ds',
                             domain=self.mesh,
                             subdomain_data=self.boundaries)

        c_zero = fe.Constant((0, 0, 0))

        # define boundary conditions
        bc_bottom = fe.DirichletBC(V, c_zero, bottom)
        bc_top = fe.DirichletBC(V, c_zero, top)

        bcs = [bc_bottom]  # , bc_top]

        # define functions
        du = TrialFunction(V)
        v = TestFunction(V)
        u = Function(V)
        B = fe.Constant((0., 2.0, 0.))
        T = fe.Constant((0.0, 0.0, 0.0))

        d = u.geometric_dimension()
        I = fe.Identity(d)
        F = I + grad(u)
        C = F.T * F

        I_1 = tr(C)
        J = det(F)

        E, mu = 10., 0.3
        mu, lmbda = fe.Constant(E / (2 * (1 + mu))), fe.Constant(
            E * mu / ((1 + mu) * (1 - 2 * mu)))

        # stored energy (comp. neo-hookean model)
        psi = (mu / 2.) * (I_1 - 3) - mu * fe.ln(J) + (lmbda /
                                                       2.) * (fe.ln(J))**2

        dx = self.dx
        ds = self.ds

        Pi = psi * fe.dx - dot(B, u) * fe.dx - dot(T, u) * fe.ds

        F = fe.derivative(Pi, u, v)
        J = fe.derivative(F, u, du)

        fe.solve(F == 0, u, bcs, J=J)

        # save results
        self.u = u

        # write to disk
        output = fe.File("/tmp/static.pvd")
        output << u