I am trying to merge a few ideas from the tutorials described in the 2017 book and simultaneously make the code a bit more Python-style so I can debug with Spyder.
Also, because I know it answers a few questions: I am running Ubuntu 20.04.2 (64-bit) on a mini-server (Meerkat5) with an i7 processor, and I installed FEniCS 2019 via Anaconda/conda-forge because I am an engineer and I like to use the Spyder IDE to debug my code. I do have mshr and matplotlib verified as properly installed and connected from running the previous tutorial codes.
When trying to apply the FEniCS command assign from ft03, I started with the updates and then added the Python-style of importing things (e.g. import fenics as fe
instead of from fenics import *
). The errors I get are associated with the syntax of last line of the file…
If I use u_n.fe.assign(u)
I get:
AttributeError: 'Function' object has no attribute 'fe'
If I use u_n=fe.assign(u)
I get:
TypeError: assign(): incompatible function arguments. The following argument types are supported:
1. (arg0: object, arg1: object) -> None
Invoked with: Coefficient(FunctionSpace(Mesh(VectorElement(FiniteElement('Lagrange', triangle, 1), dim=2), 669), FiniteElement('Lagrange', triangle, 1)), 680)
I understand from the book that I can’t use u_n = u because that would set them to be the same variable; and we need to keep them as two variables.
the pydoc fenics.assign
command in a terminal window gives me this:
Help on built-in function assign in fenics:
fenics.assign = assign(...) method of builtins.PyCapsule instance
assign(arg0: object, arg1: object) -> None
(END)
which I don’t find to be very helpful (possibly because I am still new at Python!)
When I simply use the original u_n.assign(u)
it appears that every single time step gives the same graph
Since the original ft03 didn’t include an image of the plot nor a way to visualize it, in neither the book nor online (to my knowledge) - I am unsure of whether the code is actually finding the changes in heat at each step, and I’m unsure how to add a sense of scale to the plot.
Since I am dealing with tutorial code, there’s no minimum working example…but here’s the code that doesn’t have the errors but doesn’t appear to update at each timestep:
"""
FEniCS tutorial demo program: Time-dependent Heat equation with Dirichlet conditions.
Test problem is chosen to give an exact solution at all nodes of the mesh.
u'= Laplace(u) + f in the unit square
u = u_D on the boundary
u = u_0 at t = 0
u = 1 + x^2 + alpha*y^2 + \beta*t
f = beta - 2 - 2*alpha
"""
# Updated from ft03_heat.py file
# Last changed: 2021-06-09 by Kristin Schaefer
# Revised for syntax updates in Python 3.8 & FEniCS 2019.1.0
# and to include ft03 fixes at https://github.com/hplgit/fenics-tutorial/pull/74/commits/9c67e6d0c844a17f02b46a47d1bcdf2029c6fb25
# ~> 2017 Tutorial book Ch. 3.1 (test problem 1 in 3.1.3)
import fenics as fe
import numpy as np
import matplotlib.pyplot as plt
T = 2.0 # final time
num_steps = 10 # number of time steps
dt = T / num_steps # time step size (time discretization)
alpha = 3 # parameter alpha
beta = 1.2 # parameter beta
# Create mesh and define function space
nx = ny = 8
mesh = fe.UnitSquareMesh(nx, ny)
V = fe.FunctionSpace(mesh, 'P', 1)
# Define boundary condition
u_D = fe.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 = fe.DirichletBC(V, u_D, boundary)
# Define initial value ~ two choices for variational problem (use # to suppress one u_n)
u_n = fe.interpolate(u_D, V) # recovers exact solution to machine precision (allows verification of code)
# u_n = project(u_D, V) # computes approximate values at nodes (u_0 as L^2 projection into the FE space)
# Define variational problem: define F, ask for a & L
u = fe.TrialFunction(V)
v = fe.TestFunction(V)
f = fe.Constant(beta - 2 - 2*alpha)
F = u*v*fe.dx + dt*fe.dot(fe.grad(u), fe.grad(v))*fe.dx - (u_n + dt*f)*v*fe.dx
a, L = fe.lhs(F), fe.rhs(F)
# Create VTK format file for saving solutions as time iterates
vtkfile = fe.File("ft03/heat_solution.pvd")
# Time-stepping
u = fe.Function(V)
t = 0
for n in range(num_steps):
# Update expression objects with current time
t += dt
u_D.t = t
# Compute solution
fe.solve(a == L, u, bc)
# Save to file and Plot solution to screen
vtkfile << (u, t) # appends heat in body and time to file
fe.plot(u, title="ft03: Solution u")
plt.show()
# Compute error at vertices by
u_e = fe.interpolate(u_D, V)
error = np.abs(u_e.vector() - u.vector()).max()
print('t = %.2f: error = %.3g' % (t, error))
# Update previous solution, keeping u and u_n as separate variables
u_n.assign(u)