Derivatives (gradients) of Symmetric Tensors

271 views
Skip to first unread message

Ernesto Ismail

unread,
Dec 10, 2015, 10:44:13 AM12/10/15
to deal.II User Group
Hi Everyone,

I am using deal.II for a problem where the variable of interest is a second order Symmetric Tensor (e.g solving for the stress in an evolution equation with a given velocity field). My question is in two parts, both relating to derivatives of Symmetric Tensors.


1) I have a field of symmetric tensors that I have found. I need to use the divergence of this field in a second computation. Were it a vector field I would use get_function_gradients and then take the trace of this for the divergence. How should I go about doing this for the SymmetricTensor<2,dim> field?


2) I am building an equation where I am solving for a field of symmetric tensors. At assembly I would like to use the gradient associated with the shape functions of the elements describing them. For a vector valued problem there is a "view" type which allows me to extract the symmetric tensor itself (const Tensor<2,dim> phi_j_T      = fe_values[Ts].value (j, q);) but there doesn't seem to be an equivalent (const Tensor<3,dim> phi_j_T_grad     = fe_values[Ts].gradient (j, q);) How should I tackle this?


Thanks in advance,

Ernesto

Wolfgang Bangerth

unread,
Dec 10, 2015, 11:03:41 AM12/10/15
to dea...@googlegroups.com

> 1) I have a field of symmetric tensors that I have found. I need to use the
> divergence of this field in a second computation. Were it a vector field I
> would use get_function_gradients and then take the trace of this for the
> divergence. How should I go about doing this for the SymmetricTensor<2,dim> field?

You'd use something like
FEValuesExtractors::SymmetricTensor<2> Ts;
fe_values[Ts].get_function_divergences (input, output);


> 2) I am building an equation where I am solving for a field of symmetric
> tensors. At assembly I would like to use the gradient associated with the
> shape functions of the elements describing them. For a vector valued problem
> there is a "view" type which allows me to extract the symmetric tensor itself
> (const Tensor<2,dim> phi_j_T = fe_values[Ts].value (j, q);) but there
> doesn't seem to be an equivalent (const Tensor<3,dim> phi_j_T_grad =
> fe_values[Ts].gradient (j, q);) How should I tackle this?

There are corresponding extractors and views for symmetric tensors of rank 2.
What code do you have that doesn't compile for you?

Best
W.

--
------------------------------------------------------------------------
Wolfgang Bangerth email: bang...@math.tamu.edu
www: http://www.math.tamu.edu/~bangerth/

Ernesto Ismail

unread,
Dec 10, 2015, 11:45:46 AM12/10/15
to deal.II User Group
Thanks for the prompt reply!

With regards to point 1)
I had not noted that there was a get_function_divergences function:
https://www.dealii.org/developer/doxygen/deal.II/classFEValuesViews_1_1Vector.html#aa20eae586e7a296f95770cb02c5ad773

However, a function to find the gradients does not seem to exist eg if I use:
fe_values[Ts].get_function_gradients (old_solution, old_T_grads);

I get the compiler error:
error: ‘const class dealii::FEValuesViews::SymmetricTensor<2, 2, 2>’ has no member named ‘get_function_gradients’

With regards to point 2)
I am trying to do something along the lines of:
const Tensor<3,dim> phi_i_P_grad = fe_values[Ps].gradient (i, q);

The compiler error I get is:
error: ‘const class dealii::FEValuesViews::SymmetricTensor<2, 2, 2>’ has no member named ‘gradient’

Am I correct in my understanding that at present it is not possible to find gradients of second order tensors directly? If yes, how would I go about finding them?

Regards,
Ernesto

Wolfgang Bangerth

unread,
Dec 10, 2015, 12:23:55 PM12/10/15
to dea...@googlegroups.com

> However, a function to find the gradients does not seem to exist eg if I use:
> fe_values[Ts].get_function_gradients (old_solution, old_T_grads);
>
> I get the compiler error:
> error: ‘const class dealii::FEValuesViews::SymmetricTensor<2, 2, 2>’ has no
> member named ‘get_function_gradients’
>
> With regards to point 2)
> I am trying to do something along the lines of:
> const Tensor<3,dim> phi_i_P_grad = fe_values[Ps].gradient (i, q);
>
> The compiler error I get is:
> error: ‘const class dealii::FEValuesViews::SymmetricTensor<2, 2, 2>’ has no
> member named ‘gradient’
>
> Am I correct in my understanding that at present it is not possible to find
> gradients of second order tensors directly? If yes, how would I go about
> finding them?

It seems like you are correct that there are neither gradient() nor
get_function_gradients() functions in this class.

I think the simplest way for you around this problem would actually be to add
these missing functions to the FEValuesViews::SymmetricTensor class. Take a
look at include/deal.II/fe/fe_values.h, starting around line 900 of the
current development sources. The function already has divergence() and
get_function_divergences() members. It shouldn't be too difficult to write the
missing functions in a similar style. The computed type should in both cases
be Tensor<3,spacedim>.

I think adding these functions is going to be simpler than trying to work
around the lack thereof.

Of course we would be very happy to take whatever code you write. Let us know
if you need help!

Andrew Mcbride

unread,
Dec 10, 2015, 2:16:51 PM12/10/15
to dea...@googlegroups.com
Hi Ernesto

You might want to make the return type a SymmetricTensor<3,spacedim> as you will have symmetry in A_ij,k = A_ji,k as A_ij = A_ji. That should be fine as long as you define symmetry of a third-order tensor to be in the first two slots.

Wolfgang is correct, the functions are not there. The reason for this was that we simply did not need them at the time.

Andrew
> --
> The deal.II project is located at http://www.dealii.org/
> For mailing list/forum options, see https://groups.google.com/d/forum/dealii?hl=en
> --- You received this message because you are subscribed to the Google Groups "deal.II User Group" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to dealii+un...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Andrew Mcbride

unread,
Dec 10, 2015, 2:25:58 PM12/10/15
to dea...@googlegroups.com
but you would need to implement said SymmetricTensor<3,dim> …
maybe stick with Wolfgang’s suggestion

A

Ernesto Ismail

unread,
Dec 10, 2015, 3:57:49 PM12/10/15
to dea...@googlegroups.com
Thanks for the feedback Andrew and Wolfgang.

From my understanding of the SymmetricTensor class it only supports orders 2,4 etc. The wording from the documentation is "Provide a class that stores symmetric tensors of rank 2,4,..." from https://www.dealii.org/developer/doxygen/deal.II/classSymmetricTensor.html

I will take a look at the existing 
FEValuesViews::SymmetricTensor class and try write the functions. I'll try get to this early next week.

Regards,
Ernesto

You received this message because you are subscribed to a topic in the Google Groups "deal.II User Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/dealii/79newCZGhhM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to dealii+un...@googlegroups.com.

Wolfgang Bangerth

unread,
Dec 10, 2015, 4:00:54 PM12/10/15
to dea...@googlegroups.com
On 12/10/2015 02:57 PM, Ernesto Ismail wrote:
>
> From my understanding of the SymmetricTensor class it only supports
> orders 2,4 etc. The wording from the documentation is "Provide a class
> that stores symmetric tensors of rank 2,4,..." from
> https://www.dealii.org/developer/doxygen/deal.II/classSymmetricTensor.html

Correct.


> I will take a look at the existing FEValuesViews::SymmetricTensor class
> and try write the functions. I'll try get to this early next week.

Great, we're looking forward to seeing what you come up with.

Make sure you start from the current version you can find on github as
that makes later merging the changes a lot easier!

Best
Wolfgang

Ernesto Ismail

unread,
Dec 10, 2015, 4:04:30 PM12/10/15
to dea...@googlegroups.com
I just pulled the latest version and am planning my approach. Once I'm done, how would you like me to contribute it? Is it possible for me to push my submission to the repository for review?

Ernesto

--
The deal.II project is located at http://www.dealii.org/
For mailing list/forum options, see https://groups.google.com/d/forum/dealii?hl=en

Wolfgang Bangerth

unread,
Dec 10, 2015, 4:07:17 PM12/10/15
to dea...@googlegroups.com
On 12/10/2015 03:04 PM, Ernesto Ismail wrote:
> I just pulled the latest version and am planning my approach. Once I'm
> done, how would you like me to contribute it? Is it possible for me to
> push my submission to the repository for review?

Yes. You need to fork the github repository with your own github user
name; you then pull a copy of this fork onto your local harddrive (i.e.,
you "clone" it). You should then make all of your changes on a branch,
push this branch to your forked repository, and then create a "pull
request" that we can look at, comment on, and ultimately merge.

There are a number of tutorials online that illustrate how this works if
you are unfamiliar with this language.

Best
W.

Metin C.

unread,
Sep 29, 2016, 10:21:59 AM9/29/16
to deal.II User Group, bang...@tamu.edu
Dear Wolfgang,

I would like to implement the gradients (or symmetric_gradient) and laplacians functions for the symmetric_tensor class.

I need help to figure out some functions in fe_values.h and fe_values.cc sources.

Could you please help me understand what's happening in the divergence function (SymmetricTensor<2, dim, spacedim>::divergence) and the symmetric_gradient function for the vectors (Vector<dim,spacedim>::symmetric_gradient), or point out any material (manual, video etc.)?

Thank you in advance.

Best,
Metin

Wolfgang Bangerth

unread,
Sep 29, 2016, 12:22:26 PM9/29/16
to dea...@googlegroups.com

Metin,

> I need help to figure out some functions in fe_values.h and fe_values.cc
> sources.
>
> Could you please help me understand what's happening in the divergence
> function (SymmetricTensor<2, dim, spacedim>::divergence) and the
> symmetric_gradient function for the vectors
> (Vector<dim,spacedim>::symmetric_gradient), or point out any material
> (manual, video etc.)?

Can you be more specific which functions and which parts within them you
have trouble with?

Best
Wolfgang

--
------------------------------------------------------------------------
Wolfgang Bangerth email: bang...@colostate.edu
www: http://www.math.colostate.edu/~bangerth/

Metin Cakircali

unread,
Sep 30, 2016, 4:16:41 AM9/30/16
to deal.II User Group, bang...@colostate.edu
Hi Wolfgang,

In the fe_values.cc, the function "FEValuesViews::internal::do_function_derivatives" (for vectors), and in the fe_values.h, the type functions "vector::gradient" and "vector::symmetric_gradient"; are not clear to me because I'm not familiar with the data structure.

Inside the fe_values.cc, there are 3 do_function_divergences functions; for the vectors, for the tensors, and for the symmetric tensors. For the symmetric tensors and the tensors, (snc == -2) and (snc != -1) cases have been implemented but the else case is just "Assert (false, ExcNotImplemented());". 

For the vectors, the implementation (for the else case) is as following;

      for (unsigned int shape_function=0;

           shape_function<dofs_per_cell; ++shape_function)

        {

            for (unsigned int d=0; d<spacedim; ++d)

              if (shape_function_data[shape_function].is_nonzero_shape_function_component[d])

                {

                  const dealii::Tensor<1,spacedim> *shape_gradient_ptr =

                    &shape_gradients[shape_function_data[shape_function].

                                     row_index[d]][0];

                  for (unsigned int q_point=0; q_point<n_quadrature_points; ++q_point)

                    divergences[q_point] += value * (*shape_gradient_ptr++)[d];

                }

          }

To me, it's not clear how the "value and shape_gradient_ptr" is used or in general how the (e.g.) u_x+v_y+w_z is done..


For the SymmetricTensor, the code differs as;

              const unsigned int ii = dealii::SymmetricTensor<2,spacedim>::

                                      unrolled_to_component_indices(comp)[0];

              const unsigned int jj = dealii::SymmetricTensor<2,spacedim>::

                                      unrolled_to_component_indices(comp)[1];


              for (unsigned int q_point = 0; q_point < n_quadrature_points;

                   ++q_point, ++shape_gradient_ptr)

                {

                  divergences[q_point][ii] += value * (*shape_gradient_ptr)[jj];


                  if (ii != jj)

                    divergences[q_point][jj] += value * (*shape_gradient_ptr)[ii];

                }

I again cannot follow it. and what should I understand, that the loop over spacedim (or SymmetricTensor<2,spacedim>::n_independent_components) not implemented or not needed? please see, Assert (false, ExcNotImplemented());


Also, as a general question, how/where does the "Tensor<2, dim, spacedim>::divergence" function operate?


I'd appreciate if you could walk me through these, so that I can proceed with the gradient function implementation. 

Thank you in advance.

Cheers,
Metin

Daniel Arndt

unread,
Oct 2, 2016, 7:13:55 AM10/2/16
to deal.II User Group, bang...@colostate.edu
Metin,

[...]
For the vectors, the implementation (for the else case) is as following;

      for (unsigned int shape_function=0;

           shape_function<dofs_per_cell; ++shape_function)

        {

            for (unsigned int d=0; d<spacedim; ++d)

              if (shape_function_data[shape_function].is_nonzero_shape_function_component[d])

                {

                  const dealii::Tensor<1,spacedim> *shape_gradient_ptr =

                    &shape_gradients[shape_function_data[shape_function].

                                     row_index[d]][0];

                  for (unsigned int q_point=0; q_point<n_quadrature_points; ++q_point)

                    divergences[q_point] += value * (*shape_gradient_ptr++)[d];

                }

          }

To me, it's not clear how the "value and shape_gradient_ptr" is used or in general how the (e.g.) u_x+v_y+w_z is done..

Let me just comment on this: 
The divergence at a quadrature point is decomposed into a sum over all shape functions and all of their components.
Since the value at a certain quadrature point q_p of a FE function u can be written as u(q_p)=\sum_i u_i \phi_i(q_p),
it holds \nabla \cdot u(q_p) = \sum_i u_i \nabla \cdot \phi_i(q_p) = \sum_i u_i \sum_c \partial_c \phi_i^c(q_p) where \phi_i^c is the cth component of the ith shape function. 
This is exactly what is done in the last line.
shape_gradient_ptr is initialized with the gradient of the dth component of the considered shape_function at the first quadrature point.
By "*shape_gradient_ptr++", the gradient at this quadrature point is returned and the pointer incremented such that it points to the
gradient at the next quadrature point.

Best,
Daniel

Metin Cakircali

unread,
Oct 4, 2016, 5:59:08 AM10/4/16
to deal.II User Group, bang...@colostate.edu
Daniel,

thank you for the explanation. I understand that the components are in space (x/y/z), and (*shape_gradient_ptr++)[d] would be derivative of phi in each direction; is that correct?

(compared to vectors) the implementation of divergence function for the tensors is as following;

          if (snc != -1)

            {

              const unsigned int comp =

                shape_function_data[shape_function].single_nonzero_component_index;


              const dealii::Tensor < 1, spacedim> *shape_gradient_ptr =

                &shape_gradients[snc][0];


              const TableIndices<2> indices = dealii::Tensor<2,spacedim>::unrolled_to_component_indices(comp);

              const unsigned int ii = indices[0];

              const unsigned int jj = indices[1];


              for (unsigned int q_point = 0; q_point < n_quadrature_points;

                   ++q_point, ++shape_gradient_ptr)

                {

                  divergences[q_point][jj] += value * (*shape_gradient_ptr)[ii];

                }

            }

          else

            {

              for (unsigned int d = 0;

                   d < dim*dim; ++d)

                if (shape_function_data[shape_function].is_nonzero_shape_function_component[d])

                  {

                    Assert (false, ExcNotImplemented());

                  }

            }


There is only the "snc != 1" case, and it seems that the component now means the tensor components and not the directions in space. Is this function (for tensors) not yet implemented? or is it sth related to non-primitive shape functions (I would appreciate if you could comment on this as well)?


Thank you in advance.


Best,

Metin


Daniel Arndt

unread,
Oct 4, 2016, 4:15:00 PM10/4/16
to deal.II User Group, bang...@colostate.edu
Metin,


I understand that the components are in space (x/y/z), and (*shape_gradient_ptr++)[d] would be derivative of phi in each direction; is that correct?
Yes, that is the derivative of the dth component in direction d.

(compared to vectors) the implementation of divergence function for the tensors is as following;

          if (snc != -1)

            {

              const unsigned int comp =

                shape_function_data[shape_function].single_nonzero_component_index;


              const dealii::Tensor < 1, spacedim> *shape_gradient_ptr =

                &shape_gradients[snc][0];


              const TableIndices<2> indices = dealii::Tensor<2,spacedim>::unrolled_to_component_indices(comp);

              const unsigned int ii = indices[0];

              const unsigned int jj = indices[1];


              for (unsigned int q_point = 0; q_point < n_quadrature_points;

                   ++q_point, ++shape_gradient_ptr)

                {

                  divergences[q_point][jj] += value * (*shape_gradient_ptr)[ii];

                }

            }

This is similar to the previous one. Note that the ith component of the divergence of a rank-2-tensor is defined as sum_i \partial_i T_{ij}.
This is what is implemented for the general (non-symmetric) Tensor class. You have to compare this to the Vector implementation for primitive shape functions.
Basically, ii corresponds to the first index of the non-zero component and jj corresponds to the second index of the non-zero component.
We figure the correct component of the divergence add add the appropriate derivative to it.
For a SymmetricTensor, only T_{ij} for i\leq j is stored.Therefore, we need to have the line

if (ii != jj)
  divergences[q_point][jj] += value * (*shape_gradient_ptr)[ii];

additionally to account for the contribution of T_{ji} add the same time.


There is only the "snc != 1" case, and it seems that the component now means the tensor components and not the directions in space. Is this function (for tensors) not yet implemented? or is it sth related to non-primitive shape functions (I would appreciate if you could comment on this as well)?

This is only implemented for primitive shape functions.

Best,
Daniel 

Metin Cakircali

unread,
Oct 5, 2016, 9:20:18 AM10/5/16
to deal.II User Group, bang...@colostate.edu
Daniel,

Thanks again. To summarize, I want to implement the gradients and the laplacian functions for the SymmetricTensor class.

The laplacian (trace of hessian) for the fe_values block extractor is straightforward, but the gradients (of the solution field) for the SymmetricTensor has some issues.

e.g., what would be the type for the gradient of SymmetricTensor<2,dim> ? how to represent this --> [(S_1,x),(S_1,y);(S_2,x),(S_2,y);(S_3,x),(S_3,y)]... Each component of the SymmetricTensor is a vector.

Best,
Metin
Reply all
Reply to author
Forward
0 new messages