diff --git a/python/cast.hh b/python/cast.hh index 05562597..2975a4d4 100644 --- a/python/cast.hh +++ b/python/cast.hh @@ -1,208 +1,208 @@ /** * @file * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @section LICENSE * * Copyright (©) 2017 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Tamaas 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Tamaas. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __CAST_HH__ #define __CAST_HH__ /* -------------------------------------------------------------------------- */ #include "grid_base.hh" #include "surface.hh" #include "numpy.hh" /* -------------------------------------------------------------------------- */ #include <pybind11/cast.h> #include <boost/preprocessor/seq.hpp> /* -------------------------------------------------------------------------- */ namespace pybind11 { // Format descriptor necessary for correct wrap of tamaas complex type template <typename T> struct format_descriptor< tamaas::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> { static constexpr const char c = format_descriptor<T>::c; static constexpr const char value[3] = {'Z', c, '\0'}; static std::string format() { return std::string(value); } }; #ifndef PYBIND11_CPP17 template <typename T> constexpr const char format_descriptor< tamaas::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>>::value[3]; #endif namespace detail { // declare tamaas complex as a complex type for pybind11 template <typename T> struct is_complex<tamaas::complex<T>> : std::true_type {}; template <typename T> struct is_fmt_numeric<tamaas::complex<T>, - detail::enable_if_t<std::is_floating_point<T>::value>> { - static constexpr bool value = true; + detail::enable_if_t<std::is_floating_point<T>::value>> + : std::true_type { static constexpr int index = is_fmt_numeric<T>::index + 3; }; /** * Type caster for grid classes * inspired by https://tinyurl.com/y8m47qh3 from T. De Geus * and pybind11/eigen.h */ template <template <typename, unsigned int> class G, typename T, unsigned int dim> struct type_caster<G<T, dim>> { using type = G<T, dim>; template <typename U> using array_type = array_t<U, array::c_style | array::forcecast>; public: PYBIND11_TYPE_CASTER(type, _("GridWrap<T, dim>")); /** * Conversion part 1 (Python->C++): convert a PyObject into a grid * instance or return false upon failure. The second argument * indicates whether implicit conversions should be applied. */ bool load(handle src, bool convert) { if (!convert && !array_type<typename type::value_type>::check_(src)) return false; auto buf = array_type<typename type::value_type>::ensure(src); value.move(tamaas::wrap::GridNumpy<G<T, dim>>(buf)); return true; } /** * Conversion part 2 (C++ -> Python): convert a grid instance into * a Python object. The second and third arguments are used to * indicate the return value policy and parent object (for * ``return_value_policy::reference_internal``) and are generally * ignored by implicit casters. * * TODO: do not ignore policy (see pybind11/eigen.h) */ static handle cast(const type& src, return_value_policy /* policy */, handle /*parent*/) { if (src.getNbComponents() == 1) { // none() passed as parent to get a correct nocopy auto a = array_type<typename type::value_type>( src.sizes(), src.getInternalData(), none()); return a.release(); } else { std::array<unsigned int, dim+1> sizes; std::copy_n(src.sizes().begin(), dim, sizes.begin()); sizes.back() = src.getNbComponents(); // none() passed as parent to get a correct nocopy auto a = array_type<typename type::value_type>( sizes, src.getInternalData(), none()); return a.release(); } } }; /** * Type caster for GridBase classes */ template <typename T> struct type_caster<tamaas::GridBase<T>> { using type = tamaas::GridBase<T>; template <typename U> using array_type = array_t<U, array::c_style | array::forcecast>; public: PYBIND11_TYPE_CASTER(type, _("GridBaseWrap<T>")); bool load(handle src, bool convert) { if (!convert && !array_type<T>::check_(src)) return false; auto buf = array_type<T>::ensure(src); value.move(tamaas::wrap::GridBaseNumpy<T>(buf)); return true; } static handle cast(const type& src, return_value_policy /* policy */, handle /*parent*/) { #define GRID_BASE_CASE(unused1, unused2, dim) \ case dim: { \ const tamaas::Grid<T, dim>& conv = static_cast<decltype(conv)>(src); \ if (src.getNbComponents() != 1) { \ std::array<unsigned int, dim + 1> sizes; \ std::copy_n(conv.sizes().begin(), dim, sizes.begin()); \ sizes.back() = src.getNbComponents(); \ return array_type<T>(sizes, src.getInternalData(), none()).release(); \ } else { \ return array_type<T>(conv.sizes(), src.getInternalData(), none()) \ .release(); \ } \ } switch (src.getDimension()) { BOOST_PP_SEQ_FOR_EACH(GRID_BASE_CASE, ~, (1)(2)(3)); default: return nullptr; } #undef GRID_BASE_CASE } }; /** * Type caster for surface class */ template <typename T> struct type_caster<tamaas::Surface<T>> { using type = tamaas::Surface<T>; template <typename U> using array_type = array_t<U, array::c_style | array::forcecast>; public: PYBIND11_TYPE_CASTER(type, _("SurfaceWrap<T, dim>")); bool load(handle src, bool convert) { if (!convert && !array_type<T>::check_(src)) return false; auto buf = array_type<T>::ensure(src); value.move(tamaas::wrap::SurfaceNumpy<type>(buf)); return true; } static handle cast(const type& src, return_value_policy /* policy */, handle /*parent*/) { auto a = array_type<T>(src.sizes(), src.getInternalData(), none()); return a.release(); } }; } // namespace detail } // namespace pybind11 #endif // __CAST_HH__ diff --git a/python/wrap/model.cpp b/python/wrap/model.cpp index 40890e58..a7269f4f 100644 --- a/python/wrap/model.cpp +++ b/python/wrap/model.cpp @@ -1,150 +1,147 @@ /** * @file * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @section LICENSE * * Copyright (©) 2017 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Tamaas 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Tamaas. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "wrap.hh" #include "model.hh" #include "model_factory.hh" #include "functional.hh" #include "adhesion_functional.hh" #include <pybind11/stl.h> /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ namespace functional { namespace wrap { /// Class for extension of Functional in python class PyFunctional : public Functional { public: using Functional::Functional; // Overriding pure virtual functions Real computeF(GridBase<Real>& variable, GridBase<Real>& dual) const override { PYBIND11_OVERLOAD_PURE(Real, Functional, computeF, variable, dual); } void computeGradF(GridBase<Real>& variable, GridBase<Real>& gradient) const override { PYBIND11_OVERLOAD_PURE(void, Functional, computeGradF, variable, gradient); } }; } } namespace wrap { using namespace py::literals; /// Wrap functional classes void wrapFunctionals(py::module& mod) { py::class_<functional::Functional, functional::wrap::PyFunctional> func( mod, "Functional"); - func.def(py::init<const BEEngine&>()) + func.def(py::init<>()) .def("computeF", &functional::Functional::computeF) .def("computeGradF", &functional::Functional::computeGradF); py::class_<functional::AdhesionFunctional> adh(mod, "AdhesionFunctional", func); adh.def_property("parameters", &functional::AdhesionFunctional::getParameters, &functional::AdhesionFunctional::setParameters) // legacy wrapper code .def("setParameters", &functional::AdhesionFunctional::setParameters); py::class_<functional::ExponentialAdhesionFunctional>( mod, "ExponentialAdhesionFunctional", adh) - .def(py::init<const BEEngine&, const GridBase<Real>&>(), "be_engine"_a, - "surface"_a); + .def(py::init<const GridBase<Real>&>(), "surface"_a); py::class_<functional::MaugisAdhesionFunctional>( mod, "MaugisAdhesionFunctional", adh) - .def(py::init<const BEEngine&, const GridBase<Real>&>(), "be_engine"_a, - "surface"_a); + .def(py::init<const GridBase<Real>&>(), "surface"_a); py::class_<functional::SquaredExponentialAdhesionFunctional>( mod, "SquaredExponentialAdhesionFunctional", adh) - .def(py::init<const BEEngine&, const GridBase<Real>&>(), "be_engine"_a, - "surface"_a); + .def(py::init<const GridBase<Real>&>(), "surface"_a); } /// Wrap BEEngine classes void wrapBEEngine(py::module& mod) { py::class_<BEEngine>(mod, "BEEngine") .def("solveNeumann", &BEEngine::solveNeumann) .def("solveDirichlet", &BEEngine::solveDirichlet) .def("getModel", &BEEngine::getModel, py::return_value_policy::reference); } /// Wrap Models void wrapModelClass(py::module& mod) { py::enum_<model_type>(mod, "model_type") .value("basic_1d", model_type::basic_1d) .value("basic_2d", model_type::basic_2d) .value("surface_1d", model_type::surface_1d) .value("surface_2d", model_type::surface_2d) .value("volume_1d", model_type::volume_1d) .value("volume_2d", model_type::volume_2d); py::class_<Model>(mod, "Model") .def("setElasticity", &Model::setElasticity, "E"_a, "nu"_a) .def_property("E", &Model::getYoungModulus, &Model::setYoungModulus) .def_property("nu", &Model::getPoissonRatio, &Model::setPoissonRatio) .def("getHertzModulus", &Model::getHertzModulus) .def("getYoungModulus", &Model::getYoungModulus) .def("getShearModulus", &Model::getShearModulus) .def("getPoissonRatio", &Model::getPoissonRatio) .def("getTraction", (GridBase<Real> & (Model::*)()) & Model::getTraction) .def("getDisplacement", (GridBase<Real> & (Model::*)()) & Model::getDisplacement) .def("getSystemSize", &Model::getSystemSize) .def("getDiscretization", &Model::getDiscretization) .def("solveNeumann", &Model::solveNeumann) .def("solveDirichlet", &Model::solveDirichlet) .def("getBEEngine", &Model::getBEEngine, py::return_value_policy::reference) .def("__repr__", [](const Model& m) { std::stringstream ss; ss << m; return ss.str(); }); } /// Wrap factor for models void wrapModelFactory(py::module& mod) { py::class_<ModelFactory>(mod, "ModelFactory") .def_static("createModel", &ModelFactory::createModel, "model_type"_a, "system_size"_a, "discretization"_a); } void wrapModel(py::module& mod) { wrapBEEngine(mod); wrapModelClass(mod); wrapModelFactory(mod); wrapFunctionals(mod); } } // namespace wrap __END_TAMAAS__ diff --git a/src/model/adhesion_functional.hh b/src/model/adhesion_functional.hh index 88cf66a4..7aad8d6b 100644 --- a/src/model/adhesion_functional.hh +++ b/src/model/adhesion_functional.hh @@ -1,110 +1,107 @@ /** * @file * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @section LICENSE * * Copyright (©) 2017 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Tamaas 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Tamaas. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __ADHESION_FUNCTIONAL_HH__ #define __ADHESION_FUNCTIONAL_HH__ /* -------------------------------------------------------------------------- */ #include "functional.hh" #include <map> /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ namespace functional { /// Functional class for adhesion energy class AdhesionFunctional : public Functional { protected: /// Constructor - AdhesionFunctional(const BEEngine& engine, const GridBase<Real>& surface) - : Functional(engine), surface() { + AdhesionFunctional(const GridBase<Real>& surface) + : Functional(), surface() { this->surface.wrap(surface); } public: /// Get parameters const std::map<std::string, Real>& getParameters() const { return parameters; } /// Set parameters void setParameters(std::map<std::string, Real> other) { parameters = other; } protected: GridBase<Real> surface; std::map<std::string, Real> parameters; }; /// Exponential adhesion functional class ExponentialAdhesionFunctional : public AdhesionFunctional { public: /// Explicit declaration of constructor for swig - ExponentialAdhesionFunctional(const BEEngine& engine, - const GridBase<Real>& surface) - : AdhesionFunctional(engine, surface) {} + ExponentialAdhesionFunctional(const GridBase<Real>& surface) + : AdhesionFunctional(surface) {} /// Compute the total adhesion energy Real computeF(GridBase<Real>& gap, GridBase<Real>& pressure) const override; /// Compute the gradient of the adhesion functional void computeGradF(GridBase<Real>& gap, GridBase<Real>& gradient) const override; }; /// Constant adhesion functional class MaugisAdhesionFunctional : public AdhesionFunctional { public: /// Explicit declaration of constructor for swig - MaugisAdhesionFunctional(const BEEngine& engine, - const GridBase<Real>& surface) - : AdhesionFunctional(engine, surface) {} + MaugisAdhesionFunctional(const GridBase<Real>& surface) + : AdhesionFunctional(surface) {} /// Compute the total adhesion energy Real computeF(GridBase<Real>& gap, GridBase<Real>& pressure) const override; /// Compute the gradient of the adhesion functional void computeGradF(GridBase<Real>& gap, GridBase<Real>& gradient) const override; }; /// Squared exponential adhesion functional class SquaredExponentialAdhesionFunctional : public AdhesionFunctional { public: /// Explicit declaration of constructor for swig - SquaredExponentialAdhesionFunctional(const BEEngine& engine, - const GridBase<Real>& surface) - : AdhesionFunctional(engine, surface) {} + SquaredExponentialAdhesionFunctional(const GridBase<Real>& surface) + : AdhesionFunctional(surface) {} /// Compute the total adhesion energy Real computeF(GridBase<Real>& gap, GridBase<Real>& pressure) const override; /// Compute the gradient of the adhesion functional void computeGradF(GridBase<Real>& gap, GridBase<Real>& gradient) const override; }; } // namespace functional __END_TAMAAS__ #endif // __ADHESION_FUNCTIONAL_HH__ diff --git a/src/model/elastic_functional.cpp b/src/model/elastic_functional.cpp index f79ab853..e88a4e34 100644 --- a/src/model/elastic_functional.cpp +++ b/src/model/elastic_functional.cpp @@ -1,77 +1,77 @@ /** * @file * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @section LICENSE * * Copyright (©) 2017 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Tamaas 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Tamaas. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "elastic_functional.hh" /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ namespace functional { Real ElasticFunctionalPressure::computeF(GridBase<Real>& pressure, GridBase<Real>& dual) const { // This doesn't work if dual is multi-component *buffer = dual; // this can get large unsigned long long n = dual.getNbPoints(); n *= n; return (0.5 * pressure.dot(*buffer) - pressure.dot(surface)) / n; } /* -------------------------------------------------------------------------- */ void ElasticFunctionalPressure::computeGradF(GridBase<Real>& pressure, GridBase<Real>& gradient) const { - this->engine.solveNeumann(pressure, *buffer); + this->op.apply(pressure, *buffer); // This doesn't work if dual is multi-component *buffer -= surface; gradient += *buffer; } /* -------------------------------------------------------------------------- */ Real ElasticFunctionalGap::computeF(GridBase<Real>& gap, GridBase<Real>& dual) const { // This doesn't work if dual is multi-component *buffer = gap; *buffer += surface; UInt n = dual.getNbPoints(); Real F = 0.5 * buffer->dot(dual); return F / n / n; // avoid integer overflow } /* -------------------------------------------------------------------------- */ void ElasticFunctionalGap::computeGradF(GridBase<Real>& gap, GridBase<Real>& gradient) const { *buffer = gap; *buffer += surface; // Now we have displacements - this->engine.solveDirichlet(*buffer, *buffer); + this->op.apply(*buffer, *buffer); gradient += *buffer; } } // namespace functional __END_TAMAAS__ diff --git a/src/model/elastic_functional.hh b/src/model/elastic_functional.hh index 42fc94b6..04484e3b 100644 --- a/src/model/elastic_functional.hh +++ b/src/model/elastic_functional.hh @@ -1,84 +1,84 @@ /** * @file * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @section LICENSE * * Copyright (©) 2017 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Tamaas 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Tamaas. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __ELASTIC_FUNCTIONAL_HH__ #define __ELASTIC_FUNCTIONAL_HH__ /* -------------------------------------------------------------------------- */ #include "functional.hh" #include "model.hh" #include "tamaas.hh" /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ namespace functional { /// Generic functional for elastic energy class ElasticFunctional : public Functional { public: - ElasticFunctional(BEEngine& engine, const GridBase<Real>& surface) - : Functional(engine), surface(surface) { - const Model& model = engine.getModel(); - buffer = - allocateGrid<true, Real>(model.getType(), model.getDiscretization(), - model.getTraction().getNbComponents()); + ElasticFunctional(const IntegralOperator& op, const GridBase<Real>& surface) + : Functional(), op(op), surface(surface) { + const Model& model = op.getModel(); + buffer = allocateGrid<true, Real>(op.getType(), + model.getBoundaryDiscretization()); } protected: + const IntegralOperator& op; const GridBase<Real>& surface; std::unique_ptr<GridBase<Real>> mutable buffer; }; /* -------------------------------------------------------------------------- */ /// Functional with pressure as primal field class ElasticFunctionalPressure : public ElasticFunctional { public: using ElasticFunctional::ElasticFunctional; /// Compute functional with input pressure Real computeF(GridBase<Real>& pressure, GridBase<Real>& dual) const override; /// Compute functional gradient with input pressure void computeGradF(GridBase<Real>& pressure, GridBase<Real>& gradient) const override; }; /* -------------------------------------------------------------------------- */ /// Functional with gap as primal field class ElasticFunctionalGap : public ElasticFunctional { public: using ElasticFunctional::ElasticFunctional; /// Compute functional with input gap Real computeF(GridBase<Real>& gap, GridBase<Real>& dual) const override; /// Compute functional gradient with input gap void computeGradF(GridBase<Real>& gap, GridBase<Real>& gradient) const override; }; } // namespace functional __END_TAMAAS__ /* -------------------------------------------------------------------------- */ #endif // __ELASTIC_FUNCTIONAL_HH__ diff --git a/src/model/functional.hh b/src/model/functional.hh index 0b48d1ef..0250689b 100644 --- a/src/model/functional.hh +++ b/src/model/functional.hh @@ -1,61 +1,56 @@ /** * @file * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @section LICENSE * * Copyright (©) 2017 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Tamaas 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Tamaas. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __FUNCTIONAL_HH__ #define __FUNCTIONAL_HH__ /* -------------------------------------------------------------------------- */ #include "be_engine.hh" #include "tamaas.hh" /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ namespace functional { /// Generic functional class for the cost function of the optimization problem class Functional { public: - /// Constructor - explicit Functional(const BEEngine& engine) : engine(engine) {} /// Destructor virtual ~Functional() = default; public: /// Compute functional virtual Real computeF(GridBase<Real>& variable, GridBase<Real>& dual) const = 0; /// Compute functional gradient virtual void computeGradF(GridBase<Real>& variable, GridBase<Real>& gradient) const = 0; - -protected: - const BEEngine& engine; }; } // namespace functional __END_TAMAAS__ /* -------------------------------------------------------------------------- */ #endif // ___FUNCTIONAL_HH__ diff --git a/src/model/integral_operator.hh b/src/model/integral_operator.hh index 4a2a9c95..b872d88f 100644 --- a/src/model/integral_operator.hh +++ b/src/model/integral_operator.hh @@ -1,91 +1,98 @@ /** * @file * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @section LICENSE * * Copyright (©) 2017 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Tamaas 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Tamaas. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef INTEGRAL_OPERATOR_HH #define INTEGRAL_OPERATOR_HH /* -------------------------------------------------------------------------- */ #include "grid_base.hh" +#include "model_type.hh" #include <boost/preprocessor/seq.hpp> #include <boost/preprocessor/cat.hpp> #include <boost/preprocessor/stringize.hpp> /* -------------------------------------------------------------------------- */ namespace tamaas { /* -------------------------------------------------------------------------- */ class Model; /** * @brief Generic class for integral operators */ class IntegralOperator { public: /// Kind of operator enum kind { neumann, dirichlet }; public: /// Constructor IntegralOperator(Model* model) : model(model) {} /// Virtual destructor for subclasses virtual ~IntegralOperator() = default; /// Apply operator on input virtual void apply(GridBase<Real>& input, GridBase<Real>& output) const = 0; /// Update any data dependent on model parameters virtual void updateFromModel() = 0; /// Get model const Model& getModel() const { return *model; } + /// Kind + virtual kind getKind() const = 0; + + /// Type + virtual model_type getType() const = 0; + protected: Model* model = nullptr; }; /* -------------------------------------------------------------------------- */ /* Printing IntegralOperator::kind to string */ /* -------------------------------------------------------------------------- */ #define INTEGRAL_KINDS (neumann)(dirichlet) inline std::ostream& operator<<(std::ostream& o, const IntegralOperator::kind& val) { switch (val) { #define PRINT_INTEGRAL_KIND(r, data, kind) \ case data::kind: \ o << BOOST_PP_STRINGIZE(kind); \ break; BOOST_PP_SEQ_FOR_EACH(PRINT_INTEGRAL_KIND, IntegralOperator, INTEGRAL_KINDS); #undef PRINT_INTEGRAL_KIND } return o; } #undef INTEGRAL_KINDS /* -------------------------------------------------------------------------- */ } // namespace tamaas #endif // INTEGRAL_OPERATOR_HH diff --git a/src/model/meta_functional.hh b/src/model/meta_functional.hh index 65dd5aad..57543457 100644 --- a/src/model/meta_functional.hh +++ b/src/model/meta_functional.hh @@ -1,70 +1,68 @@ /** * @file * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @section LICENSE * * Copyright (©) 2017 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Tamaas 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Tamaas. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __META_FUNCTIONAL_HH__ #define __META_FUNCTIONAL_HH__ #include "functional.hh" #include "tamaas.hh" #include <list> #include <memory> __BEGIN_TAMAAS__ namespace functional { /// Meta functional that contains list of functionals class MetaFunctional : public Functional { using FunctionalList = std::list<std::pair<Functional*, bool>>; public: - using Functional::Functional; - ~MetaFunctional() override; public: /// Compute functional Real computeF(GridBase<Real>& variable, GridBase<Real>& dual) const override; /// Compute functional gradient void computeGradF(GridBase<Real>& variable, GridBase<Real>& gradient) const override; /// Add functional to the list void addFunctionalTerm(Functional* term, bool own); /// Add functional to the list void addFunctionalTerm(std::pair<Functional*, bool> element); protected: FunctionalList functionals; }; } // namespace functional __END_TAMAAS__ #endif // __META_FUNCTIONAL_HH__ diff --git a/src/model/model.hh b/src/model/model.hh index 9abfcb36..b9e8db4c 100644 --- a/src/model/model.hh +++ b/src/model/model.hh @@ -1,135 +1,135 @@ /** * @file * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @section LICENSE * * Copyright (©) 2017 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Tamaas 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Tamaas. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef MODEL_HH #define MODEL_HH /* -------------------------------------------------------------------------- */ #include "grid_base.hh" #include "model_type.hh" #include "integral_operator.hh" #include "be_engine.hh" #include "tamaas.hh" #include <map> #include <memory> #include <vector> #include <algorithm> /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ /** * @brief Model containing pressure and displacement * This class is a container for the model fields. It is supposed to be * dimension agnostic, hence the GridBase members. */ class Model { protected: /// Constructor Model(const std::vector<Real>& system_size, const std::vector<UInt>& discretization); public: /// Destructor virtual ~Model(); public: /// Set elasticity parameters void setElasticity(Real E, Real nu); /// Get Hertz contact modulus Real getHertzModulus() const; /// Get Young's modulus Real getYoungModulus() const { return E; } /// Get Poisson's ratio Real getPoissonRatio() const { return nu; } /// Get shear modulus Real getShearModulus() const { return E / (2 * (1 + nu)); } /// Set Young's modulus void setYoungModulus(Real E_) { this->E = E_; } /// Set Poisson's ratio void setPoissonRatio(Real nu_) { this->nu = nu_; } public: /// Get pressure GridBase<Real>& getTraction(); /// Get pressure const GridBase<Real>& getTraction() const; /// Get displacement GridBase<Real>& getDisplacement(); /// Get displacement const GridBase<Real>& getDisplacement() const; - /// Get displacement on boundary - virtual GridBase<Real>& getBoundaryDisplacement() = 0; /// Get model type virtual ::tamaas::model_type getType() const = 0; /// Get system physical size const std::vector<Real>& getSystemSize() const; /// Get discretization const std::vector<UInt>& getDiscretization() const; + /// Get boundary discretization + virtual std::vector<UInt> getBoundaryDiscretization() const = 0; /// Get boundary element engine BEEngine& getBEEngine() { TAMAAS_ASSERT(engine, "BEEngine was not initialized"); return *engine; } /// Solve Neumann problem using default neumann operator void solveNeumann(); /// Solve Dirichlet problem using default dirichlet operator void solveDirichlet(); public: /// Register a new integral operator template <typename Operator> std::shared_ptr<IntegralOperator> registerIntegralOperator(const std::string& name) { operators[name] = std::make_shared<Operator>(this); return operators[name]; } /// Get a registerd integral operator std::shared_ptr<IntegralOperator> getIntegralOperator(const std::string& name); /// Tell operators to update their cache void updateOperators(); protected: Real E = 1, nu = 0; std::vector<Real> system_size; std::vector<UInt> discretization; std::unique_ptr<GridBase<Real>> traction = nullptr; std::unique_ptr<GridBase<Real>> displacement = nullptr; std::unique_ptr<BEEngine> engine = nullptr; std::map<std::string, std::shared_ptr<IntegralOperator>> operators; }; /* -------------------------------------------------------------------------- */ /* Output model to stream */ /* -------------------------------------------------------------------------- */ std::ostream& operator<<(std::ostream& o, const Model& _this); __END_TAMAAS__ #endif // MODEL_HH diff --git a/src/model/model_factory.cpp b/src/model/model_factory.cpp index b85dd5b0..a6702d8e 100644 --- a/src/model/model_factory.cpp +++ b/src/model/model_factory.cpp @@ -1,58 +1,56 @@ /** * @file * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @section LICENSE * * Copyright (©) 2017 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Tamaas 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Tamaas. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "model_factory.hh" #include "model_template.hh" #include <boost/preprocessor/seq.hpp> /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ #define MODEL_TYPE_CASE_MACRO(truc, unused, type) \ case type: { \ model = new ModelTemplate<type>(system_size, discretization); \ break; \ } -#define IMPLEMENTED_MODEL_TYPES \ - (model_type::basic_2d)(model_type::basic_1d)(model_type::volume_2d)( \ - model_type::surface_2d) +#define IMPLEMENTED_MODEL_TYPES TAMAAS_MODEL_TYPES Model* ModelFactory::createModel(model_type type, const std::vector<Real>& system_size, const std::vector<UInt>& discretization) { Model* model = nullptr; switch (type) { BOOST_PP_SEQ_FOR_EACH(MODEL_TYPE_CASE_MACRO, ~, IMPLEMENTED_MODEL_TYPES); default: TAMAAS_EXCEPTION("Model type not implemented"); } return model; } __END_TAMAAS__ diff --git a/src/model/model_template.cpp b/src/model/model_template.cpp index d4de8079..b6d40728 100644 --- a/src/model/model_template.cpp +++ b/src/model/model_template.cpp @@ -1,85 +1,99 @@ /** * @file * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @section LICENSE * * Copyright (©) 2016-2017 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Tamaas 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Tamaas. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "model_template.hh" #include "westergaard.hh" /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ /* -------------------------------------------------------------------------- */ template <model_type type> ModelTemplate<type>::ModelTemplate(const std::vector<Real>& system_size, const std::vector<UInt>& discretization) : Model(system_size, discretization) { constexpr UInt dim = trait::dimension; constexpr UInt dim_b = trait::boundary_dimension; constexpr UInt nb_components = trait::components; if (system_size.size() != dim) TAMAAS_EXCEPTION("System size does not match model type"); if (discretization.size() != dim) TAMAAS_EXCEPTION("Discretization size does not match model type"); // Copying sizes for traction grid std::array<UInt, dim_b> traction_size; auto disc_it = discretization.begin(); if (dim > dim_b) ++disc_it; std::copy(disc_it, discretization.end(), traction_size.begin()); // Allocating traction = std::make_unique<Grid<Real, dim_b>>(traction_size, nb_components); displacement = std::make_unique<Grid<Real, dim>>(discretization, nb_components); - boundary_displacement = - std::make_unique<ViewType>(*displacement, trait::indices); this->initializeBEEngine(); } /* -------------------------------------------------------------------------- */ template <model_type type> void ModelTemplate<type>::initializeBEEngine() { engine = std::make_unique<BEEngineTmpl<type>>(this); } -/* -------------------------------------------------------------------------- */ - template <model_type type> -GridBase<Real>& ModelTemplate<type>::getBoundaryDisplacement() { - return *boundary_displacement; +std::vector<UInt> ModelTemplate<type>::getBoundaryDiscretization() const { + return getDiscretization(); +} + +template <> +std::vector<UInt> +ModelTemplate<model_type::volume_1d>::getBoundaryDiscretization() const { + auto begin = getDiscretization().begin() + 1, end = getDiscretization().end(); + std::vector<UInt> size(getDiscretization().size() - 1); + std::copy(begin, end, size.begin()); + return size; +} + +template <> +std::vector<UInt> +ModelTemplate<model_type::volume_2d>::getBoundaryDiscretization() const { + auto begin = getDiscretization().begin() + 1, end = getDiscretization().end(); + std::vector<UInt> size(getDiscretization().size() - 1); + std::copy(begin, end, size.begin()); + return size; } /* -------------------------------------------------------------------------- */ /* Template instanciation */ /* -------------------------------------------------------------------------- */ template class ModelTemplate<model_type::basic_1d>; template class ModelTemplate<model_type::basic_2d>; template class ModelTemplate<model_type::surface_1d>; template class ModelTemplate<model_type::surface_2d>; template class ModelTemplate<model_type::volume_1d>; template class ModelTemplate<model_type::volume_2d>; __END_TAMAAS__ diff --git a/src/model/model_template.hh b/src/model/model_template.hh index bf59eb47..51fcfbbf 100644 --- a/src/model/model_template.hh +++ b/src/model/model_template.hh @@ -1,64 +1,65 @@ /** * @file * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @section LICENSE * * Copyright (©) 2016-2017 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Tamaas 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Tamaas. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __MODEL_TEMPLATE_HH__ #define __MODEL_TEMPLATE_HH__ /* -------------------------------------------------------------------------- */ #include "grid_view.hh" #include "model.hh" #include "model_type.hh" /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ /** * @brief Model class templated with model type * Specializations of this class should take care of dimension specific code */ template <model_type type> class ModelTemplate : public Model { using trait = model_type_traits<type>; using ViewType = GridView<Grid, Real, trait::dimension, trait::boundary_dimension>; public: /// Constructor ModelTemplate(const std::vector<Real>& system_size, const std::vector<UInt>& discretization); - GridBase<Real>& getBoundaryDisplacement() override; - // Get model type model_type getType() const override { return type; } + std::vector<UInt> getBoundaryDiscretization() const override; + protected: virtual void initializeBEEngine(); protected: - std::unique_ptr<ViewType> boundary_displacement = nullptr; + std::unique_ptr<ViewType> displacement_view = nullptr; + std::unique_ptr<ViewType> traction_view = nullptr; }; __END_TAMAAS__ /* -------------------------------------------------------------------------- */ #endif // __MODEL_TEMPLATE_HH__ diff --git a/src/model/model_type.hh b/src/model/model_type.hh index 50fc3685..23aff783 100644 --- a/src/model/model_type.hh +++ b/src/model/model_type.hh @@ -1,122 +1,140 @@ /** * @file * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @section LICENSE * * Copyright (©) 2016-2017 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Tamaas 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Tamaas. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __MODEL_TYPE_HH__ #define __MODEL_TYPE_HH__ /* -------------------------------------------------------------------------- */ #include "grid.hh" #include "grid_base.hh" #include "tamaas.hh" #include <boost/preprocessor/seq.hpp> #include <boost/preprocessor/cat.hpp> #include <boost/preprocessor/stringize.hpp> #include <memory> +#include <algorithm> /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ // clang-format off +/// Models types **for printing only** #define TAMAAS_MODEL_TYPES \ (basic_1d) \ (basic_2d) \ (surface_1d) \ (surface_2d) \ (volume_1d) \ (volume_2d) // clang-format on /// Types for grid dimensions and number of components enum class model_type { basic_1d, ///< one component line basic_2d, ///< one component surface surface_1d, ///< two components line surface_2d, ///< three components surface volume_1d, ///< two components volume volume_2d ///< three components volume }; inline std::ostream& operator<<(std::ostream& o, const model_type& val) { switch (val) { #define PRINT_MODEL_TYPE(r, data, type) \ case data::type: \ o << BOOST_PP_STRINGIZE(type); \ break; BOOST_PP_SEQ_FOR_EACH(PRINT_MODEL_TYPE, model_type, TAMAAS_MODEL_TYPES); #undef PRINT_MODEL_TYPE } return o; } /// Trait class to store physical dimension of domain, of boundary and /// number of components template <model_type type> struct model_type_traits {}; #define MODEL_TYPE_TRAITS_MACRO(type, dim, comp, bdim) \ template <> \ struct model_type_traits<model_type::type> { \ static constexpr UInt dimension = dim; \ static constexpr UInt components = comp; \ static constexpr UInt boundary_dimension = bdim; \ static std::vector<UInt> indices; \ } MODEL_TYPE_TRAITS_MACRO(basic_1d, 1, 1, 1); MODEL_TYPE_TRAITS_MACRO(basic_2d, 2, 1, 2); MODEL_TYPE_TRAITS_MACRO(surface_1d, 1, 2, 1); MODEL_TYPE_TRAITS_MACRO(surface_2d, 2, 3, 2); MODEL_TYPE_TRAITS_MACRO(volume_1d, 2, 2, 1); MODEL_TYPE_TRAITS_MACRO(volume_2d, 3, 3, 2); #undef MODEL_TYPE_TRAITS_MACRO #define ALLOC_GRID_CASE_MACRO(a, data, type) \ case data::type: { \ - constexpr UInt dim = \ - (boundary) ? model_type_traits<data::type>::boundary_dimension \ - : model_type_traits<data::type>::dimension; \ - ptr = new Grid<T, dim>(n, nc); \ + constexpr UInt bdim = model_type_traits<data::type>::boundary_dimension; \ + constexpr UInt dim = model_type_traits<data::type>::dimension; \ + ptr = new Grid < T, \ + (boundary) ? bdim \ + : dim > (std::begin(n), std::end(n), \ + model_type_traits<data::type>::components); \ break; \ } /// Helper function for grid allocation -template <bool boundary, typename T> +template <bool boundary, typename T, typename Container> std::unique_ptr<GridBase<T>> allocateGrid(model_type type, - const std::vector<UInt> n, UInt nc) { + Container&& n) { GridBase<T>* ptr = nullptr; + switch (type) { BOOST_PP_SEQ_FOR_EACH(ALLOC_GRID_CASE_MACRO, model_type, TAMAAS_MODEL_TYPES); } return std::unique_ptr<GridBase<T>>{ptr}; } #undef ALLOC_GRID_CASE_MACRO +// clang-format off +#ifdef TAMAAS_MODEL_TYPES +#undef TAMAAS_MODEL_TYPES +#endif +#define TAMAAS_MODEL_TYPES \ + (model_type::basic_1d) \ + (model_type::basic_2d) \ + (model_type::surface_1d) \ + (model_type::surface_2d) \ + (model_type::volume_1d) \ + (model_type::volume_2d) +// clang-format on + __END_TAMAAS__ /* -------------------------------------------------------------------------- */ #endif // __MODEL_TYPE_HH__ diff --git a/src/model/volume_potential.hh b/src/model/volume_potential.hh index a1f0c4ee..6c72af0b 100644 --- a/src/model/volume_potential.hh +++ b/src/model/volume_potential.hh @@ -1,97 +1,105 @@ /** * @file * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @section LICENSE * * Copyright (©) 2017 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Tamaas 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Tamaas. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef VOLUME_POTENTIAL_HH #define VOLUME_POTENTIAL_HH /* -------------------------------------------------------------------------- */ #include "integral_operator.hh" #include "model_type.hh" #include "grid_view.hh" #include "grid_hermitian.hh" #include "fft_plan_manager.hh" /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ /** * @brief Volume potential operator class. Applies the operators for computation * of displacements and strains due to residual/eigen strains */ template <model_type type> class VolumePotential : public IntegralOperator { using trait = model_type_traits<type>; public: VolumePotential(Model * model); /// Update from model (does nothing) void updateFromModel() override {} + /// Kind + IntegralOperator::kind getKind() const override { + return IntegralOperator::neumann; + } + + /// Type + model_type getType() const override { return this->model->getType(); } + protected: /// Function to handle layer-by-layer Fourier treatment of operators template <typename Func> void fourierApply(Func func, GridBase<Real>& in, GridBase<Real>& out) const; protected: Grid<Real, trait::boundary_dimension> wavevectors; using BufferType = GridHermitian<Real, trait::boundary_dimension>; mutable std::vector<BufferType> source_buffers; mutable BufferType disp_buffer; }; /* -------------------------------------------------------------------------- */ /* Template implementation */ /* -------------------------------------------------------------------------- */ template <model_type type> template <typename Func> void VolumePotential<type>::fourierApply(Func func, GridBase<Real>& in, GridBase<Real>& out) const { constexpr UInt dim = trait::dimension; Grid<Real, dim>& i = dynamic_cast<decltype(i)>(in); Grid<Real, dim>& o = dynamic_cast<decltype(o)>(out); // TAMAAS_ASSERT(i.sizes().front() == o.sizes().front(), // "Number of layers does not match"); // ^^^^ not applicable for Boussinesq for (UInt layer : Loop::range(i.sizes().front())) { auto in_layer = make_view(i, layer); FFTPlanManager::get() .createPlan(in_layer, source_buffers[layer]) .forwardTransform(); } for (UInt layer : Loop::range(o.sizes().front())) { func(layer, source_buffers, disp_buffer); auto out_layer = make_view(o, layer); FFTPlanManager::get() .createPlan(out_layer, disp_buffer) .backwardTransform(); } } __END_TAMAAS__ #endif // VOLUME_POTENTIAL_HH diff --git a/src/model/westergaard.cpp b/src/model/westergaard.cpp index 8d58549e..7e2fd877 100644 --- a/src/model/westergaard.cpp +++ b/src/model/westergaard.cpp @@ -1,215 +1,209 @@ /** * @file * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @section LICENSE * * Copyright (©) 2017 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Tamaas 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Tamaas. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "fft_plan_manager.hh" #include "influence.hh" #include "loop.hh" #include "model.hh" #include "grid_view.hh" #include "static_types.hh" #include "westergaard.hh" /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ /* -------------------------------------------------------------------------- */ template <model_type mtype, IntegralOperator::kind otype> Westergaard<mtype, otype>::Westergaard(Model* model) : IntegralOperator(model) { // Copy sizes - std::array<UInt, trait::dimension> sizes; - std::copy(model->getDiscretization().begin(), - model->getDiscretization().end(), sizes.begin()); + std::array<UInt, trait::boundary_dimension> sizes; + auto bdisc = model->getBoundaryDiscretization(); - // Copy boundary sizes - auto sizes_it = sizes.begin(); - std::array<UInt, trait::boundary_dimension> boundary_hermitian_sizes; // Ignoring first dimension if model is volumetric - if (trait::dimension > trait::boundary_dimension) - ++sizes_it; - std::copy(sizes_it, sizes.end(), boundary_hermitian_sizes.begin()); - boundary_hermitian_sizes = + std::copy(bdisc.begin(), + bdisc.end(), sizes.begin()); + + auto boundary_hermitian_sizes = GridHermitian<Real, trait::boundary_dimension>::hermitianDimensions( - boundary_hermitian_sizes); + sizes); constexpr UInt nb_components = trait::components; buffer.setNbComponents(nb_components); buffer.resize(boundary_hermitian_sizes); influence.setNbComponents(nb_components * nb_components); influence.resize(boundary_hermitian_sizes); initInfluence(); } /* -------------------------------------------------------------------------- */ template <model_type mtype, IntegralOperator::kind otype> template <typename Functor> void Westergaard<mtype, otype>::fourierApply(Functor func, GridBase<Real>& in, GridBase<Real>& out) const try { Grid<Real, bdim>& i = dynamic_cast<decltype(i)>(in); Grid<Real, dim>& full_out = dynamic_cast<decltype(full_out)>(out); FFTPlanManager::get().createPlan(i, buffer).forwardTransform(); /// Applying influence func(buffer, influence); /// Backward fourier transform on boundary only if constexpr (bdim == dim) FFTPlanManager::get().createPlan(full_out, buffer).backwardTransform(); else { auto view = make_view(full_out, 0); FFTPlanManager::get() .createPlan(view, buffer) .backwardTransform(); } } catch (const std::bad_cast& e) { TAMAAS_EXCEPTION("Neumann and dirichlet types do not match model type"); } /* -------------------------------------------------------------------------- */ template <model_type mtype, IntegralOperator::kind otype> template <typename Functor> void Westergaard<mtype, otype>::initFromFunctor(Functor func) { // Compute wavevectors for influence auto wavevectors = FFTransform<Real, bdim>::template computeFrequencies<true>( influence.sizes()); // Get boundary physical size VectorProxy<const Real, bdim> domain( this->model->getSystemSize()[(bdim == dim) ? 0 : 1]); // Normalize wavevectors wavevectors *= 2 * M_PI; wavevectors /= domain; // Apply functor Loop::stridedLoop(func, wavevectors, influence); // Set fundamental mode to zero MatrixProxy<Complex, trait::components, trait::components> mat(influence(0)); mat = 0; } /* -------------------------------------------------------------------------- */ #define NEUMANN_BASIC(type) \ template <> \ void Westergaard<type, IntegralOperator::neumann>::initInfluence() { \ auto E_star = model->getHertzModulus(); \ auto basic = [E_star] CUDA_LAMBDA(VectorProxy<Real, bdim> && q, \ Complex & k) { \ k = 2. / (E_star * q.l2norm()); \ }; \ initFromFunctor(basic); \ } #define DIRICHLET_BASIC(type) \ template <> \ void Westergaard<type, IntegralOperator::dirichlet>::initInfluence() { \ auto E_star = model->getHertzModulus(); \ auto basic = [E_star] CUDA_LAMBDA(VectorProxy<Real, bdim> && q, \ Complex & k) { \ k = E_star * q.l2norm() / 2; \ }; \ initFromFunctor(basic); \ } NEUMANN_BASIC(model_type::basic_1d); NEUMANN_BASIC(model_type::basic_2d); DIRICHLET_BASIC(model_type::basic_1d); DIRICHLET_BASIC(model_type::basic_2d); #undef NEUMANN_BASIC #undef DIRICHLET_BASIC /* -------------------------------------------------------------------------- */ template <> void Westergaard<model_type::surface_2d, IntegralOperator::neumann>::initInfluence() { auto E = model->getYoungModulus(); auto nu = model->getPoissonRatio(); const Complex I(0, 1); auto surface = [E, nu, I] CUDA_LAMBDA(VectorProxy<Real, bdim> && q, MatrixProxy<Complex, comp, comp>&& F) { Real q_norm = q.l2norm(); q /= q_norm; F(0, 0) = 2 * (1 + nu) * (1 - nu * q(0) * q(0)); F(1, 1) = 2 * (1 + nu) * (1 - nu * q(1) * q(1)); F(2, 2) = 2 * (1 - nu * nu); F(0, 1) = F(1, 0) = -q(0) * q(1) * 2 * nu * (1 + nu); F(0, 2) = I * q(0) * (1 + nu) * (1. - 2. * nu); F(1, 2) = I * q(1) * (1 + nu) * (1 - 2 * nu); F(2, 0) = -F(0, 2); F(2, 1) = -F(1, 2); F *= 1. / (E * q_norm); }; initFromFunctor(surface); } /* -------------------------------------------------------------------------- */ template <model_type mtype, IntegralOperator::kind otype> -void Westergaard<mtype, otype>::initInfluence() { - TAMAAS_EXCEPTION("the requested operator has not been implemented"); -} +void Westergaard<mtype, otype>::initInfluence() {} /* ------------------------------------------------------------------------ */ template <model_type mtype, IntegralOperator::kind otype> void Westergaard<mtype, otype>::apply(GridBase<Real>& input, GridBase<Real>& output) const { auto apply = [](decltype(buffer)& buffer, const decltype(influence)& influence) { Loop::stridedLoop([] CUDA_LAMBDA(VectorProxy<Complex, comp> && i, MatrixProxy<const Complex, comp, comp> && F) { i = F * i; }, buffer, influence); }; fourierApply(apply, input, output); } /* -------------------------------------------------------------------------- */ /* Template instanciation */ /* -------------------------------------------------------------------------- */ template class Westergaard<model_type::basic_1d, IntegralOperator::neumann>; template class Westergaard<model_type::basic_2d, IntegralOperator::neumann>; template class Westergaard<model_type::basic_1d, IntegralOperator::dirichlet>; template class Westergaard<model_type::basic_2d, IntegralOperator::dirichlet>; template class Westergaard<model_type::surface_1d, IntegralOperator::neumann>; template class Westergaard<model_type::surface_2d, IntegralOperator::neumann>; template class Westergaard<model_type::surface_1d, IntegralOperator::dirichlet>; template class Westergaard<model_type::surface_2d, IntegralOperator::dirichlet>; template class Westergaard<model_type::volume_1d, IntegralOperator::neumann>; template class Westergaard<model_type::volume_2d, IntegralOperator::neumann>; template class Westergaard<model_type::volume_1d, IntegralOperator::dirichlet>; template class Westergaard<model_type::volume_2d, IntegralOperator::dirichlet>; /* -------------------------------------------------------------------------- */ __END_TAMAAS__ /* -------------------------------------------------------------------------- */ diff --git a/src/model/westergaard.hh b/src/model/westergaard.hh index acd2f85c..2272861b 100644 --- a/src/model/westergaard.hh +++ b/src/model/westergaard.hh @@ -1,87 +1,93 @@ /** * @file * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @section LICENSE * * Copyright (©) 2017 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Tamaas 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Tamaas. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __WESTERGAARD_HH__ #define __WESTERGAARD_HH__ /* -------------------------------------------------------------------------- */ #include "be_engine.hh" #include "fft_plan_manager.hh" #include "grid_hermitian.hh" #include "integral_operator.hh" #include "model_type.hh" #include "tamaas.hh" /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ /** * @brief Operator based on Westergaard solution and the Dicrete Fourier * Transform. * This class is templated with model type to allow efficient storage of the * influence coefficients. * The integral operator is only applied to surface pressure/displacements, * even for volume models. */ template <model_type mtype, IntegralOperator::kind otype> class Westergaard : public IntegralOperator { using trait = model_type_traits<mtype>; static constexpr UInt dim = trait::dimension; static constexpr UInt bdim = trait::boundary_dimension; static constexpr UInt comp = trait::components; public: /// Constuctor: initalizes influence coefficients and allocates buffer Westergaard(Model* model); /// Get influence coefficients const GridHermitian<Real, bdim>& getInfluence() const { return influence; } /// Apply influence coefficients to input void apply(GridBase<Real>& input, GridBase<Real>& ouput) const override; /// Update the influence coefficients void updateFromModel() override { initInfluence(); } + /// Kind + IntegralOperator::kind getKind() const override { return otype; } + + /// Type + model_type getType() const override { return mtype; } + private: /// Initialize influence coefficients void initInfluence(); template <typename Functor> void initFromFunctor(Functor func); /// Apply a functor in Fourier space template <typename Functor> void fourierApply(Functor func, GridBase<Real>& in, GridBase<Real>& out) const; public: GridHermitian<Real, bdim> influence; mutable GridHermitian<Real, bdim> buffer; }; __END_TAMAAS__ #endif // __WESTERGAARD_HH__ diff --git a/src/solvers/contact_solver.cpp b/src/solvers/contact_solver.cpp index d2d313c0..40c77c5e 100644 --- a/src/solvers/contact_solver.cpp +++ b/src/solvers/contact_solver.cpp @@ -1,67 +1,67 @@ /** * @file * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @section LICENSE * * Copyright (©) 2016-2017 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Tamaas 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Tamaas. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "contact_solver.hh" #include "fft_plan_manager.hh" #include <iomanip> #include <iostream> /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ ContactSolver::ContactSolver(Model& model, const GridBase<Real>& surface, Real tolerance) - : model(model), surface(), functional(model.getBEEngine()), + : model(model), surface(), functional(), tolerance(tolerance), surface_stddev(std::sqrt(surface.var())) { this->surface.wrap(surface); - _gap = allocateGrid<true, Real>(model.getType(), model.getDiscretization(), - model.getTraction().getNbComponents()); + _gap = allocateGrid<true, Real>(model.getType(), + model.getBoundaryDiscretization()); } /* -------------------------------------------------------------------------- */ ContactSolver::~ContactSolver() { FFTPlanManager::get().clean(); /// TODO find a smarter way to clean up } /* -------------------------------------------------------------------------- */ void ContactSolver::printState(UInt iter, Real cost_f, Real error) { // UInt precision = std::cout.precision(); if (iter % dump_frequency) return; std::cout << std::setw(5) << iter << " "; std::cout << std::setw(15) << std::scientific << cost_f << " "; std::cout << std::setw(15) << error << std::endl; std::cout << std::fixed; } /* -------------------------------------------------------------------------- */ void ContactSolver::addFunctionalTerm(functional::Functional* func) { functional.addFunctionalTerm(func, false); } __END_TAMAAS__ /* -------------------------------------------------------------------------- */ diff --git a/src/solvers/polonsky_keer_rey.cpp b/src/solvers/polonsky_keer_rey.cpp index 77a9216d..9c773293 100644 --- a/src/solvers/polonsky_keer_rey.cpp +++ b/src/solvers/polonsky_keer_rey.cpp @@ -1,295 +1,289 @@ /** * @file * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @section LICENSE * * Copyright (©) 2016-2017 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Tamaas 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Tamaas. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "polonsky_keer_rey.hh" #include "elastic_functional.hh" #include "fft_plan_manager.hh" #include "loop.hh" #include "model_type.hh" +#include <boost/preprocessor/seq.hpp> #include <iomanip> #include <iterator> /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ PolonskyKeerRey::PolonskyKeerRey(Model& model, const GridBase<Real>& surface, Real tolerance, type variable_type, type constraint_type) : ContactSolver(model, surface, tolerance), variable_type(variable_type), constraint_type(constraint_type) { - if (model.getType() != model_type::basic_1d && - model.getType() != model_type::basic_2d) { - TAMAAS_EXCEPTION( - "Model type is not compatible with PolonskyKeerRey solver"); + +#define SET_VIEWS(_, __, type) \ + case type: { \ + setViews<type>(); \ + break; \ + } + + switch (model.getType()) { + BOOST_PP_SEQ_FOR_EACH(SET_VIEWS, ~, TAMAAS_MODEL_TYPES); } - auto pressure_ = &model.getTraction(); +#undef SET_VIEWS + + search_direction = allocateGrid<true, Real>( + operation_type, model.getBoundaryDiscretization()); + + projected_search_direction = allocateGrid<true, Real>( + operation_type, model.getBoundaryDiscretization()); switch (variable_type) { case gap: { model.getBEEngine().registerDirichlet(); - primal = this->_gap.get(); - dual = pressure_; - this->functional.addFunctionalTerm(new functional::ElasticFunctionalGap( - model.getBEEngine(), this->surface), - true); + primal = gap_view.get(); + dual = pressure_view.get(); + this->functional.addFunctionalTerm( + new functional::ElasticFunctionalGap(*integral_op, this->surface), + true); break; } case pressure: { model.getBEEngine().registerNeumann(); - primal = pressure_; - dual = this->_gap.get(); + primal = pressure_view.get(); + dual = gap_view.get(); this->functional.addFunctionalTerm( - new functional::ElasticFunctionalPressure(model.getBEEngine(), - this->surface), + new functional::ElasticFunctionalPressure(*integral_op, this->surface), true); break; } } - - search_direction = - allocateGrid<true, Real>(model.getType(), model.getDiscretization(), - model.getTraction().getNbComponents()); - - projected_search_direction = - allocateGrid<true, Real>(model.getType(), model.getDiscretization(), - model.getTraction().getNbComponents()); } /* -------------------------------------------------------------------------- */ Real PolonskyKeerRey::solve(Real target) { Real G = 0, Gold = 1, error = 0, error_norm = 1; UInt n = 0; bool delta = false; *search_direction = 0; //*dual = 0; // Printing column headers std::cout << std::setw(5) << "Iter" << " " << std::setw(15) << "Cost_f" << " " << std::setw(15) << "Error" << '\n' << std::fixed; // Setting uniform value if constraint if (constraint_type == variable_type && std::abs(primal->sum()) <= 0) *primal = target; else if (constraint_type == variable_type) *primal *= target / primal->mean(); else if (constraint_type != variable_type) *primal = this->surface_stddev; do { // Computing functional gradient functional.computeGradF(*primal, *dual); Real dbar = meanOnUnsaturated(*dual); // Enforcing dual constraint via gradient if (constraint_type != variable_type) { *dual += 2 * target + dbar; } else { // Centering dual on primal > 0 *dual -= dbar; } // Computing gradient norm G = computeSquaredNorm(*dual); // Updating search direction (conjugate gradient) updateSearchDirection(delta * G / Gold); Gold = G; // Computing critical step Real tau = computeCriticalStep(target); // Update primal variable delta = updatePrimal(tau); // We should scale to constraint if (constraint_type == variable_type) *primal *= target / primal->mean(); error = computeError() / error_norm; Real cost_f = functional.computeF(*primal, *dual); printState(n, cost_f, error); } while (error > this->tolerance && n++ < this->max_iterations); // Final update of dual variable functional.computeGradF(*primal, *dual); Real dual_min = dual->min(); *dual -= dual_min; // Primal is pressure: need to make sure gap is positive if (variable_type == pressure) { - model.getDisplacement() = *dual; - model.getDisplacement() += this->surface; + *displacement_view = *dual; + *displacement_view += this->surface; } // Primal is gap: need to make sure dual is positive (pressure + adhesion) else { - model.getDisplacement() = *primal; - model.getDisplacement() += this->surface; - this->model.solveDirichlet(); - model.getTraction() -= dual_min; + *displacement_view = *primal; + *displacement_view += this->surface; + integral_op->apply(*displacement_view, *pressure_view); + *pressure_view -= dual_min; } return error; } /* -------------------------------------------------------------------------- */ /** * Computes \f$ \frac{1}{\mathrm{card}(\{p > 0\})} \sum_{\{p > 0\}}{f_i} \f$ */ Real PolonskyKeerRey::meanOnUnsaturated(const GridBase<Real>& field) const { // Sum on unsaturated Real sum = Loop::reduce<operation::plus>( [] CUDA_LAMBDA(Real & p, const Real& f) { return (p > 0) ? f : 0; }, *primal, field); // Number of unsaturated points UInt n_unsat = Loop::reduce<operation::plus>( [] CUDA_LAMBDA(Real & p) -> UInt { return (p > 0); }, *primal); return sum / n_unsat; } /* -------------------------------------------------------------------------- */ /** * Computes \f$ \sum_{\{p > 0\}}{f_i^2} \f$ */ Real PolonskyKeerRey::computeSquaredNorm(const GridBase<Real>& field) const { return Loop::reduce<operation::plus>( [] CUDA_LAMBDA(Real & p, const Real& f) { return (p > 0) ? f * f : 0; }, *primal, field); } /* -------------------------------------------------------------------------- */ /** * Computes \f$ \tau = \frac{ \sum_{\{p > 0\}}{q_i't_i} }{ \sum_{\{p > 0\}}{r_i' * t_i} } \f$ */ Real PolonskyKeerRey::computeCriticalStep(Real target) { - switch (variable_type) { - case gap: - model.getBEEngine().solveDirichlet(*search_direction, - *projected_search_direction); - break; - case pressure: - model.getBEEngine().solveNeumann(*search_direction, - *projected_search_direction); - break; - } + integral_op->apply(*search_direction, *projected_search_direction); Real rbar = meanOnUnsaturated(*projected_search_direction); if (constraint_type == variable_type) *projected_search_direction -= rbar; else { *projected_search_direction += 2 * target + rbar; } Real num = Loop::reduce<operation::plus>( [] CUDA_LAMBDA(Real & p, Real & q, Real & t) { return (p > 0) ? q * t : 0; }, *primal, *dual, *search_direction); Real denum = Loop::reduce<operation::plus>( [] CUDA_LAMBDA(Real & p, Real & r, Real & t) { return (p > 0) ? r * t : 0; }, *primal, *projected_search_direction, *search_direction); return num / denum; } /* -------------------------------------------------------------------------- */ /** * Update steps: * 1. \f$\mathbf{p} = \mathbf{p} - \tau \mathbf{t} \f$ * 2. Truncate all \f$p\f$ negative * 3. For all points in \f$I_\mathrm{na} = \{p = 0 \land q < 0 \}\f$ do \f$p_i = * p_i - \tau q_i\f$ */ bool PolonskyKeerRey::updatePrimal(Real step) { UInt na_num = Loop::reduce<operation::plus>( [step] CUDA_LAMBDA(Real & p, Real & q, Real & t) -> UInt { p -= step * t; // Updating primal if (p < 0) p = 0; // Truncating neg values if (p == 0 && q < 0) { // If non-admissible state p -= step * q; return 1; } else return 0; }, *primal, *dual, *search_direction); return na_num == 0; } /* -------------------------------------------------------------------------- */ /** * Error is based on \f$ \sum{p_i q_i} \f$ */ Real PolonskyKeerRey::computeError() { /// Making sure dual respects constraint *dual -= dual->min(); Real error = primal->dot(*dual); Real norm = 1; if (variable_type == pressure) norm = std::abs(primal->sum() * this->surface_stddev); else norm = std::abs(dual->sum() * this->surface_stddev); norm *= primal->getNbPoints(); return std::abs(error) / norm; } /* -------------------------------------------------------------------------- */ /** * Do \f$\mathbf{t} = \mathbf{q}' + \delta \frac{R}{R_\mathrm{old}}\mathbf{t} * \f$ */ void PolonskyKeerRey::updateSearchDirection(Real factor) { Loop::loop( [factor] CUDA_LAMBDA(Real & p, Real & q, Real & t) { t = (p > 0) ? q + factor * t : 0; }, *primal, *dual, *search_direction); } /* -------------------------------------------------------------------------- */ void PolonskyKeerRey::addFunctionalTerm(functional::Functional* func) { functional.addFunctionalTerm(func, false); } __END_TAMAAS__ /* -------------------------------------------------------------------------- */ diff --git a/src/solvers/polonsky_keer_rey.hh b/src/solvers/polonsky_keer_rey.hh index dd30bc65..759f4315 100644 --- a/src/solvers/polonsky_keer_rey.hh +++ b/src/solvers/polonsky_keer_rey.hh @@ -1,74 +1,130 @@ /** * @file * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @section LICENSE * * Copyright (©) 2016-2017 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Tamaas 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Tamaas. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __POLONSKY_KEER_REY_HH__ #define __POLONSKY_KEER_REY_HH__ /* -------------------------------------------------------------------------- */ #include "contact_solver.hh" +#include "grid_view.hh" #include "meta_functional.hh" -#include "tamaas.hh" +#include "westergaard.hh" /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ class PolonskyKeerRey : public ContactSolver { public: /// Types of algorithm (primal/dual) or constraint enum type { gap, pressure }; public: /// Constructor PolonskyKeerRey(Model& model, const GridBase<Real>& surface, Real tolerance, type variable_type, type constraint_type); public: /// Solve Real solve(Real target); /// Mean on unsaturated constraint zone Real meanOnUnsaturated(const GridBase<Real>& field) const; /// Compute squared norm Real computeSquaredNorm(const GridBase<Real>& field) const; /// Update search direction void updateSearchDirection(Real factor); /// Compute critical step Real computeCriticalStep(Real target = 0); /// Update primal and check non-admissible state bool updatePrimal(Real step); /// Compute error/stopping criterion Real computeError(); /// Add term to functional - void addFunctionalTerm(functional::Functional * func); + void addFunctionalTerm(functional::Functional* func); + +private: + /// Set correct views on normal traction and gap + template <model_type type> + void setViews(); protected: type variable_type, constraint_type; - GridBase<Real>* primal = nullptr; - GridBase<Real>* dual = nullptr; + model_type operation_type; + GridBase<Real>* primal = nullptr; ///< non-owning pointer for primal varaible + GridBase<Real>* dual = nullptr; ///< non-owning pointer for dual variable + + /// CG search direction std::unique_ptr<GridBase<Real>> search_direction = nullptr; + /// Projected CG search direction std::unique_ptr<GridBase<Real>> projected_search_direction = nullptr; + /// View on normal pressure, gap, displacement + std::unique_ptr<GridBase<Real>> pressure_view, gap_view, + displacement_view = nullptr; + + /// Integral operator for gradient computation + std::unique_ptr<IntegralOperator> integral_op = nullptr; }; +/* -------------------------------------------------------------------------- */ +template <model_type mtype> +void PolonskyKeerRey::setViews() { + constexpr UInt dim = model_type_traits<mtype>::dimension; + constexpr UInt bdim = model_type_traits<mtype>::boundary_dimension; + constexpr UInt comp = model_type_traits<mtype>::components; + + pressure_view = std::unique_ptr<GridBase<Real>>{ + new GridView<Grid, Real, bdim, bdim>(model.getTraction(), {}, comp - 1)}; + gap_view = std::unique_ptr<GridBase<Real>>{ + new GridView<Grid, Real, bdim, bdim>(*this->_gap, {}, comp - 1)}; + displacement_view = + std::unique_ptr<GridBase<Real>>{new GridView<Grid, Real, dim, bdim>( + model.getDisplacement(), model_type_traits<mtype>::indices, + comp - 1)}; + + // I noz is fugly - TODO factory? + if (bdim == 1) { + operation_type = model_type::basic_1d; + if (variable_type == gap) + integral_op = std::unique_ptr<IntegralOperator>{ + new Westergaard<model_type::basic_1d, IntegralOperator::dirichlet>( + &this->model)}; + else + integral_op = std::unique_ptr<IntegralOperator>{ + new Westergaard<model_type::basic_1d, IntegralOperator::neumann>( + &this->model)}; + } else if (bdim == 2) { + operation_type = model_type::basic_2d; + if (variable_type == gap) + integral_op = std::unique_ptr<IntegralOperator>{ + new Westergaard<model_type::basic_2d, IntegralOperator::dirichlet>( + &this->model)}; + else + integral_op = std::unique_ptr<IntegralOperator>{ + new Westergaard<model_type::basic_2d, IntegralOperator::neumann>( + &this->model)}; + } +} + __END_TAMAAS__ #endif // __POLONSKY_KEER_REY_HH__ diff --git a/tests/test_westergaard.py b/tests/test_westergaard.py index a9bc094a..383097be 100644 --- a/tests/test_westergaard.py +++ b/tests/test_westergaard.py @@ -1,62 +1,81 @@ #!/usr/bin/env python # coding: utf-8 # ----------------------------------------------------------------------------- # @author Lucas Frérot <lucas.frerot@epfl.ch> # # @section LICENSE # # Copyright (©) 2016 EPFL (Ecole Polytechnique Fédérale de # Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des # Solides) # # Tamaas is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Tamaas 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 Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with Tamaas. If not, see <http://www.gnu.org/licenses/>. # ----------------------------------------------------------------------------- from __future__ import division, print_function import sys import numpy as np from numpy.linalg import norm import tamaas as tm import pytest @pytest.fixture(scope="module", params=[tm.PolonskyKeerRey.pressure, tm.PolonskyKeerRey.gap]) def pkr(westergaard, request): loads = { tm.PolonskyKeerRey.pressure: westergaard.load, tm.PolonskyKeerRey.gap: 0.06697415181446396 } model = tm.ModelFactory.createModel(tm.model_type.basic_1d, [1.], [westergaard.n]) model.setElasticity(westergaard.e_star, 0) solver = tm.PolonskyKeerRey(model, westergaard.surface, 1e-12, request.param, request.param) solver.solve(loads[request.param]) return model, westergaard def test_energy(pkr): model, sol = pkr traction, displacement = model.getTraction(), model.getDisplacement() error = norm((traction - sol.pressure)*(displacement - sol.displacement)) error /= norm(sol.pressure * sol.displacement) assert error < 4e-6 +def test_pkr_multi(westergaard): + model_basic = tm.ModelFactory.createModel(tm.model_type.basic_1d, [1.], [westergaard.n]) + model_volume = tm.ModelFactory.createModel(tm.model_type.volume_1d, [1., 1.], + [20, westergaard.n]) + + pressures = {} + for model in [model_basic, model_volume]: + print(model) + solver = tm.PolonskyKeerRey(model, westergaard.surface, 1e-12, + tm.PolonskyKeerRey.pressure, + tm.PolonskyKeerRey.pressure) + solver.solve(westergaard.load) + pressures[model] = model.getTraction() + + error = norm(pressures[model_basic] - pressures[model_volume][:, 1]) / westergaard.load + assert error < 1e-16 + + + if __name__ == "__main__": print("Test is meant to run with pytest")