Inverse of a SUPG term

Hello,

I’m working on a SUPG-stabilised finite element solver in the FEniCSx library. Many solvers, including fund3D, Coffe …, use a very specific SUPG term and I would like to implement :

image

in many paper we can read “The inverse of the stabilization matrix is evaluated at each Gaussian quadrature point for volume integrations and [τ ] is then obtained by means of local matrix inversion”

My question is: how do I implement this term in FenicsX/UFL? It seems that `ufl.inv` won’t work for a 6×6 matrix ? I have no problem with the terms, but i have no idea for the inversion of the matrix. In fact, I think this term should also be taken into account in the differentiation of the Jacobian.

Thank you for your time; I’ll take all your suggestions on board!

I think you could do this with @a-latyshev’s external operator to do this inversion numerically with numpy: GitHub - a-latyshev/dolfinx-external-operator: Extension of DOLFINx implementing the concept of external operator · GitHub

@ruhsnay, you need to be careful with wrapping tensors with external operators, especially when you are going to compute the derivative with respect to them. If you wrap a 6x6 tensor with FEMExternalOperator, it will generate a quadrature space and FE coefficient of the size 6x6x(num of dofs of the quadrature space). If you take a derivative with respect to an operand, the library will generate a new quadrature space and a coefficient of the same size multiplied by the mathematical size of the operand. It’s a lot of RAM. Instead of wrapping the tensor itself, it’s better to represent its contraction with a vector (I assume that in your variational formulation, your [\tau] is multiplied by smth).

If you consider the differentiation of a variational form with such a term, NumPy won’t be enough. Try to use JAX instead. We have a tutorial on using JAX with external operators to solve a plasticity problem: Plasticity of Mohr-Coulomb with apex-smoothing — External operators within FEniCSx/DOLFINx.

Hi!

I’m currently trying to code the term using the external operator, but I can’t see an ‘easy’ solution at the moment. The term I’m trying to code is Tau, which is the inverse of a 6×6 matrix in 3D. This term is in fact multiplied on the left and right by another term. On the left by the gradient of the test function and the Jacobian of the convective flux from the Navier–Stokes equations, and on the right by the strong residue of the Navier–Stokes equations.

My idea then (and following your recommendation) was to calculate the term y = Tau*StrongRes using Jax and the external operator. However, the strong residual of the Navier–Stokes equations contains the divergence of the convective and diffusive fluxes (which are tensors), and the latter depends on the gradient of the variables. In summary: div(Fc(Q)) – div(Fd(Q, grad(Q))). It therefore seems to me that it would be rather complicated to recode these divergences exactly in JAX – am I wrong? This method would also increase the number of operands (time step …).

My other idea was to leave StrongRes in ufl\ (which works very well) and pass it as an operand to `ExternalOperator`, so that it evaluates at all Gaussian points, multiplied by Tau. But in that case, when JAX calculates the derivative for the Jacobian dy/dQ, the component dStrongRes/dQ will be ignored because JAX won’t ‘see’ that StrongRes depends on Q – am I wrong? I don’t have enough perspective to identify the best solution.

I hope I’ve made myself clear; please don’t hesitate to ask if you’re not sure.
Thank you for your time!

Dear @Nathan_Langlet,

Sorry for the confusion in the last message. There is a lot of stuff here, let’s try to unpack…

I mentioned JAX because a Jacobian was mentioned; that’s why you need two operations that go beyond UFL:

  1. Inverse of a high-order tensor
  2. Since 1. goes beyond UFL, you need to compute the derivative of \tau, which is inverse.
    JAX is able to do both, that’s why.

Supposing that \tau = M^{-1} and you consider then a term like v^TM^{-1}w.
During the FEniCS conference, I mentioned that instead of computing M^{-1} each iteration for every Gauss point, maybe it makes sense to solve a small linear problem My = w, where y = M^{-1}w and then you compute v^T y instead. In this case, y is an external operator indeed, but w is not an operand. As for the derivative, if Q is your main field variable with respect to which you take a directional derivative and y(Q) = M^{-1}(Q)w(Q), you need to understand what y^\prime(Q) looks like and what you need to compute via JAX/NumPy/DOLFINx… In particular, you need to compute w(Q), which is your StrongRes. Since it’s perfectly expressible with UFL, express it with UFL! Then use fem.Expression to compute its values wherever you want. Then you can compute the derivative of w(Q) with UFL and then compute its values via fem.Expression. BTW, this concerns the computation of M as well. Then you wrap all this with a Python function, something like:

def y_impl(Q: np.ndarray):
  w_values = w_expr.eval(domain, cells)
  M_values = M_expr.eval(domain, cells)
  y_values = solve_linear(M_values, w_values) #any code inside
  return y_values.reshape(-1)

Then for the derivative, it’s gonna be more complicated, but possible I think!

All this looks pretty complex, but the reason here is really to reduce the size of the external operator and the allocated memory.

What I’d suggest now is to implement the direct matrix inverse without the extra complexity I’ve just introduced, i.e. now \tau is an external operator. This should be much more straightforward to implement, and thus you will get an idea of how external operators work. You can come back to optimiziation like suggested above, later.

But before doing anything, I’d really recommend explicitly deriving the variational problem you are solving, and the following may be useful.

I recently dropped an update for the documentation: Some Notation for External Operators — External operators within FEniCSx/DOLFINx. This introduces a notation around directional derivatives and external operators. Since the use case of external operators is when the variational formulations are really complex, it may be challenging to understand how the external operators play their role. I see it as a context for a modern agentic LLM like Claude or Gemini. You give it two files: your formulation and this notation dolfinx-external-operator/doc/notes/notation.md at main · a-latyshev/dolfinx-external-operator · GitHub. Then it may guide you through your problem using our package. Never tested though, hope it will be helpful :smiley: