diff --git a/src/system/system_base.cc b/src/system/system_base.cc index f5e14ab..eb8c96f 100644 --- a/src/system/system_base.cc +++ b/src/system/system_base.cc @@ -1,164 +1,165 @@ /** * file system_base.cc * * @author Till Junge * * @date 01 Nov 2017 * * @brief Implementation for system base class * * @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 #include #include "system/system_base.hh" #include "common/ccoord_operations.hh" namespace muSpectre { /* ---------------------------------------------------------------------- */ template - SystemBase::SystemBase(Projection_ptr projection) - :resolutions{projection->get_resolutions()}, + SystemBase::SystemBase(Projection_ptr projection_) + :resolutions{projection_->get_resolutions()}, pixels(resolutions), - lengths{projection->get_lengths()}, + lengths{projection_->get_lengths()}, + fields{}, F{make_field("Gradient", this->fields)}, P{make_field("Piola-Kirchhoff-1", this->fields)}, - K_ptr{nullptr}, projection{std::move(projection)} - {} + K_ptr{nullptr}, projection{std::move(projection_)} + { } /* ---------------------------------------------------------------------- */ template void SystemBase::add_material(Material_ptr mat) { this->materials.push_back(std::move(mat)); } /* ---------------------------------------------------------------------- */ template typename SystemBase::FullResponse_t SystemBase::evaluate_stress_tangent(StrainField_t & grad) { if (this->is_initialised == false) { this->initialise(); } //! High level compatibility checks if (grad.size() != this->F.size()) { throw std::runtime_error("Size mismatch"); } if (this->K_ptr == nullptr) { K_ptr = &make_field("Tangent Stiffness", this->fields); } for (auto & mat: this->materials) { mat->compute_stresses_tangent(grad, this->P, *this->K_ptr, form); } return std::tie(this->P, *this->K_ptr); } /* ---------------------------------------------------------------------- */ template typename SystemBase::StrainField_t & SystemBase::get_strain() { if (this->is_initialised == false) { this->initialise(); } return this->F; } /* ---------------------------------------------------------------------- */ template const typename SystemBase::StressField_t & SystemBase::get_stress() const { return this->P; } /* ---------------------------------------------------------------------- */ template void SystemBase::initialise() { this->check_material_coverage(); this->fields.initialise(this->resolutions); for (auto && mat: this->materials) { mat->initialise(); } this->is_initialised = true; } /* ---------------------------------------------------------------------- */ template typename SystemBase::iterator SystemBase::begin() { return this->pixels.begin(); } /* ---------------------------------------------------------------------- */ template typename SystemBase::iterator SystemBase::end() { return this->pixels.end(); } /* ---------------------------------------------------------------------- */ template void SystemBase::check_material_coverage() { auto nb_pixels = CcoordOps::get_size(this->resolutions); std::vector*> assignments(nb_pixels, nullptr); for (auto & mat: this->materials) { for (auto & pixel: *mat) { auto index = CcoordOps::get_index(this->resolutions, pixel); auto& assignment{assignments.at(index)}; if (assignment != nullptr) { std::stringstream err{}; err << "Pixel " << pixel << "is already assigned to material '" << assignment->get_name() << "' and cannot be reassigned to material '" << mat->get_name(); throw std::runtime_error(err.str()); } else { assignments[index] = mat.get(); } } } // find and identify unassigned pixels std::vector unassigned_pixels; for (size_t i = 0; i < assignments.size(); ++i) { if (assignments[i] == nullptr) { unassigned_pixels.push_back(CcoordOps::get_ccoord(this->resolutions, i)); } } if (unassigned_pixels.size() != 0) { std::stringstream err {}; err << "The following pixels have were not assigned a material: "; for (auto & pixel: unassigned_pixels) { err << pixel << ", "; } err << "and that cannot be handled"; throw std::runtime_error(err.str()); } } template class SystemBase; template class SystemBase; } // muSpectre diff --git a/src/system/system_base.hh b/src/system/system_base.hh index ec20757..e190c4b 100644 --- a/src/system/system_base.hh +++ b/src/system/system_base.hh @@ -1,123 +1,123 @@ /** * file system_base.hh * * @author Till Junge * * @date 01 Nov 2017 * * @brief Base class representing a unit cell system with single * projection operator * * @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 #include #include #include "common/common.hh" #include "common/ccoord_operations.hh" #include "common/field_collection.hh" #include "materials/material_base.hh" #include "fft/projection_base.hh" #ifndef SYSTEM_BASE_H #define SYSTEM_BASE_H namespace muSpectre { //! DimS spatial dimension (dimension of problem //! DimM material_dimension (dimension of constitutive law) template class SystemBase { public: constexpr static Formulation form{Formulation::finite_strain}; using Ccoord = Ccoord_t; using Rcoord = Rcoord_t; using FieldCollection_t = FieldCollection; using Material_ptr = std::unique_ptr>; using Projection_ptr = std::unique_ptr>; using StrainField_t = TensorField; using StressField_t = TensorField; using TangentField_t = TensorField; using FullResponse_t = std::tuple; using iterator = typename CcoordOps::Pixels::iterator; //! Default constructor SystemBase() = delete; //! constructor using sizes and resolution SystemBase(Projection_ptr projection); //! Copy constructor SystemBase(const SystemBase &other) = delete; //! Move constructor SystemBase(SystemBase &&other) noexcept = default; //! Destructor virtual ~SystemBase() noexcept = default; //! Copy assignment operator SystemBase& operator=(const SystemBase &other) = delete; //! Move assignment operator SystemBase& operator=(SystemBase &&other) = default; /** * Materials can only be moved. This is to assure exclusive * ownership of any material by this system */ void add_material(Material_ptr mat); FullResponse_t evaluate_stress_tangent(StrainField_t & F); StrainField_t & get_strain(); const StressField_t & get_stress() const; void initialise(); iterator begin(); iterator end(); size_t size() const {return pixels.size();} protected: //! make sure that every pixel is assigned to one and only one material void check_material_coverage(); const Ccoord & resolutions; CcoordOps::Pixels pixels; const Rcoord & lengths; - FieldCollection_t fields{}; + FieldCollection_t fields; StrainField_t & F; StressField_t & P; //! Tangent field migth not even be required; so this is a //! pointer instead of a ref TangentField_t * K_ptr; std::vector materials{}; Projection_ptr projection; bool is_initialised{false}; private: }; } // muSpectre #endif /* SYSTEM_BASE_H */ diff --git a/src/system/system_factory.hh b/src/system/system_factory.hh index c680a8e..4eb4b87 100644 --- a/src/system/system_factory.hh +++ b/src/system/system_factory.hh @@ -1,60 +1,80 @@ /** * file system_factory.hh * * @author Till Junge * * @date 15 Dec 2017 * * @brief System factories to help create systems with ease * * @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 SYSTEM_FACTORY_H #define SYSTEM_FACTORY_H #include #include "common/common.hh" #include "common/ccoord_operations.hh" #include "system/system_base.hh" #include "fft/projection_finite_strain_fast.hh" #include "fft/projection_finite_strain.hh" #include "fft/fftw_engine.hh" namespace muSpectre { + + /** + * Create a unique ptr to a Projection operator (with appropriate + * FFT_engine) to be used in a system constructor + */ + template , + typename Projection=ProjectionFiniteStrainFast> + inline + std::unique_ptr system_input(Ccoord_t resolutions, + Rcoord_t lengths=CcoordOps::get_cube(1.)) { + auto fft_ptr{std::make_unique(resolutions, lengths)}; + return std::make_unique(std::move(fft_ptr)); + } + + + /** + * convenience function to create a system (avoids having to build + * and move the chain of unique_ptrs + */ template , typename FFT_Engine=FFTW_Engine, typename Projection=ProjectionFiniteStrainFast> inline System make_system(Ccoord_t resolutions, Rcoord_t lengths=CcoordOps::get_cube(1.)) { - auto && fft_ptr{std::make_unique(resolutions, lengths)}; - auto && proj_ptr{std::make_unique(std::move(fft_ptr))}; - return System{std::move(proj_ptr)}; + return System{ + std::move(system_input + (resolutions, lengths))}; } } // muSpectre #endif /* SYSTEM_FACTORY_H */ diff --git a/tests/test_system_base.cc b/tests/test_system_base.cc index 0ce2ee8..045741c 100644 --- a/tests/test_system_base.cc +++ b/tests/test_system_base.cc @@ -1,156 +1,171 @@ /** * file test_system_base.cc * * @author Till Junge * * @date 14 Dec 2017 * * @brief Tests for the basic system class * * @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 #include #include "tests.hh" #include "common/common.hh" #include "common/iterators.hh" #include "common/field_map.hh" #include "common/test_goodies.hh" #include "system/system_factory.hh" #include "materials/material_hyper_elastic1.hh" namespace muSpectre { BOOST_AUTO_TEST_SUITE(system_base); template struct Sizes { }; template<> struct Sizes { constexpr static Dim_t sdim{twoD}; constexpr static Ccoord_t get_resolution() { return Ccoord_t{3, 5};} constexpr static Rcoord_t get_lengths() { return Rcoord_t{3.4, 5.8};} }; template<> struct Sizes { constexpr static Dim_t sdim{threeD}; constexpr static Ccoord_t get_resolution() { return Ccoord_t{3, 5, 7};} constexpr static Rcoord_t get_lengths() { return Rcoord_t{3.4, 5.8, 6.7};} }; template struct SystemBaseFixture: SystemBase { constexpr static Dim_t sdim{DimS}; constexpr static Dim_t mdim{DimM}; SystemBaseFixture() :SystemBase{ - make_system(Sizes::get_resolution(), - Sizes::get_lengths())} {} + std::move(system_input(Sizes::get_resolution(), + Sizes::get_lengths()))} {} }; using fixlist = boost::mpl::list, SystemBaseFixture>; + BOOST_AUTO_TEST_CASE(manual_construction) { + constexpr Dim_t dim{twoD}; + + Ccoord_t resolutions{3, 3}; + Rcoord_t lengths{2.3, 2.7}; + auto fft_ptr{std::make_unique>(resolutions, lengths)}; + auto proj_ptr{std::make_unique>(std::move(fft_ptr))}; + SystemBase sys{std::move(proj_ptr)}; + + auto sys2{make_system(resolutions, lengths)}; + auto sys2b{std::move(sys2)}; + BOOST_CHECK_EQUAL(sys2b.size(), sys.size()); + } + BOOST_FIXTURE_TEST_CASE_TEMPLATE(constructor_test, fix, fixlist, fix) { BOOST_CHECK_THROW(fix::check_material_coverage(), std::runtime_error); BOOST_CHECK_THROW(fix::initialise(), std::runtime_error); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(add_material_test, fix, fixlist, fix) { constexpr Dim_t dim{fix::sdim}; using Material_t = MaterialHyperElastic1; auto Material_hard = std::make_unique("hard", 210e9, .33); BOOST_CHECK_NO_THROW(fix::add_material(std::move(Material_hard))); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(simple_evaluation_test, fix, fixlist, fix) { using fc = typename fix::FieldCollection_t; constexpr Dim_t dim{fix::sdim}; using Mat_t = MaterialHyperElastic1; const Real Young{210e9}, Poisson{.33}; const Real lambda{Young*Poisson/((1+Poisson)*(1-2*Poisson))}; const Real mu{Young/(2*(1+Poisson))}; auto Material_hard = std::make_unique("hard", Young, Poisson); for (auto && pixel: *this) { Material_hard->add_pixel(pixel); } fix::add_material(std::move(Material_hard)); auto & F = fix::get_strain(); MatrixFieldMap F_map(F); for (auto grad: F_map) { grad = grad.Identity(); } auto res_tup{fix::evaluate_stress_tangent(F)}; MatrixFieldMap stress(std::get<0>(res_tup)); T4MatrixFieldMap tangent(std::get<1>(res_tup)); auto tup = testGoodies::objective_hooke_explicit (lambda, mu, Matrices::I2()); auto P_ref = std::get<0>(tup); for (auto mat: stress) { Real norm = (mat - P_ref).norm(); BOOST_CHECK_EQUAL(norm, 0.); } auto tan_ref = std::get<1>(tup); for (const auto tan: tangent) { Real norm = (tan - tan_ref).norm(); BOOST_CHECK_EQUAL(norm, 0.); } } BOOST_FIXTURE_TEST_CASE_TEMPLATE(evaluation_test, fix, fixlist, fix) { - auto & F = fix::get_strain(); - BOOST_CHECK_THROW(fix::evaluate_stress_tangent(F), std::runtime_error); constexpr Dim_t dim{fix::sdim}; using Mat_t = MaterialHyperElastic1; auto Material_hard = std::make_unique("hard", 210e9, .33); auto Material_soft = std::make_unique("soft", 70e9, .3); for (auto && cnt_pixel: akantu::enumerate(*this)) { auto counter = std::get<0>(cnt_pixel); auto && pixel = std::get<1>(cnt_pixel); if (counter < 5) { Material_hard->add_pixel(pixel); } else { Material_soft->add_pixel(pixel); } } fix::add_material(std::move(Material_hard)); fix::add_material(std::move(Material_soft)); + auto & F = fix::get_strain(); + fix::evaluate_stress_tangent(F); + fix::evaluate_stress_tangent(F); } BOOST_AUTO_TEST_SUITE_END(); } // muSpectre