NameError: name 'nabla_div' is not defined

hi all, I tried the testing program on fenics on ubuntu18.04. however, the error caused “NameError: name ‘nabla_div’ is not defined”. how can I fix it?
best,
jian

Hi
Try this:

from ufl import nabla_div
3 Likes

Thank you Leo.

Best,

Jian

Leo via FEniCS Project fenicsproject1@discoursemail.com于2019年2月20日 周三13:10写道:

Hallo Leo,

Thank you for the solution.

Following up this topic, I still have question, what is the difference between nabla_div() and div()?
In the help documentation of both functions, both of them are identical function.

Best regards

Thomas

Hi
Based on definitions of these operators in UFL (Please check it out):
For vector expressions v, and arbitrary rank tensor expressions T div and nabla_div are defined as:

div:

def div(f):
      div(v) = v[i].dx(i)
      div(T)[:] = T[:,i].dx(i)
    f = as_ufl(f)
    return Div(f)

nabla_div:

def nabla_div(f):
      nabla_div(v) = v[i].dx(i)
      nabla_div(T)[:] = T[i,:].dx(i)      
    f = as_ufl(f)
    return NablaDiv(f)

Hi Leo,

thank you for your answer. So, they are not identical for high order Tensor

div(T)[:] = T[:,i].dx(i)
nabla_div(T)[:] = T[i,:].dx(i)   

Best Regards

Some background:
There is a deeper reason for the existence of these two functions.

Consider a vector-valued function (for simplicity in 2D), with an orthonormal base \vec e_i:
\vec f = \begin{pmatrix}u\\v\end{pmatrix} = f^i \vec e_i
and its gradient
\nabla\vec f = \begin{pmatrix}\partial_x u & \partial_y u \\ \partial_x v & \partial_y v\end{pmatrix} = \partial_j f^i \vec e_i\otimes \vec e^j.
The sign \otimes denotes the outer product of the two basis vectors.
This definition of the gradient matches the definition of the Jacobi matrix and stems from the definition of the total differential
\mathrm d\vec f = \partial_j\vec f\cdot\mathrm dx^j = \partial_j f^i\vec e_i\cdot\mathrm dx^j = \partial_j f^i\vec e_i\otimes\vec e^j\mathrm d\vec x = \nabla\vec f\,\mathrm d\vec x.
Sometimes, people define the gradient of a vector valued function to be the transpose of the Jacobi matrix, which seems strange at first sight.

Now, the question arises, how to express the divergence of tensors.
For vectors we want to have \nabla\cdot\vec f = \partial_i f^i, which can be expressed as
\nabla\cdot\vec f = \partial_i\vec e^i\cdot\vec f = \partial_i\vec e^i\cdot f^j\vec e_j = \partial_i f^j \delta^i_j = \partial_i f^i.

Now we can apply the same thing to a tensor:
\nabla\cdot\sigma = \partial_i\vec e^i\cdot\sigma^{jk}\vec e_j\otimes\vec e_k = \partial_i\sigma^{jk}\underbrace{\vec e^i\cdot\vec e_j}_{\delta^i_j}\otimes\vec e_k = \partial_i\sigma^{ik}\vec e_k = \sigma^{ik}_{,i}\vec e_k.

In coordinates, this means:
\nabla\cdot\sigma = \begin{pmatrix}\partial_x&\partial_y\end{pmatrix}\cdot\begin{pmatrix}\sigma^{xx}&\sigma^{xy}\\\sigma^{yx}&\sigma^{yy}\end{pmatrix} = \begin{pmatrix}\sigma^{xx}_{,x} + \sigma^{yx}_{,y}\\\sigma^{xy}_{,x} + \sigma^{yy}_{,y}\end{pmatrix}
Note, how the components of the resulting vector look like the dot product of the nabla operator with the columns of the matrix.

This way, Gauß’ theorem becomes:
\int_\Omega\nabla\cdot\sigma\,\mathrm d\Omega = \int_\Omega\begin{pmatrix}\sigma^{xx}_{,x} + \sigma^{yx}_{,y}\\\sigma^{xy}_{,x} + \sigma^{yy}_{,y}\end{pmatrix}\,\mathrm d\Omega = \oint_\Gamma\begin{pmatrix}n_x\sigma^{xx} + n_y\sigma^{yx}\\n_x\sigma^{xy} + n_y\sigma^{yy}\end{pmatrix}\mathrm dS = \oint_\Gamma\vec n\cdot\sigma\,\mathrm dS = \oint_\Gamma\sigma^T\cdot\vec n\,\mathrm dS
Note, how the normal vector is multiplied from the left into the tensor - or from the right into the transpose of the tensor.

Also, with this definition, it holds that
\nabla\cdot\nabla\vec f = \partial_i\vec e^i\cdot\partial_k f^j\vec e_j\otimes\vec e^k = \partial_k \partial_i f^j \underbrace{\vec e^i\cdot\vec e_j}_{=\delta^i_j}\otimes\vec e^k = \partial_k\left(\partial_i f^i\right)\vec e^k = \nabla\left(\nabla\cdot\vec f\right)
and
\nabla\cdot\left(\nabla\vec f\right)^T = \partial_i\vec e^i\cdot\partial_k f^j\vec e^k\otimes\vec e_j = \partial_i\partial_k f^j(\underbrace{\vec e^i\cdot\vec e^k}_{=\delta^{ik}})\otimes\vec e_j = \partial_i\partial^i f^j\vec e_j = \begin{pmatrix}\Delta f_x\\\Delta f_y\end{pmatrix} = \vec\Delta\vec f.

These last three results look kind of strange to some people, and so they define the application of the nabla operator on a tensor in a transposed way, such that a normal looking matrix-vector-product arises in Gauß’ theorem and the Laplacian is equivalent to the divergence of the gradient, rather than the divergence of the transposed gradient.

Now, FEniCS gives you two functions, div and nabla_div.
The first, div(sigma), corresponds to \sigma^{ij}_{,j} and thus to a transposed formulation compared the one derived above.
The second, nabla_div(sigma), corresponds \sigma^{ij}_{,i} and thus to the definitions derived above.
Which function to use depends on how you derived your equations in the first place.

Here is also some explanation (you need to scroll down a bit): https://fenicsproject.org/pub/tutorial/html/._ftut1009.html#ftut1:NS:varform

2 Likes