Page MenuHomec4science

kelvin_helper.hh
No OneTemporary

File Metadata

Created
Sat, May 11, 10:01

kelvin_helper.hh

/**
* @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 KELVIN_HELPER_HH
#define KELVIN_HELPER_HH
/* -------------------------------------------------------------------------- */
#include "grid.hh"
#include "grid_hermitian.hh"
#include "influence.hh"
#include "integration/accumulator.hh"
#include "model.hh"
#include "model_type.hh"
/* -------------------------------------------------------------------------- */
__BEGIN_TAMAAS__
namespace detail {
/* -------------------------------------------------------------------------- */
/// Trait for kelvin local types
template <typename T>
struct KelvinTrait;
template <UInt dim>
struct KelvinTrait<influence::Kelvin<dim, 0>> {
using source_t = VectorProxy<Complex, dim>;
using out_t = VectorProxy<Complex, dim>;
};
template <UInt dim>
struct KelvinTrait<influence::Kelvin<dim, 1>> {
using source_t = MatrixProxy<Complex, dim, dim>;
using out_t = VectorProxy<Complex, dim>;
};
template <UInt dim>
struct KelvinTrait<influence::Kelvin<dim, 2>> {
using source_t = MatrixProxy<Complex, dim, dim>;
using out_t = MatrixProxy<Complex, dim, dim>;
};
template <UInt dim>
struct KelvinTrait<influence::Boussinesq<dim, 0>> {
using source_t = VectorProxy<Complex, dim>;
using out_t = VectorProxy<Complex, dim>;
};
template <UInt dim>
struct KelvinTrait<influence::Boussinesq<dim, 1>> {
using source_t = VectorProxy<Complex, dim>;
using out_t = MatrixProxy<Complex, dim, dim>;
};
/* -------------------------------------------------------------------------- */
/// Helper to apply integral representation on output
template <model_type type, typename kelvin_t,
typename = typename KelvinTrait<kelvin_t>::source_t>
struct KelvinHelper {
using trait = model_type_traits<type>;
static constexpr UInt dim = trait::dimension;
static constexpr UInt bdim = trait::boundary_dimension;
using BufferType = GridHermitian<Real, bdim>;
using source_t = typename KelvinTrait<kelvin_t>::source_t;
using out_t = typename KelvinTrait<kelvin_t>::out_t;
/// Apply the regular part of Kelvin to source and sum into output
void applyIntegral(std::vector<BufferType>& source,
std::vector<BufferType>& out,
const Grid<Real, bdim>& wavevectors, Real domain_size,
const kelvin_t& kelvin) {
accumulator.makeUniformMesh(source.size(), domain_size);
auto waverange = range<VectorProxy<const Real, bdim>>(wavevectors);
for (auto [l, xl_, acc_g0, acc_g1] :
accumulator.forward(source, wavevectors)) {
Loop::loop(
[xl = xl_, &kelvin](auto qv, auto u, auto acc_g0, auto acc_g1) {
Real q = qv.l2norm();
auto tmp = kelvin.template applyU1<false, true>(qv, acc_g0);
tmp *= -q * xl;
tmp += kelvin.template applyU0<false, true>(qv, acc_g0);
tmp += kelvin.template applyU1<false, true>(qv, acc_g1);
tmp *= std::exp(-q * xl);
u += tmp;
},
waverange.headless(), range<out_t>(out[l]).headless(),
range<source_t>(acc_g0).headless(),
range<source_t>(acc_g1).headless());
}
for (auto [l, xl_, acc_g0, acc_g1] :
accumulator.backward(source, wavevectors)) {
Loop::loop(
[xl = xl_, &kelvin](auto qv, auto u, auto acc_g0, auto acc_g1) {
Real q = qv.l2norm();
auto tmp = kelvin.template applyU1<true, true>(qv, acc_g0);
tmp *= -q * xl;
tmp += kelvin.template applyU0<true, true>(qv, acc_g0);
tmp += kelvin.template applyU1<true, true>(qv, acc_g1);
tmp *= std::exp(q * xl);
u += tmp;
},
waverange.headless(), range<out_t>(out[l]).headless(),
range<source_t>(acc_g0).headless(),
range<source_t>(acc_g1).headless());
}
}
/// Apply free term of distribution derivative
void applyFreeTerm(std::vector<BufferType>& /*source*/,
std::vector<BufferType>& /*out*/,
const kelvin_t& /*kelvin*/) {}
/// Making the output free of communist NaN
/// TODO change interface
void makeFundamentalGreatAgain(std::vector<BufferType>& /*out*/) {}
protected:
Accumulator<type, source_t> accumulator;
};
/// Applying free term for double gradient of Kelvin
template <>
inline void
KelvinHelper<model_type::volume_2d, influence::Kelvin<3, 2>>::applyFreeTerm(
std::vector<BufferType>& source, std::vector<BufferType>& out,
const influence::Kelvin<3, 2>& kelvin) {
for (UInt l : Loop::range(source.size())) {
// No need for headless loops as discontinuity term does not depend on q
Loop::loop(
[&kelvin](auto u, auto w) { u += kelvin.applyDiscontinuityTerm(w); },
range<out_t>(out[l]), range<source_t>(source[l]));
}
}
/// Setting fundamental mode to zero: we've got no other choice here
template <>
inline void KelvinHelper<model_type::volume_2d, influence::Kelvin<3, 0>>::
makeFundamentalGreatAgain(std::vector<BufferType>& out) {
for (auto&& layer : out) {
out_t u(&layer(0));
u = 0;
}
}
/* -------------------------------------------------------------------------- */
template <model_type type>
struct SurfaceTractionHelper {
using trait = model_type_traits<type>;
static constexpr UInt dim = trait::dimension;
static constexpr UInt bdim = trait::boundary_dimension;
using BufferType = GridHermitian<Real, bdim>;
using kelvin_t = influence::Kelvin<3, 2>;
using source_t = typename KelvinTrait<kelvin_t>::source_t;
using out_t = typename KelvinTrait<kelvin_t>::out_t;
/// Compute surface tractions due to eigenstress distribution
template <bool apply_q_power>
void computeSurfaceTractions(std::vector<BufferType>& source,
BufferType& tractions,
const Grid<Real, bdim>& wavevectors,
Real domain_size, const kelvin_t& kelvin,
const influence::ElasticHelper<dim>& el) {
accumulator.makeUniformMesh(source.size(), domain_size);
// only doing backward loop because forward loop gives 0 for l = 0
for (auto [l, xl_, acc_g0, acc_g1] :
accumulator.backward(source, wavevectors)) {
// Just skip all layers and let the accumulator accumulate
if (l != 0)
continue;
Loop::loop(
[&kelvin, &el](auto qv, auto t, auto acc_g0, auto acc_g1) {
// computing strains
auto strains =
kelvin.template applyU0<true, apply_q_power>(qv, acc_g0);
strains += kelvin.template applyU1<true, apply_q_power>(qv, acc_g1);
// computing traction vector
Vector<Real, dim> normal{{{0, 0, -1}}};
t = el(strains) * normal;
},
range<VectorProxy<const Real, bdim>>(wavevectors).headless(),
range<VectorProxy<Complex, dim>>(tractions).headless(),
range<source_t>(acc_g0).headless(),
range<source_t>(acc_g1).headless());
}
}
protected:
Accumulator<type, source_t> accumulator;
};
} // namespace detail
__END_TAMAAS__
#endif // KELVIN_HELPER_HH

Event Timeline