diff --git a/src/common/field.hh b/src/common/field.hh index 7927e4a..ee72fea 100644 --- a/src/common/field.hh +++ b/src/common/field.hh @@ -1,1030 +1,1029 @@ /** * @file field.hh * * @author Till Junge * * @date 07 Sep 2017 * * @brief header-only implementation of a field for field collections * * Copyright © 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 "common/T4_map_proxy.hh" #include #include #include #include #include #include #include #include #include #include namespace muSpectre { /* ---------------------------------------------------------------------- */ /** * base class for field collection-related exceptions */ class FieldCollectionError: public std::runtime_error { public: //! constructor explicit FieldCollectionError(const std::string& what) :std::runtime_error(what){} //! constructor explicit FieldCollectionError(const char * what) :std::runtime_error(what){} }; /// base class for field-related exceptions class FieldError: public FieldCollectionError { using Parent = FieldCollectionError; public: //! constructor explicit FieldError(const std::string& what) :Parent(what){} //! constructor explicit FieldError(const char * what) :Parent(what){} }; /** * Thrown when a associating a field map to and incompatible field * is attempted */ class FieldInterpretationError: public FieldError { public: //! constructor explicit FieldInterpretationError(const std::string & what) :FieldError(what){} //! constructor explicit FieldInterpretationError(const char * what) :FieldError(what){} }; namespace internal { /* ---------------------------------------------------------------------- */ /** * Virtual base class for all fields. A field represents * meta-information for the per-pixel storage for a scalar, vector * or tensor quantity and is therefore the abstract class defining * the field. It is used for type and size checking at runtime and * for storage of polymorphic pointers to fully typed and sized * fields. `FieldBase` (and its children) are templated with a * specific `FieldCollection` (derived from * `muSpectre::FieldCollectionBase`). A `FieldCollection` stores * multiple fields that all apply to the same set of * pixels. Addressing and managing the data for all pixels is * handled by the `FieldCollection`. Note that `FieldBase` does * not know anything about about mathematical operations on the * data or how to iterate over all pixels. Mapping the raw data * onto for instance Eigen maps and iterating over those is * handled by the `FieldMap`. */ template class FieldBase { protected: //! constructor //! unique name (whithin Collection) //! number of components //! collection to which this field belongs (eg, material, cell) FieldBase(std::string unique_name, size_t nb_components, FieldCollection & collection); public: using collection_t = FieldCollection; //!< for type checks //! Copy constructor FieldBase(const FieldBase &other) = delete; //! Move constructor FieldBase(FieldBase &&other) = delete; //! Destructor virtual ~FieldBase() = default; //! Copy assignment operator FieldBase& operator=(const FieldBase &other) = delete; //! Move assignment operator FieldBase& operator=(FieldBase &&other) = 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; //! number of pixels in the field virtual size_t size() const = 0; - //! allocate memory etc - virtual void resize(size_t size) = 0; - //! initialise field to zero (do more complicated initialisations through //! fully typed maps) virtual void set_zero() = 0; //! give access to collections friend FieldCollection; //! give access to collection's base class friend typename FieldCollection::Parent; protected: /* ---------------------------------------------------------------------- */ + //! allocate memory etc + virtual void resize(size_t size) = 0; const std::string name; //!< the field's unique name const size_t nb_components; //!< number of components per entry //! reference to the collection this field belongs to const FieldCollection & collection; private: }; /** * Dummy intermediate class to provide a run-time polymorphic * typed field. Mainly for binding Python. TypedFieldBase specifies methods * that return typed Eigen maps and vectors in addition to pointers to the * raw data. */ template class TypedFieldBase: public FieldBase { public: using Parent = FieldBase; //!< base class //! for type checks when mapping this field using collection_t = typename Parent::collection_t; using Scalar = T; //!< for type checks using Base = Parent; //!< for uniformity of interface //! Plain Eigen type to map using EigenRep = Eigen::Array; //! map returned when iterating over field using EigenMap = Eigen::Map; //! Plain eigen vector to map using EigenVec = Eigen::Map; //! vector map returned when iterating over field using EigenVecConst = Eigen::Map; //! Default constructor TypedFieldBase() = delete; //! constructor TypedFieldBase(std::string unique_name, size_t nb_components, FieldCollection& collection); //! Copy constructor TypedFieldBase(const TypedFieldBase &other) = delete; //! Move constructor TypedFieldBase(TypedFieldBase &&other) = delete; //! Destructor virtual ~TypedFieldBase() = default; //! Copy assignment operator TypedFieldBase& operator=(const TypedFieldBase &other) = delete; //! Move assignment operator TypedFieldBase& operator=(TypedFieldBase &&other) = delete; //! return type_id of stored type virtual const std::type_info & get_stored_typeid() const override final; virtual size_t size() const override = 0; //! initialise field to zero (do more complicated initialisations through //! fully typed maps) virtual void set_zero() override = 0; //! raw pointer to content (e.g., for Eigen maps) virtual T* data() = 0; //! raw pointer to content (e.g., for Eigen maps) virtual const T* data() const = 0; //! return a map representing the entire field as a single `Eigen::Array` EigenMap eigen(); //! return a map representing the entire field as a single Eigen vector EigenVec eigenvec(); //! return a map representing the entire field as a single Eigen vector EigenVecConst eigenvec() const; protected: private: }; /* ---------------------------------------------------------------------- */ //! declaraton for friending template class FieldMap; /* ---------------------------------------------------------------------- */ /** * A `TypedSizedFieldBase` is the base class for fields that contain a * statically known number of scalars of a statically known type per pixel * in a `FieldCollection`. The actual data for all pixels is * stored in `TypedSizeFieldBase::values`. * `TypedSizedFieldBase` is the base class for `MatrixField` and * `TensorField`. */ template class TypedSizedFieldBase: public TypedFieldBase { friend class FieldMap; friend class FieldMap; public: //! for compatibility checks constexpr static auto nb_components{NbComponents}; using Parent = TypedFieldBase; //!< base class using Scalar = T; //!< for type checking using Base = typename Parent::Base; //!< root base class //! type stored if ArrayStore is true using StoredType = Eigen::Array; //! storage container using StorageType = std::conditional_t >, std::vector>>; //! Plain type that is being mapped (Eigen lingo) using EigenRep = Eigen::Array; //! maps returned when iterating over field using EigenMap = std::conditional_t< ArrayStore, Eigen::Map>, Eigen::Map>; //! maps returned when iterating over field using ConstEigenMap = std::conditional_t< ArrayStore, Eigen::Map>, Eigen::Map>; //! constructor TypedSizedFieldBase(std::string unique_name, FieldCollection& collection); virtual ~TypedSizedFieldBase() = default; //! initialise field to zero (do more complicated initialisations through //! fully typed maps) inline void set_zero() override final; //! add a new value at the end of the field template inline void push_back(const std::enable_if_t & value); //! add a new value at the end of the field template inline std::enable_if_t push_back(const StoredType & value); //! Number of stored arrays (i.e. total number of stored //! scalars/NbComponents) size_t size() const override final; - //! set the storage size of this field - inline virtual void resize(size_t size) override final; - /** * returns an upcasted reference to a field, or throws an * exception if the field is incompatible */ static TypedSizedFieldBase & check_ref(Base & other); /** * returns an upcasted reference to a field, or throws an * exception if the field is incompatible */ static const TypedSizedFieldBase & check_ref(const Base & other); //! return raw pointer to stored data (necessary for Eigen maps) inline T* data() override final {return this->get_ptr_to_entry(0);} //! return raw pointer to stored data (necessary for Eigen maps) inline const T* data() const override final {return this->get_ptr_to_entry(0);} //! return a map representing the entire field as a single `Eigen::Array` inline EigenMap eigen(); //! return a map representing the entire field as a single `Eigen::Array` inline ConstEigenMap eigen() const; /** * return a map representing the entire field as a single * dynamically sized `Eigen::Array` (for python bindings) */ inline typename Parent::EigenMap dyn_eigen() {return Parent::eigen();} //! inner product between compatible fields template inline Real inner_product(const TypedSizedFieldBase & other) const; protected: //! returns a raw pointer to the entry, for `Eigen::Map` template inline std::enable_if_t get_ptr_to_entry(const size_t&& index); //! returns a raw pointer to the entry, for `Eigen::Map` template inline std::enable_if_t get_ptr_to_entry(const size_t&& index) const; //! returns a raw pointer to the entry, for `Eigen::Map` template inline T* get_ptr_to_entry(std::enable_if_t index); //! returns a raw pointer to the entry, for `Eigen::Map` template inline const T* get_ptr_to_entry(std::enable_if_t index) const; + //! set the storage size of this field + inline virtual void resize(size_t size) override final; + //! The actual storage container StorageType values{}; }; } // internal /* ---------------------------------------------------------------------- */ /** * The `TensorField` is a subclass of `muSpectre::internal::TypedSizedFieldBase` * that represents tensorial fields, i.e. arbitrary-dimensional arrays with * identical number of rows/columns (that typically correspond to the spatial * cartesian dimensions). It is defined by the stored scalar type @a T, the * tensorial order @a order (often also called degree or rank) and the * number of spatial dimensions @a dim. */ template class TensorField: public internal::TypedSizedFieldBase { public: //! base class using Parent = internal::TypedSizedFieldBase; using Base = typename Parent::Base; //!< root base class //! polymorphic base class using Field_p = typename FieldCollection::Field_p; using Scalar = typename Parent::Scalar; //!< for type checking //! Copy constructor TensorField(const TensorField &other) = delete; //! Move constructor TensorField(TensorField &&other) = delete; //! Destructor virtual ~TensorField() = default; //! Copy assignment operator TensorField& operator=(const TensorField &other) = delete; //! Move assignment operator TensorField& operator=(TensorField &&other) = delete; //! return the order of the stored tensor inline Dim_t get_order() const; //! return the dimension of the stored tensor inline Dim_t get_dim() const; //! factory function template friend FieldType& make_field(std::string unique_name, CollectionType & collection, Args&&... args); //! return a reference or throw an exception if `other` is incompatible static TensorField & check_ref(Base & other) { return static_cast(Parent::check_ref(other));} //! return a reference or throw an exception if `other` is incompatible static const TensorField & check_ref(const Base & other) { return static_cast(Parent::check_ref(other));} /** * Convenience functions to return a map onto this field. A map allows * iteration over all pixels. The map's iterator returns an object that * represents the underlying mathematical structure of the field and * implements common linear algebra operations on it. * Specifically, this function returns * - A `MatrixFieldMap` with @a dim rows and one column if the tensorial * order @a order is unity. * - A `MatrixFieldMap` with @a dim rows and @a dim columns if the tensorial * order @a order is 2. * - A `T4MatrixFieldMap` if the tensorial order is 4. */ decltype(auto) get_map(); /** * Convenience functions to return a map onto this field. A map allows * iteration over all pixels. The map's iterator returns an object that * represents the underlying mathematical structure of the field and * implements common linear algebra operations on it. * Specifically, this function returns * - A `MatrixFieldMap` with @a dim rows and one column if the tensorial * order @a order is unity. * - A `MatrixFieldMap` with @a dim rows and @a dim columns if the tensorial * order @a order is 2. * - A `T4MatrixFieldMap` if the tensorial order is 4. */ decltype(auto) get_const_map(); /** * Convenience functions to return a map onto this field. A map allows * iteration over all pixels. The map's iterator returns an object that * represents the underlying mathematical structure of the field and * implements common linear algebra operations on it. * Specifically, this function returns * - A `MatrixFieldMap` with @a dim rows and one column if the tensorial * order @a order is unity. * - A `MatrixFieldMap` with @a dim rows and @a dim columns if the tensorial * order @a order is 2. * - A `T4MatrixFieldMap` if the tensorial order is 4. */ decltype(auto) get_map() const; protected: //! constructor protected! TensorField(std::string unique_name, FieldCollection & collection); private: }; /* ---------------------------------------------------------------------- */ /** * The `MatrixField` is subclass of `muSpectre::internal::TypedSizedFieldBase` * that represents matrix fields, i.e. a two dimensional arrays, defined by * the stored scalar type @a T and the number of rows @a NbRow and columns * @a NbCol of the matrix. */ template class MatrixField: public internal::TypedSizedFieldBase { public: //! base class using Parent = internal::TypedSizedFieldBase; using Base = typename Parent::Base; //!< root base class //! polymorphic base field ptr to store using Field_p = std::unique_ptr>; //! Copy constructor MatrixField(const MatrixField &other) = delete; //! Move constructor MatrixField(MatrixField &&other) = delete; //! Destructor virtual ~MatrixField() = default; //! Copy assignment operator MatrixField& operator=(const MatrixField &other) = delete; //! Move assignment operator MatrixField& operator=(MatrixField &&other) = delete; //! returns the number of rows inline Dim_t get_nb_row() const; //! returns the number of columns inline Dim_t get_nb_col() const; //! factory function template friend FieldType& make_field(std::string unique_name, CollectionType & collection, Args&&... args); //! returns a `MatrixField` reference if `other` is a compatible field static MatrixField & check_ref(Base & other) { return static_cast(Parent::check_ref(other));} //! returns a `MatrixField` reference if `other` is a compatible field static const MatrixField & check_ref(const Base & other) { return static_cast(Parent::check_ref(other));} /** * Convenience functions to return a map onto this field. A map allows * iteration over all pixels. The map's iterator returns an object that * represents the underlying mathematical structure of the field and * implements common linear algebra operations on it. * Specifically, this function returns * - A `ScalarFieldMap` if @a NbRows and @a NbCols are unity. * - A `MatrixFieldMap` with @a NbRows rows and @a NbCols columns * otherwise. */ decltype(auto) get_map(); /** * Convenience functions to return a map onto this field. A map allows * iteration over all pixels. The map's iterator returns an object that * represents the underlying mathematical structure of the field and * implements common linear algebra operations on it. * Specifically, this function returns * - A `ScalarFieldMap` if @a NbRows and @a NbCols are unity. * - A `MatrixFieldMap` with @a NbRows rows and @a NbCols columns * otherwise. */ decltype(auto) get_const_map(); /** * Convenience functions to return a map onto this field. A map allows * iteration over all pixels. The map's iterator returns an object that * represents the underlying mathematical structure of the field and * implements common linear algebra operations on it. * Specifically, this function returns * - A `ScalarFieldMap` if @a NbRows and @a NbCols are unity. * - A `MatrixFieldMap` with @a NbRows rows and @a NbCols columns * otherwise. */ decltype(auto) get_map() const; protected: //! constructor protected! MatrixField(std::string unique_name, FieldCollection & collection); private: }; /* ---------------------------------------------------------------------- */ //! convenience alias ( template using ScalarField = MatrixField; /* ---------------------------------------------------------------------- */ // Implementations namespace internal { /* ---------------------------------------------------------------------- */ template FieldBase::FieldBase(std::string unique_name, size_t nb_components_, FieldCollection & collection_) :name(unique_name), nb_components(nb_components_), collection(collection_) {} /* ---------------------------------------------------------------------- */ template inline const std::string & FieldBase::get_name() const { return this->name; } /* ---------------------------------------------------------------------- */ template inline const FieldCollection & FieldBase:: get_collection() const { return this->collection; } /* ---------------------------------------------------------------------- */ template inline const size_t & FieldBase:: get_nb_components() const { return this->nb_components; } /* ---------------------------------------------------------------------- */ template TypedFieldBase:: TypedFieldBase(std::string unique_name, size_t nb_components, FieldCollection & collection) :Parent(unique_name, nb_components, collection) {} /* ---------------------------------------------------------------------- */ //! return type_id of stored type template const std::type_info & TypedFieldBase:: get_stored_typeid() const { return typeid(T); } /* ---------------------------------------------------------------------- */ template typename TypedFieldBase::EigenMap TypedFieldBase:: eigen() { return EigenMap(this->data(), this->get_nb_components(), this->size()); } /* ---------------------------------------------------------------------- */ template typename TypedFieldBase::EigenVec TypedFieldBase:: eigenvec() { return EigenVec(this->data(), this->get_nb_components() * this->size()); } /* ---------------------------------------------------------------------- */ template typename TypedFieldBase::EigenVecConst TypedFieldBase:: eigenvec() const{ return EigenVecConst(this->data(), this->get_nb_components() * this->size()); } /* ---------------------------------------------------------------------- */ template TypedSizedFieldBase:: TypedSizedFieldBase(std::string unique_name, FieldCollection & collection) :Parent(unique_name, NbComponents, collection){ static_assert ((std::is_arithmetic::value || std::is_same::value), "Use TypedSizedFieldBase for integer, real or complex scalars for T"); static_assert(NbComponents > 0, "Only fields with more than 0 components"); } /* ---------------------------------------------------------------------- */ template void TypedSizedFieldBase:: set_zero() { std::fill(this->values.begin(), this->values.end(), T{}); } /* ---------------------------------------------------------------------- */ template size_t TypedSizedFieldBase:: size() const { if (ArrayStore) { return this->values.size(); } else { return this->values.size()/NbComponents; } } /* ---------------------------------------------------------------------- */ template TypedSizedFieldBase & TypedSizedFieldBase:: check_ref(Base & other) { if (typeid(T).hash_code() != other.get_stored_typeid().hash_code()) { std::string err ="Cannot create a Reference of requested type " +( "for field '" + other.get_name() + "' of type '" + other.get_stored_typeid().name() + "'"); throw std::runtime_error (err); } //check size compatibility if (NbComponents != other.get_nb_components()) { throw std::runtime_error ("Cannot create a Reference to a field with " + std::to_string(NbComponents) + " components " + "for field '" + other.get_name() + "' with " + std::to_string(other.get_nb_components()) + " components"); } return static_cast(other); } /* ---------------------------------------------------------------------- */ template const TypedSizedFieldBase & TypedSizedFieldBase:: check_ref(const Base & other) { if (typeid(T).hash_code() != other.get_stored_typeid().hash_code()) { std::stringstream err_str{}; err_str << "Cannot create a Reference of requested type " << "for field '" << other.get_name() << "' of type '" << other.get_stored_typeid().name() << "'"; throw std::runtime_error (err_str.str()); } //check size compatibility if (NbComponents != other.get_nb_components()) { throw std::runtime_error ("Cannot create a Reference to a field with " + std::to_string(NbComponents) + " components " + "for field '" + other.get_name() + "' with " + std::to_string(other.get_nb_components()) + " components"); } return static_cast(other); } /* ---------------------------------------------------------------------- */ template typename TypedSizedFieldBase::EigenMap TypedSizedFieldBase:: eigen() { return EigenMap(this->data(), NbComponents, this->size()); } /* ---------------------------------------------------------------------- */ template typename TypedSizedFieldBase::ConstEigenMap TypedSizedFieldBase:: eigen() const { return ConstEigenMap(this->data(), NbComponents, this->size()); } /* ---------------------------------------------------------------------- */ template template Real TypedSizedFieldBase:: inner_product(const TypedSizedFieldBase & other) const { return (this->eigen() * other.eigen()).sum(); } /* ---------------------------------------------------------------------- */ template template std::enable_if_t TypedSizedFieldBase:: get_ptr_to_entry(const size_t&& index) { static_assert (isArray == ArrayStore, "SFINAE"); return &this->values[std::move(index)](0, 0); } /* ---------------------------------------------------------------------- */ template template T* TypedSizedFieldBase:: get_ptr_to_entry(std::enable_if_t index) { static_assert (noArray != ArrayStore, "SFINAE"); return &this->values[NbComponents*std::move(index)]; } /* ---------------------------------------------------------------------- */ template template std::enable_if_t TypedSizedFieldBase:: get_ptr_to_entry(const size_t&& index) const { static_assert (isArray == ArrayStore, "SFINAE"); return &this->values[std::move(index)](0, 0); } /* ---------------------------------------------------------------------- */ template template const T* TypedSizedFieldBase:: get_ptr_to_entry(std::enable_if_t index) const { static_assert (noArray != ArrayStore, "SFINAE"); return &this->values[NbComponents*std::move(index)]; } /* ---------------------------------------------------------------------- */ template void TypedSizedFieldBase:: resize(size_t size) { if (ArrayStore) { this->values.resize(size); } else { this->values.resize(size*NbComponents); } } /* ---------------------------------------------------------------------- */ template template void TypedSizedFieldBase:: push_back(const std::enable_if_t & value) { static_assert(isArrayStore == ArrayStore, "SFINAE"); this->values.push_back(value); } /* ---------------------------------------------------------------------- */ template template std::enable_if_t TypedSizedFieldBase:: push_back(const StoredType & value) { static_assert(componentStore != ArrayStore, "SFINAE"); for (Dim_t i = 0; i < NbComponents; ++i) { this->values.push_back(value(i)); } } } // internal /* ---------------------------------------------------------------------- */ //! Factory function, guarantees that only fields get created that are //! properly registered and linked to a collection. template inline FieldType & make_field(std::string unique_name, FieldCollection & collection, Args&&... args) { std::unique_ptr ptr{ new FieldType(unique_name, collection, args...)}; auto& retref{*ptr}; collection.register_field(std::move(ptr)); return retref; } /* ---------------------------------------------------------------------- */ template TensorField:: TensorField(std::string unique_name, FieldCollection & collection) :Parent(unique_name, collection) {} /* ---------------------------------------------------------------------- */ template Dim_t TensorField:: get_order() const { return order; } /* ---------------------------------------------------------------------- */ template Dim_t TensorField:: get_dim() const { return dim; } /* ---------------------------------------------------------------------- */ template MatrixField:: MatrixField(std::string unique_name, FieldCollection & collection) :Parent(unique_name, collection) {} /* ---------------------------------------------------------------------- */ template Dim_t MatrixField:: get_nb_col() const { return NbCol; } /* ---------------------------------------------------------------------- */ template Dim_t MatrixField:: get_nb_row() const { return NbRow; } } // muSpectre #include "common/field_map.hh" namespace muSpectre { namespace internal { /* ---------------------------------------------------------------------- */ /** * defines the default mapped type obtained when calling * `muSpectre::TensorField::get_map()` */ template struct tensor_map_type { }; /// specialisation for vectors template struct tensor_map_type { //! use this type using type = MatrixFieldMap; }; /// specialisation to second-order tensors (matrices) template struct tensor_map_type { //! use this type using type = MatrixFieldMap; }; /// specialisation to fourth-order tensors template struct tensor_map_type { //! use this type using type = T4MatrixFieldMap; }; /* ---------------------------------------------------------------------- */ /** * defines the default mapped type obtained when calling * `muSpectre::MatrixField::get_map()` */ template struct matrix_map_type { //! mapping type using type = MatrixFieldMap; }; //! specialisation to scalar fields template struct matrix_map_type { //! mapping type using type = ScalarFieldMap; }; } // internal /* ---------------------------------------------------------------------- */ template decltype(auto) TensorField:: get_map() { constexpr bool map_constness{false}; using RawMap_t = typename internal::tensor_map_type::type; return RawMap_t(*this); } /* ---------------------------------------------------------------------- */ template decltype(auto) TensorField:: get_const_map() { constexpr bool map_constness{true}; using RawMap_t = typename internal::tensor_map_type::type; return RawMap_t(*this); } /* ---------------------------------------------------------------------- */ template decltype(auto) TensorField:: get_map() const { constexpr bool map_constness{true}; using RawMap_t = typename internal::tensor_map_type::type; return RawMap_t(*this); } /* ---------------------------------------------------------------------- */ template decltype(auto) MatrixField:: get_map() { constexpr bool map_constness{false}; using RawMap_t = typename internal::matrix_map_type::type; return RawMap_t(*this); } /* ---------------------------------------------------------------------- */ template decltype(auto) MatrixField:: get_const_map() { constexpr bool map_constness{true}; using RawMap_t = typename internal::matrix_map_type::type; return RawMap_t(*this); } /* ---------------------------------------------------------------------- */ template decltype(auto) MatrixField:: get_map() const { constexpr bool map_constness{true}; using RawMap_t = typename internal::matrix_map_type::type; return RawMap_t(*this); } } // muSpectre #endif /* FIELD_H */