VectorFunctionSpace to functionspace: Function value size not equal to Expression value size

When I run my code (described here, I get a deprecation warning about VectorFunctionSpace. After some research here, I now use:

# Heat flux.
    Q = functionspace(mesh, ("DG", deg-1, (mesh.geometry.dim,)))
    q = Function(Q)
    flux_calculator = Expression(-κ * grad(temp), Q.element.interpolation_points())
    q.interpolate(flux_calculator)

which seems to work fine (no error at least, no warning either).

However now this code:

    # Bridgman heat.
    Q_B = functionspace(mesh, ("DG", deg-1, (mesh.geometry.dim,)))
    QB = Function(Q_B)
    QB_flux_calculator = Expression(- temp * (s_xx * J_vector[0].dx(0) + s_yy * J_vector[1].dx(1)), Q_B.element.interpolation_points())
    QB.interpolate(QB_flux_calculator)

yields the error:

Traceback (most recent call last):
  File "/root/shared/TE_simulation/BN_example.py", line 234, in <module>
    sim = thermoelectric_simulation((12,13), (12,13), seebeck_components=(10e-6, 1e-5), T_cold=300.0, ΔT = 0)
  File "/root/shared/TE_simulation/BN_example.py", line 221, in thermoelectric_simulation
    QB.interpolate(QB_flux_calculator)
  File "/usr/local/dolfinx-real/lib/python3.10/dist-packages/dolfinx/fem/function.py", line 397, in interpolate
    _interpolate(u, cells)
  File "/usr/lib/python3.10/functools.py", line 889, in wrapper
    return dispatch(args[0].__class__)(*args, **kw)
  File "/usr/local/dolfinx-real/lib/python3.10/dist-packages/dolfinx/fem/function.py", line 388, in _
    self._cpp_object.interpolate(expr._cpp_object, cells)
RuntimeError: Function value size not equal to Expression value size

no matter the degree I choose in deg-1. A search on google falls back to using VectorFunctionSpace, but this shouldn’t be suggested anymore, as it is deprecated… Therefore, I have no idea how to fix this error…

The error is already quite informative. Your expression is a scalar field, but you are trying to interpolate it in a FE space for a vector field.

1 Like

Thanks, it’s still not obvious to me where I make the supposition that I am dealing with a vector field. As you correctly point out, I am dealing with a scalar field.

I believe I have fixed the problem with this code:

    element = FiniteElement("DG", mesh.ufl_cell(), 1)
    Q_B = FunctionSpace(mesh, element)
    QB = Function(Q_B)
    QB_flux_calculator = Expression(- temp * (s_xx * J_vector[0].dx(0) + s_yy * J_vector[1].dx(1)), Q_B.element.interpolation_points())
    QB.interpolate(QB_flux_calculator)

The last part of the triplet in Q_B indicates that you want a vector space with mesh.geometry.dim components

1 Like

Hello dokken, I am now getting an error with the exact same code I last posted above (which used to work).

I found an answer on the website, I fixed the error by adding a communicator like so:

QB_flux_calculator = Expression(- temp * (s_xx * J_vector[0].dx(0) + s_yy * J_vector[1].dx(1)), Q_B.element.interpolation_points(), comm=MPI.COMM_SELF)

Would you have an idea why I need to add this for my code to run? I compute several fluxes (this one is not a flux though, but a scalar field), none of them require the mpi comm, but this one.

The traceback is:

Could not extract MPI communicator for Expression. Maybe you need to pass a communicator?
Traceback (most recent call last):
  File "/root/shared/TE_simulation/file.py", line 475, in <module>
    out0, out1, out2, out3, out4, out5, out6 = TE_simulation(open_circuit_mode=open_circuit_mode, thermoelectric_sim=TE_sim, the_current = TE_current, current_curves=(12,13), voltages_curves=(12,13), seebeck_components=seebeck_components, T_cold=300.0, ΔT = ΔT, resistance_params=resistance_params, Bridgman_term_bool=False)
  File "/root/shared/TE_simulation/file.py", line 440, in TE_simulation
    QB_flux_calculator = Expression(- temp * (s_xx * J_vector[0].dx(0) + s_yy * J_vector[1].dx(1)), Q_B.element.interpolation_points())
  File "/usr/local/dolfinx-real/lib/python3.10/dist-packages/dolfinx/fem/function.py", line 122, in __init__
    mesh = ufl.domain.extract_unique_domain(e).ufl_cargo()
AttributeError: 'NoneType' object has no attribute 'ufl_cargo'

I don’t provide the MWE because the problem is solved. But I’m really curious why I need to specify this here…

Certain expressions are not associated with a mesh. As you haven’t provided the definition of the variables in your expression, it is hard for me to point to exactly why your expression isn’t associated with a mesh.

Hello dokken and thanks for helping me that much. On the phone, so hard to make a high quality reply.

I try to copy the relevant information below.

    # Define ME function space
    deg = 3
    el = FiniteElement("CG", mesh.ufl_cell(), deg)
    mel = MixedElement([el, el])
    ME = FunctionSpace(mesh, mel)

    u, v = TestFunction(ME)
    TempVolt = Function(ME)
    temp, volt = split(TempVolt)
    dTV = TrialFunction(ME)

    rho = 1
    sigma = 1.0 / rho
    κ = 1.8

    s_xx, s_yy = seebeck_components
    Seebeck_tensor = as_tensor([[s_xx, 0], [0, s_yy]])

    # Define the boundary conditions
    left_facets = facet_markers.find(inj_current_curve)
    right_facets = facet_markers.find(out_current_curve)
    left_dofs = locate_dofs_topological(ME.sub(1), mesh.topology.dim-1, left_facets)

    left_dofs_temp = locate_dofs_topological(ME.sub(0), mesh.topology.dim-1, left_facets)
    right_dofs_temp = locate_dofs_topological(ME.sub(0), mesh.topology.dim-1, right_facets)
    bc_temp_left = dirichletbc(ScalarType(T_cold), left_dofs_temp, ME.sub(0))
    bc_temp_right = dirichletbc(ScalarType(T_cold + ΔT), right_dofs_temp, ME.sub(0))
    bcs = [bc_temp_left, bc_temp_right]

    x = SpatialCoordinate(mesh)
    dx = Measure("dx", domain=mesh, subdomain_data=cell_markers)
    ds = Measure("ds", domain=mesh, subdomain_data=facet_markers)

    J = the_current / assemble_scalar(form(1 * ds(inj_current_curve, domain=mesh)))


    # Weak form.
    J_vector = -sigma * grad(volt) - sigma * Seebeck_tensor * grad(temp)
    Fourier_term = dot(-κ * grad(temp), grad(u)) * dx
    Joule_term = dot(rho * J_vector, J_vector) * u * dx
    Bridgman_term = - temp * (s_xx * J_vector[0].dx(0) + s_yy * J_vector[1].dx(1)) * u * dx
    F_T = Fourier_term + Joule_term
    if Bridgman_term_bool:
        F_T += Bridgman_term
    F_V = -dot(grad(v), sigma * grad(volt))*dx -dot(grad(v), sigma * Seebeck_tensor * grad(temp))*dx + v * J * ds(out_current_curve) - v * J * ds(inj_current_curve) 

    weak_form = F_T + F_V

    # Solve the PDE.
    Jac = derivative(weak_form,TempVolt,dTV)


    # Solve the PDE.
    problem = NonlinearProblem(weak_form, TempVolt, bcs=bcs, J = Jac)
    solver = NewtonSolver(MPI.COMM_WORLD, problem)
    solver.convergence_criterion = "incremental"
    solver.rtol = 1e-9
    solver.report = True
    solver.max_it = 10000

    ksp = solver.krylov_solver
    opts = PETSc.Options()
    option_prefix = ksp.getOptionsPrefix()

    opts[f"{option_prefix}pc_type"] = "lu"

    opts[f"{option_prefix}pc_type"] = "ksp" # Quick code.
    opts[f"{option_prefix}pc_factor_mat_solver_type"] = "mumps"

    opts[f"{option_prefix}ksp_max_it"]= 10000
    opts[f"{option_prefix}mat_mumps_icntl_24"] = 1
    opts[f"{option_prefix}mat_mumps_icntl_25"] = 0
    ksp.setFromOptions()
    
    # Specify the null space, because voltage is defined up to a constant and we don't use any Dirichlet boundary condition to fix the voltage.
    nullspace = PETSc.NullSpace().create(constant=True)  # type: ignore
    PETSc.Mat.setNearNullSpace(solver.A, nullspace)
    log.set_log_level(log.LogLevel.INFO)    
    
    n, converged = solver.solve(TempVolt)
    assert(converged)
    print(f'''------- Processing --------
    Number of interations: {n:d}''')

    # Compute fluxes on boundaries
    n = FacetNormal(mesh)
    down_heat_flux = form(dot(-κ * grad(temp) + Seebeck_tensor * temp * J_vector, n)*ds(inj_current_curve))
    Q_out = assemble_scalar(down_heat_flux)

    top_heat_flux = form(dot(-κ * grad(temp) + Seebeck_tensor * temp * J_vector, n)*ds(out_current_curve))
    Q_in = assemble_scalar(top_heat_flux)
    
    if thermoelectric_sim:
        # Heat flux. (Non TE).
        Q = functionspace(mesh, ("CG", deg-1, (mesh.geometry.dim,)))
        q = Function(Q)
        flux_calculator = Expression(-κ * grad(temp), Q.element.interpolation_points())
        q.interpolate(flux_calculator)

        # Current density.
        J = functionspace(mesh, ("DG", deg-1, (mesh.geometry.dim,)))
        Je = Function(J)
        Je_flux_calculator = Expression(J_vector, J.element.interpolation_points())
        Je.interpolate(Je_flux_calculator)
        element = FiniteElement("DG", mesh.ufl_cell(), 1)
        J_x = FunctionSpace(mesh, element)
        Je_x = Function(J_x)
        Je_x_calculator = Expression(J_vector[0].dx(0), J_x.element.interpolation_points())
        Je_x.interpolate(Je_x_calculator)

        element = FiniteElement("DG", mesh.ufl_cell(), 1)
        J_y = FunctionSpace(mesh, element)
        Je_y = Function(J_y)
        Je_y_calculator = Expression(J_vector[1].dx(1), J_y.element.interpolation_points())
        Je_y.interpolate(Je_y_calculator)

        # Bridgman heat.
        element = FiniteElement("DG", mesh.ufl_cell(), 1)
        Q_B = FunctionSpace(mesh, element)
        QB = Function(Q_B)
        QB_flux_calculator = Expression(- temp * (s_xx * J_vector[0].dx(0) + s_yy * J_vector[1].dx(1)), Q_B.element.interpolation_points(), comm=MPI.COMM_SELF)
        QB.interpolate(QB_flux_calculator)


        output_0 = TempVolt.sub(0).collapse()
        output_1 = TempVolt.sub(1).collapse()
        output_2 = q
        output_3 = Je
        output_4 = QB
        output_5 = Je_x
        output_6 = Je_y
        
        return output_0, output_1, output_2, output_3, output_4, output_5, output_6

I still have no clue why that term would be any different than the others. In my mind, it does depend on the mesh. It involves a sum of derivatives of a current density which is itself a grad(temp) and grad(volt) quantity, supposedly defined in a DG space of degree 2 if I understand well, since both temp and volt are defined over a FE space of order 3, CG.