]> https://gitweb.dealii.org/ - dealii.git/commitdiff
AD Helpers: Introduce base class for cell-level AD helper classes
authorJean-Paul Pelteret <jppelteret@gmail.com>
Wed, 25 Jul 2018 21:11:22 +0000 (23:11 +0200)
committerJean-Paul Pelteret <jppelteret@gmail.com>
Fri, 7 Sep 2018 10:14:27 +0000 (12:14 +0200)
include/deal.II/differentiation/ad/ad_helpers.h
source/differentiation/ad/ad_helpers.cc
source/differentiation/ad/ad_helpers.inst1.in
source/differentiation/ad/ad_helpers.inst2.in

index a74c699b9421b49e1fdd711d14f5543e2b5bc077..cf6c3cd852740c87822a3ef90b6cb09c6f8801bf 100644 (file)
@@ -29,6 +29,9 @@
 #  include <deal.II/differentiation/ad/sacado_number_types.h>
 #  include <deal.II/differentiation/ad/sacado_product_types.h>
 
+#  include <deal.II/lac/full_matrix.h>
+#  include <deal.II/lac/vector.h>
+
 #  include <algorithm>
 #  include <iostream>
 #  include <iterator>
@@ -712,10 +715,368 @@ namespace Differentiation
     }; // class ADHelperBase
 
 
+
+    /**
+     * A general helper class that facilitates the evaluation of a vector of
+     * functions, as well as its first derivatives (their Jacobian).
+     * This class would typically be used to compute the linearization of a
+     * set of local nonlinear equations, but can also be used as the basis of
+     * the linearization of the residual vector defined on the level of a finite
+     * element (for example, in order to compute the Jacobian matrix necessary
+     * in Newton-type solvers for nonlinear problems).
+     *
+     * @note When using the cell-level taped AD methods in 3d and/or with higher
+     * order elements, it is incredibly easy to exceed the tape buffer size.
+     * The reason for this is two-fold:
+     *   1. there are are many independent variables (the local
+     *      degrees-of-freedom) to take the derivatives with respect to, and
+     *   2. the expressions for the dependent variables (each being a component
+     *      of the residual vector) in terms of all of the independent variables
+     *      are lengthy, especially when non-trivial constitutive laws are
+     *      considered.
+     * These buffer variables dictate the amount of memory allocated to a tape
+     * before it is written to file (at a significant performance loss).
+     * Therefore for ADOL-C taped AD numbers, it may be desirable to
+     * create a file ".adolcrc" in the program run directory and set the buffer
+     * size therein (as is suggested by the ADOL-C manual). For example, the
+     * following settings increase the default buffer size by 128 times:
+     * @code
+     * "OBUFSIZE" "67108864"
+     * "LBUFSIZE" "67108864"
+     * "VBUFSIZE" "67108864"
+     * "TBUFSIZE" "67108864"
+     * @endcode
+     * Note that the quotation marks are mandatory.
+     * An alternative approach that allows for run-time decision making is to
+     * use the ADHelperBase::set_tape_buffer_sizes() function before starting
+     * taping (as done via the ADHelperBase::start_recording_operations()
+     * function).
+     *
+     * @warning ADOL-C does not support the standard threading models used by
+     * deal.II, so this class should @b not be embedded within a multithreaded
+     * function when using ADOL-C number types. It is, however, suitable for use
+     * in both serial and MPI routines.
+     *
+     * @author Jean-Paul Pelteret, 2016, 2017, 2018
+     */
+    template <enum AD::NumberTypes ADNumberTypeCode,
+              typename ScalarType = double>
+    class ADHelperCellLevelBase
+      : public ADHelperBase<ADNumberTypeCode, ScalarType>
+    {
+    public:
+      /**
+       * Type definition for the floating point number type that is used in,
+       * and results from, all computations.
+       */
+      using scalar_type =
+        typename ADHelperBase<ADNumberTypeCode, ScalarType>::scalar_type;
+
+      /**
+       * Type definition for the auto-differentiation number type that is used
+       * in all computations.
+       */
+      using ad_type =
+        typename ADHelperBase<ADNumberTypeCode, ScalarType>::ad_type;
+
+      /**
+       * @name Constructor / destructor
+       */
+      //@{
+
+      /**
+       * The constructor for the class.
+       *
+       * @param[in] n_independent_variables The number of independent variables
+       * that will be used in the definition of the functions that it is
+       * desired to compute the sensitivities of. In the computation of
+       * $\mathbf{f}(\mathbf{X})$, this will be the number of inputs
+       * $\mathbf{X}$, i.e. the dimension of the domain space.
+       * @param[in] n_dependent_variables The number of scalar functions to be
+       * defined that will have a sensitivity to the given independent
+       * variables. In the computation of $\mathbf{f}(\mathbf{X})$, this will
+       * be the number of outputs $\mathbf{f}$, i.e. the dimension of the
+       * image space.
+       */
+      ADHelperCellLevelBase(const unsigned int n_independent_variables,
+                            const unsigned int n_dependent_variables);
+
+      /**
+       * Destructor
+       */
+      virtual ~ADHelperCellLevelBase() = default;
+
+      //@}
+
+      /**
+       * @name Independent variables
+       */
+      //@{
+
+      /**
+       * Register the complete set of independent variables $\mathbf{X}$ that
+       * represent the local degree-of-freedom values.
+       *
+       * @param[in] dof_values A vector field associated with local
+       * degree-of-freedom values on the current finite element. These define
+       * the values of all independent variables. When considering taped AD
+       * numbers with branching functions, to avoid potential issues with branch
+       * switching it may be a good idea to choose these values close or equal
+       * to those that will be later evaluated and linearized around.
+       *
+       * @note The input value type must correspond to this class's @p scalar_type.
+       * Depending on the selected @p ADNumberTypeCode, this may or may not
+       * correspond with the @p ScalarType prescribed as a template argument.
+       *
+       * @note For taped AD numbers, this operation is only valid in recording mode.
+       */
+      void
+      register_dof_values(const std::vector<scalar_type> &dof_values);
+
+      /**
+       * Register the complete set of independent variables $\mathbf{X}$ that
+       * represent the local degree-of-freedom values.
+       *
+       * @param[in] values A global field from which the values of all
+       * independent variables will be extracted. This typically will be the
+       * solution vector around which point a residual vector is to be
+       * computed and around which linearization is to occur.
+       * When considering taped AD numbers with branching functions, to avoid
+       * potential issues with branch switching it may be a good idea to choose
+       * these values close or equal to those that will be later evaluated and
+       * linearized around.
+       * @param[in] local_dof_indices A vector of degree-of-freedom indices from
+       * which to extract the local degree-of-freedom values. This would
+       * typically obtained by calling <code>cell->get_dof_indices()</code>.
+       *
+       * @note For taped AD numbers, this operation is only valid in recording mode.
+       */
+      template <typename VectorType>
+      void
+      register_dof_values(
+        const VectorType &                                  values,
+        const std::vector<dealii::types::global_dof_index> &local_dof_indices);
+
+      /**
+       * Returns the complete set of degree-of-freedom values as represented by
+       * auto-differentiable numbers. These are the independent
+       * variables $\mathbf{X}$ about which the solution is linearized.
+       *
+       * It is indicated to the AD library that operations performed with these
+       * numbers are to be tracked, so they are considered "sensitive"
+       * variables. This is, therefore, the set of variables with which one
+       * would then perform computations, and based on which one can then
+       * extract both the value of the function and its derivatives with the
+       * member functions below. The values of the components of the returned
+       * object are initialized to the values set with
+       * register_independent_variable().
+       *
+       * @return An array of auto-differentiable type numbers representing the
+       * local degree-of-freedom values.
+       *
+       * @note For taped AD numbers, this operation is only valid in recording mode.
+       */
+      const std::vector<ad_type> &
+      get_sensitive_dof_values();
+
+      //@}
+
+      /**
+       * @name Post-processing
+       */
+      //@{
+
+      /*
+       * Returns the complete set of degree-of-freedom values of
+       * auto-differentiable number type. These store the same scalar values as
+       * the independent variables $\mathbf{X}$ about which the solution is
+       * linearized.
+       *
+       * Operations performed with these numbers are not tracked by the AD,
+       * libraries so they are considered "non-sensitive" variables.
+       * The values of the components of the returned object are initialized to
+       * the values set with register_dof_values().
+       *
+       * @return An array of auto-differentiable type numbers representing the
+       * local degree-of-freedom values.
+       *
+       * @note This function is not typically used within the context of automatic
+       * differentation computations, but can make performing substutitions in
+       * other post-processing computations more straight forward.
+       *
+       * @note For taped AD numbers, this operation is only valid outside recording mode.
+       */
+      std::vector<ad_type>
+      get_non_sensitive_dof_values() const;
+
+      //@}
+
+      /**
+       * @name Operations specific to taped mode: Reusing tapes
+       */
+      //@{
+
+      /**
+       * Set the values for the independent variables $\mathbf{X}$, i.e. the
+       * linearization point.
+       *
+       * @param[in] dof_values A vector field associated with local
+       * degree-of-freedom values on the current finite element. These define
+       * the values of all independent variables.
+       *
+       * @note The input value type must correspond to this class's @p scalar_type.
+       * Depending on the selected @p ADNumberTypeCode, this may or may not
+       * correspond with the @p ScalarType prescribed as a template argument.
+       *
+       * @note If the keep flag has been set when
+       * ADHelperBase::start_recording_operations() is called then the tape is
+       * immediately usable after creation, and the values of the independent
+       * variables set by register_dof_values() are those at which the function
+       * is to be evaluated. In this case, a separate call to this function is
+       * not strictly necessary.
+       */
+      void
+      set_dof_values(const std::vector<scalar_type> &dof_values);
+
+      /**
+       * Set the values for the independent variables $\mathbf{X}$, i.e. the
+       * linearization point.
+       *
+       * @param[in] values A vector field from which the values of all
+       * independent variables is to be extracted.
+       * @param[in] local_dof_indices A vector of degree-of-freedom indices from
+       * which to extract the local degree-of-freedom values. This would
+       * typically obtained by calling <code>cell->get_dof_indices()</code>.
+       *
+       * @note If the keep flag has been set when
+       * ADHelperBase::start_recording_operations() is called then the tape is
+       * immediately usable after creation, and the values of the independent
+       * variables set by register_dof_values() are those at which the function
+       * is to be evaluated. In this case, a separate call to this function is
+       * not strictly necessary.
+       */
+      template <typename VectorType>
+      void
+      set_dof_values(
+        const VectorType &                                  values,
+        const std::vector<dealii::types::global_dof_index> &local_dof_indices);
+
+      //@}
+
+      /**
+       * @name Dependent variables
+       */
+      //@{
+
+      /**
+       * Computes the value of the residual vector field
+       * $\mathbf{r}(\mathbf{X})$.
+       *
+       * @param[out] residual A Vector object with the value for each component
+       * of the vector field evaluated at the point defined by the independent
+       * variable values.
+       *
+       * @note The size of the @p residual vector is determined by the derived
+       * classes, as it depends on the order of the dependent variable(s)
+       * derivative(s) that it represents. Code examples that show how to use
+       * this interface will be provided in the documentation of the derived
+       * classes.
+       */
+      virtual void
+      compute_residual(Vector<scalar_type> &residual) const = 0;
+
+      /**
+       * Computes the gradient (first derivative) of the residual vector field
+       * with respect to all independent variables, i.e.
+       * @f[
+       *   \frac{\partial\mathbf{r}(\mathbf{X})}{\partial\mathbf{X}}
+       * @f]
+       *
+       * @param[out] linearization A FullMatrix with the gradient of each
+       * component of the vector field evaluated at the point defined by the
+       * independent variable values.
+       *
+       * @note The dimensions of the @p linearization matrix is determined by
+       * the derived classes, as it depends on the order of the dependent
+       * variable(s) derivative(s) that it represents. Code examples that show
+       * how to use this interface will be provided in the documentation of
+       * the derived classes.
+       */
+      virtual void
+      compute_linearization(FullMatrix<scalar_type> &linearization) const = 0;
+
+      //@}
+
+    }; // class ADHelperCellLevelBase
+
+
+  } // namespace AD
+} // namespace Differentiation
+
+
+/* ----------------- inline and template functions ----------------- */
+
+
+#  ifndef DOXYGEN
+
+namespace Differentiation
+{
+  namespace AD
+  {
+    /* ----------------- ADHelperCellLevelBase ----------------- */
+
+
+
+    template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
+    template <typename VectorType>
+    void
+    ADHelperCellLevelBase<ADNumberTypeCode, ScalarType>::register_dof_values(
+      const VectorType &                                  values,
+      const std::vector<dealii::types::global_dof_index> &local_dof_indices)
+    {
+      // This is actually the same thing the set_dof_values() function,
+      // in the sense that we simply populate our array of independent values
+      // with a meaningful number. However, in this case we need to double check
+      // that we're not registering these variables twice
+      Assert(
+        local_dof_indices.size() == this->n_independent_variables(),
+        ExcMessage(
+          "Degree-of-freedom index vector size does not match number of independent variables"));
+#    ifdef DEBUG
+      for (unsigned int i = 0; i < this->n_independent_variables(); ++i)
+        {
+          Assert(this->registered_independent_variable_values[i] == false,
+                 ExcMessage("Independent variables already registered."));
+        }
+#    endif
+      set_dof_values(values, local_dof_indices);
+    }
+
+
+
+    template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
+    template <typename VectorType>
+    void
+    ADHelperCellLevelBase<ADNumberTypeCode, ScalarType>::set_dof_values(
+      const VectorType &                                  values,
+      const std::vector<dealii::types::global_dof_index> &local_dof_indices)
+    {
+      Assert(local_dof_indices.size() == this->n_independent_variables(),
+             ExcMessage(
+               "Vector size does not match number of independent variables"));
+      for (unsigned int i = 0; i < this->n_independent_variables(); ++i)
+        ADHelperBase<ADNumberTypeCode, ScalarType>::set_sensitivity_value(
+          i, values[local_dof_indices[i]]);
+    }
+
+
   } // namespace AD
 } // namespace Differentiation
 
 
+#  endif // DOXYGEN
+
+
 DEAL_II_NAMESPACE_CLOSE
 
 #endif // defined(DEAL_II_WITH_ADOLC) || defined(DEAL_II_TRILINOS_WITH_SACADO)
index db9ed5325f1c4089c27ac2e663ef17d1d6b0fc71..fed7fe4d93a721a826fe3ee7d99b83d04eb4e33c 100644 (file)
@@ -725,6 +725,111 @@ namespace Differentiation
                                                      func);
       registered_marked_dependent_variables[index] = true;
     }
+
+
+
+    /* -------------------- ADHelperCellLevelBase -------------------- */
+
+
+
+    template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
+    ADHelperCellLevelBase<ADNumberTypeCode, ScalarType>::ADHelperCellLevelBase(
+      const unsigned int n_independent_variables,
+      const unsigned int n_dependent_variables)
+      : ADHelperBase<ADNumberTypeCode, ScalarType>(n_independent_variables,
+                                                   n_dependent_variables)
+    {}
+
+
+
+    template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
+    void
+    ADHelperCellLevelBase<ADNumberTypeCode, ScalarType>::register_dof_values(
+      const std::vector<scalar_type> &dof_values)
+    {
+      // This is actually the same thing the set_independent_variable function,
+      // in the sense that we simply populate our array of independent values
+      // with a meaningful number. However, in this case we need to double check
+      // that we're not registering these variables twice
+      Assert(dof_values.size() == this->n_independent_variables(),
+             ExcMessage(
+               "Vector size does not match number of independent variables"));
+      for (unsigned int i = 0; i < this->n_independent_variables(); ++i)
+        {
+          Assert(this->registered_independent_variable_values[i] == false,
+                 ExcMessage("Independent variable value already registered."));
+        }
+      set_dof_values(dof_values);
+    }
+
+
+
+    template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
+    const std::vector<
+      typename ADHelperCellLevelBase<ADNumberTypeCode, ScalarType>::ad_type> &
+    ADHelperCellLevelBase<ADNumberTypeCode,
+                          ScalarType>::get_sensitive_dof_values()
+    {
+      if (ADNumberTraits<ad_type>::is_taped == true)
+        {
+          Assert(this->active_tape() != numbers::invalid_tape_index,
+                 ExcMessage("Invalid tape index"));
+        }
+
+      // If necessary, initialize the internally stored vector of
+      // AD numbers that represents the independent variables
+      this->finalize_sensitive_independent_variables();
+      Assert(this->independent_variables.size() ==
+               this->n_independent_variables(),
+             ExcInternalError());
+
+      return this->independent_variables;
+    }
+
+
+
+    template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
+    std::vector<
+      typename ADHelperCellLevelBase<ADNumberTypeCode, ScalarType>::ad_type>
+    ADHelperCellLevelBase<ADNumberTypeCode,
+                          ScalarType>::get_non_sensitive_dof_values() const
+    {
+      if (ADNumberTraits<ad_type>::is_taped == true)
+        {
+          Assert(this->active_tape() != numbers::invalid_tape_index,
+                 ExcMessage("Invalid tape index"));
+        }
+
+      std::vector<ad_type> out(this->n_independent_variables(),
+                               dealii::internal::NumberType<ad_type>::value(
+                                 0.0));
+      for (unsigned int i = 0; i < this->n_independent_variables(); ++i)
+        this->initialize_non_sensitive_independent_variable(i, out[i]);
+
+      return out;
+    }
+
+
+
+    template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
+    void
+    ADHelperCellLevelBase<ADNumberTypeCode, ScalarType>::set_dof_values(
+      const std::vector<scalar_type> &values)
+    {
+      if (ADNumberTraits<ad_type>::is_taped == true)
+        {
+          Assert(this->active_tape() != numbers::invalid_tape_index,
+                 ExcMessage("Invalid tape index"));
+        }
+      Assert(values.size() == this->n_independent_variables(),
+             ExcMessage(
+               "Vector size does not match number of independent variables"));
+      for (unsigned int i = 0; i < this->n_independent_variables(); ++i)
+        ADHelperBase<ADNumberTypeCode, ScalarType>::set_sensitivity_value(
+          i, values[i]);
+    }
+
+
   } // namespace AD
 } // namespace Differentiation
 
index b91a64ed0b3ab4024d737de781e2830d9e644eaa..9ede62db6e45ab8c54f8c70737c5cc04bf64383d 100644 (file)
@@ -29,6 +29,14 @@ for (number : REAL_SCALARS)
     template
     class ADHelperBase<NumberTypes::adolc_tapeless,number>;
 
+    // -------------------------- ADHelperCellLevelBase ----------------------
+
+    template
+    class ADHelperCellLevelBase<NumberTypes::adolc_taped,number>;
+
+    template
+    class ADHelperCellLevelBase<NumberTypes::adolc_tapeless,number>;
+
     \}
     \}
 }
@@ -49,6 +57,14 @@ for ()
     template
     class ADHelperBase<NumberTypes::adolc_tapeless,typename NumberTraits<double,NumberTypes::adolc_tapeless>::ad_type>;
 
+    // -------------------------- ADHelperCellLevelBase ----------------------
+
+    template
+    class ADHelperCellLevelBase<NumberTypes::adolc_taped,typename NumberTraits<double,NumberTypes::adolc_taped>::ad_type>;
+
+    template
+    class ADHelperCellLevelBase<NumberTypes::adolc_tapeless,typename NumberTraits<double,NumberTypes::adolc_tapeless>::ad_type>;
+
 
     \}
     \}
index 793f417da17990cdc46519521ab5362fa153c152..0b436715cda8e855283d91cb6646b8bf2ea7d3b5 100644 (file)
@@ -35,6 +35,20 @@ for (number : REAL_SCALARS)
     template
     class ADHelperBase<NumberTypes::sacado_rad_dfad,number>;
 
+    // -------------------------- ADHelperCellLevelBase ----------------------
+
+    template
+    class ADHelperCellLevelBase<NumberTypes::sacado_dfad_dfad,number>;
+
+    template
+    class ADHelperCellLevelBase<NumberTypes::sacado_dfad,number>;
+
+    template
+    class ADHelperCellLevelBase<NumberTypes::sacado_rad,number>;
+
+    template
+    class ADHelperCellLevelBase<NumberTypes::sacado_rad_dfad,number>;
+
     \}
     \}
 }
@@ -61,6 +75,20 @@ for ()
     template
     class ADHelperBase<NumberTypes::sacado_rad_dfad,typename NumberTraits<double,NumberTypes::sacado_rad_dfad>::ad_type>;
 
+    // -------------------------- ADHelperCellLevelBase ----------------------
+
+    template
+    class ADHelperCellLevelBase<NumberTypes::sacado_dfad_dfad,typename NumberTraits<double,NumberTypes::sacado_dfad_dfad>::ad_type>;
+
+    template
+    class ADHelperCellLevelBase<NumberTypes::sacado_dfad,typename NumberTraits<double,NumberTypes::sacado_dfad>::ad_type>;
+
+    template
+    class ADHelperCellLevelBase<NumberTypes::sacado_rad,typename NumberTraits<double,NumberTypes::sacado_rad>::ad_type>;
+
+    template
+    class ADHelperCellLevelBase<NumberTypes::sacado_rad_dfad,typename NumberTraits<double,NumberTypes::sacado_rad_dfad>::ad_type>;
+
 
     \}
     \}

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.