diff --git a/python/wrap/test_features.cpp b/python/wrap/test_features.cpp index 6d4c0ae2..a9a075d3 100644 --- a/python/wrap/test_features.cpp +++ b/python/wrap/test_features.cpp @@ -1,93 +1,96 @@ /** * @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 "kelvin.hh" #include "mindlin.hh" +#include "boussinesq.hh" #include "model.hh" #include "model_type.hh" #include "volume_potential.hh" #include "isotropic_hardening.hh" #include "wrap.hh" /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ namespace wrap { template <template <model_type, UInt> class KOp, model_type type, UInt tensor_order> void wrapKOp(const std::string& basename, py::module& mod) { constexpr UInt dim = model_type_traits<type>::dimension; std::stringstream str; str << basename << tensor_order; py::class_<KOp<type, tensor_order>>(mod, str.str().c_str()) .def(py::init<Model*>()) .def("apply", [](const KOp<type, tensor_order>& engine, Grid<Real, dim>& in, Grid<Real, dim>& out) { engine.apply(in, out); }); } template <model_type type> void wrapIsotropicHardening(py::module& mod) { constexpr UInt dim = model_type_traits<type>::dimension; py::class_<IsotropicHardening<type>>(mod, "IsotropicHardening") .def(py::init<Model*, Real, Real>()) .def_property("h", &IsotropicHardening<type>::getHardeningModulus, &IsotropicHardening<type>::setHardeningModulus) .def_property("sigma_0", &IsotropicHardening<type>::getYieldStress, &IsotropicHardening<type>::setYieldStress) .def("computeStress", [](IsotropicHardening<type>& iso, Grid<Real, dim>& stress, const Grid<Real, dim>& strain, const Grid<Real, dim>& strain_increment) { iso.template computeStress<false>(stress, strain, strain_increment); }) .def("computeStressUpdate", [](IsotropicHardening<type>& iso, Grid<Real, dim>& stress, const Grid<Real, dim>& strain, const Grid<Real, dim>& strain_increment) { iso.template computeStress<true>(stress, strain, strain_increment); }); } /// Wrap temporary features for testing void wrapTestFeatures(py::module& mod) { auto test_module = mod.def_submodule("_test_features"); test_module.doc() = "Module for testing new features.\n" "DISCLAIMER: this API is subject to frequent and unannounced changes " "and should **not** be relied upon!"; wrapKOp<Kelvin, model_type::volume_2d, 2>("Kelvin_", test_module); wrapKOp<Kelvin, model_type::volume_2d, 3>("Kelvin_", test_module); wrapKOp<Kelvin, model_type::volume_2d, 4>("Kelvin_", test_module); wrapKOp<Mindlin, model_type::volume_2d, 3>("Mindlin_", test_module); wrapKOp<Mindlin, model_type::volume_2d, 4>("Mindlin_", test_module); + wrapKOp<Boussinesq, model_type::volume_2d, 0>("Boussinesq_", test_module); + wrapKOp<Boussinesq, model_type::volume_2d, 1>("Boussinesq_", test_module); wrapIsotropicHardening<model_type::volume_2d>(test_module); } } __END_TAMAAS__ diff --git a/src/SConscript b/src/SConscript index 32569169..6389279d 100644 --- a/src/SConscript +++ b/src/SConscript @@ -1,116 +1,117 @@ import os Import('main_env') def prepend(path, list): return [os.path.join(path, x) for x in list] env = main_env # Core core_list = """ fft_plan_manager.cpp fftransform.cpp fftransform_fftw.cpp grid.cpp grid_hermitian.cpp statistics.cpp surface.cpp tamaas.cpp legacy_types.cpp loop.cpp """.split() core_list = prepend('core', core_list) core_list.append('tamaas_info.cpp') # Lib roughcontact generator_list = """ surface_generator.cpp surface_generator_filter.cpp surface_generator_filter_fft.cpp isopowerlaw.cpp """.split() generator_list = prepend('surface', generator_list) # Lib PERCOLATION percolation_list = """ flood_fill.cpp """.split() percolation_list = prepend('percolation', percolation_list) # BEM PERCOLATION bem_list = """ bem_kato.cpp bem_polonski.cpp bem_gigi.cpp bem_gigipol.cpp bem_penalty.cpp bem_uzawa.cpp bem_fft_base.cpp bem_functional.cpp bem_meta_functional.cpp elastic_energy_functional.cpp exponential_adhesion_functional.cpp squared_exponential_adhesion_functional.cpp maugis_adhesion_functional.cpp complimentary_term_functional.cpp bem_grid.cpp bem_grid_polonski.cpp bem_grid_kato.cpp bem_grid_teboulle.cpp bem_grid_condat.cpp """.split() bem_list = prepend('bem', bem_list) # Model model_list = """ model.cpp model_factory.cpp model_type.cpp model_template.cpp be_engine.cpp westergaard.cpp elastic_functional.cpp meta_functional.cpp adhesion_functional.cpp elasto_plastic_model.cpp volume_potential.cpp kelvin.cpp mindlin.cpp +boussinesq.cpp isotropic_hardening.cpp """.split() model_list = prepend('model', model_list) # Solvers solvers_list = """ contact_solver.cpp polonsky_keer_rey.cpp """.split() solvers_list = prepend('solvers', solvers_list) # GPU API gpu_list = """ fftransform_cufft.cpp """.split() gpu_list = prepend('gpu', gpu_list) # Assembling total list rough_contact_list = \ core_list + generator_list + percolation_list + model_list + solvers_list + bem_list # Adding GPU if needed if env['backend'] == 'cuda': rough_contact_list += gpu_list # Generating dependency files # env.AppendUnique(CXXFLAGS=['-MMD']) # for file_name in rough_contact_list: # obj = file_name.replace('.cpp', '.os') # dep_file_name = file_name.replace('.cpp', '.d') # env.SideEffect(dep_file_name, obj) # env.ParseDepends(dep_file_name) libTamaas = env.SharedLibrary('Tamaas', rough_contact_list) Export('libTamaas') diff --git a/src/model/boussinesq.cpp b/src/model/boussinesq.cpp new file mode 100644 index 00000000..5e87d389 --- /dev/null +++ b/src/model/boussinesq.cpp @@ -0,0 +1,133 @@ +/** + * @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 "boussinesq.hh" +#include "influence.hh" +#include "kelvin_helper.hh" +#include "model.hh" +/* -------------------------------------------------------------------------- */ +__BEGIN_TAMAAS__ +/* -------------------------------------------------------------------------- */ + +namespace detail { +template <model_type type, typename T> +class BoussinesqHelper { + using boussinesq_t = T; + using trait = model_type_traits<type>; + static constexpr UInt dim = trait::dimension; + static constexpr UInt bdim = trait::boundary_dimension; + +public: + BoussinesqHelper(const T& boussinesq, Real y_3, Real cutoff) + : boussinesq(boussinesq), y_3(y_3), cutoff(cutoff) {} + + inline void applyIntegral(GridHermitian<Real, bdim>& out, + GridHermitian<Real, bdim>& source, + const Grid<Real, bdim>& wavevectors) const { + Loop::stridedLoop( + [&](typename KelvinTrait<T>::out_t&& out_local, + VectorProxy<Complex, dim>&& traction, + VectorProxy<const Real, bdim>&& q) { + // Cutoff + if (-q.l2norm() * std::abs(y_3) < std::log(cutoff)) + return; + + out_local += + boussinesq.applyU0(traction, q) * + influence::KelvinIntegrator<0>::g0<true>(q.l2norm() * y_3); + out_local += + (boussinesq.applyU1(traction, q) * + influence::KelvinIntegrator<0>::g1<true>(q.l2norm() * y_3)); + }, + out, source, wavevectors); + } + +protected: + const T& boussinesq; + const Real y_3, cutoff; +}; +} // namespace detail + +template <> +Boussinesq<model_type::volume_2d, 0>::Boussinesq(Model* model) : parent(model) { + this->initialize(trait::dimension, trait::dimension); +} + +template <> +Boussinesq<model_type::volume_2d, 1>::Boussinesq(Model* model) : parent(model) { + this->initialize(trait::dimension, trait::dimension * trait::dimension); +} + +/* -------------------------------------------------------------------------- */ +/* Operator implementation */ +/* -------------------------------------------------------------------------- */ +template <model_type type, UInt derivative> +void Boussinesq<type, derivative>::apply(GridBase<Real>& source, + GridBase<Real>& out) const { + Real nu = this->model->getPoissonRatio(), mu = this->model->getShearModulus(); + influence::Boussinesq<trait::dimension, derivative> boussinesq(mu, nu); + + auto apply = [&](UInt i, decltype(this->source_buffers)& source_buffers, + decltype(this->disp_buffer)& out_buffer) { + const Real L = this->model->getSystemSize().front(); + const UInt N = this->model->getDiscretization().front(); + const Real dl = L / (N - 1); + + out_buffer = 0; + const Real xi = i * dl; + detail::BoussinesqHelper<type, decltype(boussinesq)> helper(boussinesq, xi, + 1e-2); + helper.applyIntegral(out_buffer, source_buffers.front(), this->wavevectors); + typename detail::KelvinTrait<decltype(boussinesq)>::out_t out_fundamental( + out_buffer(0)); + out_fundamental = 0; + }; + + this->fourierApply(apply, source, out); +} + +/* -------------------------------------------------------------------------- */ + +template <model_type type, UInt derivative> +void Boussinesq<type, derivative>::initialize(UInt source_components, + UInt out_components) { + // Copy horizontal sizes + std::array<UInt, trait::boundary_dimension> sizes; + std::copy(this->model->getDiscretization().begin() + 1, + this->model->getDiscretization().end(), sizes.begin()); + + auto hermitian_sizes = + GridHermitian<Real, trait::boundary_dimension>::hermitianDimensions( + sizes); + this->disp_buffer.setNbComponents(out_components); + this->disp_buffer.resize(hermitian_sizes); + this->source_buffers.resize(1); + auto& source = this->source_buffers.front(); + source.setNbComponents(source_components); + source.resize(hermitian_sizes); +} + +__END_TAMAAS__ diff --git a/src/model/boussinesq.hh b/src/model/boussinesq.hh new file mode 100644 index 00000000..1f019227 --- /dev/null +++ b/src/model/boussinesq.hh @@ -0,0 +1,60 @@ +/** + * @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 BOUSSINESQ_HH +#define BOUSSINESQ_HH +/* -------------------------------------------------------------------------- */ +#include "grid_hermitian.hh" +#include "model_type.hh" +#include "volume_potential.hh" +/* -------------------------------------------------------------------------- */ +__BEGIN_TAMAAS__ + +/** + * @brief Boussinesq tensor + */ +template <model_type type, UInt derivative> +class Boussinesq : public VolumePotential<type> { + static_assert(type == model_type::volume_1d || type == model_type::volume_2d, + "Only volume types are supported"); + using trait = model_type_traits<type>; + using parent = VolumePotential<type>; + +public: + /// Constructor + Boussinesq(Model* model); + +protected: + void initialize(UInt source_components, UInt out_components); + +public: + /// Apply the Boussinesq operator + void apply(GridBase<Real>& source, GridBase<Real>& out) const override; +}; + +__END_TAMAAS__ + +#endif // BOUSSINESQ_HH diff --git a/src/model/mindlin.cpp b/src/model/mindlin.cpp index f159fd22..6df0eb91 100644 --- a/src/model/mindlin.cpp +++ b/src/model/mindlin.cpp @@ -1,161 +1,158 @@ /** * @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 "mindlin.hh" #include "elasto_plastic_model.hh" #include "influence.hh" #include "kelvin_helper.hh" /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ /* -------------------------------------------------------------------------- */ namespace detail { template <model_type type, typename T> class MindlinBoussinesqHelper { using boussinesq_t = T; using trait = model_type_traits<type>; static constexpr UInt dim = trait::dimension; static constexpr UInt bdim = trait::boundary_dimension; public: MindlinBoussinesqHelper(const T& boussinesq, const influence::ElasticHelper<dim>& el, Real y_3, Real cutoff) : boussinesq(boussinesq), el(el), y_3(y_3), cutoff(cutoff) {} inline void applyIntegral(GridHermitian<Real, bdim>& out, GridHermitian<Real, bdim>& source, const Grid<Real, bdim>& wavevectors) const { Loop::stridedLoop( [&](typename KelvinTrait<T>::out_t&& out_local, MatrixProxy<Complex, dim, dim>&& source_local, VectorProxy<const Real, bdim>&& q) { // Cutoff if (-q.l2norm() * std::abs(y_3) < std::log(cutoff)) return; Vector<Real, dim> normal{{{0, 0, 1}}}; auto traction{el(source_local) * normal}; out_local += boussinesq.applyU0(traction, q) * influence::KelvinIntegrator<0>::g0<true>(q.l2norm() * y_3); out_local += (boussinesq.applyU1(traction, q) * influence::KelvinIntegrator<0>::g1<true>(q.l2norm() * y_3)); }, out, source, wavevectors); } protected: const T& boussinesq; const influence::ElasticHelper<dim>& el; const Real y_3, cutoff; }; } // namespace detail template <model_type type, UInt order> void Mindlin<type, order>::apply(GridBase<Real>& source, GridBase<Real>& out) const { Real nu = this->model->getPoissonRatio(), mu = this->model->getShearModulus(); constexpr UInt derivative = order - 2; influence::Kelvin<trait::dimension, derivative> kelvin(mu, nu); influence::Kelvin<trait::dimension, 2> kelvin_strain(mu, nu); influence::Boussinesq<trait::dimension, derivative - 1> boussinesq(mu, nu); influence::ElasticHelper<trait::dimension> elasticity(mu, nu); auto apply = [&](UInt i, decltype(this->source_buffers)& source_buffers, decltype(this->disp_buffer)& out_buffer) { - constexpr UInt dim = trait::dimension; const Real L = this->model->getSystemSize().front(); const UInt N = this->model->getDiscretization().front(); const Real dl = L / (N - 1); out_buffer = 0; /// Compute surface strains only once (dirty) if (i == 0) { surface_strains = 0; for (UInt j : Loop::range(N)) { const Real dij = j * dl; auto& source = source_buffers[j]; - detail::KelvinHelper<type, influence::Kelvin<dim, 2>> helper( + detail::KelvinHelper<type, decltype(kelvin_strain)> helper( kelvin_strain, dij, dl, 1e-2); if (j > i) { helper.template applyIntegral<1>(surface_strains, source, this->wavevectors); } else if (j == i) { helper.template applyIntegral<0>(surface_strains, source, this->wavevectors); helper.applyFreeTerm(surface_strains, source, this->wavevectors); } else { helper.template applyIntegral<-1>(surface_strains, source, this->wavevectors); } } } for (UInt j : Loop::range(N)) { const Real dij = j * dl - i * dl; // don't factorize! auto& source = source_buffers[j]; - detail::KelvinHelper<type, influence::Kelvin<dim, derivative>> helper( + detail::KelvinHelper<type, decltype(kelvin)> helper( kelvin, dij, dl, 1e-2); if (j > i) { helper.template applyIntegral<1>(out_buffer, source, this->wavevectors); } else if (j == i) { helper.template applyIntegral<0>(out_buffer, source, this->wavevectors); helper.applyFreeTerm(out_buffer, source, this->wavevectors); } else { helper.template applyIntegral<-1>(out_buffer, source, this->wavevectors); } } // Correcting for the tractions on the surface - Real xi = i * dl; - detail::MindlinBoussinesqHelper<type, - influence::Boussinesq<dim, derivative - 1>> - helper(boussinesq, elasticity, xi, 1e-2); + const Real xi = i * dl; + detail::MindlinBoussinesqHelper<type, decltype(boussinesq)> helper( + boussinesq, elasticity, xi, 1e-2); helper.applyIntegral(out_buffer, surface_strains, this->wavevectors); // Setting fundamental frequency to zero - typename detail::KelvinTrait< - influence::Kelvin<trait::dimension, derivative>>::out_t - out_fundamental(out_buffer(0)); + typename detail::KelvinTrait<decltype(kelvin)>::out_t out_fundamental( + out_buffer(0)); out_fundamental = 0; }; this->fourierApply(apply, source, out); } /* -------------------------------------------------------------------------- */ /* Template instanciation */ /* -------------------------------------------------------------------------- */ template class Mindlin<model_type::volume_2d, 3>; template class Mindlin<model_type::volume_2d, 4>; /* -------------------------------------------------------------------------- */ __END_TAMAAS__ diff --git a/src/model/volume_potential.hh b/src/model/volume_potential.hh index 3f85f1aa..a1f0c4ee 100644 --- a/src/model/volume_potential.hh +++ b/src/model/volume_potential.hh @@ -1,95 +1,97 @@ /** * @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 {} 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"); + // 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(i.sizes().front())) { + 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