diff --git a/src/common/field.hh b/src/common/field.hh index a0e8c07..f6ed3c2 100644 --- a/src/common/field.hh +++ b/src/common/field.hh @@ -1,412 +1,413 @@ /** * file field.hh * * @author Till Junge <till.junge@epfl.ch> * * @date 07 Sep 2017 * * @brief header-only implementation of a field for field collections * * @section LICENCE * * Copyright (C) 2017 Till Junge * * µSpectre is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3, or (at * your option) any later version. * * µSpectre is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef FIELD_H #define FIELD_H #include <string> #include <utility> #include <typeinfo> #include <vector> #include <algorithm> #include <Eigen/Dense> #include <cmath> #include <memory> #include <type_traits> namespace muSpectre { namespace internal { /* ---------------------------------------------------------------------- */ template <class FieldCollection> class FieldBase { protected: //! constructor //! unique name (whithin Collection) //! number of components //! collection to which this field belongs (eg, material, system) FieldBase(std::string unique_name, size_t nb_components, FieldCollection & collection); public: using collection_t = FieldCollection; //! Copy constructor FieldBase(const FieldBase &other) = delete; //! Move constructor FieldBase(FieldBase &&other) noexcept = delete; //! Destructor virtual ~FieldBase() noexcept = default; //! Copy assignment operator FieldBase& operator=(const FieldBase &other) = delete; //! Move assignment operator FieldBase& operator=(FieldBase &&other) noexcept = delete; /* ---------------------------------------------------------------------- */ //!Identifying accessors //! return field name inline const std::string & get_name() const; //! return field type //inline const Field_t & get_type() const; //! return my collection (for iterating) inline const FieldCollection & get_collection() const; //! return my collection (for iterating) inline const size_t & get_nb_components() const; //! return type_id of stored type virtual const std::type_info & get_stored_typeid() const = 0; virtual size_t size() const = 0; //! initialise field to zero (do more complicated initialisations through //! fully typed maps) virtual void set_zero() = 0; //! give access to collections friend FieldCollection; protected: /* ---------------------------------------------------------------------- */ //! allocate memory etc virtual void resize(size_t size) = 0; const std::string name; const size_t nb_components; const FieldCollection & collection; private: }; /* ---------------------------------------------------------------------- */ //! declaraton for friending - template <class FieldCollection, typename T, Dim_t NbComponents> + template <class FieldCollection, typename T, Dim_t NbComponents, bool isConst> class FieldMap; /* ---------------------------------------------------------------------- */ template <class FieldCollection, typename T, Dim_t NbComponents> class TypedFieldBase: public FieldBase<FieldCollection> { - friend class FieldMap<FieldCollection, T, NbComponents>; + friend class FieldMap<FieldCollection, T, NbComponents, true>; + friend class FieldMap<FieldCollection, T, NbComponents, false>; public: constexpr static auto nb_components{NbComponents}; using Parent = FieldBase<FieldCollection>; using Parent::collection_t; using Scalar = T; using Base = Parent; //using storage_type = Eigen::Array<T, Eigen::Dynamic, NbComponents>; using StoredType = Eigen::Array<T, NbComponents, 1>; using StorageType = std::vector<StoredType, Eigen::aligned_allocator<StoredType>>; TypedFieldBase(std::string unique_name, FieldCollection& collection); virtual ~TypedFieldBase() = default; //! return type_id of stored type virtual const std::type_info & get_stored_typeid() const; //! initialise field to zero (do more complicated initialisations through //! fully typed maps) inline void set_zero() override final; inline void push_back(const StoredType & value); template< class... Args> inline void emplace_back(Args&&... args); size_t size() const override final; protected: inline T* get_ptr_to_entry(const size_t&& index); inline T& get_ref_to_entry(const size_t&& index); inline virtual void resize(size_t size) override final; StorageType array{}; }; } // internal /* ---------------------------------------------------------------------- */ template <class FieldCollection, typename T, Dim_t order, Dim_t dim> class TensorField: public internal::TypedFieldBase<FieldCollection, T, ipow(dim,order)> { public: using Parent = internal::TypedFieldBase<FieldCollection, T, ipow(dim,order)>; using Base = typename Parent::Base; using Field_p = typename FieldCollection::Field_p; using component_type = T; //! Copy constructor TensorField(const TensorField &other) = delete; //! Move constructor TensorField(TensorField &&other) noexcept = delete; //! Destructor virtual ~TensorField() noexcept = default; //! Copy assignment operator TensorField& operator=(const TensorField &other) = delete; //! Move assignment operator TensorField& operator=(TensorField &&other) noexcept = delete; //! accessors inline Dim_t get_order() const; inline Dim_t get_dim() const; //! factory function template<class FieldType, class CollectionType, typename... Args> friend typename FieldType::Base& make_field(std::string unique_name, CollectionType & collection, Args&&... args); protected: //! constructor protected! TensorField(std::string unique_name, FieldCollection & collection); private: }; /* ---------------------------------------------------------------------- */ template <class FieldCollection, typename T, Dim_t NbRow, Dim_t NbCol=NbRow> class MatrixField: public internal::TypedFieldBase<FieldCollection, T, NbRow*NbCol> { public: using Parent = internal::TypedFieldBase<FieldCollection, T, NbRow*NbCol>; using Base = typename Parent::Base; using Field_p = std::unique_ptr<internal::FieldBase<FieldCollection>>; using component_type = T; //! Copy constructor MatrixField(const MatrixField &other) = delete; //! Move constructor MatrixField(MatrixField &&other) noexcept = delete; //! Destructor virtual ~MatrixField() noexcept = default; //! Copy assignment operator MatrixField& operator=(const MatrixField &other) = delete; //! Move assignment operator MatrixField& operator=(MatrixField &&other) noexcept = delete; //! accessors inline Dim_t get_nb_row() const; inline Dim_t get_nb_col() const; //! factory function template<class FieldType, class CollectionType, typename... Args> friend typename FieldType::Base& make_field(std::string unique_name, CollectionType & collection, Args&&... args); protected: //! constructor protected! MatrixField(std::string unique_name, FieldCollection & collection); private: }; /* ---------------------------------------------------------------------- */ //! convenience alias template <class FieldCollection, typename T> using ScalarField = TensorField<FieldCollection, T, 1, 1>; /* ---------------------------------------------------------------------- */ // Implementations namespace internal { /* ---------------------------------------------------------------------- */ template <class FieldCollection> FieldBase<FieldCollection>::FieldBase(std::string unique_name, size_t nb_components_, FieldCollection & collection_) :name(unique_name), nb_components(nb_components_), collection(collection_) {} /* ---------------------------------------------------------------------- */ template <class FieldCollection> inline const std::string & FieldBase<FieldCollection>::get_name() const { return this->name; } /* ---------------------------------------------------------------------- */ template <class FieldCollection> inline const FieldCollection & FieldBase<FieldCollection>:: get_collection() const { return this->collection; } /* ---------------------------------------------------------------------- */ template <class FieldCollection> inline const size_t & FieldBase<FieldCollection>:: get_nb_components() const { return this->nb_components; } /* ---------------------------------------------------------------------- */ template <class FieldCollection, typename T, Dim_t NbComponents> TypedFieldBase<FieldCollection, T, NbComponents>:: TypedFieldBase(std::string unique_name, FieldCollection & collection) :FieldBase<FieldCollection>(unique_name, NbComponents, collection){ static_assert ((std::is_arithmetic<T>::value || std::is_same<T, Complex>::value), "Use TypedFieldBase for integer, real or complex scalars for T"); static_assert(NbComponents > 0, "Only fields with more than 0 components"); } /* ---------------------------------------------------------------------- */ //! return type_id of stored type template <class FieldCollection, typename T, Dim_t NbComponents> const std::type_info & TypedFieldBase<FieldCollection, T, NbComponents>:: get_stored_typeid() const { return typeid(T); } /* ---------------------------------------------------------------------- */ template<class FieldCollection, typename T, Dim_t NbComponents> void TypedFieldBase<FieldCollection, T, NbComponents>:: set_zero() { std::fill(this->array.begin(), this->array.end(), T{}); } /* ---------------------------------------------------------------------- */ template <class FieldCollection, typename T, Dim_t NbComponents> size_t TypedFieldBase<FieldCollection, T, NbComponents>:: size() const { return this->array.size(); } /* ---------------------------------------------------------------------- */ template <class FieldCollection, typename T, Dim_t NbComponents> T* TypedFieldBase<FieldCollection, T, NbComponents>:: get_ptr_to_entry(const size_t&& index) { return &this->array[std::move(index)](0, 0); } /* ---------------------------------------------------------------------- */ template <class FieldCollection, typename T, Dim_t NbComponents> T& TypedFieldBase<FieldCollection, T, NbComponents>:: get_ref_to_entry(const size_t && index) { return this->array[std::move(index)](0, 0); } /* ---------------------------------------------------------------------- */ template <class FieldCollection, typename T, Dim_t NbComponents> void TypedFieldBase<FieldCollection, T, NbComponents>:: resize(size_t size) { this->array.resize(size); } /* ---------------------------------------------------------------------- */ template <class FieldCollection, typename T, Dim_t NbComponents> void TypedFieldBase<FieldCollection, T, NbComponents>:: push_back(const StoredType & value) { this->array.push_back(value); } /* ---------------------------------------------------------------------- */ template <class FieldCollection, typename T, Dim_t NbComponents> template <class... Args> void TypedFieldBase<FieldCollection, T, NbComponents>:: emplace_back(Args&&... args) { this->array.emplace_back(std::move(args...)); } } // internal /* ---------------------------------------------------------------------- */ //! Factory function, guarantees that only fields get created that are //! properly registered and linked to a collection. template<class FieldType, class FieldCollection, typename... Args> typename FieldType::Base & make_field(std::string unique_name, FieldCollection & collection, Args&&... args) { auto && ptr = std::unique_ptr<FieldType>{ new FieldType(unique_name, collection, args...)}; auto& retref = *ptr; collection.register_field(std::move(ptr)); return retref; } /* ---------------------------------------------------------------------- */ template <class FieldCollection, typename T, Dim_t order, Dim_t dim> TensorField<FieldCollection, T, order, dim>:: TensorField(std::string unique_name, FieldCollection & collection) :Parent(unique_name, collection) {} /* ---------------------------------------------------------------------- */ template <class FieldCollection, typename T, Dim_t order, Dim_t dim> Dim_t TensorField<FieldCollection, T, order, dim>:: get_order() const { return order; } /* ---------------------------------------------------------------------- */ template <class FieldCollection, typename T, Dim_t order, Dim_t dim> Dim_t TensorField<FieldCollection, T, order, dim>:: get_dim() const { return dim; } /* ---------------------------------------------------------------------- */ template <class FieldCollection, typename T, Dim_t NbRow, Dim_t NbCol> MatrixField<FieldCollection, T, NbRow, NbCol>:: MatrixField(std::string unique_name, FieldCollection & collection) :Parent(unique_name, collection) {} /* ---------------------------------------------------------------------- */ template <class FieldCollection, typename T, Dim_t NbRow, Dim_t NbCol> Dim_t MatrixField<FieldCollection, T, NbRow, NbCol>:: get_nb_col() const { return NbCol; } /* ---------------------------------------------------------------------- */ template <class FieldCollection, typename T, Dim_t NbRow, Dim_t NbCol> Dim_t MatrixField<FieldCollection, T, NbRow, NbCol>:: get_nb_row() const { return NbRow; } } // muSpectre #endif /* FIELD_H */ diff --git a/src/common/field_map_base.hh b/src/common/field_map_base.hh index 9c355a3..b9d1dc2 100644 --- a/src/common/field_map_base.hh +++ b/src/common/field_map_base.hh @@ -1,529 +1,548 @@ /** * file field_map.hh * * @author Till Junge <till.junge@epfl.ch> * * @date 12 Sep 2017 * * @brief Defined a strongly defines proxy that iterates efficiently over a field * * @section LICENCE * * Copyright (C) 2017 Till Junge * * µSpectre is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3, or (at * your option) any later version. * * µSpectre is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef FIELD_MAP_H #define FIELD_MAP_H #include <array> #include <string> #include <memory> #include <type_traits> #include <unsupported/Eigen/CXX11/Tensor> #include "common/field.hh" #include "common/common.hh" namespace muSpectre { namespace internal { //----------------------------------------------------------------------------// //! little helper to automate creation of const maps without duplication template<class T, bool isConst> struct const_corrector { using type = typename T::reference; }; template<class T> struct const_corrector<T, true> { using type = typename T::const_reference; }; template<class T, bool isConst> using const_corrector_t = typename const_corrector<T, isConst>::type; //----------------------------------------------------------------------------// - template <class FieldCollection, typename T, Dim_t NbComponents> + template <class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> class FieldMap { public: constexpr static auto nb_components{NbComponents}; using TypedField = ::muSpectre::internal::TypedFieldBase <FieldCollection, T, NbComponents>; using Field = typename TypedField::Parent; using size_type = std::size_t; //! Default constructor FieldMap() = delete; - FieldMap(Field & field); + template <bool isntConst=!ConstField> + FieldMap(std::enable_if_t<isntConst, Field &> field); + template <bool isConst=ConstField> + FieldMap(std::enable_if_t<isConst, const Field &> field); template<class FC, typename T2, Dim_t NbC> FieldMap(TypedFieldBase<FC, T2, NbC> & field); //! Copy constructor FieldMap(const FieldMap &other) = delete; //! Move constructor FieldMap(FieldMap &&other) noexcept = delete; //! Destructor virtual ~FieldMap() noexcept = default; //! Copy assignment operator FieldMap& operator=(const FieldMap &other) = delete; //! Move assignment operator FieldMap& operator=(FieldMap &&other) noexcept = delete; //! give human-readable field map type virtual std::string info_string() const = 0; //! return field name inline const std::string & get_name() const; //! return my collection (for iterating) inline const FieldCollection & get_collection() const; //! member access needs to be implemented by inheriting classes //inline value_type operator[](size_t index); //inline value_type operator[](Ccoord ccord); //! check compatibility (must be called by all inheriting classes at the //! end of their constructors inline void check_compatibility(); //! convenience call to collection's size method inline size_t size() const; //! compile-time compatibility check template<class Field> struct is_compatible; - template <class FullyTypedFieldMap, bool isConst=false> + template <class FullyTypedFieldMap, bool ConstIter=false> class iterator { + static_assert(!((ConstIter==false) && (ConstField==true)), + "You can't have a non-const iterator over a const " + "field"); public: using value_type = - const_corrector_t<FullyTypedFieldMap, isConst>; + const_corrector_t<FullyTypedFieldMap, ConstIter>; using pointer = typename FullyTypedFieldMap::pointer; using difference_type = std::ptrdiff_t; using iterator_category = std::random_access_iterator_tag; using Ccoord = typename FieldCollection::Ccoord; + using reference = typename FullyTypedFieldMap::reference; //! Default constructor iterator() = delete; //! constructor inline iterator(FullyTypedFieldMap & fieldmap, bool begin=true); //! constructor for random access inline iterator(FullyTypedFieldMap & fieldmap, size_t index); //! Copy constructor iterator(const iterator &other)= default; //! Move constructor iterator(iterator &&other) noexcept = default; //! Destructor virtual ~iterator() noexcept = default; //! Copy assignment operator iterator& operator=(const iterator &other) = default; //! Move assignment operator iterator& operator=(iterator &&other) noexcept = default; //! pre-increment inline iterator & operator++(); //! post-increment inline iterator operator++(int); //! dereference inline value_type operator*(); //! member of pointer inline pointer operator->(); //! pre-decrement inline iterator & operator--(); //! post-decrement inline iterator operator--(int); //! access subscripting inline value_type operator[](difference_type diff); //! equality inline bool operator==(const iterator & other) const; //! inequality inline bool operator!=(const iterator & other) const; //! div. comparisons inline bool operator<(const iterator & other) const; inline bool operator<=(const iterator & other) const; inline bool operator>(const iterator & other) const; inline bool operator>=(const iterator & other) const; //! additions, subtractions and corresponding assignments inline iterator operator+(difference_type diff) const; inline iterator operator-(difference_type diff) const; inline iterator& operator+=(difference_type diff); inline iterator& operator-=(difference_type diff); //! get pixel coordinates inline Ccoord get_ccoord() const; //! ostream operator (mainly for debug friend std::ostream & operator<<(std::ostream & os, const iterator& it) { - if (isConst) { + if (ConstIter) { os << "const "; } os << "iterator on field '" << it.fieldmap.get_name() << "', entry " << it.index; return os; } protected: const FieldCollection & collection; FullyTypedFieldMap & fieldmap; size_t index; private: }; protected: inline T* get_ptr_to_entry(size_t index); inline T& get_ref_to_entry(size_t index); const FieldCollection & collection; TypedField & field; private: }; } // internal namespace internal { /* ---------------------------------------------------------------------- */ - template<class FieldCollection, typename T, Dim_t NbComponents> - FieldMap<FieldCollection, T, NbComponents>:: - FieldMap(Field & field) + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template <bool isntConst> + FieldMap<FieldCollection, T, NbComponents, ConstField>:: + FieldMap(std::enable_if_t<isntConst, Field &> field) :collection(field.get_collection()), field(static_cast<TypedField&>(field)) { static_assert(NbComponents>0, "Only fields with more than 0 components allowed"); } /* ---------------------------------------------------------------------- */ - template <class FieldCollection, typename T, Dim_t NbComponents> + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template <bool isConst> + FieldMap<FieldCollection, T, NbComponents, ConstField>:: + FieldMap(std::enable_if_t<isConst, const Field &> field) + :collection(field.get_collection()), field(static_cast<TypedField&>(field)) { + static_assert(NbComponents>0, + "Only fields with more than 0 components allowed"); + } + + /* ---------------------------------------------------------------------- */ + template <class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> template <class FC, typename T2, Dim_t NbC> - FieldMap<FieldCollection, T, NbComponents>:: + FieldMap<FieldCollection, T, NbComponents, ConstField>:: FieldMap(TypedFieldBase<FC, T2, NbC> & field) :collection(field.get_collection()), field(static_cast<TypedField&>(field)) { static_assert(std::is_same<FC, FieldCollection>::value, "The field does not have the expected FieldCollection type"); static_assert(std::is_same<T2, T>::value, "The field does not have the expected Scalar type"); static_assert((NbC == NbComponents), "The field does not have the expected number of components"); } /* ---------------------------------------------------------------------- */ - template<class FieldCollection, typename T, Dim_t NbComponents> + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> void - FieldMap<FieldCollection, T, NbComponents>:: + FieldMap<FieldCollection, T, NbComponents, ConstField>:: check_compatibility() { if (typeid(T).hash_code() != this->field.get_stored_typeid().hash_code()) { throw FieldInterpretationError ("Cannot create a Map of type '" + this->info_string() + "' for field '" + this->field.get_name() + "' of type '" + this->field.get_stored_typeid().name() + "'"); } //check size compatibility if (NbComponents != this->field.get_nb_components()) { throw FieldInterpretationError ("Cannot create a Map of type '" + this->info_string() + "' for field '" + this->field.get_name() + "' with " + std::to_string(this->field.get_nb_components()) + " components"); } } /* ---------------------------------------------------------------------- */ - template<class FieldCollection, typename T, Dim_t NbComponents> + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> size_t - FieldMap<FieldCollection, T, NbComponents>:: + FieldMap<FieldCollection, T, NbComponents, ConstField>:: size() const { return this->collection.size(); } /* ---------------------------------------------------------------------- */ - template <class FieldCollection, typename T, Dim_t NbComponents> + template <class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> template <class Field> - struct FieldMap<FieldCollection, T, NbComponents>::is_compatible { + struct FieldMap<FieldCollection, T, NbComponents, ConstField>::is_compatible { constexpr static bool explain() { static_assert (std::is_same<typename Field::collection_t, FieldCollection>::value, "The field does not have the expected FieldCollection type"); static_assert (std::is_same<typename Field::Scalar, T>::value, "The // FIXME: eld does not have the expected Scalar type"); static_assert((Field::nb_components == NbComponents), "The field does not have the expected number of components"); //The static asserts wouldn't pass in the incompatible case, so this is it return true; } constexpr static bool value{std::is_base_of<TypedField, Field>::value}; }; /* ---------------------------------------------------------------------- */ - template<class FieldCollection, typename T, Dim_t NbComponents> + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> const std::string & - FieldMap<FieldCollection, T, NbComponents>:: + FieldMap<FieldCollection, T, NbComponents, ConstField>:: get_name() const { return this->field.get_name(); } /* ---------------------------------------------------------------------- */ - template<class FieldCollection, typename T, Dim_t NbComponents> + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> const FieldCollection & - FieldMap<FieldCollection, T, NbComponents>:: + FieldMap<FieldCollection, T, NbComponents, ConstField>:: get_collection() const { return this->collection; } /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ // Iterator implementations //! constructor - template<class FieldCollection, typename T, Dim_t NbComponents> - template<class FullyTypedFieldMap, bool isConst> - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst>:: + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template<class FullyTypedFieldMap, bool ConstIter> + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator + <FullyTypedFieldMap, ConstIter>:: iterator(FullyTypedFieldMap & fieldmap, bool begin) :collection(fieldmap.get_collection()), fieldmap(fieldmap), index(begin ? 0 : fieldmap.field.size()) {} /* ---------------------------------------------------------------------- */ //! constructor for random access - template<class FieldCollection, typename T, Dim_t NbComponents> - template<class FullyTypedFieldMap, bool isConst> - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst>:: + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template<class FullyTypedFieldMap, bool ConstIter> + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter>:: iterator(FullyTypedFieldMap & fieldmap, size_t index) :collection(fieldmap.collection), fieldmap(fieldmap), index(index) {} /* ---------------------------------------------------------------------- */ //! pre-increment - template<class FieldCollection, typename T, Dim_t NbComponents> - template<class FullyTypedFieldMap, bool isConst> - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst> & - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst>:: + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template<class FullyTypedFieldMap, bool ConstIter> + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter> & + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter>:: operator++() { this->index++; return *this; } /* ---------------------------------------------------------------------- */ //! post-increment - template<class FieldCollection, typename T, Dim_t NbComponents> - template<class FullyTypedFieldMap, bool isConst> - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst> - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst>:: + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template<class FullyTypedFieldMap, bool ConstIter> + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter> + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter>:: operator++(int) { iterator current = *this; this->index++; return current; } /* ---------------------------------------------------------------------- */ //! dereference - template<class FieldCollection, typename T, Dim_t NbComponents> - template<class FullyTypedFieldMap, bool isConst> - typename FieldMap<FieldCollection, T, NbComponents>::template iterator<FullyTypedFieldMap, isConst>::value_type - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst>:: + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template<class FullyTypedFieldMap, bool ConstIter> + typename FieldMap<FieldCollection, T, NbComponents, ConstField>::template iterator<FullyTypedFieldMap, ConstIter>::value_type + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter>:: operator*() { return this->fieldmap.template operator[]<value_type>(this->index); } /* ---------------------------------------------------------------------- */ //! member of pointer - template<class FieldCollection, typename T, Dim_t NbComponents> - template<class FullyTypedFieldMap, bool isConst> + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template<class FullyTypedFieldMap, bool ConstIter> typename FullyTypedFieldMap::pointer - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst>:: + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter>:: operator->() { return this->fieldmap.ptr_to_val_t(this->index); } /* ---------------------------------------------------------------------- */ //! pre-decrement - template<class FieldCollection, typename T, Dim_t NbComponents> - template<class FullyTypedFieldMap, bool isConst> - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst> & - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst>:: + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template<class FullyTypedFieldMap, bool ConstIter> + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter> & + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter>:: operator--() { this->index--; return *this; } /* ---------------------------------------------------------------------- */ //! post-decrement - template<class FieldCollection, typename T, Dim_t NbComponents> - template<class FullyTypedFieldMap, bool isConst> - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst> - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst>:: + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template<class FullyTypedFieldMap, bool ConstIter> + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter> + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter>:: operator--(int) { iterator current = *this; this->index--; return current; } /* ---------------------------------------------------------------------- */ //! Access subscripting - template<class FieldCollection, typename T, Dim_t NbComponents> - template<class FullyTypedFieldMap, bool isConst> - typename FieldMap<FieldCollection, T, NbComponents>::template iterator<FullyTypedFieldMap, isConst>::value_type - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst>:: + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template<class FullyTypedFieldMap, bool ConstIter> + typename FieldMap<FieldCollection, T, NbComponents, ConstField>::template iterator<FullyTypedFieldMap, ConstIter>::value_type + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter>:: operator[](difference_type diff) { return this->fieldmap[this->index+diff]; } /* ---------------------------------------------------------------------- */ //! equality - template<class FieldCollection, typename T, Dim_t NbComponents> - template<class FullyTypedFieldMap, bool isConst> + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template<class FullyTypedFieldMap, bool ConstIter> bool - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst>:: + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter>:: operator==(const iterator & other) const { return (this->index == other.index && &this->fieldmap == &other.fieldmap); } /* ---------------------------------------------------------------------- */ //! inquality - template<class FieldCollection, typename T, Dim_t NbComponents> - template<class FullyTypedFieldMap, bool isConst> + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template<class FullyTypedFieldMap, bool ConstIter> bool - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst>:: + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter>:: operator!=(const iterator & other) const { return !(*this == other); } /* ---------------------------------------------------------------------- */ //! div. comparisons - template<class FieldCollection, typename T, Dim_t NbComponents> - template<class FullyTypedFieldMap, bool isConst> + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template<class FullyTypedFieldMap, bool ConstIter> bool - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst>:: + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter>:: operator<(const iterator & other) const { return (this->index < other.index); } - template<class FieldCollection, typename T, Dim_t NbComponents> - template<class FullyTypedFieldMap, bool isConst> + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template<class FullyTypedFieldMap, bool ConstIter> bool - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst>:: + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter>:: operator<=(const iterator & other) const { return (this->index <= other.index); } - template<class FieldCollection, typename T, Dim_t NbComponents> - template<class FullyTypedFieldMap, bool isConst> + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template<class FullyTypedFieldMap, bool ConstIter> bool - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst>:: + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter>:: operator>(const iterator & other) const { return (this->index > other.index); } - template<class FieldCollection, typename T, Dim_t NbComponents> - template<class FullyTypedFieldMap, bool isConst> + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template<class FullyTypedFieldMap, bool ConstIter> bool - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst>:: + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter>:: operator>=(const iterator & other) const { return (this->index >= other.index); } /* ---------------------------------------------------------------------- */ //! additions, subtractions and corresponding assignments - template<class FieldCollection, typename T, Dim_t NbComponents> - template<class FullyTypedFieldMap, bool isConst> - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst> - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst>:: + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template<class FullyTypedFieldMap, bool ConstIter> + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter> + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter>:: operator+(difference_type diff) const { return iterator(this->fieldmap, this->index + diff); } - template<class FieldCollection, typename T, Dim_t NbComponents> - template<class FullyTypedFieldMap, bool isConst> - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst> - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst>:: + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template<class FullyTypedFieldMap, bool ConstIter> + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter> + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter>:: operator-(difference_type diff) const { return iterator(this->fieldmap, this->index - diff); } - template<class FieldCollection, typename T, Dim_t NbComponents> - template<class FullyTypedFieldMap, bool isConst> - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst> & - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst>:: + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template<class FullyTypedFieldMap, bool ConstIter> + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter> & + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter>:: operator+=(difference_type diff) { this->index += diff; return *this; } - template<class FieldCollection, typename T, Dim_t NbComponents> - template<class FullyTypedFieldMap, bool isConst> - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst> & - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst>:: + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template<class FullyTypedFieldMap, bool ConstIter> + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter> & + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter>:: operator-=(difference_type diff) { this->index -= diff; return *this; } /* ---------------------------------------------------------------------- */ //! get pixel coordinates - template<class FieldCollection, typename T, Dim_t NbComponents> - template<class FullyTypedFieldMap, bool isConst> + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> + template<class FullyTypedFieldMap, bool ConstIter> typename FieldCollection::Ccoord - FieldMap<FieldCollection, T, NbComponents>::iterator<FullyTypedFieldMap, isConst>:: + FieldMap<FieldCollection, T, NbComponents, ConstField>::iterator<FullyTypedFieldMap, ConstIter>:: get_ccoord() const { return this->collection.get_ccoord(this->index); } ////----------------------------------------------------------------------------// //template<class FieldCollection, typename T, Dim_t NbComponents, class FullyTypedFieldMap> //std::ostream & operator << //(std::ostream &os, -// const typename FieldMap<FieldCollection, T, NbComponents>:: -// template iterator<FullyTypedFieldMap, isConst> & it) { +// const typename FieldMap<FieldCollection, T, NbComponents, ConstField>:: +// template iterator<FullyTypedFieldMap, ConstIter> & it) { // os << "iterator on field '" // << it.field.get_name() // << "', entry " << it.index; // return os; //} /* ---------------------------------------------------------------------- */ - template<class FieldCollection, typename T, Dim_t NbComponents> + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> T* - FieldMap<FieldCollection, T, NbComponents>::get_ptr_to_entry(size_t index) { + FieldMap<FieldCollection, T, NbComponents, ConstField>::get_ptr_to_entry(size_t index) { return this->field.get_ptr_to_entry(std::move(index)); } /* ---------------------------------------------------------------------- */ - template<class FieldCollection, typename T, Dim_t NbComponents> + template<class FieldCollection, typename T, Dim_t NbComponents, bool ConstField> T& - FieldMap<FieldCollection, T, NbComponents>::get_ref_to_entry(size_t index) { + FieldMap<FieldCollection, T, NbComponents, ConstField>::get_ref_to_entry(size_t index) { return this->field.get_ref_to_entry(std::move(index)); } } // internal } // muSpectre #endif /* FIELD_MAP_H */ diff --git a/src/common/field_map_matrixlike.hh b/src/common/field_map_matrixlike.hh index 055b53f..c4f7492 100644 --- a/src/common/field_map_matrixlike.hh +++ b/src/common/field_map_matrixlike.hh @@ -1,227 +1,268 @@ /** * file field_map_matrixlike.hh * * @author Till Junge <till.junge@epfl.ch> * * @date 26 Sep 2017 * * @brief Eigen-Matrix and -Array maps over strongly typed fields * * @section LICENCE * * Copyright (C) 2017 Till Junge * * µSpectre is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3, or (at * your option) any later version. * * µSpectre is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef FIELD_MAP_MATRIXLIKE_H #define FIELD_MAP_MATRIXLIKE_H #include <memory> #include <Eigen/Dense> #include "common/field_map_base.hh" #include "common/T4_map_proxy.hh" namespace muSpectre { namespace internal { /* ---------------------------------------------------------------------- */ enum class Map_t{Matrix, Array, T4Matrix}; template<Map_t map_type> struct NameWrapper { const static std::string field_info_root; }; template<> const std::string NameWrapper<Map_t::Array>::field_info_root{"Array"}; template<> const std::string NameWrapper<Map_t::Matrix>::field_info_root{"Matrix"}; template<> const std::string NameWrapper<Map_t::T4Matrix>::field_info_root{"T4Matrix"}; /* ---------------------------------------------------------------------- */ - template <class FieldCollection, class EigenArray, Map_t map_type> + template <class FieldCollection, class EigenArray, Map_t map_type, + bool ConstField> class MatrixLikeFieldMap: public FieldMap<FieldCollection, typename EigenArray::Scalar, - EigenArray::SizeAtCompileTime> + EigenArray::SizeAtCompileTime, + ConstField> { public: using Parent = FieldMap<FieldCollection, typename EigenArray::Scalar, - EigenArray::SizeAtCompileTime>; + EigenArray::SizeAtCompileTime, ConstField>; using Ccoord = Ccoord_t<FieldCollection::spatial_dim()>; using value_type = EigenArray; - using reference = value_type; // since it's a resource handle using const_reference = const value_type; + using reference = std::conditional_t<ConstField, + const_reference, + value_type>; // since it's a resource handle using size_type = typename Parent::size_type; using pointer = std::unique_ptr<EigenArray>; using TypedField = typename Parent::TypedField; using Field = typename TypedField::Parent; - using iterator = typename Parent::template iterator<MatrixLikeFieldMap>; using const_iterator= typename Parent::template iterator<MatrixLikeFieldMap, true>; + using iterator = std::conditional_t< + ConstField, + const_iterator, + typename Parent::template iterator<MatrixLikeFieldMap>>; using reverse_iterator = std::reverse_iterator<iterator>; using const_reverse_iterator = std::reverse_iterator<const_iterator>; friend iterator; //! Default constructor MatrixLikeFieldMap() = delete; /** * Constructor using a (non-typed) field. Compatibility is enforced at * runtime. This should not be a performance concern, as this constructor * will not be called in anny inner loops (if used as intended). */ - MatrixLikeFieldMap(Field & field); + template <bool isntConst=!ConstField> + MatrixLikeFieldMap(std::enable_if_t<isntConst, Field &> field); + template <bool isConst=ConstField> + MatrixLikeFieldMap(std::enable_if_t<isConst, const Field &> field); /** * Constructor using a typed field. Compatibility is enforced * statically. It is not always possible to call this constructor, as the * type of the field might not be known at compile time. */ template<class FC, typename T2, Dim_t NbC> MatrixLikeFieldMap(TypedFieldBase<FC, T2, NbC> & field); //! Copy constructor MatrixLikeFieldMap(const MatrixLikeFieldMap &other) = delete; //! Move constructor MatrixLikeFieldMap(MatrixLikeFieldMap &&other) noexcept = delete; //! Destructor virtual ~MatrixLikeFieldMap() noexcept = default; //! Copy assignment operator MatrixLikeFieldMap& operator=(const MatrixLikeFieldMap &other) = delete; //! Move assignment operator MatrixLikeFieldMap& operator=(MatrixLikeFieldMap &&other) noexcept = delete; //! give human-readable field map type inline std::string info_string() const override final; //! member access template <class ref = reference> inline ref operator[](size_type index); inline reference operator[](const Ccoord& ccoord); //! return an iterator to head of field for ranges inline iterator begin(){return iterator(*this);} inline const_iterator cbegin(){return const_iterator(*this);} //! return an iterator to tail of field for ranges inline iterator end(){return iterator(*this, false);}; inline const_iterator cend(){return const_iterator(*this, false);} protected: //! for sad, legacy iterator use inline pointer ptr_to_val_t(size_type index); const static std::string field_info_root; private: }; - template <class FieldCollection, class EigenArray, Map_t map_type> - const std::string MatrixLikeFieldMap<FieldCollection, EigenArray, map_type>:: + /* ---------------------------------------------------------------------- */ + template <class FieldCollection, class EigenArray, Map_t map_type, + bool ConstField> + const std::string MatrixLikeFieldMap<FieldCollection, EigenArray, map_type, ConstField>:: field_info_root{NameWrapper<map_type>::field_info_root}; /* ---------------------------------------------------------------------- */ - template<class FieldCollection, class EigenArray, Map_t map_type> - MatrixLikeFieldMap<FieldCollection, EigenArray, map_type>:: - MatrixLikeFieldMap(Field & field) + template<class FieldCollection, class EigenArray, Map_t map_type, + bool ConstField> + template <bool isntConst> + MatrixLikeFieldMap<FieldCollection, EigenArray, map_type, ConstField>:: + MatrixLikeFieldMap(std::enable_if_t<isntConst, Field &> field) + :Parent(field) { + static_assert((isntConst != ConstField), + "let the compiler deduce isntConst, this is a SFINAE " + "parameter"); + this->check_compatibility(); + } + + /* ---------------------------------------------------------------------- */ + template<class FieldCollection, class EigenArray, Map_t map_type, + bool ConstField> + template <bool isConst> + MatrixLikeFieldMap<FieldCollection, EigenArray, map_type, ConstField>:: + MatrixLikeFieldMap(std::enable_if_t<isConst, const Field &> field) :Parent(field) { + static_assert((isConst == ConstField), + "let the compiler deduce isntConst, this is a SFINAE " + "parameter"); this->check_compatibility(); } /* ---------------------------------------------------------------------- */ - template<class FieldCollection, class EigenArray, Map_t map_type> + template<class FieldCollection, class EigenArray, Map_t map_type, + bool ConstField> template<class FC, typename T2, Dim_t NbC> - MatrixLikeFieldMap<FieldCollection, EigenArray, map_type>:: + MatrixLikeFieldMap<FieldCollection, EigenArray, map_type, ConstField>:: MatrixLikeFieldMap(TypedFieldBase<FC, T2, NbC> & field) :Parent(field) { } /* ---------------------------------------------------------------------- */ //! human-readable field map type - template<class FieldCollection, class EigenArray, Map_t map_type> + template<class FieldCollection, class EigenArray, Map_t map_type, + bool ConstField> std::string - MatrixLikeFieldMap<FieldCollection, EigenArray, map_type>:: + MatrixLikeFieldMap<FieldCollection, EigenArray, map_type, ConstField>:: info_string() const { std::stringstream info; info << field_info_root << "(" << typeid(typename EigenArray::value_type).name() << ", " << EigenArray::RowsAtCompileTime << "x" << EigenArray::ColsAtCompileTime << ")"; return info.str(); } /* ---------------------------------------------------------------------- */ //! member access - template<class FieldCollection, class EigenArray, Map_t map_type> + template<class FieldCollection, class EigenArray, Map_t map_type, + bool ConstField> template <class ref> ref - MatrixLikeFieldMap<FieldCollection, EigenArray, map_type>:: + MatrixLikeFieldMap<FieldCollection, EigenArray, map_type, ConstField>:: operator[](size_type index) { return ref(this->get_ptr_to_entry(index)); } - template<class FieldCollection, class EigenArray, Map_t map_type> - typename MatrixLikeFieldMap<FieldCollection, EigenArray, map_type>::reference - MatrixLikeFieldMap<FieldCollection, EigenArray, map_type>:: + template<class FieldCollection, class EigenArray, Map_t map_type, + bool ConstField> + typename MatrixLikeFieldMap<FieldCollection, EigenArray, map_type, ConstField>::reference + MatrixLikeFieldMap<FieldCollection, EigenArray, map_type, ConstField>:: operator[](const Ccoord & ccoord) { auto && index = this->collection.get_index(ccoord); return reference(this->get_ptr_to_entry(std::move(index))); } /* ---------------------------------------------------------------------- */ - template<class FieldCollection, class EigenArray, Map_t map_type> - typename MatrixLikeFieldMap<FieldCollection, EigenArray, map_type>::pointer - MatrixLikeFieldMap<FieldCollection, EigenArray, map_type>:: + template<class FieldCollection, class EigenArray, Map_t map_type, + bool ConstField> + typename MatrixLikeFieldMap<FieldCollection, EigenArray, map_type, ConstField>::pointer + MatrixLikeFieldMap<FieldCollection, EigenArray, map_type, ConstField>:: ptr_to_val_t(size_type index) { return std::make_unique<value_type> (this->get_ptr_to_entry(std::move(index))); } } // internal /* ---------------------------------------------------------------------- */ //! short-hand for an Eigen matrix map as iterate - template <class FieldCollection, typename T, Dim_t NbRows, Dim_t NbCols> + template <class FieldCollection, typename T, Dim_t NbRows, Dim_t NbCols, + bool ConstField=false> using MatrixFieldMap = internal::MatrixLikeFieldMap <FieldCollection, - Eigen::Map<Eigen::Matrix<T, NbRows, NbCols>>, - internal::Map_t::Matrix>; + std::conditional_t<ConstField, + Eigen::Map<const Eigen::Matrix<T, NbRows, NbCols>>, + Eigen::Map<Eigen::Matrix<T, NbRows, NbCols>>>, + internal::Map_t::Matrix, ConstField>; /* ---------------------------------------------------------------------- */ //! short-hand for an Eigen matrix map as iterate template <class FieldCollection, typename T, Dim_t Dim, bool MapConst=false, bool Symmetric=false> using T4MatrixFieldMap = internal::MatrixLikeFieldMap <FieldCollection, T4Map<T, Dim, MapConst, Symmetric>, - internal::Map_t::T4Matrix>; + internal::Map_t::T4Matrix, MapConst>; /* ---------------------------------------------------------------------- */ //! short-hand for an Eigen array map as iterate - template <class FieldCollection, typename T, Dim_t NbRows, Dim_t NbCols> + template <class FieldCollection, typename T, Dim_t NbRows, Dim_t NbCols, + bool ConstField=false> using ArrayFieldMap = internal::MatrixLikeFieldMap <FieldCollection, - Eigen::Map<Eigen::Array<T, NbRows, NbCols>>, - internal::Map_t::Array>; + std::conditional_t<ConstField, + Eigen::Map<const Eigen::Array<T, NbRows, NbCols>>, + Eigen::Map<Eigen::Array<T, NbRows, NbCols>>>, + internal::Map_t::Array, ConstField>; } // muSpectre #endif /* FIELD_MAP_MATRIXLIKE_H */ diff --git a/src/common/field_map_scalar.hh b/src/common/field_map_scalar.hh index 8f74a98..4ad0897 100644 --- a/src/common/field_map_scalar.hh +++ b/src/common/field_map_scalar.hh @@ -1,139 +1,165 @@ /** * file field_map_scalar.hh * * @author Till Junge <till.junge@epfl.ch> * * @date 26 Sep 2017 * * @brief maps over scalar fields * * @section LICENCE * * Copyright (C) 2017 Till Junge * * µSpectre is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3, or (at * your option) any later version. * * µSpectre is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef FIELD_MAP_SCALAR_H #define FIELD_MAP_SCALAR_H #include "common/field_map_base.hh" namespace muSpectre { - template <class FieldCollection, typename T> + template <class FieldCollection, typename T, bool ConstField=false> class ScalarFieldMap - : public internal::FieldMap<FieldCollection, T, 1> + : public internal::FieldMap<FieldCollection, T, 1, ConstField> { public: - using parent = internal::FieldMap<FieldCollection, T, 1>; + using parent = internal::FieldMap<FieldCollection, T, 1, ConstField>; using Ccoord = Ccoord_t<FieldCollection::spatial_dim()>; using value_type = T; - using reference = value_type &; using const_reference = const value_type &; + using reference = std::conditional_t<ConstField, + const_reference, + value_type &>; using size_type = typename parent::size_type; using pointer = T*; using Field = typename parent::Field; - using iterator = typename parent::template iterator<ScalarFieldMap>; using const_iterator= typename parent::template iterator<ScalarFieldMap, true>; + using iterator = std::conditional_t + <ConstField, + const_iterator, + typename parent::template iterator<ScalarFieldMap>>; using reverse_iterator = std::reverse_iterator<iterator>; using const_reverse_iterator = std::reverse_iterator<const_iterator>; friend iterator; //! Default constructor ScalarFieldMap() = delete; - ScalarFieldMap(Field & field); + template <bool isntConst=!ConstField> + ScalarFieldMap(std::enable_if_t<isntConst, Field &> field); + template <bool isConst=ConstField> + ScalarFieldMap(std::enable_if_t<isConst, const Field &> field); //! Copy constructor ScalarFieldMap(const ScalarFieldMap &other) = delete; //! Move constructor ScalarFieldMap(ScalarFieldMap &&other) noexcept = delete; //! Destructor virtual ~ScalarFieldMap() noexcept = default; //! Copy assignment operator ScalarFieldMap& operator=(const ScalarFieldMap &other) = delete; //! Move assignment operator ScalarFieldMap& operator=(ScalarFieldMap &&other) noexcept = delete; //! give human-readable field map type inline std::string info_string() const override final; //! member access template <class ref_t = reference> inline ref_t operator[](size_type index); inline reference operator[](const Ccoord& ccoord); //! return an iterator to head of field for ranges inline iterator begin(){return iterator(*this);} inline const_iterator cbegin(){return const_iterator(*this);} //! return an iterator to tail of field for ranges inline iterator end(){return iterator(*this, false);} inline const_iterator cend(){return const_iterator(*this, false);} protected: //! for sad, legacy iterator use inline pointer ptr_to_val_t(size_type index); const static std::string field_info_root; private: }; + + /* ---------------------------------------------------------------------- */ + template <class FieldCollection, typename T, bool ConstField> + template <bool isntConst> + ScalarFieldMap<FieldCollection, T, ConstField>:: + ScalarFieldMap(std::enable_if_t<isntConst, Field &> field) + :parent(field) { + static_assert((isntConst != ConstField), + "let the compiler deduce isntConst, this is a SFINAE " + "parameter"); + this->check_compatibility(); + } + /* ---------------------------------------------------------------------- */ - template <class FieldCollection, typename T> - ScalarFieldMap<FieldCollection, T>::ScalarFieldMap(Field & field) + template <class FieldCollection, typename T, bool ConstField> + template <bool isConst> + ScalarFieldMap<FieldCollection, T, ConstField>:: + ScalarFieldMap(std::enable_if_t<isConst, const Field &> field) :parent(field) { + static_assert((isConst == ConstField), + "let the compiler deduce isntConst, this is a SFINAE " + "parameter"); this->check_compatibility(); } /* ---------------------------------------------------------------------- */ //! human-readable field map type - template<class FieldCollection, typename T> + template<class FieldCollection, typename T, bool ConstField> std::string - ScalarFieldMap<FieldCollection, T>::info_string() const { + ScalarFieldMap<FieldCollection, T, ConstField>::info_string() const { std::stringstream info; info << "Scalar(" << typeid(T).name() << ")"; return info.str(); } /* ---------------------------------------------------------------------- */ - template <class FieldCollection, typename T> - const std::string ScalarFieldMap<FieldCollection, T>::field_info_root{ + template <class FieldCollection, typename T, bool ConstField> + const std::string ScalarFieldMap<FieldCollection, T, ConstField>::field_info_root{ "Scalar"}; /* ---------------------------------------------------------------------- */ //! member access - template <class FieldCollection, typename T> + template <class FieldCollection, typename T, bool ConstField> template <class ref_t> ref_t - ScalarFieldMap<FieldCollection, T>::operator[](size_type index) { + ScalarFieldMap<FieldCollection, T, ConstField>::operator[](size_type index) { return this->get_ref_to_entry(std::move(index)); } /* ---------------------------------------------------------------------- */ //! member access - template <class FieldCollection, typename T> - typename ScalarFieldMap<FieldCollection, T>::reference - ScalarFieldMap<FieldCollection, T>::operator[](const Ccoord& ccoord) { + template <class FieldCollection, typename T, bool ConstField> + typename ScalarFieldMap<FieldCollection, T, ConstField>::reference + ScalarFieldMap<FieldCollection, T, ConstField>::operator[](const Ccoord& ccoord) { auto && index = this->collection.get_index(std::move(ccoord)); return this->get_ref_to_entry(std::move(index)); } } // muSpectre #endif /* FIELD_MAP_SCALAR_H */ diff --git a/src/common/field_map_tensor.hh b/src/common/field_map_tensor.hh index 6c4204c..3a9fc87 100644 --- a/src/common/field_map_tensor.hh +++ b/src/common/field_map_tensor.hh @@ -1,169 +1,195 @@ /** * file field_map_tensor.hh * * @author Till Junge <till.junge@epfl.ch> * * @date 26 Sep 2017 * * @brief Defines an Eigen-Tensor map over strongly typed fields * * @section LICENCE * * Copyright (C) 2017 Till Junge * * µSpectre is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3, or (at * your option) any later version. * * µSpectre is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef FIELD_MAP_TENSOR_H #define FIELD_MAP_TENSOR_H #include <sstream> #include <memory> #include "common/eigen_tools.hh" #include "common/field_map_base.hh" namespace muSpectre { /* ---------------------------------------------------------------------- */ - template <class FieldCollection, typename T, Dim_t order, Dim_t dim> + template <class FieldCollection, typename T, Dim_t order, Dim_t dim, + bool ConstField=false> class TensorFieldMap: public internal::FieldMap<FieldCollection, T, - SizesByOrder<order, dim>::Sizes::total_size - > + SizesByOrder<order, dim>::Sizes::total_size, + ConstField> { public: using Parent = internal::FieldMap<FieldCollection, T, - TensorFieldMap::nb_components>; + TensorFieldMap::nb_components, ConstField>; using Ccoord = Ccoord_t<FieldCollection::spatial_dim()>; using Sizes = typename SizesByOrder<order, dim>::Sizes; using T_t = Eigen::TensorFixedSize<T, Sizes>; using value_type = Eigen::TensorMap<T_t>; - using reference = value_type; // since it's a resource handle using const_reference = Eigen::TensorMap<const T_t>; + using reference = std::conditional_t<ConstField, + const_reference, + value_type>; // since it's a resource handle using size_type = typename Parent::size_type; using pointer = std::unique_ptr<value_type>; using TypedField = typename Parent::TypedField; using Field = typename TypedField::Parent; - using iterator = typename Parent::template iterator<TensorFieldMap>; using const_iterator = typename Parent::template iterator<TensorFieldMap, true>; + using iterator = std::conditional_t< + ConstField, + const_iterator, + typename Parent::template iterator<TensorFieldMap>>; using reverse_iterator = std::reverse_iterator<iterator>; using const_reverse_iterator = std::reverse_iterator<const_iterator>; friend iterator; //! Default constructor TensorFieldMap() = delete; - TensorFieldMap(Field & field); + template <bool isntConst=!ConstField> + TensorFieldMap(std::enable_if_t<isntConst, Field &> field); + template <bool isConst=ConstField> + TensorFieldMap(std::enable_if_t<isConst, const Field &> field); //! Copy constructor TensorFieldMap(const TensorFieldMap &other) = delete; //! Move constructor TensorFieldMap(TensorFieldMap &&other) noexcept = delete; //! Destructor virtual ~TensorFieldMap() noexcept = default; //! Copy assignment operator TensorFieldMap& operator=(const TensorFieldMap &other) = delete; //! Move assignment operator TensorFieldMap& operator=(TensorFieldMap &&other) noexcept = delete; //! give human-readable field map type inline std::string info_string() const override final; //! member access template <class ref_t = reference> inline ref_t operator[](size_type index); inline reference operator[](const Ccoord & ccoord); //! return an iterator to head of field for ranges inline iterator begin(){return iterator(*this);} inline const_iterator cbegin(){return const_iterator(*this);} //! return an iterator to tail of field for ranges inline iterator end(){return iterator(*this, false);} inline const_iterator cend(){return const_iterator(*this, false);} protected: //! for sad, legacy iterator use inline pointer ptr_to_val_t(size_type index); private: }; /* ---------------------------------------------------------------------- */ - template<class FieldCollection, typename T, Dim_t order, Dim_t dim> - TensorFieldMap<FieldCollection, T, order, dim>:: - TensorFieldMap(Field & field) + template<class FieldCollection, typename T, Dim_t order, Dim_t dim, + bool ConstField> + template <bool isntConst> + TensorFieldMap<FieldCollection, T, order, dim, ConstField>:: + TensorFieldMap(std::enable_if_t<isntConst, Field &> field) :Parent(field) { + static_assert((isntConst != ConstField), + "let the compiler deduce isntConst, this is a SFINAE " + "parameter"); this->check_compatibility(); } + /* ---------------------------------------------------------------------- */ + template<class FieldCollection, typename T, Dim_t order, Dim_t dim, + bool ConstField> + template <bool isConst> + TensorFieldMap<FieldCollection, T, order, dim, ConstField>:: + TensorFieldMap(std::enable_if_t<isConst, const Field &> field) + :Parent(field) { + static_assert((isConst == ConstField), + "let the compiler deduce isntConst, this is a SFINAE " + "parameter"); + this->check_compatibility(); + } /* ---------------------------------------------------------------------- */ //! human-readable field map type - template<class FieldCollection, typename T, Dim_t order, Dim_t dim> + template<class FieldCollection, typename T, Dim_t order, Dim_t dim, bool ConstField> std::string - TensorFieldMap<FieldCollection, T, order, dim>::info_string() const { + TensorFieldMap<FieldCollection, T, order, dim, ConstField>::info_string() const { std::stringstream info; info << "Tensor(" << typeid(T).name() << ", " << order << "_o, " << dim << "_d)"; return info.str(); } /* ---------------------------------------------------------------------- */ //! member access - template <class FieldCollection, typename T, Dim_t order, Dim_t dim> + template <class FieldCollection, typename T, Dim_t order, Dim_t dim, bool ConstField> template <class ref_t> ref_t - TensorFieldMap<FieldCollection, T, order, dim>::operator[](size_type index) { + TensorFieldMap<FieldCollection, T, order, dim, ConstField>::operator[](size_type index) { auto && lambda = [this, &index](auto&&...tens_sizes) { return ref_t(this->get_ptr_to_entry(index), tens_sizes...); }; return call_sizes<order, dim>(lambda); } - template<class FieldCollection, typename T, Dim_t order, Dim_t dim> - typename TensorFieldMap<FieldCollection, T, order, dim>::reference - TensorFieldMap<FieldCollection, T, order, dim>:: + template<class FieldCollection, typename T, Dim_t order, Dim_t dim, bool ConstField> + typename TensorFieldMap<FieldCollection, T, order, dim, ConstField>::reference + TensorFieldMap<FieldCollection, T, order, dim, ConstField>:: operator[](const Ccoord & ccoord) { auto && index = this->collection.get_index(ccoord); auto && lambda = [this, &index](auto&&...sizes) { return ref_t(this->get_ptr_to_entry(index), sizes...); }; return call_sizes<order, dim>(lambda); } /* ---------------------------------------------------------------------- */ //! for sad, legacy iterator use. Don't use unless you have to. - template<class FieldCollection, typename T, Dim_t order, Dim_t dim> - typename TensorFieldMap<FieldCollection, T, order, dim>::pointer - TensorFieldMap<FieldCollection, T, order, dim>:: + template<class FieldCollection, typename T, Dim_t order, Dim_t dim, bool ConstField> + typename TensorFieldMap<FieldCollection, T, order, dim, ConstField>::pointer + TensorFieldMap<FieldCollection, T, order, dim, ConstField>:: ptr_to_val_t(size_type index) { auto && lambda = [this, &index](auto&&... tens_sizes) { return std::make_unique<value_type>(this->get_ptr_to_entry(index), tens_sizes...); }; return call_sizes<order, dim>(lambda); } } // muSpectre #endif /* FIELD_MAP_TENSOR_H */ diff --git a/src/materials/material_hyper_elastic1.hh b/src/materials/material_hyper_elastic1.hh index ff108d9..dd9739c 100644 --- a/src/materials/material_hyper_elastic1.hh +++ b/src/materials/material_hyper_elastic1.hh @@ -1,104 +1,104 @@ /** * file material_hyper_elastic1.hh * * @author Till Junge <till.junge@epfl.ch> * * @date 13 Nov 2017 * * @brief Implementation for hyperelastic reference material like in de Geus * 2017. This follows the simplest and likely not most efficient * implementation (with exception of the Python law) * * @section LICENCE * * Copyright (C) 2017 Till Junge * * µSpectre is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3, or (at * your option) any later version. * * µSpectre is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "materials/material_muSpectre_base.hh" #ifndef MATERIAL_HYPER_ELASTIC1_H #define MATERIAL_HYPER_ELASTIC1_H namespace muSpectre { //! DimS spatial dimension (dimension of problem //! DimM material_dimension (dimension of constitutive law) template<Dim_t DimS, Dim_t DimM> class MaterialHyperElastic1: public MaterialMuSpectre<MaterialHyperElastic1<DimS, DimM>, DimS, DimM> { public: using Parent = MaterialMuSpectre<MaterialHyperElastic1, DimS, DimM>; using NeedTangent = typename Parent::NeedTangent; using GFieldCollection_t = typename Parent::GFieldCollection_t; // declare what type of strain measure your law takes as input constexpr static auto strain_measure{StrainMeasure::GreenLagrange}; // declare what type of stress measure your law yields as output constexpr static auto stress_measure{StressMeasure::PK2}; // declare whether the derivative of stress with respect to strain is uniform constexpr static bool uniform_stiffness = true; // declare the type in which you wish to receive your strain measure - using StrainMap_t = MatrixFieldMap<GFieldCollection_t, Real, DimM, DimM>; - using StressMap_t = StrainMap_t; + using StrainMap_t = MatrixFieldMap<GFieldCollection_t, Real, DimM, DimM, true>; + using StressMap_t = MatrixFieldMap<GFieldCollection_t, Real, DimM, DimM>; using TangentMap_t = T4MatrixFieldMap<GFieldCollection_t, Real, DimM>; using Strain_t = typename StrainMap_t::const_reference; using Stress_t = typename StressMap_t::reference; using Tangent_t = typename TangentMap_t::reference::ConstType; using Stiffness_t = Eigen::TensorFixedSize <Real, Eigen::Sizes<DimM, DimM, DimM, DimM>>; using InternalVariables = typename Parent::DefaultInternalVariables; //! Default constructor MaterialHyperElastic1() = delete; //! Copy constructor MaterialHyperElastic1(const MaterialHyperElastic1 &other) = delete; //! Construct by name, Young's modulus and Poisson's ratio MaterialHyperElastic1(std::string name, Real young, Real poisson); //! Move constructor MaterialHyperElastic1(MaterialHyperElastic1 &&other) noexcept = delete; //! Destructor virtual ~MaterialHyperElastic1() noexcept = default; //! Copy assignment operator MaterialHyperElastic1& operator=(const MaterialHyperElastic1 &other) = delete; //! Move assignment operator MaterialHyperElastic1& operator=(MaterialHyperElastic1 &&other) noexcept = delete; template <class s_t> decltype(auto) evaluate_stress(s_t && E); template <class s_t> decltype(auto) evaluate_stress_tangent(s_t && E); const Tangent_t & get_stiffness() const; protected: const Real young, poisson, lambda, mu; const Stiffness_t C; private: }; } // muSpectre #endif /* MATERIAL_HYPER_ELASTIC1_H */ diff --git a/src/materials/material_muSpectre_base.hh b/src/materials/material_muSpectre_base.hh index 72cdeb5..d1ad361 100644 --- a/src/materials/material_muSpectre_base.hh +++ b/src/materials/material_muSpectre_base.hh @@ -1,503 +1,508 @@ /** * file material_muSpectre_base.hh * * @author Till Junge <till.junge@epfl.ch> * * @date 25 Oct 2017 * * @brief Base class for materials written for µSpectre specifically. These * can take full advantage of the configuration-change utilities of * µSpectre. The user can inherit from them to define new constitutive * laws and is merely required to provide the methods for computing the * second Piola-Kirchhoff stress and Tangent. This class uses the * "curiously recurring template parameter" to avoid virtual calls. * * @section LICENCE * * Copyright (C) 2017 Till Junge * * µSpectre is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3, or (at * your option) any later version. * * µSpectre is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include <tuple> #include <type_traits> #include <iterator> #include <stdexcept> #include <boost/range/combine.hpp> #include "materials/material_base.hh" #include "materials/materials_toolbox.hh" #include "common/field_collection.hh" #include "common/field.hh" #ifndef MATERIAL_MUSPECTRE_BASE_H #define MATERIAL_MUSPECTRE_BASE_H namespace muSpectre { //! 'Material' is a CRTP template<class Material, Dim_t DimS, Dim_t DimM> class MaterialMuSpectre: public MaterialBase<DimS, DimM> { public: enum class NeedTangent {yes, no}; using Parent = MaterialBase<DimS, DimM>; using GFieldCollection_t = typename Parent::GFieldCollection_t; using MFieldCollection_t = typename Parent::MFieldCollection_t; using StressField_t = typename Parent::StressField_t; using StrainField_t = typename Parent::StrainField_t; using TangentField_t = typename Parent::TangentField_t; using DefaultInternalVariables = std::tuple<>; //! Default constructor MaterialMuSpectre() = delete; //! Construct by name MaterialMuSpectre(std::string name); //! Copy constructor MaterialMuSpectre(const MaterialMuSpectre &other) = delete; //! Move constructor MaterialMuSpectre(MaterialMuSpectre &&other) noexcept = delete; //! Destructor virtual ~MaterialMuSpectre() noexcept = default; //! Copy assignment operator MaterialMuSpectre& operator=(const MaterialMuSpectre &other) = delete; //! Move assignment operator MaterialMuSpectre& operator=(MaterialMuSpectre &&other) noexcept = delete; //! computes stress virtual void compute_stresses(const StrainField_t & F, StressField_t & P, Formulation form) override final; //! computes stress and tangent modulus virtual void compute_stresses_tangent(const StrainField_t & F, StressField_t & P, TangentField_t & K, Formulation form) override final; protected: //! computes stress with the formulation available at compile time template <Formulation Form> inline void compute_stresses_worker(const StrainField_t & F, StressField_t & P); //! computes stress with the formulation available at compile time template <Formulation Form> inline void compute_stresses_worker(const StrainField_t & F, StressField_t & P, TangentField_t & K); //! this iterable class is a default for simple laws that just take a strain //! the iterable is just a templated wrapper to provide a range to iterate over //! that does or does not include tangent moduli //template<NeedTangent need_tgt = NeedTangent::no> //class iterable_proxy; TODO: clean this /** * get a combined range that can be used to iterate over all fields */ inline decltype(auto) get_zipped_fields(const StrainField_t & F, StressField_t & P); inline decltype(auto) get_zipped_fields(const StrainField_t & F, StressField_t & P, TangentField_t & K); template <class... Args> inline decltype(auto) get_zipped_fields_worker(Args && ... args); /** * inheriting classes with internal variables need to overload this function */ decltype(auto) get_internals() { return typename Material::InternalVariables{};} private: }; /* ---------------------------------------------------------------------- */ template <class Material, Dim_t DimS, Dim_t DimM> MaterialMuSpectre<Material, DimS, DimM>:: MaterialMuSpectre(std::string name):Parent(name) { using stress_compatible = typename Material::StressMap_t:: template is_compatible<StressField_t>; using strain_compatible = typename Material::StrainMap_t:: template is_compatible<StrainField_t>; using tangent_compatible = typename Material::TangentMap_t:: template is_compatible<TangentField_t>; static_assert((stress_compatible::value && stress_compatible::explain()), "The material's declared stress map is not compatible " "with the stress field. More info in previously shown " "assert."); static_assert((strain_compatible::value && strain_compatible::explain()), "The material's declared strain map is not compatible " "with the strain field. More info in previously shown " "assert."); static_assert((tangent_compatible::value && tangent_compatible::explain()), "The material's declared tangent map is not compatible " "with the tangent field. More info in previously shown " "assert."); } /* ---------------------------------------------------------------------- */ template <class Material, Dim_t DimS, Dim_t DimM> void MaterialMuSpectre<Material, DimS, DimM>:: compute_stresses(const StrainField_t &F, StressField_t &P, muSpectre::Formulation form) { switch (form) { case Formulation::finite_strain: { this->template compute_stresses_worker<Formulation::finite_strain>(F, P); break; } case Formulation::small_strain: { this->template compute_stresses_worker<Formulation::small_strain>(F, P); break; } default: throw std::runtime_error("Unknown formulation"); break; } } /* ---------------------------------------------------------------------- */ template <class Material, Dim_t DimS, Dim_t DimM> void MaterialMuSpectre<Material, DimS, DimM>:: compute_stresses_tangent(const StrainField_t & F, StressField_t & P, TangentField_t & K, muSpectre::Formulation form) { switch (form) { case Formulation::finite_strain: { this->template compute_stresses_worker<Formulation::finite_strain>(F, P, K); break; } case Formulation::small_strain: { this->template compute_stresses_worker<Formulation::small_strain>(F, P, K); break; } default: throw std::runtime_error("Unknown formulation"); break; } } /* ---------------------------------------------------------------------- */ template <class Material, Dim_t DimS, Dim_t DimM> template <Formulation Form> void MaterialMuSpectre<Material, DimS, DimM>:: compute_stresses_worker(const StrainField_t & F, StressField_t & P, TangentField_t & K){ //! in small strain problems, we always want Cauchy stress as a function //! of the infinitesimal strain tensor // using IterableSmallStrain_t = iterable_proxy<NeedTangent::yes>; // using IterableFiniteStrain_t = iterable_proxy<NeedTangent::yes>; // using iterable = // std::conditional_t // <(Form==Formulation::small_strain), // IterableSmallStrain_t, // IterableFiniteStrain_t>; // TODO: CLEAN THIS /* These lambdas are executed for every integration point. F contains the transformation gradient for finite strain calculations and the infinitesimal strain tensor in small strain problems The internal_variables tuple contains whatever internal variables Material declared (e.g., eigenstrain, strain rate, etc.) */ auto constitutive_law_small_strain = [this] (auto && F, auto && ... internal_variables) { constexpr StrainMeasure stored_strain_m{get_stored_strain_type(Form)}; constexpr StrainMeasure expected_strain_m{ get_formulation_strain_type(Form, Material::strain_measure)}; auto && strain = MatTB::convert_strain<stored_strain_m, expected_strain_m>(F); // return value contains a tuple of rvalue_refs to both stress and tangent moduli auto && stress_tgt = static_cast<Material&>(*this).evaluate_stress_tangent(std::move(strain), internal_variables...); return std::move(stress_tgt); }; auto constitutive_law_finite_strain = [this] (auto && F, auto && ... internal_variables) { constexpr StrainMeasure stored_strain_m{get_stored_strain_type(Form)}; constexpr StrainMeasure expected_strain_m{ get_formulation_strain_type(Form, Material::strain_measure)}; auto && strain = MatTB::convert_strain<stored_strain_m, expected_strain_m>(F); // return value contains a tuple of rvalue_refs to both stress and tangent moduli auto && stress_tgt = static_cast<Material&>(*this).evaluate_stress_tangent(std::move(strain), internal_variables...); auto && stress = std::get<0>(stress_tgt); auto && tangent = std::get<1>(stress_tgt); return MatTB::PK1_stress<Material::stress_measure, Material::strain_measure> (F, stress, tangent); }; - MatrixFieldMap<GFieldCollection_t, Real, DimM, DimM> Pmap(P); - const MatrixFieldMap<GFieldCollection_t, Real, DimM, DimM> Fmap(F); auto it{this->get_zipped_fields(F, P, K)}; for (auto && tuples: it) { // the iterator yields a pair of tuples. this first tuple contains // references to stress and stiffness in the global arrays, the second // contains references to the deformation gradient and internal variables // (some of them are const). auto && stress_tgt = std::get<0>(tuples); auto && inputs = std::get<1>(tuples); switch (Form) { case Formulation::small_strain: { stress_tgt = std::apply(constitutive_law_small_strain, std::move(inputs)); break; } case Formulation::finite_strain: { stress_tgt = std::apply(constitutive_law_finite_strain, std::move(inputs)); break; } } } } /* ---------------------------------------------------------------------- */ template <class Material, Dim_t DimS, Dim_t DimM> decltype(auto) MaterialMuSpectre<Material, DimS, DimM>:: get_zipped_fields(const StrainField_t & F, StressField_t & P) { - return this->get_zipped_fields_worker(F, P); + typename Material::StrainMap_t Fmap(F);//TODO: think about whether F and P should be std::forward<>()'ed + typename Material::StressMap_t Pmap(P); + + return this->get_zipped_fields_worker(std::move(Fmap), + std::move(Pmap)); } /* ---------------------------------------------------------------------- */ template <class Material, Dim_t DimS, Dim_t DimM> decltype(auto) MaterialMuSpectre<Material, DimS, DimM>:: get_zipped_fields(const StrainField_t & F, StressField_t & P, TangentField_t & K) { - auto test = boost::begin(F); - std::cout << test ; + typename Material::StrainMap_t Fmap(F); + typename Material::StressMap_t Pmap(P); + typename Material::TangentMap_t Kmap(K); - return this->get_zipped_fields_worker(F, P, K); + return this->get_zipped_fields_worker(std::move(Fmap), + std::move(Pmap), + std::move(Kmap)); } /* ---------------------------------------------------------------------- */ template <class Material, Dim_t DimS, Dim_t DimM> template <class... Args> decltype(auto) MaterialMuSpectre<Material, DimS, DimM>:: get_zipped_fields_worker(Args && ... args) { return std::apply ([this, &args...] (auto & ... internal_fields) { return boost::combine(args..., internal_fields...);}, this->get_internals()); } //TODO: CLEAN BELOW ///* ---------------------------------------------------------------------- */ ////! this iterator class is a default for simple laws that just take a strain //template <class Material, Dim_t DimS, Dim_t DimM> //template <typename MaterialMuSpectre<Material, DimS, DimM>::NeedTangent NeedTgt> //class MaterialMuSpectre<Material, DimS, DimM>::iterable_proxy { //public: // //! Default constructor // iterable_proxy() = delete; // using NeedTangent = // typename MaterialMuSpectre<Material, DimS, DimM>::NeedTangent; // /** Iterator uses the material's internal variables field // collection to iterate selectively over the global fields // (such as the transformation gradient F and first // Piola-Kirchhoff stress P. // **/ // template<bool DoNeedTgt=(NeedTgt == NeedTangent::yes)> // iterable_proxy(const MaterialMuSpectre & mat, // const StrainField_t & F, // StressField_t & P, // std::enable_if_t<DoNeedTgt, TangentField_t> & K); // // template<bool DontNeedTgt=(NeedTgt == NeedTangent::no)> // iterable_proxy(const MaterialMuSpectre & mat, // const StrainField_t & F, // std::enable_if_t<DontNeedTgt, StressField_t> & P); // // using Strain_t = typename Material::Strain_t; // using Stress_t = typename Material::Stress_t; // using Tangent_t = typename Material::Tangent_t; // // //! Copy constructor // iterable_proxy(const iterable_proxy &other) = default; // // //! Move constructor // iterable_proxy(iterable_proxy &&other) noexcept = default; // // //! Destructor // virtual ~iterable_proxy() noexcept = default; // // //! Copy assignment operator // iterable_proxy& operator=(const iterable_proxy &other) = default; // // //! Move assignment operator // iterable_proxy& operator=(iterable_proxy &&other) noexcept = default; // // class iterator // { // public: // using value_type = // std::conditional_t // <(NeedTgt == NeedTangent::yes), // std::tuple<std::tuple<Stress_t, Tangent_t>, std::tuple<Strain_t>>, // std::tuple<std::tuple<Stress_t>, std::tuple<Strain_t>>>; // using iterator_category = std::forward_iterator_tag; // // //! Default constructor // iterator() = delete; // // /** Iterator uses the material's internal variables field // collection to iterate selectively over the global fields // (such as the transformation gradient F and first // Piola-Kirchhoff stress P. // **/ // iterator(const iterable_proxy & it, bool begin = true) // : it{it}, index{begin ? 0:it.mat.internal_fields.size()}{} // // // //! Copy constructor // iterator(const iterator &other) = default; // // //! Move constructor // iterator(iterator &&other) noexcept = default; // // //! Destructor // virtual ~iterator() noexcept = default; // // //! Copy assignment operator // iterator& operator=(const iterator &other) = default; // // //! Move assignment operator // iterator& operator=(iterator &&other) noexcept = default; // // //! pre-increment // inline iterator & operator++(); // //! dereference // inline value_type operator*(); // //! inequality // inline bool operator!=(const iterator & other) const; // // // protected: // const iterable_proxy & it; // size_t index; // private: // }; // // iterator begin() {return iterator(*this);} // iterator end() {return iterator(*this, false);} // //protected: // using StressTup = std::conditional_t // <(NeedTgt == NeedTangent::yes), // std::tuple<StressField_t&, TangentField_t&>, // std::tuple<StressField_t&>>; // const MaterialMuSpectre & material; // const StrainField_t & strain_field; // auto ZippedFields; // std::tupleStrainField_t // StressTup stress_tup; //private: //}; // ///* ---------------------------------------------------------------------- */ //template <class Material, Dim_t DimS, Dim_t DimM> //template <typename MaterialMuSpectre<Material, DimS, DimM>::NeedTangent Tangent> //template <bool DoNeedTgt> //MaterialMuSpectre<Material, DimS, DimM>::iterable_proxy<Tangent>:: //iterable_proxy(const MaterialMuSpectre<Material, DimS, DimM> & mat, // const StrainField_t & F, // StressField_t & P, // std::enable_if_t<DoNeedTgt, TangentField_t> & K) // : material{mat}, strain_field{F}, stress_tup(P, K), // ZippedFields{std::apply(boost::combine, // std::tuple_cat(std::tuple<F>, // stress_tup, // get_internals()))} //{ // static_assert((Tangent == NeedTangent::yes), // "Explicitly choosing the template parameter 'DoNeedTgt' " // "breaks the SFINAE intention of thi code. Let it be deduced " // "by the compiler."); //} // ///* ---------------------------------------------------------------------- */ //template <class Material, Dim_t DimS, Dim_t DimM> //template <typename MaterialMuSpectre<Material, DimS, DimM>::NeedTangent Tangent> //template <bool DontNeedTgt> //MaterialMuSpectre<Material, DimS, DimM>::iterable_proxy<Tangent>:: //iterable_proxy(const MaterialMuSpectre<Material, DimS, DimM> & mat, // const StrainField_t & F, // std::enable_if_t<DontNeedTgt, StressField_t> & P) // : material{mat}, strain_field{F}, stress_tup(P), // ZippedFields{std::apply(boost::combine, // std::tuple_cat(std::tuple<F>, // stress_tup, // get_internals()))} { // static_assert((Tangent == NeedTangent::no), // "Explicitly choosing the template parameter 'DontNeedTgt' " // "breaks the SFINAE intention of thi code. Let it be deduced " // "by the compiler."); //} // ///* ---------------------------------------------------------------------- */ ////! pre-increment //template<class Material, Dim_t DimS, Dim_t DimM> //template<typename MaterialMuSpectre<Material, DimS, DimM>::NeedTangent Tangent> // //typename MaterialMuSpectre<Material, DimS, DimM>:: //template iterable_proxy<Tangent>::iterator & // //MaterialMuSpectre<Material, DimS, DimM>:: //template iterable_proxy<Tangent>::iterator:: //operator++() { // ++this->index; // return *this; //} // ///* ---------------------------------------------------------------------- */ ////! dereference //template<class Material, Dim_t DimS, Dim_t DimM> //template<typename MaterialMuSpectre<Material, DimS, DimM>::NeedTangent Tangent> // //typename MaterialMuSpectre<Material, DimS, DimM>:: //template iterable_proxy<Tangent>::iterator::value_type // //MaterialMuSpectre<Material, DimS, DimM>:: //template iterable_proxy<Tangent>::iterator:: //operator*() { // static_assert(Tangent, "Template specialisation failed"); // return std::make_tuple // (this->material.internal_fields); //} } // muSpectre #endif /* MATERIAL_MUSPECTRE_BASE_H */