diff --git a/src/model/westergaard.cpp b/src/model/westergaard.cpp index ad709f8..7604742 100644 --- a/src/model/westergaard.cpp +++ b/src/model/westergaard.cpp @@ -1,238 +1,238 @@ /** * @file * * @author Lucas Frérot * * @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 . * */ /* -------------------------------------------------------------------------- */ #include "westergaard.hh" #include "fft_plan_manager.hh" #include "influence.hh" #include "loop.hh" #include "model.hh" #include "static_types.hh" /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ /* -------------------------------------------------------------------------- */ template Westergaard::Westergaard(Model* model) : BEEngine(model) { // Copy sizes std::array sizes; std::copy(model->getDiscretization().begin(), model->getDiscretization().end(), sizes.begin()); auto hermitian_sizes = GridHermitian::hermitianDimensions(sizes); // Copy boundary sizes auto sizes_it = sizes.begin(); std::array 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 = GridHermitian::hermitianDimensions( boundary_hermitian_sizes); constexpr UInt nb_components = trait::components; buffer.setNbComponents(nb_components); buffer.resize(boundary_hermitian_sizes); influence.setNbComponents(nb_components * nb_components); influence.resize(hermitian_sizes); } /* -------------------------------------------------------------------------- */ template void Westergaard::initInfluence() { TAMAAS_EXCEPTION("Not implemented"); } /* -------------------------------------------------------------------------- */ #define INFLUENCE_BASIC_MACRO \ do { \ constexpr UInt bdim = trait::boundary_dimension; \ auto wavevectors = \ FFTransform::computeFrequencies(influence.sizes()); \ Real E_star = model->getHertzModulus(); \ VectorProxy domain(model->getSystemSize()[0]); \ Loop::stridedLoop(influence::Basic(E_star, domain), wavevectors, \ influence); \ influence(0) = 0; \ } while (0) template <> void Westergaard::initInfluence() { INFLUENCE_BASIC_MACRO; } template <> void Westergaard::initInfluence() { INFLUENCE_BASIC_MACRO; } #undef INFLUENCE_BASIC_MACRO #define INFLUENCE_SURFACE_MACRO \ do { \ constexpr UInt bdim = trait::boundary_dimension; \ auto wavevectors = \ FFTransform::computeFrequencies(influence.sizes()); \ Real E = model->getYoungModulus(); \ Real nu = model->getPoissonRatio(); \ VectorProxy domain(model->getSystemSize()[0]); \ Loop::stridedLoop(influence::Surface(E, nu, domain), wavevectors, \ influence); \ } while (0) template <> void Westergaard::initInfluence() { INFLUENCE_SURFACE_MACRO; } template <> void Westergaard::initInfluence() { INFLUENCE_SURFACE_MACRO; } #undef INFLUENCE_SURFACE_MACRO /* ------------------------------------------------------------------------ */ #define NEUMANN_BASIC(type) \ template <> \ void Westergaard::solveNeumann(GridBase& in, \ GridBase& out) const { \ auto apply = [](decltype(buffer)& buffer, \ const decltype(influence)& influence) { \ buffer *= influence; \ buffer(0) = 0; \ }; \ \ fourierApply(apply, in, out); \ } #define DIRICHLET_BASIC(type) \ template <> \ void Westergaard::solveDirichlet(GridBase& in, \ GridBase& out) const { \ auto apply = [](decltype(buffer)& buffer, \ const decltype(influence)& influence) { \ buffer /= influence; \ buffer(0) = 0; \ }; \ \ fourierApply(apply, in, out); \ } 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 /* -------------------------------------------------------------------------- */ namespace detail { /// Class needed for cuda template struct SurfaceApply { void operator()(GridHermitian& buffer_, const GridHermitian& influence) { Loop::stridedLoop( [] CUDA_LAMBDA(VectorProxy && buf, MatrixProxy && inf) { Vector copy(buf); buf.mul(inf, copy); }, buffer_, influence); VectorProxy buff_0(buffer_(0)); buff_0 = 0; } }; } // namespace detail #define NEUMANN_SURFACE(type) \ template <> \ void Westergaard::solveNeumann(GridBase& in, \ GridBase& out) const { \ fourierApply(detail::SurfaceApply(), in, out); \ } /// \TODO Find a way to make it work with cuda NEUMANN_SURFACE(model_type::surface_1d); NEUMANN_SURFACE(model_type::surface_2d); #undef NEUMANN_SURFACE /* -------------------------------------------------------------------------- */ template void Westergaard::solveNeumann(GridBase& /*neumann*/, GridBase& /*dirichlet*/) const { TAMAAS_EXCEPTION("Not yet implemented"); } /* -------------------------------------------------------------------------- */ template void Westergaard::solveDirichlet(GridBase& /*neumann*/, GridBase& /*dirichlet*/) const { TAMAAS_EXCEPTION("Not yet implemented"); } /* -------------------------------------------------------------------------- */ template Real Westergaard::getNeumannNorm() { constexpr UInt comp = model_type_traits::components; Real _norm = 0.0; _norm = Loop::stridedReduce( - [] CUDA_LAMBDA(StaticVector&& m) { + [] CUDA_LAMBDA(MatrixProxy&& m) { Real n = thrust::norm(m.l2squared()); return std::isnan(n) ? 0 : n; }, influence); return std::sqrt(_norm); } /* -------------------------------------------------------------------------- */ /* Template instanciation */ /* -------------------------------------------------------------------------- */ template class Westergaard; template class Westergaard; template class Westergaard; template class Westergaard; template class Westergaard; template class Westergaard; /* -------------------------------------------------------------------------- */ __END_TAMAAS__ /* -------------------------------------------------------------------------- */ diff --git a/src/solvers/kato.cpp b/src/solvers/kato.cpp index d61ea66..7ec0b3d 100644 --- a/src/solvers/kato.cpp +++ b/src/solvers/kato.cpp @@ -1,366 +1,366 @@ /** * @file * * @author Son Pham-Ba * * @section LICENSE * * Copyright (©) 2016-2018 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 . * */ /* -------------------------------------------------------------------------- */ #include "kato.hh" #include "elastic_functional.hh" #include "loop.hh" #include "fft_plan_manager.hh" #include #include /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ Kato::Kato(Model& model, const GridBase& surface, Real tolerance, Real mu) : ContactSolver(model, surface, tolerance), engine(model.getBEEngine()), mu(mu) { if (model.getType() != model_type::surface_1d && model.getType() != model_type::surface_2d) { TAMAAS_EXCEPTION( "Model type is not compatible with Kato solver"); } gap = this->_gap.get(); // locally allocated pressure = &model.getTraction(); comp = pressure->getNbComponents(); N = pressure->getNbPoints(); if (model.getType() == model_type::surface_1d) { initSurfaceWithComponents(); } else { initSurfaceWithComponents(); } } /* -------------------------------------------------------------------------- */ Real Kato::solve(GridBase& p0) { if (p0.getNbPoints() != comp) { TAMAAS_EXCEPTION( "Target mean pressure does not have the right number of components"); } Real cost = 0; switch (model.getType()) { case model_type::surface_1d: cost = solveTmpl(p0); break; case model_type::surface_2d: cost = solveTmpl(p0); break; default: break; } return cost; } template Real Kato::solveTmpl(GridBase& p0) { Real cost = 0; UInt n = 0; // Printing column headers std::cout << std::setw(5) << "Iter" << " " << std::setw(15) << "Cost_f" << " " << std::setw(15) << "Error" << '\n' << std::fixed; pressure->uniformSetComponents(p0); // setMaxIterations(10); // setDumpFrequency(1); do { engine.solveNeumann(*pressure, *gap); *gap -= surfaceComp; *pressure -= *gap; enforcePressureConstraints(p0); cost = computeCost(); printState(n, cost, cost); } while (cost > this->tolerance && n++ < this->max_iterations); Real beta = computeBeta(); computeFinalGap(beta); model.getDisplacement() = *gap; return cost; } /* -------------------------------------------------------------------------- */ Real Kato::solveRelaxed(GridBase& g0) { if (g0.getNbPoints() != comp) { TAMAAS_EXCEPTION( "Target mean gap does not have the right number of components"); } Real cost = 0; switch (model.getType()) { case model_type::surface_1d: cost = solveRelaxedTmpl(g0); break; case model_type::surface_2d: cost = solveRelaxedTmpl(g0); break; default: break; } return cost; } template Real Kato::solveRelaxedTmpl(GridBase& g0) { constexpr UInt comp = model_type_traits::components; Real cost = 0; UInt n = 0; // Printing column headers std::cout << std::setw(5) << "Iter" << " " << std::setw(15) << "Cost_f" << " " << std::setw(15) << "Error" << '\n' << std::fixed; *pressure = 0; do { engine.solveNeumann(*pressure, *gap); addUniform(*gap, g0); *gap -= surfaceComp; *pressure -= *gap; enforcePressureCoulomb(); cost = computeCost(); printState(n, cost, cost); } while (cost > this->tolerance && n++ < this->max_iterations); *gap += surfaceComp; model.getDisplacement() = *gap; return cost; } /* -------------------------------------------------------------------------- */ template void Kato::initSurfaceWithComponents() { constexpr UInt comp = model_type_traits::components; surfaceComp.setNbComponents(comp); surfaceComp.resize({N}); surfaceComp = 0; Loop::stridedLoop( - [] CUDA_LAMBDA(Real& s, StaticVector&& sc) { + [] CUDA_LAMBDA(Real& s, VectorProxy&& sc) { sc(comp - 1) = s; }, surface, surfaceComp); } /* -------------------------------------------------------------------------- */ /** * Projects $\vec{p}$ on $\mathcal{C}$ and $\mathcal{D}$. */ template void Kato::enforcePressureConstraints(GridBase& p0) { UInt n = 50; for (UInt i = 0; i < n; i++) { enforcePressureMean(p0); enforcePressureCoulomb(); } } /* -------------------------------------------------------------------------- */ template void Kato::enforcePressureMean(GridBase& p0) { constexpr UInt comp = model_type_traits::components; Grid corr({1}, comp); computeMean(*pressure, corr); corr -= p0; - StaticVector corr_(corr(0)); + VectorProxy corr_(corr(0)); Loop::stridedLoop( - [corr_] CUDA_LAMBDA(StaticVector&& p) { + [corr_] CUDA_LAMBDA(VectorProxy&& p) { p -= corr_; }, *pressure); } /* -------------------------------------------------------------------------- */ template void Kato::enforcePressureCoulomb() { constexpr UInt comp = model_type_traits::components; Loop::stridedLoop( - [this] CUDA_LAMBDA(StaticVector&& p) { - StaticVector p_T(p(0)); + [this] CUDA_LAMBDA(VectorProxy&& p) { + VectorProxy p_T(p(0)); Real p_N = p(comp - 1); Real p_T_sqrd= p_T.l2squared(); bool cond1 = (p_N >= 0 && p_T_sqrd <= mu * mu * p_N * p_N); bool cond2 = (p_N <= 0 && p_T_sqrd <= p_N * p_N / mu / mu); if (cond2) { p_T = 0; p(comp - 1) = 0; } else if (!cond1) { Real p_T_norm = std::sqrt(p_T_sqrd); Real k = (p_N + mu * p_T_norm) / (1 + mu * mu); p_T *= k * mu / p_T_norm; p(comp - 1) = k; } }, *pressure); } /* -------------------------------------------------------------------------- */ /** * Compute mean of the field taking each component separately. */ template void Kato::computeMean(GridBase& field, GridBase& mean) { + auto _mean = Loop::stridedReduce( + [] CUDA_LAMBDA(VectorProxy&& f) -> Vector { + return f; + }, + field); + for (UInt i = 0; i < comp; i++) { - mean(i) = Loop::stridedReduce( - [i] CUDA_LAMBDA(StaticVector&& f) { - return f(i); - }, - field); + mean(i) = _mean(i) / N; } - - mean /= N; } /* -------------------------------------------------------------------------- */ template void Kato::addUniform(GridBase& field, GridBase& vec) { - for (UInt i = 0; i < comp; i++) { - Loop::stridedLoop( - [&] CUDA_LAMBDA(StaticVector&& f) { + Loop::stridedLoop( + [&] CUDA_LAMBDA(VectorProxy&& f) { + for (UInt i = 0; i < comp; i++) { f(i) += vec(i); - }, - field); - } + } + }, + field); } /* -------------------------------------------------------------------------- */ Real Kato::computeCost() { UInt N = pressure->getNbPoints(); Real beta = 0; Grid lambda({N}, 1); Grid eta({N}, 1); Grid p_N({N}, 1); Grid p_C({N}, 1); switch (model.getType()) { case model_type::surface_1d: beta = computeBeta(); computeValuesForCost(beta, lambda, eta, p_N, p_C); break; case model_type::surface_2d: beta = computeBeta(); computeValuesForCost(beta, lambda, eta, p_N, p_C); break; default: break; } return p_N.dot(lambda) + p_C.dot(eta); } /* -------------------------------------------------------------------------- */ template Real Kato::computeBeta() { constexpr UInt comp = model_type_traits::components; return Loop::stridedReduce( - [this] CUDA_LAMBDA(StaticVector&& g) { - StaticVector g_T(g(0)); + [this] CUDA_LAMBDA(VectorProxy&& g) { + VectorProxy g_T(g(0)); Real g_N = g(comp - 1); Real g_T_norm = g_T.l2norm(); return mu * g_T_norm - g_N; }, *gap); } /* -------------------------------------------------------------------------- */ template void Kato::computeValuesForCost(Real beta, GridBase& lambda, GridBase& eta, GridBase& p_N, GridBase& p_C) { constexpr UInt comp = model_type_traits::components; Loop::stridedLoop( - [this, beta] CUDA_LAMBDA(StaticVector&& p, - StaticVector&& g, + [this, beta] CUDA_LAMBDA(VectorProxy&& p, + VectorProxy&& g, Real& lambda_, Real& eta_, Real& p_N_, Real& p_C_) { - StaticVector g_T(g(0)); + VectorProxy g_T(g(0)); Real g_N = g(comp - 1); Real g_T_norm = g_T.l2norm(); lambda_ = g_N - mu * g_T_norm + beta; eta_ = g_T_norm; - StaticVector p_T(p(0)); + VectorProxy p_T(p(0)); Real p_N = p(comp - 1); Real p_T_norm = p_T.l2norm(); p_N_ = p(comp - 1); p_C_ = mu * p_N - p_T_norm; }, *pressure, *gap, lambda, eta, p_N, p_C); } /* -------------------------------------------------------------------------- */ template void Kato::computeFinalGap(Real beta) { constexpr UInt comp = model_type_traits::components; Loop::stridedLoop( - [beta] CUDA_LAMBDA(StaticVector&& g, - StaticVector&& h) { + [beta] CUDA_LAMBDA(VectorProxy&& g, + VectorProxy&& h) { g(comp - 1) += h(comp - 1) + beta; }, *gap, surfaceComp); } __END_TAMAAS__ /* -------------------------------------------------------------------------- */