Skip to content

Commit

Permalink
Merge branch 'io-for-strong-type' into 'master'
Browse files Browse the repository at this point in the history
Enable reflected I/O for StrongTypes

See merge request ogs/ogs!5004
  • Loading branch information
endJunction committed Jun 10, 2024
2 parents f52a3b5 + 2d00072 commit a6a646a
Show file tree
Hide file tree
Showing 12 changed files with 192 additions and 99 deletions.
30 changes: 30 additions & 0 deletions BaseLib/BoostMP11Utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* \file
* \copyright
* Copyright (c) 2012-2024, OpenGeoSys Community (http://www.opengeosys.org)
* Distributed under a Modified BSD License.
* See accompanying file LICENSE.txt or
* http://www.opengeosys.org/project/license
*/

#pragma once

#include <boost/mp11.hpp>

namespace boost::mp11
{
// Alias to be used together with static_assert to improve possible compile
// error messages.
template <typename List, typename Elem>
constexpr bool mp_contains_v = mp_contains<List, Elem>::value;

// Alias to be used together with static_assert to improve possible compile
// error messages
template <typename Set>
constexpr bool mp_is_list_v = mp_is_list<Set>::value;

// Alias to be used together with static_assert to improve possible compile
// error messages
template <typename Set>
constexpr bool mp_is_set_v = mp_is_set<Set>::value;
} // namespace boost::mp11
4 changes: 2 additions & 2 deletions ProcessLib/Graph/Apply.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,14 +229,14 @@ auto applyImpl(Function&& f, Args&&... args) ->
mp_transform<std::remove_cvref_t, FlattenedTuple>;

static_assert(
boost::mp11::mp_is_set<FlattenedTupleOfPlainTypes>::value,
mp_is_set_v<FlattenedTupleOfPlainTypes>,
"The types of all elements of all passed tuples must be unique.");

using FunctionArgumentTypesPlain =
typename detail::GetFunctionArgumentTypesPlain<FunctionPlain>::type;

static_assert(
boost::mp11::mp_is_set<FunctionArgumentTypesPlain>::value,
mp_is_set_v<FunctionArgumentTypesPlain>,
"The argument types of the function to be called must be unique.");

return unpackAndInvoke(FunctionArgumentTypesPlain{},
Expand Down
16 changes: 4 additions & 12 deletions ProcessLib/Graph/Get.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

#include <boost/mp11.hpp>

#include "BaseLib/BoostMP11Utils.h"

namespace ProcessLib::Graph
{
namespace detail
Expand Down Expand Up @@ -43,16 +45,6 @@ struct GetFlattenedTupleTypes

using type = boost::mp11::mp_flatten<std::tuple<Tuples...>>;
};

// Alias to be used together with static_assert to improve possible compile
// error messages.
template <typename List, typename Elem>
constexpr bool mp_contains_v = boost::mp11::mp_contains<List, Elem>::value;

// Alias to be used together with static_assert to improve possible compile
// error messages
template <typename Set>
constexpr bool mp_is_set_v = boost::mp11::mp_is_set<Set>::value;
} // namespace detail

/// Type-based access of an element of any of the passed tuples.
Expand All @@ -77,10 +69,10 @@ auto& get(Tuples&... ts)
mp_transform<std::remove_cvref_t, FlattenedTuple>;

static_assert(
detail::mp_is_set_v<FlattenedTupleOfPlainTypes>,
mp_is_set_v<FlattenedTupleOfPlainTypes>,
"The types of all elements of all passed tuples must be unique.");

static_assert(detail::mp_contains_v<FlattenedTupleOfPlainTypes, T>,
static_assert(mp_contains_v<FlattenedTupleOfPlainTypes, T>,
"Type T must be inside any of the passed tuples.");

return detail::getImpl<T>(ts...);
Expand Down
141 changes: 103 additions & 38 deletions ProcessLib/Reflection/ReflectionIPData.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,41 +12,15 @@

#include <boost/mp11.hpp>

#include "BaseLib/BoostMP11Utils.h"
#include "BaseLib/StrongType.h"
#include "MathLib/KelvinVector.h"
#include "ReflectionData.h"

namespace ProcessLib::Reflection
{
namespace detail
{
template <typename T>
concept has_reflect = requires { T::reflect(); };

template <typename... Ts>
auto reflect(std::type_identity<std::tuple<Ts...>>)
{
using namespace boost::mp11;

// The types Ts... must be unique. Duplicate types are incompatible with the
// concept of "reflected" I/O: they would lead to duplicate names for the
// I/O data.
static_assert(mp_is_set<mp_list<Ts...>>::value);

return reflectWithoutName<std::tuple<Ts...>>(
[](auto& tuple_) -> auto& { return std::get<Ts>(tuple_); }...);
}

template <has_reflect T>
auto reflect(std::type_identity<T>)
{
return T::reflect();
}

template <typename T>
concept is_reflectable = requires {
ProcessLib::Reflection::detail::reflect(std::type_identity<T>{});
};

/**
* Raw data is data that will be read or written, e.g., double values or Eigen
* vectors.
Expand Down Expand Up @@ -126,6 +100,79 @@ struct NumberOfComponents
{
};

template <typename T>
concept has_reflect = requires
{
T::reflect();
};

template <typename... Ts>
auto reflect(std::type_identity<std::tuple<Ts...>>)
{
using namespace boost::mp11;

// The types Ts... must be unique. Duplicate types are incompatible with the
// concept of "reflected" I/O: they would lead to duplicate names for the
// I/O data.
static_assert(mp_is_set_v<mp_list<Ts...>>);

return reflectWithoutName<std::tuple<Ts...>>(
[](auto& tuple_) -> auto& { return std::get<Ts>(tuple_); }...);
}

template <has_reflect T>
auto reflect(std::type_identity<T>)
{
return T::reflect();
}

template <typename T>
concept has_ioName = requires(T* t)
{
ioName(t);
};

template <typename T, typename Tag>
auto reflect(std::type_identity<BaseLib::StrongType<T, Tag>>)
{
using ST = BaseLib::StrongType<T, Tag>;

auto accessor = [](auto& o) -> auto&
{
return *o;
};

// Maybe in the future we might want to lift the following two constraints.
// But beware: that generalization has to be tested thoroughly such that we
// don't accidentally produce I/O data without name and the like.
static_assert(
has_ioName<Tag>,
/* We use ioName(Tag* tag), because it works with an incomplete type
* Tag, as opposed to ioName(Tag tag), i.e. declaring
* std::string_view ioName(struct SomeTag*);
* is possible, whereas
* std::string_view ioName(struct SomeTag);
* is not.
* This choice makes the code for every ioName() definition rather
* compact.
*/
"For I/O of StrongType<T, Tag> you have to define an ioName(Tag* tag) "
"function returning the name used for I/O.");
static_assert(
is_raw_data_v<T>,
"I/O of StrongTypes is supported only for StrongTypes wrapping 'raw "
"data' such as double values, vectors and matrices.");

return std::tuple{makeReflectionData<ST>(
std::string{ioName(static_cast<Tag*>(nullptr))}, std::move(accessor))};
}

template <typename T>
concept is_reflectable = requires
{
ProcessLib::Reflection::detail::reflect(std::type_identity<T>{});
};

/** A function object taking a local assembler as its argument and returning a
* <tt>std::vector\<double\></tt> of some specific "flattened" integration point
* (IP) data.
Expand Down Expand Up @@ -328,6 +375,13 @@ void forEachReflectedFlattenedIPDataAccessor(
Accessor_CurrentLevelFromIPDataVecElement const&
accessor_current_level_from_ip_data_vec_element)
{
static_assert(boost::mp11::mp_is_list_v<ReflectionDataTuple>,
"The passed reflection data is not a std::tuple.");
static_assert(
std::is_same_v<ReflectionDataTuple,
boost::mp11::mp_rename<ReflectionDataTuple, std::tuple>>,
"The passed reflection data is not a std::tuple.");

boost::mp11::tuple_for_each(
reflection_data,
[&accessor_ip_data_vec_in_loc_asm,
Expand Down Expand Up @@ -357,12 +411,13 @@ void forEachReflectedFlattenedIPDataAccessor(
}
else
{
static_assert(is_raw_data<Member>::value,
static_assert(is_raw_data_v<Member>,
"The current member is not reflectable, so we "
"expect it to be raw data.");

constexpr unsigned num_comp = NumberOfComponents<Member>::value;

assert(!refl_data.name.empty());
callback(refl_data.name, num_comp,
getFlattenedIPDataFromLocAsm<Dim>(
accessor_ip_data_vec_in_loc_asm,
Expand Down Expand Up @@ -401,7 +456,14 @@ template <int Dim, typename LocAsmIF, typename Callback, typename ReflData>
void forEachReflectedFlattenedIPDataAccessor(ReflData const& reflection_data,
Callback const& callback)
{
boost::mp11::tuple_for_each(
using namespace boost::mp11;

static_assert(mp_is_list_v<ReflData>,
"The passed reflection data is not a std::tuple.");
static_assert(std::is_same_v<ReflData, mp_rename<ReflData, std::tuple>>,
"The passed reflection data is not a std::tuple.");

tuple_for_each(
reflection_data,
[&callback]<typename Class, typename Accessor>(
ReflectionData<Class, Accessor> const& refl_data)
Expand All @@ -416,13 +478,13 @@ void forEachReflectedFlattenedIPDataAccessor(ReflData const& reflection_data,

// AccessorResult must be a std::vector<SomeType, SomeAllocator>. We
// check that, now.
static_assert(boost::mp11::mp_is_list<AccessorResult>::
value); // std::vector<SomeType, SomeAllocator>
// is a list in the Boost MP11 sense
static_assert(
std::is_same_v<
AccessorResult,
boost::mp11::mp_rename<AccessorResult, std::vector>>,
mp_is_list_v<AccessorResult>); // std::vector<SomeType,
// SomeAllocator> is a list in
// the Boost MP11 sense
static_assert(
std::is_same_v<AccessorResult,
mp_rename<AccessorResult, std::vector>>,
"We expect a std::vector, here.");
// Now, we know that AccessorResult is std::vector<Member>. To be
// more specific, AccessorResult is a std::vector<IPData> and Member
Expand All @@ -432,7 +494,9 @@ void forEachReflectedFlattenedIPDataAccessor(ReflData const& reflection_data,
auto accessor_ip_data_vec_in_loc_asm =
[ip_data_vector_accessor =
refl_data.accessor](LocAsmIF const& loc_asm) -> auto const&
{ return ip_data_vector_accessor(loc_asm); };
{
return ip_data_vector_accessor(loc_asm);
};

if constexpr (detail::is_reflectable<Member>)
{
Expand All @@ -443,13 +507,14 @@ void forEachReflectedFlattenedIPDataAccessor(ReflData const& reflection_data,
}
else
{
static_assert(detail::is_raw_data<Member>::value,
static_assert(detail::is_raw_data_v<Member>,
"The current member is not reflectable, so we "
"expect it to be raw data.");

constexpr unsigned num_comp =
detail::NumberOfComponents<Member>::value;

assert(!refl_data.name.empty());
callback(refl_data.name, num_comp,
detail::getFlattenedIPDataFromLocAsm<Dim>(
accessor_ip_data_vec_in_loc_asm));
Expand Down
9 changes: 4 additions & 5 deletions ProcessLib/RichardsMechanics/RichardsMechanicsFEM-impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -809,8 +809,8 @@ void RichardsMechanicsLocalAssembler<ShapeFunctionDisplacement,

auto const mu = liquid_phase.property(MPL::PropertyType::viscosity)
.template value<double>(variables, x_position, t, dt);
std::get<ProcessLib::ThermoRichardsMechanics::LiquidViscosityData>(CD)
.viscosity = mu;
*std::get<ProcessLib::ThermoRichardsMechanics::LiquidViscosityData>(CD) =
mu;

// Swelling and possibly volumetric strain rate update.
updateSwellingStressAndVolumetricStrain<DisplacementDim>(
Expand Down Expand Up @@ -1141,9 +1141,8 @@ void RichardsMechanicsLocalAssembler<ShapeFunctionDisplacement,
DisplacementDim>>(CD)
.Ki;
double const mu =
std::get<ProcessLib::ThermoRichardsMechanics::LiquidViscosityData>(
CD)
.viscosity;
*std::get<ProcessLib::ThermoRichardsMechanics::LiquidViscosityData>(
CD);

GlobalDimMatrixType const rho_Ki_over_mu = K_intrinsic * rho_LR / mu;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@

#include "DarcyLaw.h"

#include "MaterialLib/MPL/Utils/FormEigenTensor.h"

namespace ProcessLib::ThermoRichardsMechanics
{
template <int DisplacementDim>
Expand All @@ -23,10 +21,10 @@ void DarcyLawModel<DisplacementDim>::eval(
ThermoOsmosisData<DisplacementDim> const& th_osmosis_data,
DarcyLawData<DisplacementDim>& out) const
{
out.v_darcy = perm_data.Ki / mu_L_data.viscosity *
(perm_data.k_rel *
(p_cap_data.grad_p_cap + rho_L_data.rho_LR * b_)) +
th_osmosis_data.seepage_velocity_contribution;
*out = perm_data.Ki / mu_L_data() *
(perm_data.k_rel *
(p_cap_data.grad_p_cap + rho_L_data.rho_LR * b_)) +
th_osmosis_data.seepage_velocity_contribution;
}

template struct DarcyLawModel<2>;
Expand Down
18 changes: 7 additions & 11 deletions ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/DarcyLaw.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#pragma once

#include "BaseLib/StrongType.h"
#include "LiquidDensity.h"
#include "LiquidViscosity.h"
#include "PermeabilityData.h"
Expand All @@ -19,18 +20,13 @@
namespace ProcessLib::ThermoRichardsMechanics
{
template <int DisplacementDim>
struct DarcyLawData
{
Eigen::Vector<double, DisplacementDim> v_darcy;

static auto reflect()
{
using Self = DarcyLawData<DisplacementDim>;
using DarcyLawData = BaseLib::StrongType<Eigen::Vector<double, DisplacementDim>,
struct DarcyLawDataTag>;

return ProcessLib::Reflection::reflectWithName("velocity",
&Self::v_darcy);
}
};
constexpr std::string_view ioName(struct DarcyLawDataTag*)
{
return "velocity";
}

template <int DisplacementDim>
struct DarcyLawModel
Expand Down
Loading

0 comments on commit a6a646a

Please sign in to comment.