// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FVECTOR_HH #define DUNE_FVECTOR_HH #include <cmath> #include <cstddef> #include <cstdlib> #include <complex> #include <cstring> #include <utility> #include <initializer_list> #include <algorithm> #include <dune/common/std/constexpr.hh> #include "typetraits.hh" #include "exceptions.hh" #include "array.hh" #include "ftraits.hh" #include "densevector.hh" #include "unused.hh" namespace Dune { /** @addtogroup DenseMatVec @{ */ /*! \file * \brief Implements a vector constructed from a given type representing a field and a compile-time given size. */ template< class K, int SIZE > class FieldVector; template< class K, int SIZE > struct DenseMatVecTraits< FieldVector<K,SIZE> > { typedef FieldVector<K,SIZE> derived_type; typedef Dune::array<K,SIZE> container_type; typedef K value_type; typedef typename container_type::size_type size_type; }; template< class K, int SIZE > struct FieldTraits< FieldVector<K,SIZE> > { typedef typename FieldTraits<K>::field_type field_type; typedef typename FieldTraits<K>::real_type real_type; }; /** * @brief TMP to check the size of a DenseVectors statically, if possible. * * If the implementation type of C is a FieldVector, we statically check * whether its dimension is SIZE. * @tparam C The implementation of the other DenseVector * @tparam SIZE The size we need assume. */ template<typename C, int SIZE> struct IsFieldVectorSizeCorrect { enum { /** *@param True if C is not of type FieldVector or its dimension * is not equal SIZE. */ value = true }; }; template<typename T, int SIZE> struct IsFieldVectorSizeCorrect<FieldVector<T,SIZE>,SIZE> { enum {value = true}; }; template<typename T, int SIZE, int SIZE1> struct IsFieldVectorSizeCorrect<FieldVector<T,SIZE1>,SIZE> { enum {value = false}; }; /** \brief vector space out of a tensor product of fields. * * \tparam K the field type (use float, double, complex, etc) * \tparam SIZE number of components. */ template< class K, int SIZE > class FieldVector : public DenseVector< FieldVector<K,SIZE> > { Dune::array<K,SIZE> _data; typedef DenseVector< FieldVector<K,SIZE> > Base; public: //! export size enum { //! The size of this vector. dimension = SIZE }; typedef typename Base::size_type size_type; typedef typename Base::value_type value_type; //! Constructor making default-initialized vector FieldVector() : _data{} {} //! Constructor making vector with identical coordinates explicit FieldVector (const K& t) { fill(t); } //! Constructor making vector with identical coordinates FieldVector (const FieldVector & x) : _data(x._data) {} FieldVector (std::initializer_list<K> const &l) { assert(l.size() == dimension);// Actually, this is not needed any more! std::copy_n(l.begin(), std::min(static_cast<std::size_t>(dimension), l.size()), _data.begin()); } /** * \brief Copy constructor from a second vector of possibly different type * * If the DenseVector type of the this constructor's argument * is implemented by a FieldVector, it is statically checked * if it has the correct size. If this is not the case * the constructor is removed from the overload set using SFINAE. * * \param[in] x A DenseVector with correct size. * \param[in] dummy A void* dummy argument needed by SFINAE. */ template<class C> FieldVector (const DenseVector<C> & x, typename Dune::enable_if<IsFieldVectorSizeCorrect<C,SIZE>::value>::type* dummy=0 ) { DUNE_UNUSED_PARAMETER(dummy); // do a run-time size check, for the case that x is not a FieldVector assert(x.size() == SIZE); // Actually this is not needed any more! std::copy_n(x.begin(), std::min(static_cast<std::size_t>(SIZE),x.size()), _data.begin()); } //! Constructor making vector with identical coordinates template<class K1, int SIZE1> explicit FieldVector (const FieldVector<K1,SIZE1> & x) { static_assert(SIZE1 == SIZE, "FieldVector in constructor has wrong size"); for (size_type i = 0; i<SIZE; i++) _data[i] = x[i]; } using Base::operator=; DUNE_CONSTEXPR size_type size () const { return vec_size(); } // make this thing a vector DUNE_CONSTEXPR size_type vec_size () const { return SIZE; } K & vec_access(size_type i) { return _data[i]; } const K & vec_access(size_type i) const { return _data[i]; } private: void fill(const K& t) { for (int i=0; i<SIZE; i++) _data[i]=t; } }; /** \brief Read a FieldVector from an input stream * \relates FieldVector * * \note This operator is STL compliant, i.e., the content of v is only * changed if the read operation is successful. * * \param[in] in std :: istream to read from * \param[out] v FieldVector to be read * * \returns the input stream (in) */ template<class K, int SIZE> inline std::istream &operator>> ( std::istream &in, FieldVector<K, SIZE> &v ) { FieldVector<K, SIZE> w; for( typename FieldVector<K, SIZE>::size_type i = 0; i < SIZE; ++i ) in >> w[ i ]; if(in) v = w; return in; } #ifndef DOXYGEN template< class K > struct DenseMatVecTraits< FieldVector<K,1> > { typedef FieldVector<K,1> derived_type; typedef K container_type; typedef K value_type; typedef size_t size_type; }; /** \brief Vectors containing only one component */ template<class K> class FieldVector<K, 1> : public DenseVector< FieldVector<K,1> > { K _data; typedef DenseVector< FieldVector<K,1> > Base; public: //! export size enum { //! The size of this vector. dimension = 1 }; typedef typename Base::size_type size_type; //===== construction /** \brief Default constructor */ FieldVector () : _data() {} /** \brief Constructor with a given scalar */ template<typename T, typename EnableIf = typename std::enable_if< std::is_convertible<T, K>::value && ! std::is_same<K, DenseVector<typename FieldTraits<T>::field_type> >::value >::type > FieldVector (const T& k) : _data(k) {} //! Constructor making vector with identical coordinates template<class C> FieldVector (const DenseVector<C> & x) { static_assert(((bool)IsFieldVectorSizeCorrect<C,1>::value), "FieldVectors do not match in dimension!"); assert(x.size() == 1); _data = x[0]; } //! copy constructor FieldVector ( const FieldVector &other ) : _data( other._data ) {} //! Assignment operator for scalar template<typename T, typename EnableIf = typename std::enable_if< std::is_convertible<T, K>::value && ! std::is_same<K, DenseVector<typename FieldTraits<T>::field_type> >::value >::type > inline FieldVector& operator= (const T& k) { _data = k; return *this; } DUNE_CONSTEXPR size_type size () const { return vec_size(); } //===== forward methods to container DUNE_CONSTEXPR size_type vec_size () const { return 1; } K & vec_access(size_type i) { assert(i == 0); return _data; } const K & vec_access(size_type i) const { assert(i == 0); return _data; } //===== conversion operator /** \brief Conversion operator */ operator K& () { return _data; } /** \brief Const conversion operator */ operator const K& () const { return _data; } }; /* ----- FV / FV ----- */ /* mostly not necessary as these operations are already covered via the cast operator */ //! Binary compare, when using FieldVector<K,1> like K template<class K> inline bool operator> (const FieldVector<K,1>& a, const FieldVector<K,1>& b) { return a[0]>b[0]; } //! Binary compare, when using FieldVector<K,1> like K template<class K> inline bool operator>= (const FieldVector<K,1>& a, const FieldVector<K,1>& b) { return a[0]>=b[0]; } //! Binary compare, when using FieldVector<K,1> like K template<class K> inline bool operator< (const FieldVector<K,1>& a, const FieldVector<K,1>& b) { return a[0]<b[0]; } //! Binary compare, when using FieldVector<K,1> like K template<class K> inline bool operator<= (const FieldVector<K,1>& a, const FieldVector<K,1>& b) { return a[0]<=b[0]; } /* ----- FV / scalar ----- */ //! Binary addition, when using FieldVector<K,1> like K template<class K> inline FieldVector<K,1> operator+ (const FieldVector<K,1>& a, const K b) { return a[0]+b; } //! Binary subtraction, when using FieldVector<K,1> like K template<class K> inline FieldVector<K,1> operator- (const FieldVector<K,1>& a, const K b) { return a[0]-b; } //! Binary multiplication, when using FieldVector<K,1> like K template<class K> inline FieldVector<K,1> operator* (const FieldVector<K,1>& a, const K b) { return a[0]*b; } //! Binary division, when using FieldVector<K,1> like K template<class K> inline FieldVector<K,1> operator/ (const FieldVector<K,1>& a, const K b) { return a[0]/b; } //! Binary compare, when using FieldVector<K,1> like K template<class K> inline bool operator> (const FieldVector<K,1>& a, const K b) { return a[0]>b; } //! Binary compare, when using FieldVector<K,1> like K template<class K> inline bool operator>= (const FieldVector<K,1>& a, const K b) { return a[0]>=b; } //! Binary compare, when using FieldVector<K,1> like K template<class K> inline bool operator< (const FieldVector<K,1>& a, const K b) { return a[0]<b; } //! Binary compare, when using FieldVector<K,1> like K template<class K> inline bool operator<= (const FieldVector<K,1>& a, const K b) { return a[0]<=b; } //! Binary compare, when using FieldVector<K,1> like K template<class K> inline bool operator== (const FieldVector<K,1>& a, const K b) { return a[0]==b; } //! Binary compare, when using FieldVector<K,1> like K template<class K> inline bool operator!= (const FieldVector<K,1>& a, const K b) { return a[0]!=b; } /* ----- scalar / FV ------ */ //! Binary addition, when using FieldVector<K,1> like K template<class K> inline FieldVector<K,1> operator+ (const K a, const FieldVector<K,1>& b) { return a+b[0]; } //! Binary subtraction, when using FieldVector<K,1> like K template<class K> inline FieldVector<K,1> operator- (const K a, const FieldVector<K,1>& b) { return a-b[0]; } //! Binary multiplication, when using FieldVector<K,1> like K template<class K> inline FieldVector<K,1> operator* (const K a, const FieldVector<K,1>& b) { return a*b[0]; } //! Binary division, when using FieldVector<K,1> like K template<class K> inline FieldVector<K,1> operator/ (const K a, const FieldVector<K,1>& b) { return a/b[0]; } //! Binary compare, when using FieldVector<K,1> like K template<class K> inline bool operator> (const K a, const FieldVector<K,1>& b) { return a>b[0]; } //! Binary compare, when using FieldVector<K,1> like K template<class K> inline bool operator>= (const K a, const FieldVector<K,1>& b) { return a>=b[0]; } //! Binary compare, when using FieldVector<K,1> like K template<class K> inline bool operator< (const K a, const FieldVector<K,1>& b) { return a<b[0]; } //! Binary compare, when using FieldVector<K,1> like K template<class K> inline bool operator<= (const K a, const FieldVector<K,1>& b) { return a<=b[0]; } //! Binary compare, when using FieldVector<K,1> like K template<class K> inline bool operator== (const K a, const FieldVector<K,1>& b) { return a==b[0]; } //! Binary compare, when using FieldVector<K,1> like K template<class K> inline bool operator!= (const K a, const FieldVector<K,1>& b) { return a!=b[0]; } #endif /** @} end documentation */ } // end namespace #endif