Beispiel #1
0
 def construct_variation_problem(self) -> Tuple[Form, Form]:
     p = self.params
     u_t = (p.T - p.T_prev) / p.dt
     f = p.Q_pc + p.Q_sw + p.Q_mm
     F = p.P_s * p.c_s * u_t * p.v * dx + p.k_e * dot(grad(p.T), grad(
         p.v)) * dx - f * p.v * dx
     return lhs(F), rhs(F)
Beispiel #2
0
def solver(f, u_D, bc_funs, ndim, length, nx, ny, nz=None, degree=1):
    """Fenics 求解器

    Args:
        f (Expression): [description]
        u_D (Expression): [description]
        bc_funs (List[Callable]): [description]
        ndim (int): [description]
        length (float): [description]
        nx (int): [description]
        ny (int): [description]
        nz (int, optional): [description]. Defaults to None.
        degree (int, optional): [description]. Defaults to 1.

    Returns:
        Function: 解 u
    """

    mesh = get_mesh(length, nx, ny, nz)
    V = fs.FunctionSpace(mesh, "P", degree)
    bcs = [fs.DirichletBC(V, u_D, bc) for bc in bc_funs]
    u = fs.TrialFunction(V)
    v = fs.TestFunction(V)
    FF = fs.dot(fs.grad(u), fs.grad(v)) * fs.dx - f * v * fs.dx
    a = fs.lhs(FF)
    L = fs.rhs(FF)
    u = fs.Function(V)
    fs.solve(a == L, u, bcs)
    return u
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() 
Beispiel #4
0
 def geneForwardMatrix(self, q_fun=fe.Constant(0.0), fR=fe.Constant(0.0), \
                       fI=fe.Constant(0.0)):
     if self.haveFunctionSpace == False:
         self.geneFunctionSpace()
         
     xx, yy, dPML, sig0_, p_ = self.domain.xx, self.domain.yy, self.domain.dPML,\
                               self.domain.sig0, self.domain.p
     # define the coefficents induced by PML
     sig1 = fe.Expression('x[0] > x1 && x[0] < x1 + dd ? sig0*pow((x[0]-x1)/dd, p) : (x[0] < 0 && x[0] > -dd ? sig0*pow((-x[0])/dd, p) : 0)', 
                  degree=3, x1=xx, dd=dPML, sig0=sig0_, p=p_)
     sig2 = fe.Expression('x[1] > x2 && x[1] < x2 + dd ? sig0*pow((x[1]-x2)/dd, p) : (x[1] < 0 && x[1] > -dd ? sig0*pow((-x[1])/dd, p) : 0)', 
                  degree=3, x2=yy, dd=dPML, sig0=sig0_, p=p_)
     
     sR = fe.as_matrix([[(1+sig1*sig2)/(1+sig1*sig1), 0.0], [0.0, (1+sig1*sig2)/(1+sig2*sig2)]])
     sI = fe.as_matrix([[(sig2-sig1)/(1+sig1*sig1), 0.0], [0.0, (sig1-sig2)/(1+sig2*sig2)]])
     cR = 1 - sig1*sig2
     cI = sig1 + sig2
     
     # define the coefficients with physical meaning
     angl_fre = self.kappa*np.pi
     angl_fre2 = fe.Constant(angl_fre*angl_fre)
     
     # define equations
     u_ = fe.TestFunction(self.V)
     du = fe.TrialFunction(self.V)
     
     u_R, u_I = fe.split(u_)
     duR, duI = fe.split(du)
     
     def sigR(v):
         return fe.dot(sR, fe.nabla_grad(v))
     def sigI(v):
         return fe.dot(sI, fe.nabla_grad(v))
     
     F1 = - fe.inner(sigR(duR)-sigI(duI), fe.nabla_grad(u_R))*(fe.dx) \
         - fe.inner(sigR(duI)+sigI(duR), fe.nabla_grad(u_I))*(fe.dx) \
         - fR*u_R*(fe.dx) - fI*u_I*(fe.dx)
     
     a2 = fe.inner(angl_fre2*q_fun*(cR*duR-cI*duI), u_R)*(fe.dx) \
          + fe.inner(angl_fre2*q_fun*(cR*duI+cI*duR), u_I)*(fe.dx) \
     
     # define boundary conditions
     def boundary(x, on_boundary):
         return on_boundary
     
     bc = [fe.DirichletBC(self.V.sub(0), fe.Constant(0.0), boundary), \
           fe.DirichletBC(self.V.sub(1), fe.Constant(0.0), boundary)]
     
     a1, L1 = fe.lhs(F1), fe.rhs(F1)
     self.u = fe.Function(self.V)
     self.A1 = fe.assemble(a1)
     self.b1 = fe.assemble(L1)
     self.A2 = fe.assemble(a2)
     bc[0].apply(self.A1, self.b1)
     bc[1].apply(self.A1, self.b1)
     bc[0].apply(self.A2)
     bc[1].apply(self.A2)
     self.A = self.A1 + self.A2
 def construct_variation_problem(self) -> Tuple[Form, Form]:
     p = self.params
     ds = self.make_ds(p.mesh)
     u_t = (p.u - p.P_prev) / p.dt
     term = p.alpha_th * p.u * p.P_d * (p.my_v + p.my_d)**2 / (
         (p.P_prev + p.P_d) * p.my_v * p.my_d) / p.T_s * grad(p.T_s)
     F = p.theta_a * u_t * p.v * dx + p.theta_a * p.D_e * dot(
         grad(p.u) - term, grad(
             p.v)) * dx - p.M_mm * p.v * dx + p.q_h * p.v * ds(1)
     return lhs(F), rhs(F)
Beispiel #6
0
    def xest_second_tutorial(self):
        T = 2.0  # final time
        num_steps = 50  # number of time steps
        dt = T / num_steps  # time step size
        # Create mesh and define function space
        nx = ny = 30
        mesh = fenics.RectangleMesh(fenics.Point(-2, -2), fenics.Point(2, 2),
                                    nx, ny)
        V = fenics.FunctionSpace(mesh, 'P', 1)

        # Define boundary condition
        def boundary(x, on_boundary):
            return on_boundary

        bc = fenics.DirichletBC(V, fenics.Constant(0), boundary)
        # Define initial value
        u_0 = fenics.Expression('exp(-a*pow(x[0], 2) - a*pow(x[1], 2))',
                                degree=2,
                                a=5)
        u_n = fenics.interpolate(u_0, V)
        # Define variational problem
        u = fenics.TrialFunction(V)
        v = fenics.TestFunction(V)
        f = fenics.Constant(0)
        F = u * v * fenics.dx + dt * fenics.dot(fenics.grad(u), fenics.grad(
            v)) * fenics.dx - (u_n + dt * f) * v * fenics.dx
        a, L = fenics.lhs(F), fenics.rhs(F)
        # Create VTK file for saving solution
        vtkfile = fenics.File(
            os.path.join(os.path.dirname(__file__), 'output', 'heat_gaussian',
                         'solution.pvd'))
        # Time-stepping
        u = fenics.Function(V)
        t = 0
        not_initialised = True
        for n in range(num_steps):
            # Update current time
            t += dt
            # Compute solution
            fenics.solve(a == L, u, bc)
            # Save to file and plot solution
            vtkfile << (u, t)
            # Here we'll need to call tripcolor ourselves to get access to the color range
            fenics.plot(u)
            animation_camera.snap()
            u_n.assign(u)
        animation = animation_camera.animate()
        animation.save(
            os.path.join(os.path.dirname(__file__), 'output',
                         'heat_gaussian.mp4'))
    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
Beispiel #8
0
def integrate(system_matrix, field, bcs):
    """Integrates the equation"""
    left_side, right_side = fe.lhs(system_matrix), fe.rhs(system_matrix)
    fe.solve(left_side == right_side, field, bcs)
    if ARGS['--verbose']:
        print('Checking periodicity:')
        print('Value at XMIN:',
              field(XMIN, (YMIN + YMAX) / 3, (ZMIN + ZMAX) / 3))
        print('Value at XMAX:',
              field(XMAX, (YMIN + YMAX) / 3, (ZMIN + ZMAX) / 3))
        print('Value at YMIN:',
              field((XMIN + XMAX) / 3, YMIN, (ZMIN + ZMAX) / 3))
        print('Value at YMAX:',
              field((XMIN + XMAX) / 3, YMAX, (ZMIN + ZMAX) / 3))
        print('Value at ZMIN:',
              field((XMIN + XMAX) / 3, (YMIN + YMAX) / 3, ZMIN))
        print('Value at ZMAX:',
              field((XMIN + XMAX) / 3, (YMIN + YMAX) / 3, ZMAX))
    return field
Beispiel #9
0
def solver_linear(G, d_, w_, wd_, bcs, T, dt, action=None, **namespace):
    a = lhs(G); L = rhs(G)
    A = assemble(a)
    b = assemble(L)
    t = 0

    #d_prec = PETScPreconditioner("default")
    #d_solver = PETScKrylovSolver("gmres", d_prec)
    #d_solver.parameters["monitor_convergence"] = True
    #from IPython import embed; embed()
    #d_solver.prec = d_prec

    # Solver loop
    while t < (T - dt*DOLFIN_EPS):
        t += dt

        # Assemble
        assemble(a, tensor=A)
        assemble(L, tensor=b)

        # Apply BC
        for bc in bcs: bc.apply(A, b)

        # Solve
        #d_solver.solve(A, wd_["n"].vector(), b)
        solve(A, wd_["n"].vector(), b)

        # Update solution
        times = ["n-3", "n-2", "n-1", "n"]
        for i, t_tmp in enumerate(times[:-1]):
            wd_[t_tmp].vector().zero()
            wd_[t_tmp].vector().axpy(1, wd_[times[i+1]].vector())

        # Get displacement
        if callable(action):
            action(wd_, t)

        if MPI.rank(mpi_comm_world()) == 0:
            print "Time: ",t
Beispiel #10
0
    def xest_first_tutorial(self):
        T = 2.0  # final time
        num_steps = 10  # number of time steps
        dt = T / num_steps  # time step size
        alpha = 3  # parameter alpha
        beta = 1.2  # parameter beta
        # Create mesh and define function space
        nx = ny = 8
        mesh = fenics.UnitSquareMesh(nx, ny)
        V = fenics.FunctionSpace(mesh, 'P', 1)
        # Define boundary condition
        u_D = fenics.Expression('1 + x[0]*x[0] + alpha*x[1]*x[1] + beta*t',
                                degree=2,
                                alpha=alpha,
                                beta=beta,
                                t=0)

        def boundary(x, on_boundary):
            return on_boundary

        bc = fenics.DirichletBC(V, u_D, boundary)
        # Define initial value
        u_n = fenics.interpolate(u_D, V)  #u_n = project(u_D, V)
        # Define variational problem
        u = fenics.TrialFunction(V)
        v = fenics.TestFunction(V)
        f = fenics.Constant(beta - 2 - 2 * alpha)
        F = u * v * fenics.dx + dt * fenics.dot(fenics.grad(u), fenics.grad(
            v)) * fenics.dx - (u_n + dt * f) * v * fenics.dx
        a, L = fenics.lhs(F), fenics.rhs(F)
        # Time-stepping
        u = fenics.Function(V)
        t = 0
        vtkfile = fenics.File(
            os.path.join(os.path.dirname(__file__), 'output',
                         'heat_constructed_solution', 'solution.pvd'))
        not_initialised = True
        for n in range(num_steps):
            # Update current time
            t += dt
            u_D.t = t
            # Compute solution
            fenics.solve(a == L, u, bc)
            # Plot the solution
            vtkfile << (u, t)
            fenics.plot(u)
            if not_initialised:
                animation_camera = celluloid.Camera(plt.gcf())
                not_initialised = False
            animation_camera.snap()
            # Compute error at vertices
            u_e = fenics.interpolate(u_D, V)
            error = np.abs(u_e.vector().get_local() -
                           u.vector().get_local()).max()
            print('t = %.2f: error = %.3g' % (t, error))
            # Update previous solution
            u_n.assign(u)
            # Hold plot

        animation = animation_camera.animate()
        animation.save(
            os.path.join(os.path.dirname(__file__), 'output',
                         'heat_equation.mp4'))
def solve_heat_with_fem(lightweight=False):
    T = 2.0  # final time
    num_steps = 100  # number of time steps
    dt = T / num_steps  # time step size
    alpha = 3  # parameter alpha
    beta = 1.2  # parameter beta

    # Create mesh and define function space
    nx = ny = 8
    mesh = fs.UnitSquareMesh(nx, ny)
    V = fs.FunctionSpace(mesh, 'P', 1)

    # Define boundary condition
    u_D = fs.Expression('1 + x[0]*x[0] + alpha*x[1]*x[1] + beta*t',
                        degree=2,
                        alpha=alpha,
                        beta=beta,
                        t=0)

    bc = fs.DirichletBC(V, u_D, boundary)

    # Define initial value
    u_n = fs.interpolate(u_D, V)
    # u_n = project(u_D, V)

    # Define variational problem
    u = fs.TrialFunction(V)
    v = fs.TestFunction(V)
    f = fs.Constant(beta - 2 - 2 * alpha)

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

    # Time-stepping
    u = fs.Function(V)
    t = 0

    images1d = []

    for n in range(num_steps):
        # Update current time
        t += dt
        u_D.t = t

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

        # Restore numpy object
        image1d = np.empty((81, ), dtype=np.float)
        for v in fs.vertices(mesh):
            image1d[v.index()] = u(*mesh.coordinates()[v.index()])

        images1d.append(image1d)

        if not lightweight:
            # Compute error at vertices
            u_e = fs.interpolate(u_D, V)
            error = np.abs(u_e.vector().get_local() -
                           u.vector().get_local()).max()
            print('t = %.2f: error = %.3g' % (t, error))

        # Update previous solution
        u_n.assign(u)

    # Plotting
    if not lightweight:
        fs.plot(u)
        plt.show()
        save_dynamic_contours(images1d, 1.0, 1.0, 'heat2d')

    return images1d
Beispiel #12
0
def half_exp_dyn(w0, dt=1.e-5, t_end=1.e-4, show_plots=False):

    u0 = w0.u
    p0 = w0.p
    v0 = w0.v

    bcs_u, bcs_p, bcs_v = load_2d_muscle_bc(V_u, V_pv.sub(0), V_pv.sub(1),
                                            boundaries)

    F = deformation_grad(u0)
    I_1, I_2, J = invariants(F)
    F_iso = isochronic_deformation_grad(F, J)
    #I_1_iso, I_2_iso  = invariants(F_iso)[0:2]
    W = material_mooney_rivlin(I_1, I_2, c_10, c_01)
    g = incompr_constr(J)
    # Lagrange function (without constraint)
    L = -W
    P = first_piola_stress(L, F)
    G = incompr_stress(g, F)

    # a_dyn_u = inner(u1 - u0, eta) * dx - dt * inner(v1, eta) * dx

    u1 = fe.TrialFunction(V_u)
    eta = fe.TestFunction(V_u)

    #u11 = fe.Function(V_u)
    #F1 = deformation_grad(u11)
    #g1 = incompr_constr(fe.det(F1))
    #G1 = incompr_stress(g1, F1)

    (p1, v1) = fe.TrialFunctions(V_pv)
    (q, xi) = fe.TestFunctions(V_pv)

    a_dyn_u = inner(u1 - u0, eta) * dx - dt * inner(v0, eta) * dx

    a_dyn_p = fe.tr(G * grad(v1)) * q * dx
    #a_dyn_v = rho*inner(v1-v0, xi)*dx + dt*(inner(P + p0*G, grad(xi))*dx - inner(B, xi)*dx)
    a_dyn_v = rho * inner(v1 - v0, xi) * dx + dt * (inner(
        P, grad(xi)) * dx + inner(p1 * G, grad(xi)) * dx - inner(B, xi) * dx)

    a_u = fe.lhs(a_dyn_u)
    l_u = fe.rhs(a_dyn_u)

    a_pv = fe.lhs(a_dyn_p + a_dyn_v)
    l_pv = fe.rhs(a_dyn_p + a_dyn_v)

    u1 = fe.Function(V_u)
    pv1 = fe.Function(V_pv)

    sol = []

    vol = fe.assemble(1. * dx)

    A_u = fe.assemble(a_u)
    A_pv = fe.assemble(a_pv)

    for bc in bcs_u:
        bc.apply(A_u)

    t = 0
    while t < t_end:
        print("progress: %f" % (100. * t / t_end))

        # update displacement u
        L_u = fe.assemble(l_u)
        fe.solve(A_u, u1.vector(), L_u)
        u0.assign(u1)

        L_pv = fe.assemble(l_pv)
        for bc in bcs_p + bcs_v:
            bc.apply(A_pv, L_pv)

        fe.solve(A_pv, pv1.vector(), L_pv)

        if fe.norm(pv1.vector()) > 1e8:
            print('ERROR: norm explosion')
            break

        # update initial values for next step
        w0.u = u1
        w0.pv = pv1
        p0.assign(w0.p)
        v0.assign(w0.v)

        t += dt

        if show_plots:
            # plot result
            fe.plot(w0.sub(0), mode='displacement')
            plt.show()

        # save solutions
        sol.append(Solution(t=t))
        sol[-1].upv.assign(w0)

    return sol, W
Beispiel #13
0
    # Update (u_old <- u)
    v_old.vector()[:], a_old.vector()[:] = v_vec, a_vec
    u_old.vector()[:] = u.vector()


#Tiempos intermedio entre tn y tn+1 utilizando modelo alfa generalizado
def avg(x_old, x_new, alpha):
    return alpha * x_old + (1 - alpha) * x_new


#Formulación variacional
a_new = update_a(du, u_old, v_old, a_old, ufl=True)
v_new = update_v(a_new, u_old, v_old, a_old, ufl=True)
res = m(avg(a_old, a_new, alpha_m), w) + c(avg(v_old, v_new, alpha_f), w) + k(
    avg(u_old, du, alpha_f), w) - Wext(w)
a_form = fnc.lhs(res)
L_form = fnc.rhs(res)

#Solvers (veremos luego)
K, res = fnc.assemble_system(a_form, L_form, bc)
solver = fnc.LUSolver(K, 'default')  #"mumps")
solver.parameters["symmetric"] = True

# We now initiate the time stepping loop. We will keep track of the beam vertical tip
# displacement over time as well as the different parts of the system total energy. We
# will also compute the stress field and save it, along with the displacement field, in
# a ``XDMFFile``.
# The option `flush_ouput` enables to open the result file before the loop is finished,
# the ``function_share_mesh`` option tells that only one mesh is used for all functions
# of a given time step (displacement and stress) while the ``rewrite_function_mesh`` enforces
# that the same mesh is used for all time steps. These two options enables writing the mesh
    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
Beispiel #15
0
 def F(self, new_equation):
     self.LHS = FEN.lhs(new_equation)
     self.RHS = FEN.rhs(new_equation)
Beispiel #16
0
    # assign u->u_old
    v_old.vector()[:], a_old.vector()[:] = v_vec, a_vec
    u_old.vector()[:] = u.vector()


def avg(x_old, x_new, alpha):
    return alpha * x_old + (1 - alpha) * x_new


# residual
a_np1 = update_a(du, u_n, v_n, a_n, ufl=True)
v_np1 = update_v(a_np1, u_n, v_n, a_n, ufl=True)

res = m(avg(a_n, a_np1, alpha_m), v) + k(avg(u_n, du, alpha_f), v)

a_form = lhs(res)
L_form = rhs(res)

# parameters for Time-Stepping
t = 0.0
n = 0
E_ext = 0

displacement_out = File("output/u_fsi.pvd")

u_n.rename("Displacement", "")
u_np1.rename("Displacement", "")
displacement_out << u_n

while precice.is_coupling_ongoing():
Beispiel #17
0
def main():
    """Main function. Organizes workflow."""
    fname = str(INPUTS['filename'])
    term = Terminal()
    print(term.yellow + "Working on file {}.".format(fname) + term.normal)
    # Load mesh and physical domains from file.
    mesh = fe.Mesh(fname + ".xml")
    if INPUTS['saving']['mesh']:
        fe.File(fname + "_mesh.pvd") << mesh
    if INPUTS['plotting']['mesh']:
        fe.plot(mesh, title='Mesh')
    subdomains = fe.MeshFunction('size_t', mesh,
                                 fname + '_physical_region.xml')
    if INPUTS['saving']['subdomains']:
        fe.File(fname + "_subdomains.pvd") << subdomains
    if INPUTS['plotting']['subdomains']:
        fe.plot(subdomains, title='Subdomains')
    # function space for temperature/concentration
    func_space = fe.FunctionSpace(mesh,
                                  INPUTS['element_type'],
                                  INPUTS['element_degree'],
                                  constrained_domain=PeriodicDomain())
    # discontinuous function space for visualization
    dis_func_space = fe.FunctionSpace(mesh,
                                      'DG',
                                      INPUTS['element_degree'],
                                      constrained_domain=PeriodicDomain())
    if ARGS['--verbose']:
        print('Number of cells:', mesh.num_cells())
        print('Number of faces:', mesh.num_faces())
        print('Number of edges:', mesh.num_edges())
        print('Number of vertices:', mesh.num_vertices())
        print('Number of DOFs:', len(func_space.dofmap().dofs()))
    # temperature/concentration field
    field = fe.TrialFunction(func_space)
    # test function
    test_func = fe.TestFunction(func_space)
    # function, which is equal to 1 everywhere
    unit_function = fe.Function(func_space)
    unit_function.assign(fe.Constant(1.0))
    # assign material properties to each domain
    if INPUTS['mode'] == 'conductivity':
        mat_prop = SubdomainConstant(
            subdomains,
            fe.Constant(INPUTS['conductivity']['gas']),
            fe.Constant(INPUTS['conductivity']['solid']),
            degree=0)
    elif INPUTS['mode'] == 'diffusivity':
        mat_prop = SubdomainConstant(
            subdomains,
            fe.Constant(INPUTS['diffusivity']['gas']),
            fe.Constant(INPUTS['diffusivity']['solid']) * fe.Constant(
                INPUTS['solubility'] * gas_constant * INPUTS['temperature']),
            degree=0)
    # assign 1 to gas domain, and 0 to solid domain
    gas_content = SubdomainConstant(subdomains,
                                    fe.Constant(1.0),
                                    fe.Constant(0.0),
                                    degree=0)
    # define structure of foam over whole domain
    structure = fe.project(unit_function * gas_content, dis_func_space)
    # calculate porosity and wall thickness
    porosity = fe.assemble(structure * fe.dx) / ((XMAX - XMIN) *
                                                 (YMAX - YMIN) * (ZMAX - ZMIN))
    print('Porosity: {0}'.format(porosity))
    dwall = wall_thickness(porosity, INPUTS['morphology']['cell_size'],
                           INPUTS['morphology']['strut_content'])
    print('Wall thickness: {0} m'.format(dwall))
    # calculate effective conductivity/diffusivity by analytical model
    if INPUTS['mode'] == 'conductivity':
        eff_prop = analytical_conductivity(
            INPUTS['conductivity']['gas'], INPUTS['conductivity']['solid'],
            porosity, INPUTS['morphology']['strut_content'])
        print('Analytical model: {0} W/(mK)'.format(eff_prop))
    elif INPUTS['mode'] == 'diffusivity':
        eff_prop = analytical_diffusivity(
            INPUTS['diffusivity']['solid'] * INPUTS['solubility'],
            INPUTS['solubility'], porosity, INPUTS['morphology']['cell_size'],
            dwall, INPUTS['temperature'],
            INPUTS['morphology']['enhancement_par'])
        print('Analytical model: {0} m^2/s'.format(eff_prop))
    # create system matrix
    system_matrix = -mat_prop * \
        fe.inner(fe.grad(field), fe.grad(test_func)) * fe.dx
    left_side, right_side = fe.lhs(system_matrix), fe.rhs(system_matrix)
    # define boundary conditions
    bcs = [
        fe.DirichletBC(func_space,
                       fe.Constant(INPUTS['boundary_conditions']['top']),
                       top_bc),
        fe.DirichletBC(func_space,
                       fe.Constant(INPUTS['boundary_conditions']['bottom']),
                       bottom_bc)
    ]
    # compute solution
    field = fe.Function(func_space)
    fe.solve(left_side == right_side, field, bcs)
    # output temperature/concentration at the boundaries
    if ARGS['--verbose']:
        print('Checking periodicity:')
        print('Value at XMIN:',
              field(XMIN, (YMIN + YMAX) / 3, (ZMIN + ZMAX) / 3))
        print('Value at XMAX:',
              field(XMAX, (YMIN + YMAX) / 3, (ZMIN + ZMAX) / 3))
        print('Value at YMIN:',
              field((XMIN + XMAX) / 3, YMIN, (ZMIN + ZMAX) / 3))
        print('Value at YMAX:',
              field((XMIN + XMAX) / 3, YMAX, (ZMIN + ZMAX) / 3))
        print('Value at ZMIN:',
              field((XMIN + XMAX) / 3, (YMIN + YMAX) / 3, ZMIN))
        print('Value at ZMAX:',
              field((XMIN + XMAX) / 3, (YMIN + YMAX) / 3, ZMAX))
    # calculate flux, and effective properties
    vec_func_space = fe.VectorFunctionSpace(mesh, INPUTS['element_type'],
                                            INPUTS['element_degree'])
    flux = fe.project(-mat_prop * fe.grad(field), vec_func_space)
    divergence = fe.project(-fe.div(mat_prop * fe.grad(field)), func_space)
    flux_x, flux_y, flux_z = flux.split()
    av_flux = fe.assemble(flux_z * fe.dx) / ((XMAX - XMIN) * (YMAX - YMIN))
    eff_prop = av_flux * (ZMAX -
                          ZMIN) / (INPUTS['boundary_conditions']['top'] -
                                   INPUTS['boundary_conditions']['bottom'])
    if INPUTS['mode'] == 'conductivity':
        print('Numerical model: {0} W/(mK)'.format(eff_prop))
    elif INPUTS['mode'] == 'diffusivity':
        print('Numerical model: {0} m^2/s'.format(eff_prop))
    # projection of concentration has to be in discontinuous function space
    if INPUTS['mode'] == 'diffusivity':
        sol_field = SubdomainConstant(
            subdomains,
            fe.Constant(1.0),
            fe.Constant(INPUTS['solubility'] * gas_constant *
                        INPUTS['temperature']),
            degree=0)
        field = fe.project(field * sol_field, dis_func_space)
    # save results
    with open(fname + "_eff_prop.csv", 'w') as textfile:
        textfile.write('eff_prop\n')
        textfile.write('{0}\n'.format(eff_prop))
    fe.File(fname + "_solution.pvd") << field
    fe.File(fname + "_structure.pvd") << structure
    if INPUTS['saving']['flux']:
        fe.File(fname + "_flux.pvd") << flux
    if INPUTS['saving']['flux_divergence']:
        fe.File(fname + "_flux_divergence.pvd") << divergence
    if INPUTS['saving']['flux_components']:
        fe.File(fname + "_flux_x.pvd") << flux_x
        fe.File(fname + "_flux_y.pvd") << flux_y
        fe.File(fname + "_flux_z.pvd") << flux_z
    # plot results
    if INPUTS['plotting']['solution']:
        fe.plot(field, title="Solution")
    if INPUTS['plotting']['flux']:
        fe.plot(flux, title="Flux")
    if INPUTS['plotting']['flux_divergence']:
        fe.plot(divergence, title="Divergence")
    if INPUTS['plotting']['flux_components']:
        fe.plot(flux_x, title='x-component of flux (-kappa*grad(u))')
        fe.plot(flux_y, title='y-component of flux (-kappa*grad(u))')
        fe.plot(flux_z, title='z-component of flux (-kappa*grad(u))')
    if True in INPUTS['plotting'].values():
        fe.interactive()
    print(term.yellow + "End." + term.normal)
Beispiel #18
0
def boundary(x, on_boundary):
    return on_boundary

bc = fs.DirichletBC(V, u_D, boundary)

# Define initial value
u_0 = fs.Expression('exp(-a * pow(x[0], 2) - a * pow(x[1], 2))', degree=2, a=5)
u_n = fs.interpolate(u_0, V)

# Define variational problem
u = fs.TrialFunction(V)
v = fs.TestFunction(V)
f = fs.Constant(0)

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

# Create VTK file for saving solution
vtkfile = fs.File('heat_gaussian/solution.pvd')

# Time-stepping
u = fs.Function(V)
t = 0
for n in range(num_steps):

    # Update current time
    t += dt

    # Compute solution
    fs.solve(a == L, u, bc)
    def compute_conv_diff_reac(self, initial_condition=None):

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

        dt = 0.1
        t = 0.
        t_end = 1.

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

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

        if initial_condition is None:
            initial_condition = Expression(("exp(-((x[0]-0.1)*(x[0]-0.1)+x[1]*x[1])/0.01)",
                                            "exp(-((x[0]-0.12)*(x[0]-0.12)+x[1]*x[1])/0.01)",
                                            "0."), element=element)

        u_init = fe.interpolate(initial_condition, V)
        u_init_cl = u_init[0]
        u_init_na = u_init[1]
        u_init_k = u_init[2]

        assert (self.flow is not None)

        n = fe.FacetNormal(self.mesh)

        dx, ds = self.dx, self.ds
        flow = 10 * self.flow
        f_in = fe.Constant(0.00)
        D = fe.Constant(0.01)
        k1 = fe.Constant(0.1)
        k_1 = fe.Constant(0.001)
        F = (
                (u_cl - u_init_cl) * v_cl * dx
                + dt * D * inner(grad(u_cl), grad(v_cl)) * dx
                + dt * inner(flow, grad(u_cl)) * v_cl * dx
                + (u_na - u_init_na) * v_na * dx
                + dt * D * inner(grad(u_na), grad(v_na)) * dx
                + dt * inner(flow, grad(u_na)) * v_na * dx
                + (u_k - u_init_k) * v_k * dx
                + dt * D * inner(grad(u_k), grad(v_k)) * dx
                + dt * inner(flow, grad(u_k)) * v_k * dx
                + f_in * v_cl * dx
                + f_in * v_na * dx
                + f_in * v_k * dx
                + dt * k1 * u_init_cl * u_init_na * v_cl * dx
                + dt * k1 * u_init_cl * u_init_na * v_na * dx
                - dt * k1 * u_init_cl * u_init_na * v_k * dx
                - dt * k_1 * u_init_k * v_cl * dx
                - dt * k_1 * u_init_k * v_na * dx
                + dt * k_1 * u_init_k * v_k * dx
        )

        self.F = F

        a, L = fe.lhs(F), fe.rhs(F)
        a_mat = fe.assemble(a)
        L_vec = fe.assemble(L)

        output1 = fe.File('/tmp/cl_dyn.pvd')
        output2 = fe.File('/tmp/na_dyn.pvd')
        output3 = fe.File('/tmp/k_dyn.pvd')
        output4 = fe.File('/tmp/all_dyn.pvd')
        # solve

        self.sol = []

        while t < t_end:
            t = t + dt
            print(t)

            u = Function(V)

            a_mat = fe.assemble(a)
            L_vec = fe.assemble(L)
            fe.solve(a_mat, u.vector(), L_vec)
            # NonlinearVariationalProblem(F,u)
            u_init.assign(u)

            u_cl, u_na, u_k = u.split()

            # u_init_cl.assign(u_cl)
            # u_init_na.assign(u_na)
            # u_init_k.assign(u_k)

            u_cl.rename("cl", "cl")
            u_na.rename("na", "na")
            u_k.rename("k", "k")
            output1 << u_cl, t
            output2 << u_na, t
            output3 << u_k, t
            self.sol.append((u_cl, u_na, u_k))



        self.u_cl = u_cl
        self.u_na = u_na
        self.u_k = u_k
Beispiel #20
0
    # The forcing on the rhs of the PDE
    heat_source = fe.Constant(0.0)

    # Create the Finite Element Problem
    u_trial = fe.TrialFunction(lagrange_polynomial_space_first_order)
    v_test = fe.TestFunction(lagrange_polynomial_space_first_order)

    weak_form_residuum = (u_trial * v_test * fe.dx + time_step_length * fe.dot(
        fe.grad(u_trial),
        fe.grad(v_test),
    ) * fe.dx - (u_old * v_test * fe.dx +
                 time_step_length * heat_source * v_test * fe.dx))

    # We have a linear PDE that is separable into a lhs and rhs
    weak_form_lhs = fe.lhs(weak_form_residuum)
    weak_form_rhs = fe.rhs(weak_form_residuum)

    # The function we will be solving for at each point in time
    u_solution = fe.Function(lagrange_polynomial_space_first_order)

    # time stepping
    n_time_steps = 5

    time_current = 0.0
    for i in range(n_time_steps):
        time_current += time_step_length

        # Finite Element Assembly, BC imprint & solving the linear system
        fe.solve(
            weak_form_lhs == weak_form_rhs,
Beispiel #21
0
def boundary(x, on_boundary):
    return on_boundary


bc = fex.DirichletBC(V, u_D, on_boundary)

u_n = project(u_D, V)
u_n = interpolate(u_D < V)

u = fex.TrialFunction(V)
v = fex.TestFunctin(V)
f = fex.Constant(beta - 2 - 2 * alpha)

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

u = fex.Function(V)
t = 0
for n in range(num_steps):

    #Update current time
    t += dt
    u_D.t = t

    #Solve variational problem
    fex.solve(a == L, u, bc)

    #Update previous solution
    u_n.assign(u)
Beispiel #22
0
    def solve_cell_problems(self, method='regularized', plot=False):
        """
        Solve the cell problems for the given PDE by changing the geometry to exclude the zone in the middle
        :return:
        """
        class PeriodicBoundary(fe.SubDomain):

            # Left boundary is "target domain" G
            def inside(self, x, on_boundary):
                par = MembraneSimulator.w / MembraneSimulator.length
                tol = 1E-4
                return on_boundary and x[1] >= -tol and x[1] <= tol

            # Map right boundary (H) to left boundary (G)
            def map(self, x, y):
                y[1] = x[1] + 2 * self.eta / MembraneSimulator.length
                y[0] = x[0]

        mesh_size = 50
        # Domain

        if method == 'circle':
            self.obstacle_radius = self.eta / MembraneSimulator.length / 2
            box_begin_point = fe.Point(-self.w / MembraneSimulator.length, 0)
            box_end_point = fe.Point(self.w / MembraneSimulator.length,
                                     2 * self.eta / MembraneSimulator.length)
            box = mshr.Rectangle(box_begin_point, box_end_point)
            cell = box - mshr.Circle(
                fe.Point(0, self.eta / MembraneSimulator.length),
                self.obstacle_radius, mesh_size)
            self.cell_mesh = mshr.generate_mesh(cell, mesh_size)
            diff_coef = fe.Constant(
                ((0, 0), (0, self.D[1, 1])))  # limit for regularisation below.
        # elif method == 'diff_coef':
        #     print("Haha this is going to crash. Also it is horrible in accuracy")
        #     self.cell_mesh = fe.RectangleMesh(fe.Point(-self.w / MembraneSimulator.length, 0),
        #                                       fe.Point(self.w / MembraneSimulator.length,
        #                                                2 * self.eta / MembraneSimulator.length), mesh_size, mesh_size)
        #     diff_coef = fe.Expression(
        #         (('0', '0'), ('0', 'val * ((x[0] - c_x)*(x[0] - c_x) + (x[1] - c_y)*(x[1] - c_y) > r*r)')),
        #         val=(4 * self.ref_T * MembraneSimulator.d2 / MembraneSimulator.length ** 2), c_x=0,
        #         c_y=(self.eta / MembraneSimulator.length),
        #         r=self.obstacle_radius, degree=2, domain=self.cell_mesh)
        elif method == 'regularized':
            box_begin_point = fe.Point(-self.w / MembraneSimulator.length, 0)
            box_end_point = fe.Point(self.w / MembraneSimulator.length,
                                     2 * self.eta / MembraneSimulator.length)
            box = mshr.Rectangle(box_begin_point, box_end_point)
            obstacle_begin_point = fe.Point(
                -self.w / MembraneSimulator.length * self.obs_length,
                self.eta / MembraneSimulator.length * (1 - self.obs_height))
            obstacle_end_point = fe.Point(
                self.w / MembraneSimulator.length * self.obs_length,
                self.eta / MembraneSimulator.length * (1 + self.obs_height))
            obstacle = mshr.Rectangle(obstacle_begin_point, obstacle_end_point)
            cell = box - obstacle
            self.cell_mesh = mshr.generate_mesh(cell, mesh_size)
            diff_coef = fe.Constant(((self.obs_ratio * self.D[0, 0], 0),
                                     (0, self.D[1, 1])))  # defect matrix.
        else:
            raise ValueError("%s not a valid method to solve cell problem" %
                             method)
        self.cell_fs = fe.FunctionSpace(self.cell_mesh, 'P', 2)
        self.cell_solutions = [
            fe.Function(self.cell_fs),
            fe.Function(self.cell_fs)
        ]
        w = fe.TrialFunction(self.cell_fs)
        phi = fe.TestFunction(self.cell_fs)
        scaled_unit_vectors = [
            fe.Constant((1. / np.sqrt(self.obs_ratio), 0.)),
            fe.Constant((0., 1.))
        ]
        for i in range(2):
            weak_form = fe.dot(
                diff_coef *
                (fe.grad(w) + scaled_unit_vectors[i]), fe.grad(phi)) * fe.dx
            print("Solving cell problem")
            bc = fe.DirichletBC(self.cell_fs, fe.Constant(0),
                                MembraneSimulator.cell_boundary)
            if i == 0:
                # Periodicity is applied automatically
                bc = None
            fe.solve(
                fe.lhs(weak_form) == fe.rhs(weak_form), self.cell_solutions[i],
                bc)
            if plot:
                plt.rc('text', usetex=True)
                f = fe.plot(self.cell_solutions[i])
                plt.colorbar(f)
                plt.title(r'Solution to cell problem $w_%d$' % (i + 1))
                plt.xlabel(r'$Y_1$')
                plt.ylabel(r'$Y_2$')
                print("Cell solution")
                print(np.min(self.cell_solutions[i].vector().get_local()),
                      np.max(self.cell_solutions[i].vector().get_local()))
                plt.show()
Beispiel #23
0
# Define strain-rate tensor
def epsilon(u):
    return fs.sym(fs.nabla_grad(u))

# Define stress tensor
def sigma(u, p):
    return 2*mu*epsilon(u) - p*fs.Identity(len(u))

# Define variational problem for step 1 (Tentative velocity step)
F1 = rho*fs.dot((u - u_n) / k, v)*fs.dx + \
    rho*fs.dot(fs.dot(u_n, fs.nabla_grad(u_n)), v)*fs.dx \
  + fs.inner(sigma(U, p_n), epsilon(v))*fs.dx \
  + fs.dot(p_n*n, v)*fs.ds - fs.dot(mu*fs.nabla_grad(U)*n, v)*fs.ds \
  - fs.dot(f, v)*fs.dx
a1 = fs.lhs(F1)
L1 = fs.rhs(F1)

# Define variational problem for step 2 (Pressure correction step)
a2 = fs.dot(fs.nabla_grad(p),   fs.nabla_grad(q))*fs.dx
L2 = fs.dot(fs.nabla_grad(p_n), fs.nabla_grad(q))*fs.dx \
        - (1/k)*fs.div(u_)*q*fs.dx

# Define variational problem for step 3 (Velocity correction step)
a3 = fs.dot(u,  v)*fs.dx
L3 = fs.dot(u_, v)*fs.dx - k*fs.dot(fs.nabla_grad(p_ - p_n), v)*fs.dx

# Assemble matrices
A1 = fs.assemble(a1)
A2 = fs.assemble(a2)
A3 = fs.assemble(a3)
Beispiel #24
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
Beispiel #25
0
def main():
    """Main function. Organizes workflow."""
    fname = str(INPUTS['filename'])
    term = Terminal()
    print(
        term.yellow
        + "Working on file {}.".format(fname)
        + term.normal
    )
    # Load mesh and physical domains from file.
    mesh = fe.Mesh(fname + ".xml")
    if INPUTS['saving']['mesh']:
        fe.File(fname + "_mesh.pvd") << mesh
    if INPUTS['plotting']['mesh']:
        fe.plot(mesh, title='Mesh')
    subdomains = fe.MeshFunction(
        'size_t', mesh, fname + '_physical_region.xml')
    if INPUTS['saving']['subdomains']:
        fe.File(fname + "_subdomains.pvd") << subdomains
    if INPUTS['plotting']['subdomains']:
        fe.plot(subdomains, title='Subdomains')
    # function space for temperature/concentration
    func_space = fe.FunctionSpace(
        mesh,
        INPUTS['element_type'],
        INPUTS['element_degree'],
        constrained_domain=PeriodicDomain()
    )
    # discontinuous function space for visualization
    dis_func_space = fe.FunctionSpace(
        mesh,
        'DG',
        INPUTS['element_degree'],
        constrained_domain=PeriodicDomain()
    )
    if ARGS['--verbose']:
        print('Number of cells:', mesh.num_cells())
        print('Number of faces:', mesh.num_faces())
        print('Number of edges:', mesh.num_edges())
        print('Number of vertices:', mesh.num_vertices())
        print('Number of DOFs:', len(func_space.dofmap().dofs()))
    # temperature/concentration field
    field = fe.TrialFunction(func_space)
    # test function
    test_func = fe.TestFunction(func_space)
    # function, which is equal to 1 everywhere
    unit_function = fe.Function(func_space)
    unit_function.assign(fe.Constant(1.0))
    # assign material properties to each domain
    if INPUTS['mode'] == 'conductivity':
        mat_prop = SubdomainConstant(
            subdomains,
            fe.Constant(INPUTS['conductivity']['gas']),
            fe.Constant(INPUTS['conductivity']['solid']),
            degree=0
        )
    elif INPUTS['mode'] == 'diffusivity':
        mat_prop = SubdomainConstant(
            subdomains,
            fe.Constant(INPUTS['diffusivity']['gas']),
            fe.Constant(INPUTS['diffusivity']['solid']) *
            fe.Constant(INPUTS['solubility'] *
                        gas_constant * INPUTS['temperature']),
            degree=0
        )
    # assign 1 to gas domain, and 0 to solid domain
    gas_content = SubdomainConstant(
        subdomains,
        fe.Constant(1.0),
        fe.Constant(0.0),
        degree=0
    )
    # define structure of foam over whole domain
    structure = fe.project(unit_function * gas_content, dis_func_space)
    # calculate porosity and wall thickness
    porosity = fe.assemble(structure *
                           fe.dx) / ((XMAX - XMIN) * (YMAX - YMIN) * (ZMAX - ZMIN))
    print('Porosity: {0}'.format(porosity))
    dwall = wall_thickness(
        porosity, INPUTS['morphology']['cell_size'],
        INPUTS['morphology']['strut_content'])
    print('Wall thickness: {0} m'.format(dwall))
    # calculate effective conductivity/diffusivity by analytical model
    if INPUTS['mode'] == 'conductivity':
        eff_prop = analytical_conductivity(
            INPUTS['conductivity']['gas'], INPUTS['conductivity']['solid'],
            porosity, INPUTS['morphology']['strut_content'])
        print('Analytical model: {0} W/(mK)'.format(eff_prop))
    elif INPUTS['mode'] == 'diffusivity':
        eff_prop = analytical_diffusivity(
            INPUTS['diffusivity']['solid'] *
            INPUTS['solubility'], INPUTS['solubility'],
            porosity, INPUTS['morphology']['cell_size'], dwall,
            INPUTS['temperature'], INPUTS['morphology']['enhancement_par'])
        print('Analytical model: {0} m^2/s'.format(eff_prop))
    # create system matrix
    system_matrix = -mat_prop * \
        fe.inner(fe.grad(field), fe.grad(test_func)) * fe.dx
    left_side, right_side = fe.lhs(system_matrix), fe.rhs(system_matrix)
    # define boundary conditions
    bcs = [
        fe.DirichletBC(func_space, fe.Constant(
            INPUTS['boundary_conditions']['top']), top_bc),
        fe.DirichletBC(func_space, fe.Constant(
            INPUTS['boundary_conditions']['bottom']), bottom_bc)
    ]
    # compute solution
    field = fe.Function(func_space)
    fe.solve(left_side == right_side, field, bcs)
    # output temperature/concentration at the boundaries
    if ARGS['--verbose']:
        print('Checking periodicity:')
        print('Value at XMIN:', field(XMIN, (YMIN + YMAX) / 3, (ZMIN + ZMAX) / 3))
        print('Value at XMAX:', field(XMAX, (YMIN + YMAX) / 3, (ZMIN + ZMAX) / 3))
        print('Value at YMIN:', field((XMIN + XMAX) / 3, YMIN, (ZMIN + ZMAX) / 3))
        print('Value at YMAX:', field((XMIN + XMAX) / 3, YMAX, (ZMIN + ZMAX) / 3))
        print('Value at ZMIN:', field((XMIN + XMAX) / 3, (YMIN + YMAX) / 3, ZMIN))
        print('Value at ZMAX:', field((XMIN + XMAX) / 3, (YMIN + YMAX) / 3, ZMAX))
    # calculate flux, and effective properties
    vec_func_space = fe.VectorFunctionSpace(
        mesh,
        INPUTS['element_type'],
        INPUTS['element_degree']
    )
    flux = fe.project(-mat_prop * fe.grad(field), vec_func_space)
    divergence = fe.project(-fe.div(mat_prop * fe.grad(field)), func_space)
    flux_x, flux_y, flux_z = flux.split()
    av_flux = fe.assemble(flux_z * fe.dx) / ((XMAX - XMIN) * (YMAX - YMIN))
    eff_prop = av_flux * (ZMAX - ZMIN) / (
        INPUTS['boundary_conditions']['top']
        - INPUTS['boundary_conditions']['bottom']
    )
    if INPUTS['mode'] == 'conductivity':
        print('Numerical model: {0} W/(mK)'.format(eff_prop))
    elif INPUTS['mode'] == 'diffusivity':
        print('Numerical model: {0} m^2/s'.format(eff_prop))
    # projection of concentration has to be in discontinuous function space
    if INPUTS['mode'] == 'diffusivity':
        sol_field = SubdomainConstant(
            subdomains,
            fe.Constant(1.0),
            fe.Constant(INPUTS['solubility'] *
                        gas_constant * INPUTS['temperature']),
            degree=0
        )
        field = fe.project(field * sol_field, dis_func_space)
    # save results
    with open(fname + "_eff_prop.csv", 'w') as textfile:
        textfile.write('eff_prop\n')
        textfile.write('{0}\n'.format(eff_prop))
    fe.File(fname + "_solution.pvd") << field
    fe.File(fname + "_structure.pvd") << structure
    if INPUTS['saving']['flux']:
        fe.File(fname + "_flux.pvd") << flux
    if INPUTS['saving']['flux_divergence']:
        fe.File(fname + "_flux_divergence.pvd") << divergence
    if INPUTS['saving']['flux_components']:
        fe.File(fname + "_flux_x.pvd") << flux_x
        fe.File(fname + "_flux_y.pvd") << flux_y
        fe.File(fname + "_flux_z.pvd") << flux_z
    # plot results
    if INPUTS['plotting']['solution']:
        fe.plot(field, title="Solution")
    if INPUTS['plotting']['flux']:
        fe.plot(flux, title="Flux")
    if INPUTS['plotting']['flux_divergence']:
        fe.plot(divergence, title="Divergence")
    if INPUTS['plotting']['flux_components']:
        fe.plot(flux_x, title='x-component of flux (-kappa*grad(u))')
        fe.plot(flux_y, title='y-component of flux (-kappa*grad(u))')
        fe.plot(flux_z, title='z-component of flux (-kappa*grad(u))')
    if True in INPUTS['plotting'].values():
        fe.interactive()
    print(
        term.yellow
        + "End."
        + term.normal
    )
    def compute_conv_diff_reac_video(self, initial_condition=None, video_ref=None, video_size=None):

        names = {'Cl', 'K'}


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

        # load video
        video = VideoData(element=P1)
        video.load_video(self.video_filename)

        if( video_ref is not None and video_size is not None):
            video.set_reference_frame(video_ref, video_size)


        print(video)

        dt = 0.05
        t = 0.
        t_end = 20.

        u_init = Function(V)
        (u_cl, u_k) = TrialFunction(V)
        (v_cl, v_k) = TestFunction(V)

        #u_na = video


        if initial_condition is None:
            #initial_condition = Expression(("f*exp(-0.5*((x[0]-a)*(x[0]-a)+(x[1]-b)*(x[1]-b))/var)/(sqrt(2*pi)*var)",
            #                                "0."), a = 80, b= 55, var=10, f=10, pi=fe.pi, element=element)

            initial_condition = Expression(("f",
                                            "0."), a=80, b=55, var=0.1, f=0.1, pi=fe.pi, element=element)

        u_init = fe.interpolate(initial_condition, V)
        u_init_cl = u_init[0]

        u_init_k = u_init[1]
        u_init_na : VideoData= video

        assert (self.flow is not None)

        n = fe.FacetNormal(self.mesh)

        dx, ds = self.dx, self.ds
        flow = 5. * self.flow
        f_in = fe.Constant(0.00)
        f_in_cl = fe.Constant(-0.05)
        D = fe.Constant(0.1)

        C_na = fe.Constant(0.1)
        k1 = fe.Constant(0.2)
        k_1 = fe.Constant(0.00001)
        # explicit
        F = (
                (u_cl - u_init_cl) * v_cl * dx
                + dt * D * inner(grad(u_cl), grad(v_cl)) * dx
                + dt * inner(flow, grad(u_cl)) * v_cl * dx
                #+ (u_na - u_init_na) * v_na * dx
                #+ dt * D * inner(grad(u_na), grad(v_na)) * dx
                #+ dt * inner(flow, grad(u_na)) * v_na * dx
                + (u_k - u_init_k) * v_k * dx
                + dt * D * inner(grad(u_k), grad(v_k)) * dx
                + dt * inner(flow, grad(u_k)) * v_k * dx
                + f_in_cl * v_cl * dx
                #+ f_in * v_na * dx
                + f_in * v_k * dx
                + dt * k1 * u_init_cl * C_na * u_init_na * v_cl * dx
                #+ dt * k1 * u_init_cl * u_init_na * v_na * dx
                - dt * k1 * u_init_cl * C_na * u_init_na * v_k * dx
                - dt * k_1 * u_init_k * v_cl * dx
                #- dt * k_1 * u_init_k * v_na * dx
                + dt * k_1 * u_init_k * v_k * dx
        )
        # implicit
        F = (
                (u_cl - u_init_cl) * v_cl * dx
                + dt * D * inner(grad(u_cl), grad(v_cl)) * dx
                + dt * inner(flow, grad(u_cl)) * v_cl * dx
                # + (u_na - u_init_na) * v_na * dx
                # + dt * D * inner(grad(u_na), grad(v_na)) * dx
                # + dt * inner(flow, grad(u_na)) * v_na * dx
                + (u_k - u_init_k) * v_k * dx
                + dt * D * inner(grad(u_k), grad(v_k)) * dx
                + dt * inner(flow, grad(u_k)) * v_k * dx
                + f_in_cl * v_cl * dx
                # + f_in * v_na * dx
                + f_in * v_k * dx
                + dt * k1 * u_cl * C_na * u_init_na * v_cl * dx
                # + dt * k1 * u_init_cl * u_init_na * v_na * dx
                - dt * k1 * u_cl * C_na * u_init_na * v_k * dx
                - dt * k_1 * u_k * v_cl * dx
                # - dt * k_1 * u_init_k * v_na * dx
                + dt * k_1 * u_k * v_k * dx
        )

        self.F = F

        a, L = fe.lhs(F), fe.rhs(F)
        a_mat = fe.assemble(a)
        L_vec = fe.assemble(L)

        output1 = fe.File('/tmp/cl_dyn.pvd')
        output2 = fe.File('/tmp/na_dyn.pvd')
        output3 = fe.File('/tmp/k_dyn.pvd')
        output4 = fe.File('/tmp/all_dyn.pvd')
        # solve

        self.sol = []

        u_na = Function(V_single)
        u_na = fe.interpolate(u_init_na,V_single)

        na_inflow = 0

        t_plot = 0.5
        t_last_plot = 0

        while t < t_end:
            t = t + dt
            t_last_plot += dt
            print(t)

            u = Function(V)

            u_init_na.set_time(5*t)

            a_mat = fe.assemble(a)
            L_vec = fe.assemble(L)
            fe.solve(a_mat, u.vector(), L_vec)
            # NonlinearVariationalProblem(F,u)
            u_init.assign(u)

            u_cl, u_k = u.split()

            # u_init_cl.assign(u_cl)
            # u_init_na.assign(u_na)
            # u_init_k.assign(u_k)

            u_na = fe.interpolate(u_init_na, V_single)

            u_cl.rename("cl", "cl")
            u_na.rename("na", "na")
            u_k.rename("k", "k")
            output1 << u_cl, t
            output2 << u_na, t
            output3 << u_k, t
            self.sol.append((u_cl, u_na, u_k))

            print( fe.assemble(u_cl*self.dx))

            if t_last_plot > t_plot:
                t_last_plot = 0
                plt.figure(figsize=(8,16))
                plt.subplot(211)
                fe.plot(u_cl)
                plt.subplot(212)
                fe.plot(u_k)
                plt.show()



        self.u_cl = u_cl
        #self.u_na = u_na
        self.u_k = u_k
Beispiel #27
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
Beispiel #28
0
def explicit_relax_dyn(w0, kappa=1e5, dt=1.e-5, t_end=1.e-4, show_plots=False):

    (u0, p0, v0) = fe.split(w0)

    bcs_u, bcs_p, bcs_v = load_2d_muscle_bc(V_upv.sub(0), V_upv.sub(1),
                                            V_upv.sub(2), boundaries)

    kappa = fe.Constant(kappa)

    F = deformation_grad(u0)
    I_1, I_2, J = invariants(F)
    F_iso = isochronic_deformation_grad(F, J)
    #I_1_iso, I_2_iso  = invariants(F_iso)[0:2]

    W = material_mooney_rivlin(I_1, I_2, c_10, c_01) + incompr_relaxation(
        p0, kappa)
    g = incompr_constr(J)

    # Lagrange function (without constraint)

    L = -W
    P = first_piola_stress(L, F)
    G = incompr_stress(g, F)

    (u1, p1, v1) = fe.TrialFunctions(V_upv)
    (eta, q, xi) = fe.TestFunctions(V_upv)
    a_dyn_u = inner(u1 - u0, eta) * dx - dt * inner(v1, eta) * dx
    a_dyn_p = (p1 - p0) * q * dx - dt * kappa * div(v1) * J * q * dx
    #a_dyn_v = rho*inner(v1-v0, xi)*dx + dt*(inner(P + p0*G, grad(xi))*dx - inner(B, xi)*dx)
    a_dyn_v = rho * inner(v1 - v0, xi) * dx + dt * (inner(
        P, grad(xi)) * dx + inner(p0 * G, grad(xi)) * dx - inner(B, xi) * dx)

    a = fe.lhs(a_dyn_u + a_dyn_p + a_dyn_v)
    l = fe.rhs(a_dyn_u + a_dyn_p + a_dyn_v)

    w1 = fe.Function(V_upv)
    w2 = fe.Function(V_upv)

    sol = []

    vol = fe.assemble(1. * dx)

    t = 0
    while t < t_end:
        print("progress: %f" % (100. * t / t_end))

        A = fe.assemble(a)
        L = fe.assemble(l)

        for bc in bcs_u + bcs_p + bcs_v:
            bc.apply(A, L)

        fe.solve(A, w1.vector(), L)

        if fe.norm(w1.vector()) > 1e7:
            print('ERROR: norm explosion')
            break

        # update initial values for next step
        w0.assign(w1)
        t += dt

        if show_plots:
            # plot result
            fe.plot(w0.sub(0), mode='displacement')
            plt.show()

        # save solutions
        sol.append(Solution(t=t))
        sol[-1].upv.assign(w0)

    return sol, W, kappa
Beispiel #29
0
    '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
    F += precice.create_coupling_neumann_boundary_condition(v)

a, L = lhs(F), rhs(F)

# Time-stepping
u_np1 = Function(V)
u_np1.rename("Temperature", "")
t = 0

# reference solution at t=0
u_ref = interpolate(u_D, V)
u_ref.rename("reference", " ")

temperature_out = File("out/%s.pvd" % precice.get_solver_name())
ref_out = File("out/ref%s.pvd" % precice.get_solver_name())
error_out = File("out/error%s.pvd" % precice.get_solver_name())

# output solution and reference solution at t=0, n=0
Beispiel #30
0
def run_solver_time_dependent(
    ndim,
    length,
    length_unit,
    bcs,
    layout_list,
    u0,
    powers,
    nx,
    coordinates=False,
    is_plot=False,
    F=None,
    vtk=False,
):
    """求解器主函数.

    Args:
        ndim (int): 2 or 3, 问题维数
        length (float): board length
        length_unit (float): unit length
        bcs (list): bcs
        layout_list (list): unit 位置
        u0 (float): Dirichlet bc 上的值
        powers (list): 功率 list
        nx (int): x 方向上的单元数
        coordinates (bool, optional): 是否返回坐标矩阵. Defaults to False.
        is_plot (bool, optional): 是否画图. Defaults to False.
        F (ndarray, optional): 热源布局矩阵 F. Defaults to None.
        vtk (bool): 是否输出 vtk 文件.

    Returns:
        tuple: U, xs, ys, zs
    """
    T = 100.0  # final time
    num_steps = 200  # number of time steps
    dt = T / num_steps  # time step size
    degree = 1  # degree of function space
    alpha = 50  # parameter alpha

    # Create mesh and define function space
    ny = nx
    nz = nx if ndim == 3 else None
    mesh = get_mesh(length, nx, ny, nz)
    V = fs.FunctionSpace(mesh, "P", degree)

    # Define boundary condition
    if len(bcs) > 0 and bcs[0] != []:
        if ndim == 2:
            bc_funs = [LineBoundary(line).get_boundary() for line in bcs]
        else:
            bc_funs = [RecBoundary(rec).get_boundary() for rec in bcs]
    else:
        bc_funs = [lambda x, on_boundary: on_boundary]  # 边界都为 Dirichlet
    # u_D = fs.Constant(u0)
    u_D = fs.Expression('10 * sin(t / alpha) + u0',
                        degree=2,
                        alpha=alpha,
                        t=0,
                        u0=u0)
    bcs = [fs.DirichletBC(V, u_D, bc) for bc in bc_funs]

    # Define initial value
    u_n = fs.interpolate(u_D, V)

    # Define viriational problem
    # 刚的密度和比热容7.9g/cm3和0.46kJ/Kg*C
    p, c = 7.9, 0.46
    pc = p * c * 1000
    u = fs.TrialFunction(V)
    v = fs.TestFunction(V)
    if F is None:
        f = Source(layout_list, length, length_unit, powers)
    else:
        f = SourceF(F, length)

    FF = dt * fs.dot(fs.grad(u), fs.grad(v)) * fs.dx + pc * u * v * fs.dx - (
        dt * f + pc * u_n) * v * fs.dx
    a, L = fs.lhs(FF), fs.rhs(FF)

    # Time-stepping
    u = fs.Function(V)
    t = 0
    if vtk:
        vtkfile = fs.File("poisson/solution.pvd")
    for n in range(num_steps):

        # Update current time
        t += dt

        # Update boundary condition
        u_D.t = t
        bcs = [fs.DirichletBC(V, u_D, bc) for bc in bc_funs]

        # Compute solution
        fs.solve(a == L, u, bcs)

        # Save to file and plot solution
        if vtk:
            vtkfile << u
        if is_plot:
            fs.plot(u)
            plt.show()
            # plt.colorbar()

        # Update previous solution
        u_n.assign(u)

    # if ndim == 2:
    #     U = u.compute_vertex_values().reshape(nx + 1, nx + 1)
    # else:
    #     U = u.compute_vertex_values().reshape(nx + 1, nx + 1, nx + 1)
    # if coordinates:
    #     xs, ys, zs = get_mesh_grid(length, nx, ny, nz)
    # else:
    #     xs, ys, zs = None, None, None
    return u  # U, xs, ys, zs