]> https://gitweb.dealii.org/ - dealii.git/commitdiff
implement gradient of FEValuesViews::Tensor
authorDenis Davydov <davydden@gmail.com>
Thu, 12 Apr 2018 18:36:29 +0000 (20:36 +0200)
committerDenis Davydov <davydden@gmail.com>
Thu, 12 Apr 2018 18:36:29 +0000 (20:36 +0200)
Also change meaning of divergence so that
Grad(T) : I = Div(T).

include/deal.II/fe/fe_values.h
include/deal.II/fe/fe_values_extractors.h
source/fe/fe_values.cc
source/fe/fe_values.inst.in

index 37878b2a7d3745d857272f723f37a1a7446b1cc2..406404588f99e3bf1c5d2fb34d1e54d1c85dc1e1 100644 (file)
@@ -1376,17 +1376,18 @@ namespace FEValuesViews
    * @ref vector_valued
    * module.
    *
-   * This class allows to query the value and divergence of (components of)
+   * This class allows to query the value, gradient and divergence of (components of)
    * shape functions and solutions representing tensors. The divergence of a
-   * tensor $T_{ij}, 0\le i,j<\text{dim}$ is defined as $d_i = \sum_j
-   * \frac{\partial T_{ji}}{\partial x_j}, 0\le i<\text{dim}$.
+   * tensor $T_{ij},\, 0\le i,j<\text{dim}$ is defined as $d_i = \sum_j
+   * \frac{\partial T_{ij}}{\partial x_j}, \, 0\le i<\text{dim}$,
+   * whereas its gradient is $G_{ijk} = \frac{\partial T_{ij}}{\partial x_k}$.
    *
    * You get an object of this type if you apply a FEValuesExtractors::Tensor
    * to an FEValues, FEFaceValues or FESubfaceValues object.
    *
    * @ingroup feaccess vector_valued
    *
-   * @author Denis Davydov, 2013
+   * @author Denis Davydov, 2013, 2018
    */
   template <int dim, int spacedim>
   class Tensor<2,dim,spacedim>
@@ -1404,6 +1405,11 @@ namespace FEValuesViews
      */
     typedef dealii::Tensor<1, spacedim> divergence_type;
 
+    /**
+     * Data type for taking the gradient of a second order tensor: a third order tensor.
+     */
+    typedef dealii::Tensor<3, spacedim> gradient_type;
+
     /**
      * A struct that provides the output type for the product of the value
      * and derivatives of basis functions of the Tensor view and any @p Number type.
@@ -1422,6 +1428,12 @@ namespace FEValuesViews
        * divergences of the view the Tensor class.
        */
       typedef typename ProductType<Number, typename Tensor<2,dim,spacedim>::divergence_type>::type divergence_type;
+
+      /**
+       * A typedef for the data type of the product of a @p Number and the
+       * gradient of the view the Tensor class.
+       */
+      typedef typename ProductType<Number, typename Tensor<2,dim,spacedim>::gradient_type>::type gradient_type;
     };
 
     /**
@@ -1528,6 +1540,23 @@ namespace FEValuesViews
     divergence (const unsigned int shape_function,
                 const unsigned int q_point) const;
 
+    /**
+     * Return the gradient (3-rd order tensor) of the vector components selected by this
+     * view, for the shape function and quadrature point selected by the
+     * arguments.
+     *
+     * See the general discussion of this class for a definition of the
+     * gradient.
+     *
+     * @note The meaning of the arguments is as documented for the value()
+     * function.
+     *
+     * @dealiiRequiresUpdateFlags{update_gradients}
+     */
+    gradient_type
+    gradient (const unsigned int shape_function,
+              const unsigned int q_point) const;
+
     /**
      * Return the values of the selected vector components of the finite
      * element function characterized by <tt>fe_function</tt> at the
@@ -1603,8 +1632,34 @@ namespace FEValuesViews
      */
     template <class InputVector>
     void get_function_divergences_from_local_dof_values (const InputVector &dof_values,
-                                                         std::vector<typename OutputType<typename InputVector::value_type>::divergence_type> &values) const;
+                                                         std::vector<typename OutputType<typename InputVector::value_type>::divergence_type> &divergences) const;
 
+    /**
+     * Return the gradient of the selected vector components of the finite
+     * element function characterized by <tt>fe_function</tt> at the
+     * quadrature points of the cell, face or subface selected the last time
+     * the <tt>reinit</tt> function of the FEValues object was called.
+     *
+     * See the general discussion of this class for a definition of the
+     * gradient.
+     *
+     * The data type stored by the output vector must be what you get when you
+     * multiply the gradients of shape functions (i.e., @p gradient_type)
+     * times the type used to store the values of the unknowns $U_j$ of your
+     * finite element vector $U$ (represented by the @p fe_function argument).
+     *
+     * @dealiiRequiresUpdateFlags{update_gradients}
+     */
+    template <class InputVector>
+    void get_function_gradients (const InputVector &fe_function,
+                                 std::vector<typename ProductType<gradient_type,typename InputVector::value_type>::type> &gradients) const;
+
+    /**
+     * @copydoc FEValuesViews::Tensor<2,dim,spacedim>::get_function_values_from_local_dof_values()
+     */
+    template <class InputVector>
+    void get_function_gradients_from_local_dof_values (const InputVector &dof_values,
+                                                       std::vector<typename OutputType<typename InputVector::value_type>::gradient_type> &gradients) const;
 
   private:
     /**
@@ -4227,7 +4282,8 @@ namespace FEValuesViews
         const dealii::Tensor<1, spacedim> &phi_grad = fe_values->finite_element_output.shape_gradients[snc][q_point];
 
         divergence_type return_value;
-        return_value[jj] = phi_grad[ii];
+        // note that we contract \nabla from the right
+        return_value[ii] = phi_grad[jj];
 
         return return_value;
       }
@@ -4238,6 +4294,58 @@ namespace FEValuesViews
         return return_value;
       }
   }
+
+  template <int dim, int spacedim>
+  inline
+  typename Tensor<2, dim, spacedim>::gradient_type
+  Tensor<2, dim, spacedim>::gradient(const unsigned int shape_function,
+                                     const unsigned int q_point) const
+  {
+    Assert (shape_function < fe_values->fe->dofs_per_cell,
+            ExcIndexRange (shape_function, 0, fe_values->fe->dofs_per_cell));
+    Assert (fe_values->update_flags & update_gradients,
+            (typename FEValuesBase<dim,spacedim>::ExcAccessToUninitializedField("update_gradients")));
+
+    const int snc = shape_function_data[shape_function].single_nonzero_component;
+
+    if (snc == -2)
+      {
+        // shape function is zero for the selected components
+        return gradient_type();
+      }
+    else if (snc != -1)
+      {
+        // we have a single non-zero component when the tensor is
+        // represented in unrolled form.
+        //
+        // the gradient of a second-order tensor is a third order tensor.
+        //
+        // assume the second-order tensor is A with components A_{ij},
+        // then gradient is B_{ijk} := \frac{\partial A_{ij}}{\partial x_k}
+        //
+        // Now, we know the nonzero component in unrolled form: it is indicated
+        // by 'snc'. we can figure out which tensor components belong to this:
+        const unsigned int comp =
+          shape_function_data[shape_function].single_nonzero_component_index;
+        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];
+
+        const dealii::Tensor<1, spacedim> &phi_grad = fe_values->finite_element_output.shape_gradients[snc][q_point];
+
+        gradient_type return_value;
+        return_value[ii][jj] = phi_grad;
+
+        return return_value;
+      }
+    else
+      {
+        Assert (false, ExcNotImplemented());
+        gradient_type return_value;
+        return return_value;
+      }
+  }
+
 }
 
 
index c086a94d1d346c0f080ff5e79dd308ce036f6d79..0e10b6569dbbefdd0ed788268c60b8adeaabf9d8 100644 (file)
@@ -168,7 +168,7 @@ namespace FEValuesExtractors
 
 
   /**
-   * Extractor for a (possible non-)symmetric tensor of a rank specified by
+   * Extractor for a general tensor of a given rank specified by
    * the template argument. For a second order tensor, this represents a
    * collection of <code>(dim*dim)</code> components of a vector-valued
    * element. The value of <code>dim</code> is defined by the FEValues object
index b4518e7031cb08d2cef30801f5b6618289c40feb..ddbfb4888c29c82e6f5636fa2064ffc68c036e95 100644 (file)
@@ -1308,7 +1308,69 @@ namespace FEValuesViews
               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];
+                  divergences[q_point][ii] += value * (*shape_gradient_ptr)[jj];
+                }
+            }
+          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());
+                  }
+            }
+        }
+    }
+
+    template <int dim, int spacedim, typename Number>
+    void
+    do_function_gradients (const ArrayView<Number> &dof_values,
+                           const Table<2,dealii::Tensor<1,spacedim> > &shape_gradients,
+                           const std::vector<typename Tensor<2,dim,spacedim>::ShapeFunctionData> &shape_function_data,
+                           std::vector<typename Tensor<2,dim,spacedim>::template OutputType<Number>::gradient_type> &gradients)
+    {
+      const unsigned int dofs_per_cell = dof_values.size();
+      const unsigned int n_quadrature_points = dofs_per_cell > 0 ?
+                                               shape_gradients[0].size() : gradients.size();
+      AssertDimension (gradients.size(), n_quadrature_points);
+
+      std::fill (gradients.begin(), gradients.end(),
+                 typename Tensor<2,dim,spacedim>::template OutputType<Number>::gradient_type());
+
+      for (unsigned int shape_function=0;
+           shape_function<dofs_per_cell; ++shape_function)
+        {
+          const int snc = shape_function_data[shape_function].single_nonzero_component;
+
+          if (snc == -2)
+            // shape function is zero for the selected components
+            continue;
+
+          const Number &value = dof_values[shape_function];
+          // For auto-differentiable numbers, the fact that a DoF value is zero
+          // does not imply that its derivatives are zero as well. So we
+          // can't filter by value for these number types.
+          if (!Differentiation::AD::is_ad_number<Number>::value)
+            if (value == dealii::internal::NumberType<Number>::value(0.0))
+              continue;
+
+          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)
+                {
+                  gradients[q_point][ii][jj] += value * (*shape_gradient_ptr);
                 }
             }
           else
@@ -2080,6 +2142,52 @@ namespace FEValuesViews
     (make_array_view(dof_values.begin(), dof_values.end()),
      fe_values->finite_element_output.shape_gradients, shape_function_data, divergences);
   }
+
+
+
+  template <int dim, int spacedim>
+  template <class InputVector>
+  void
+  Tensor<2, dim, spacedim>::
+  get_function_gradients(const InputVector &fe_function,
+                         std::vector<typename ProductType<gradient_type,typename InputVector::value_type>::type> &gradients) const
+  {
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim,spacedim>::ExcAccessToUninitializedField("update_gradients")));
+    Assert(fe_values->present_cell.get() != nullptr,
+           ExcMessage("FEValues object is not reinit'ed to any cell"));
+    AssertDimension(fe_function.size(),
+                    fe_values->present_cell->n_dofs_for_dof_handler());
+
+    // get function values of dofs
+    // on this cell
+    dealii::Vector<typename InputVector::value_type> dof_values(fe_values->dofs_per_cell);
+    fe_values->present_cell->get_interpolated_dof_values(fe_function, dof_values);
+    internal::do_function_gradients<dim,spacedim>
+    (make_array_view(dof_values.begin(), dof_values.end()),
+     fe_values->finite_element_output.shape_gradients, shape_function_data, gradients);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <class InputVector>
+  void
+  Tensor<2, dim, spacedim>::
+  get_function_gradients_from_local_dof_values (const InputVector &dof_values,
+                                                std::vector<typename OutputType<typename InputVector::value_type>::gradient_type> &gradients) const
+  {
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim,spacedim>::ExcAccessToUninitializedField("update_gradients")));
+    Assert(fe_values->present_cell.get() != nullptr,
+           ExcMessage("FEValues object is not reinit'ed to any cell"));
+    AssertDimension (dof_values.size(), fe_values->dofs_per_cell);
+
+    internal::do_function_gradients<dim,spacedim>
+    (make_array_view(dof_values.begin(), dof_values.end()),
+     fe_values->finite_element_output.shape_gradients, shape_function_data, gradients);
+  }
+
 }
 
 
index 7a78ca1539914221ee41daacc58706bc8b6f5252..de759298b6d509c96136a88910ab36944f721d3c 100644 (file)
@@ -135,6 +135,10 @@ for (VEC : VECTOR_TYPES; deal_II_dimension : DIMENSIONS; deal_II_space_dimension
     void FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>
     ::get_function_divergences<dealii::VEC>
     (const dealii::VEC&, std::vector<ProductType<dealii::VEC::value_type,dealii::Tensor<1,deal_II_space_dimension> >::type>&) const;
+    template
+    void FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>
+    ::get_function_gradients<dealii::VEC>
+    (const dealii::VEC&, std::vector<ProductType<dealii::VEC::value_type,dealii::Tensor<3,deal_II_space_dimension> >::type>&) const;
 #endif
 }
 
@@ -235,6 +239,11 @@ for (VEC : GENERAL_CONTAINER_TYPES;
     void FEValuesViews::Tensor<2,deal_II_dimension, deal_II_space_dimension>
     ::get_function_divergences_from_local_dof_values<VEC<Number>>
             (const VEC<Number>&, std::vector<typename OutputType<Number>::divergence_type>&) const;
+
+    template
+    void FEValuesViews::Tensor<2,deal_II_dimension, deal_II_space_dimension>
+    ::get_function_gradients_from_local_dof_values<VEC<Number>>
+            (const VEC<Number>&, std::vector<typename OutputType<Number>::gradient_type>&) const;
 #endif
 }
 
@@ -396,6 +405,9 @@ for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : DIMENSIONS)
     template
     void FEValuesViews::Tensor<2,deal_II_dimension,deal_II_space_dimension>::get_function_divergences<dealii::IndexSet>
     (const dealii::IndexSet&, std::vector<ProductType<IndexSet::value_type,dealii::Tensor<1,deal_II_space_dimension> >::type>&) const;
+    template
+    void FEValuesViews::Tensor<2,deal_II_dimension,deal_II_space_dimension>::get_function_gradients<dealii::IndexSet>
+    (const dealii::IndexSet&, std::vector<ProductType<IndexSet::value_type,dealii::Tensor<3,deal_II_space_dimension> >::type>&) const;
 #endif
 }
 

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.