Page MenuHomec4science

model_type.hh
No OneTemporary

File Metadata

Created
Sun, May 5, 05:25

model_type.hh

/*
* SPDX-License-Indentifier: AGPL-3.0-or-later
*
* Copyright (©) 2016-2023 EPFL (École Polytechnique Fédérale de Lausanne),
* Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
* Copyright (©) 2020-2023 Lucas Frérot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/* -------------------------------------------------------------------------- */
#ifndef MODEL_TYPE_HH
#define MODEL_TYPE_HH
/* -------------------------------------------------------------------------- */
#include "grid.hh"
#include "grid_base.hh"
#include "static_types.hh"
#include "tamaas.hh"
#include <algorithm>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/seq.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <memory>
/* -------------------------------------------------------------------------- */
namespace tamaas {
/// 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
};
/// 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 char repr[]{#type}; \
static constexpr UInt dimension = dim; \
static constexpr UInt components = comp; \
static constexpr UInt boundary_dimension = bdim; \
static constexpr UInt voigt = voigt_size<comp>::value; \
static const 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
// 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
namespace detail {
/// Convert enum value to a type
template <model_type type>
using model_type_t = std::integral_constant<model_type, type>;
/// Convert dim value to a type
template <UInt dim>
using dim_t = std::integral_constant<UInt, dim>;
#define MAKE_MODEL_TYPE(r, x, type) (model_type_t<type>)
/// Enumeration of model types
using model_types_t = std::tuple<BOOST_PP_SEQ_ENUM(
BOOST_PP_SEQ_FOR_EACH(MAKE_MODEL_TYPE, ~, TAMAAS_MODEL_TYPES))>;
#undef MAKE_MODEL_TYPE
#define MAKE_DIM_TYPE(r, x, dim) (dim_t<dim>)
/// Enumeration of dimension types
using dims_t = std::tuple<BOOST_PP_SEQ_ENUM(
BOOST_PP_SEQ_FOR_EACH(MAKE_DIM_TYPE, ~, (1)(2)(3)))>;
#undef MAKE_DIM_TYPE
} // namespace detail
/// Print function for model_type
inline std::ostream& operator<<(std::ostream& o, const model_type& val) {
switch (val) {
#define PRINT_MODEL_TYPE(r, data, type) \
case type: \
o << model_type_traits<type>::repr; \
break;
BOOST_PP_SEQ_FOR_EACH(PRINT_MODEL_TYPE, model_type, TAMAAS_MODEL_TYPES);
#undef PRINT_MODEL_TYPE
}
return o;
}
#undef ALLOC_GRID_CASE_MACRO
// Implementing a static dispatch mechanism
// References for a generic static dispatch:
// https://stackoverflow.com/questions/39915986/solutions-for-dynamic-dispatch-on-unrelated-types
// constexpr map: Jason Turner C++ Weekly ep 233
// C++14 limited dispatch (Nicolas Richart):
// akantu/features/eigen::src/common/aka_element_classes_info_inline_impl.hh
// TODO when switching C++17, implement with constexpr map
namespace detail {
/// Specialized static dispatch for all model types
template <class Function, class DynamicType, class DefaultFunction,
std::size_t... Is>
constexpr decltype(auto) static_switch_dispatch(
const model_types_t&, Function&& function, const DynamicType& type,
DefaultFunction&& default_function, std::index_sequence<Is...>) {
#define SWITCH_DISPATCH_CASE(r, data, type) \
case type: { \
return function(model_type_t<type>{}); \
}
switch (type) {
BOOST_PP_SEQ_FOR_EACH(SWITCH_DISPATCH_CASE, ~, TAMAAS_MODEL_TYPES);
default:
return default_function(type);
}
#undef SWITCH_DISPATCH_CASE
}
/// Specialized static dispatch for all dimensions
template <class Function, class DynamicType, class DefaultFunction,
std::size_t... Is>
constexpr decltype(auto) static_switch_dispatch(
const dims_t&, Function&& function, const DynamicType& dim,
DefaultFunction&& default_function, std::index_sequence<Is...>) {
#define SWITCH_DISPATCH_CASE(r, data, dim) \
case dim: { \
return function(dim_t<dim>{}); \
}
switch (dim) {
BOOST_PP_SEQ_FOR_EACH(SWITCH_DISPATCH_CASE, ~, (1)(2)(3));
default:
return default_function(dim);
}
#undef SWITCH_DISPATCH_CASE
}
/// Dispatch to tuple of types with a default case
template <class TypeTuple, class Function, class DefaultFunction,
class DynamicType>
constexpr decltype(auto)
tuple_dispatch_with_default(Function&& function,
DefaultFunction&& default_function,
const DynamicType& type) {
return detail::static_switch_dispatch(
TypeTuple{}, std::forward<Function>(function), type,
std::forward<DefaultFunction>(default_function),
std::make_index_sequence<std::tuple_size<TypeTuple>::value>{});
}
/// Dispatch to tuple of types, error on default
template <class TypeTuple, class Function, class DynamicType>
constexpr decltype(auto) tuple_dispatch(Function&& function,
const DynamicType& type) {
return tuple_dispatch_with_default<TypeTuple>(
std::forward<Function>(function),
[](auto&& type) -> decltype(function(
std::tuple_element_t<0, TypeTuple>{})) {
throw model_type_error{
TAMAAS_MSG("Unknown type in static dispatch", type)};
},
type);
}
} // namespace detail
/// Static dispatch lambda to model types
template <class Function>
constexpr decltype(auto) model_type_dispatch(Function&& function,
model_type type) {
return detail::tuple_dispatch<detail::model_types_t>(
std::forward<Function>(function), type);
}
/// Static dispatch lambda to dimensions
template <class Function>
constexpr decltype(auto) dimension_dispatch(Function&& function, UInt dim) {
return detail::tuple_dispatch<detail::dims_t>(
std::forward<Function>(function), dim);
}
/// \cond DO_NOT_DOCUMENT
namespace detail {
template <model_type type, bool boundary>
using dim_choice = std::integral_constant<
UInt, (boundary) ? model_type_traits<type>::boundary_dimension
: model_type_traits<type>::dimension>;
} // namespace detail
/// \endcond
/// Allocate a Grid unique_ptr
template <model_type type, bool boundary, typename T,
template <typename, UInt> class GridType = Grid,
class Container = void>
std::unique_ptr<GridType<T, detail::dim_choice<type, boundary>::value>>
allocateGrid(Container&& n, UInt nc) {
return std::make_unique<
GridType<T, detail::dim_choice<type, boundary>::value>>(std::begin(n),
std::end(n), nc);
}
/// Helper function for grid allocation with model type
template <bool boundary, typename T, typename Container>
decltype(auto) allocateGrid(model_type type, Container&& n) {
return model_type_dispatch(
[&n](auto&& type) -> std::unique_ptr<GridBase<T>> {
constexpr auto mtype = std::decay_t<decltype(type)>::value;
return allocateGrid<mtype, boundary, T>(
std::forward<Container>(n), model_type_traits<mtype>::components);
},
type);
}
/// Helper function for grid allocation with non-standard components
template <bool boundary, typename T, typename Container>
decltype(auto) allocateGrid(model_type type, Container&& n, UInt nc) {
return model_type_dispatch(
[&n, nc](auto&& type) -> std::unique_ptr<GridBase<T>> {
constexpr auto mtype = std::decay_t<decltype(type)>::value;
return allocateGrid<mtype, boundary, T>(std::forward<Container>(n), nc);
},
type);
}
} // namespace tamaas
/* -------------------------------------------------------------------------- */
#endif // MODEL_TYPE_HH

Event Timeline