diff --git a/src/system/field.hh b/src/system/field.hh index a47c0e8..ba5ade5 100644 --- a/src/system/field.hh +++ b/src/system/field.hh @@ -1,195 +1,232 @@ /** * file field.hh * * @author Till Junge * * @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 #include #include #include +#include +#include namespace muSpectre { namespace internal { /* ---------------------------------------------------------------------- */ template class FieldBase { - public: protected: //! constructor //! unique name (whithin Collection) //! number of components //! collection to which this field belongs (eg, material, system) - FieldBase(std::string unique_name, Uint nb_components, + FieldBase(std::string unique_name, FieldCollection & collection); + public: //! 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; - /* ---------------------------------------------------------------------- */ - //! allocate memory etc - inline void initialise(Uint size); /* ---------------------------------------------------------------------- */ //!Identifying accessors - //! returns tensorial order of field - inline const Uint & get_nb_components() const; //! 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 type_id of stored type virtual const std::type_info & get_stored_typeid() const = 0; protected: + /* ---------------------------------------------------------------------- */ + //! allocate memory etc + inline virtual void initialise(Uint size) = 0; const std::string name; - const Uint nb_components; const FieldCollection & collection; private: }; /* ---------------------------------------------------------------------- */ template class TypedFieldBase: public FieldBase { public: + using storage_type = Eigen::Array; TypedFieldBase(std::string unique_name, FieldCollection& collection); - virtual ~TypedFieldBase(); + virtual ~TypedFieldBase() = default; //! return type_id of stored type virtual const std::type_info & get_stored_typeid() const; inline const T* get_ptr_to_entry(Uint index); protected: - Eigen::Array array; + inline virtual void initialise(Uint size) override final; + storage_type array; }; } // internal /* ---------------------------------------------------------------------- */ template class TensorField: public internal::TypedFieldBase { public: using parent = internal::TypedFieldBase; + using Field_p = std::unique_ptr>; using component_type = T; - //! constructor - TensorField(std::string unique_name, FieldCollection & collection); - //! 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 const Uint & get_order() const; inline const Uint & get_dim() const; + //! factory function + template + friend FieldType & make_field(std::string unique_name, + CollectionType & collection, + Args&&... args); + protected: + //! constructor protected! + TensorField(std::string unique_name, FieldCollection & collection); + private: }; - - + /* ---------------------------------------------------------------------- */ + /* ---------------------------------------------------------------------- */ + // Implementations namespace internal { /* ---------------------------------------------------------------------- */ template FieldBase::FieldBase(std::string unique_name, - Uint nb_components, FieldCollection & collection_) - :name(unique_name), nb_components(nb_components), - collection(collection_) { - collection_.register_field(*this); + :name(unique_name), collection(collection_) {} + + /* ---------------------------------------------------------------------- */ + template + inline const std::string & FieldBase::get_name() const { + return this->name; } + /* ---------------------------------------------------------------------- */ template TypedFieldBase:: TypedFieldBase(std::string unique_name, FieldCollection & collection) - :FieldBase(unique_name, NbComponents, collection){} + :FieldBase(unique_name, collection){ + static_assert + ((std::is_arithmetic::value || + std::is_same::value), + "Use TypedFieldBase for integer, real or complex scalars for T"); + } /* ---------------------------------------------------------------------- */ //! return type_id of stored type template const std::type_info & TypedFieldBase:: get_stored_typeid() const { return typeid(T); } /* ---------------------------------------------------------------------- */ template const T* TypedFieldBase:: get_ptr_to_entry(Uint index) { return &this->array(index, 0); } + /* ---------------------------------------------------------------------- */ + template + void TypedFieldBase:: + initialise(Uint size) { + this->array = storage_type(size, NbComponents); + } + } // internal + /* ---------------------------------------------------------------------- */ + //! Factory function, guarantees that only fields get created that are + //! properly registered and linked to a collection. + template + FieldType & make_field(std::string unique_name, + FieldCollection & collection, + Args&&... args) { + auto && ptr = std::unique_ptr{ + new FieldType(unique_name, collection, args...)}; + collection.register_field(std::move(ptr)); + return *ptr; + } + /* ---------------------------------------------------------------------- */ template TensorField:: TensorField(std::string unique_name, FieldCollection & collection) :parent(unique_name, collection) {} } // muSpectre #endif /* FIELD_H */ diff --git a/src/system/field_collection.hh b/src/system/field_collection.hh index 9718b96..b4b54ae 100644 --- a/src/system/field_collection.hh +++ b/src/system/field_collection.hh @@ -1,137 +1,213 @@ /** * file field_collection.hh * * @author Till Junge * * @date 07 Sep 2017 * * @brief Provides pixel-iterable containers for scalar and tensorial fields, * addressable by field name * * @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_COLLECTION_H #define FIELD_COLLECTION_H #include "common/common.hh" #include "system/field.hh" #include #include #include -#include "set" +#include +#include +#include +#include +#include namespace muSpectre { class FieldCollectionError: public std::runtime_error { public: explicit FieldCollectionError(const std::string& what) :std::runtime_error(what){} explicit FieldCollectionError(const char * what) :std::runtime_error(what){} }; class FieldError: public FieldCollectionError { using Parent = FieldCollectionError; public: explicit FieldError(const std::string& what) :Parent(what){} explicit FieldError(const char * what) :Parent(what){} }; class FieldInterpretationError: public FieldError { public: explicit FieldInterpretationError(const std::string & what) :FieldError(what){} explicit FieldInterpretationError(const char * what) :FieldError(what){} }; /* ---------------------------------------------------------------------- */ //! DimS spatial dimension (dimension of problem //! DimM material_dimension (dimension of constitutive law) //! Global determines whether this field is present everywhere or per material template class FieldCollection { public: - using Field_p = std::shared_ptr>; + using Field_p = std::unique_ptr>; using Field = internal::FieldBase; using Ccoord = Ccoord_t; //! Default constructor - FieldCollection() = default; + FieldCollection(); //! Copy constructor FieldCollection(const FieldCollection &other) = delete; //! Move constructor FieldCollection(FieldCollection &&other) noexcept = delete; //! Destructor virtual ~FieldCollection() noexcept = default; //! Copy assignment operator FieldCollection& operator=(const FieldCollection &other) = delete; //! Move assignment operator FieldCollection& operator=(FieldCollection &&other) noexcept = delete; //! add a pixel/voxel to the field collection template - std::enable_if_t add_pixel(const Ccoord & local_index); + inline std::enable_if_t add_pixel(const Ccoord & local_index); //! allocate memory, etc - void initialise(); + template + inline std::enable_if_t initialise(); + template + inline std::enable_if_t initialise(Ccoord sizes); - //! Register a new field - void register_field(Field& field); + //! Register a new field (fields need to be in heap, so I want to keep them + //! yas shared pointers + void register_field(Field_p&& field); //! for return values of iterators constexpr inline static Dim_t spatial_dim(); //! for return values of iterators inline Dim_t get_spatial_dim() const; protected: - std::set reserved_names; + std::map fields; bool is_initialised = false; + const Uint id; + static Uint counter; + //! container of pixel coords for non-global collections + std::vector ccoords; + //! container of indices for non-global collections (slow!) + std::map indices; private: }; + /* ---------------------------------------------------------------------- */ + template + Uint FieldCollection::counter{0}; + + /* ---------------------------------------------------------------------- */ + template + FieldCollection::FieldCollection() + :id(counter++){} + + /* ---------------------------------------------------------------------- */ + template + template + std::enable_if_t FieldCollection:: + add_pixel(const Ccoord & local_index) { + this->indices[local_index] = this->coords.size(); + this->ccoords.push_back(local_index); + } + + /* ---------------------------------------------------------------------- */ + template + template + std::enable_if_t FieldCollection:: + initialise() { + const auto && size = this->coords.size(); + std::for_each(std::begin(this->fields), std::end(this->fields), + [this, &size](auto && item) { + item.second->initialise(size); + }); + this->is_initialised = true; + } + + /* ---------------------------------------------------------------------- */ + template + template + std::enable_if_t FieldCollection:: + initialise(Ccoord sizes) { + const auto && size = std::accumulate(sizes.begin(), sizes.end(), 1, + std::multiplies()); + std::for_each(std::begin(this->fields), std::end(this->fields), + [this,&size](auto && item) { + item.second->initialise(size); + }); + this->is_initialised = true; + } + + /* ---------------------------------------------------------------------- */ + template + void FieldCollection::register_field(Field_p &&field) { + auto&& search_it = this->fields.find(field->get_name()); + auto&& does_exist = search_it != this->fields.end(); + if (does_exist) { + std::stringstream err_str; + err_str << "a field named " << field->get_name() + << "is already registered in this field collection. " + << "Currently registered fields: "; + for (const auto& name_field_pair: this->fields) { + err_str << ", " << name_field_pair.first; + } + throw FieldCollectionError(err_str.str()); + } + this->fields[field->get_name()] = std::move(field); + } /* ---------------------------------------------------------------------- */ template constexpr Dim_t FieldCollection::spatial_dim() { return DimS; } /* ---------------------------------------------------------------------- */ template Dim_t FieldCollection::get_spatial_dim() const { return DimS; } } // muSpectre #endif /* FIELD_COLLECTION_H */ diff --git a/tests/test_fields.cc b/tests/test_fields.cc index e906ebc..124331f 100644 --- a/tests/test_fields.cc +++ b/tests/test_fields.cc @@ -1,51 +1,51 @@ /** * file test_fields.cc * * @author Till Junge * * @date 20 Sep 2017 * * @brief Test Fields that are used in FieldCollections * * @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 "tests.hh" #include "system/field_collection.hh" #include "system/field.hh" namespace muSpectre { BOOST_AUTO_TEST_SUITE(field_test); - BOOST_AUTO_TEST_CASE(simple) { + BOOST_AUTO_TEST_CASE(simple_creation) { const Dim_t sdim = 2; const Dim_t mdim = 2; const Dim_t order = 4; using FC_t = FieldCollection; FC_t fc; using TF_t = TensorField; - TF_t myfield("TensorField 1", fc); + auto && myfield = make_field("TensorField 1", fc); } BOOST_AUTO_TEST_SUITE_END(); } // muSpectre