Name in Function class does not write attribute into xdmf

Hi! I’m trying to give a specific name to a field, but the method (or parameter) name provided by Function class just ignore the name string I provided, which results in some random name like f_20, f_117 etc. The MWE is as following:

from fenics import *
import os

mesh = RectangleMesh(Point(0, 0), Point(1.0, 1.0), 10, 10)

def initialize_temperature(Q):
      
      T0 = Expression('0.5*(1.0-x[1]*x[1])+0.01*cos(pi*x[0]/length)*sin(pi*x[1]/height)', length = 1, height = 1, degree=1)
      T0 = interpolate(T0, Q)
      
      return T0, 0.0
  
V = VectorElement('Lagrange', mesh.ufl_cell(), 2)
Q = FiniteElement('Lagrange', mesh.ufl_cell(), 1)
W = FunctionSpace(mesh, MixedElement([V, Q]))

QT = FunctionSpace(mesh, "DG", 1)
T_n = Function(QT, name = "Temperature")
T_n, t = initialize_temperature(QT)

dirname = "result"
outputname = "convection"
xdmfpath = os.path.abspath(dirname)+"/"+outputname+".xdmf"
xdmf_field = XDMFFile(xdmfpath)
hdf5path = os.path.abspath(dirname)+"/"+outputname
field_series = TimeSeries(hdf5path)

#Here is probably the error
xdmf_field.write(T_n, t)
field_series.store(T_n.vector(), t)
xdmf_field.close()

short notes on this snippet, T_n is a Function object with name “Temperature” I’d like to visualize in Paraview. If I debug this code, type T_n.name() in terminal, it gives “Temperature”, which is right. But the command xdmf_field.write(T_n, t) just ignores T_n’s name and writes some arbitrary string in convection.xdmf, e.g. f_20. Paraview will just show that arbitrary string for that field.

I also found a method name and rename in class XDMFFile, but I haven’t figured out how to use it. Any suggestion? Thanks!

The issue comes in the second line where you actually create a new T_n to overwrite the older one but without naming.

To fix it, conder to change your function initialize_temperature to

def initialize_temperature(Q):
      
      T0 = Expression('0.5*(1.0-x[1]*x[1])+0.01*cos(pi*x[0]/length)*sin(pi*x[1]/height)', length = 1, height = 1, degree=1)
      T0 = interpolate(T0, Q)
      T0.rename("Temperature", "")

      return T0, 0.0
1 Like

Gee! This is kinda tricky, it works now, thanks! But when you say ‘create a new T_n to overwrite the older one’, do you mean these two T_n are completely different, from a class-object point of view? If so, the first T_n is not required and can be omitted.

Yes, Since the first T_n is never accessed before the next one is created, you can remove it.

This is quite dangerous I have to say. In my full-size code, the first T_n is created to store solution, a Function object. Then temperature field is initialized and pushed into the second T_n, an interpolated Expression object. If I want to use the first T_n to save numerical solution and do some manipulation, what to do? Besides why can’t we push initialized Expression object into the first numerical solution T_n ? This is more intuitive and consistent, thanks!

This is standard Python behavior.
When you use = you redirect the variable, discarding the old variable if you do not have a reference to it somewhere Else.

You would have to use dolfin.Function.assign or dolfin.Function.interpolate to store data in an already initialized variable.

1 Like

Consider the following:

T_n = Function(QT, name = "Temperature")     # initialized

T_n_new, t = initialize_temperature(QT)
T_n.assign(T_n_new)
2 Likes

Thanks for the clarification!

Thanks! Really helpful!