From 13af5c499daea7ed65c9a94631b6881242fb1523 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Sat, 12 Aug 2017 01:08:47 -0600 Subject: [PATCH] Make the Tensor class more compatible with generic numbers. All stored number initialisation is explicitly performed, and their values are set to a safe default. Scalar values are passed by reference instead of by copy, preventing expensive and unnecessary overhead for AD numbers due to the creation of a temporary. --- include/deal.II/base/tensor.h | 107 ++++++++++++++++++++++++---------- 1 file changed, 77 insertions(+), 30 deletions(-) diff --git a/include/deal.II/base/tensor.h b/include/deal.II/base/tensor.h index a34599104e..bcc433f727 100644 --- a/include/deal.II/base/tensor.h +++ b/include/deal.II/base/tensor.h @@ -35,6 +35,7 @@ DEAL_II_NAMESPACE_OPEN template class Point; template class Tensor; template class Vector; +template class VectorizedArray; #ifndef DOXYGEN // Overload invalid tensor types of negative rank that come up during @@ -147,7 +148,7 @@ public: * Constructor, where the data is copied from a C-style array. */ template - Tensor (const OtherNumber initializer); + Tensor (const OtherNumber &initializer); /** * Return a reference to the encapsulated Number object. Since rank-0 @@ -208,13 +209,13 @@ public: * @ingroup CUDAWrappers */ template - DEAL_II_CUDA_HOST_DEV Tensor<0,dim,Number> &operator *= (const OtherNumber factor); + DEAL_II_CUDA_HOST_DEV Tensor<0,dim,Number> &operator *= (const OtherNumber &factor); /** * Divide the scalar by factor. */ template - Tensor<0,dim,Number> &operator /= (const OtherNumber factor); + Tensor<0,dim,Number> &operator /= (const OtherNumber &factor); /** * Tensor with inverted entries. @@ -437,7 +438,7 @@ public: * value allowed for d, allowing the intuitive notation * t=0 to reset all elements of the tensor to zero. */ - Tensor &operator = (const Number d); + Tensor &operator = (const Number &d); /** * Test for equality of two tensors. @@ -470,13 +471,13 @@ public: * @ingroup CUDAWrappers */ template - DEAL_II_CUDA_HOST_DEV Tensor &operator *= (const OtherNumber factor); + DEAL_II_CUDA_HOST_DEV Tensor &operator *= (const OtherNumber &factor); /** * Scale the vector by 1/factor. */ template - Tensor &operator /= (const OtherNumber factor); + Tensor &operator /= (const OtherNumber &factor); /** * Unary minus operator. Negate all entries of a tensor. @@ -585,13 +586,51 @@ private: }; +namespace internal +{ + /** + * The structs below are needed since VectorizedArray is a POD-type without a constructor and + * can be a template argument for Tensor<...,T2> where T2 would equal Tensor<1, dim, VectorizedArray >. + * Internally, in previous versions of deal.II, Tensor<...,T2> would make use of the constructor + * of T2 leading to a compile-time error. However simply adding a constructor for VectorizedArray + * breaks the POD-idioms needed elsewhere. Calls to constructors of T2 subsequently got replaced by a + * call to internal::NumberType which then determines the right function to use by template deduction. + * A detailed discussion can be found at https://github.com/dealii/dealii/pull/3967 . Also see + * numbers.h for another specialization. + */ + template + struct NumberType > + { + static Tensor value (const T &t) + { + Tensor tmp; + tmp=t; + return tmp; + } + }; + + template + struct NumberType > > + { + static Tensor > value (const T &t) + { + Tensor > tmp; + tmp=internal::NumberType >::value(t); + return tmp; + } + }; +} + + /*---------------------- Inline functions: Tensor<0,dim> ---------------------*/ template inline DEAL_II_CUDA_HOST_DEV Tensor<0,dim,Number>::Tensor () - : value() +// Some auto-differentiable numbers need explicit +// zero initialization. + : value(internal::NumberType::value(0.0)) { } @@ -599,7 +638,7 @@ DEAL_II_CUDA_HOST_DEV Tensor<0,dim,Number>::Tensor () template template inline -Tensor<0,dim,Number>::Tensor (const OtherNumber initializer) +Tensor<0,dim,Number>::Tensor (const OtherNumber &initializer) { value = initializer; } @@ -683,7 +722,7 @@ Tensor<0,dim,Number> &Tensor<0,dim,Number>::operator -= (const Tensor<0,dim,Othe template template inline -DEAL_II_CUDA_HOST_DEV Tensor<0,dim,Number> &Tensor<0,dim,Number>::operator *= (const OtherNumber s) +DEAL_II_CUDA_HOST_DEV Tensor<0,dim,Number> &Tensor<0,dim,Number>::operator *= (const OtherNumber &s) { value *= s; return *this; @@ -693,7 +732,7 @@ DEAL_II_CUDA_HOST_DEV Tensor<0,dim,Number> &Tensor<0,dim,Number>::operator *= (c template template inline -Tensor<0,dim,Number> &Tensor<0,dim,Number>::operator /= (const OtherNumber s) +Tensor<0,dim,Number> &Tensor<0,dim,Number>::operator /= (const OtherNumber &s) { value /= s; return *this; @@ -745,7 +784,9 @@ template inline void Tensor<0,dim,Number>::clear () { - value = value_type(); + // Some auto-differentiable numbers need explicit + // zero initialization. + value = internal::NumberType::value(0.0); } @@ -900,13 +941,14 @@ Tensor::operator = (const Tensor &t) template inline Tensor & -Tensor::operator = (const Number d) +Tensor::operator = (const Number &d) { - Assert (d == Number(), ExcMessage ("Only assignment with zero is allowed")); + Assert (d == internal::NumberType::value(0.0), + ExcMessage ("Only assignment with zero is allowed")); (void) d; for (unsigned int i=0; i::value(0.0); return *this; } @@ -977,7 +1019,7 @@ template inline DEAL_II_CUDA_HOST_DEV Tensor & -Tensor::operator *= (const OtherNumber s) +Tensor::operator *= (const OtherNumber &s) { for (unsigned int i=0; i template inline Tensor & -Tensor::operator /= (const OtherNumber s) +Tensor::operator /= (const OtherNumber &s) { for (unsigned int i=0; i::real_type Tensor::norm_square () const { - typename numbers::NumberTraits::real_type s = typename numbers::NumberTraits::real_type(); + typename numbers::NumberTraits::real_type s + = internal::NumberType::real_type>::value(0.0); for (unsigned int i=0; i::clear () { for (unsigned int i=0; i::value(0.0); } @@ -1184,7 +1227,7 @@ std::ostream &operator << (std::ostream &out, const Tensor<0,dim,Number> &p) template inline typename ProductType::type -operator * (const Other object, +operator * (const Other &object, const Tensor<0,dim,Number> &t) { return object * static_cast(t); @@ -1204,7 +1247,7 @@ template inline typename ProductType::type operator * (const Tensor<0,dim,Number> &t, - const Other object) + const Other &object) { return static_cast(t) * object; } @@ -1239,9 +1282,9 @@ template inline Tensor<0,dim,typename ProductType::type>::type> operator / (const Tensor<0,dim,Number> &t, - const OtherNumber factor) + const OtherNumber &factor) { - return static_cast(t) / factor; + return static_cast(t) / factor; } @@ -1253,7 +1296,8 @@ operator / (const Tensor<0,dim,Number> &t, template inline Tensor<0, dim, typename ProductType::type> -operator+ (const Tensor<0,dim,Number> &p, const Tensor<0,dim,OtherNumber> &q) +operator+ (const Tensor<0,dim,Number> &p, + const Tensor<0,dim,OtherNumber> &q) { return static_cast(p) + static_cast(q); } @@ -1267,7 +1311,8 @@ operator+ (const Tensor<0,dim,Number> &p, const Tensor<0,dim,OtherNumber> &q) template inline Tensor<0, dim, typename ProductType::type> -operator- (const Tensor<0,dim,Number> &p, const Tensor<0,dim,OtherNumber> &q) +operator- (const Tensor<0,dim,Number> &p, + const Tensor<0,dim,OtherNumber> &q) { return static_cast(p) - static_cast(q); } @@ -1289,7 +1334,7 @@ template ::type>::type> operator * (const Tensor &t, - const OtherNumber factor) + const OtherNumber &factor) { // recurse over the base objects Tensor::type> tt; @@ -1314,7 +1359,7 @@ template inline Tensor::type, OtherNumber>::type> -operator * (const Number factor, +operator * (const Number &factor, const Tensor &t) { // simply forward to the operator above @@ -1335,7 +1380,7 @@ template ::type>::type> operator / (const Tensor &t, - const OtherNumber factor) + const OtherNumber &factor) { // recurse over the base objects Tensor::type> tt; @@ -1355,7 +1400,8 @@ operator / (const Tensor &t, template inline Tensor::type> -operator+ (const Tensor &p, const Tensor &q) +operator+ (const Tensor &p, + const Tensor &q) { Tensor::type> tmp (p); @@ -1376,7 +1422,8 @@ operator+ (const Tensor &p, const Tensor template inline Tensor::type> -operator- (const Tensor &p, const Tensor &q) +operator- (const Tensor &p, + const Tensor &q) { Tensor::type> tmp (p); @@ -1741,7 +1788,7 @@ Number determinant (const Tensor<2,dim,Number> &t) { // Compute the determinant using the Laplace expansion of the // determinant. We expand along the last row. - Number det = Number(); + Number det = internal::NumberType::value(0.0); for (unsigned int k=0; k