21 constexpr
int SOURCE = 0;
22 constexpr
int FLUX = 1;
23 constexpr
int VALUE = 0;
24 constexpr
int DERIVATIVE = 1;
36 template <
int dim,
typename shape_type>
60 template <
typename trial_type,
typename space_type>
63 if constexpr (space_type{}.family == Family::H1 || space_type{}.family == Family::L2) {
68 auto trial_derivative =
dot(get<DERIVATIVE>(u), inv_J_);
73 if constexpr (space_type{}.family == Family::HCURL) {
74 auto modified_val =
dot(get<VALUE>(u), inv_J_);
75 if constexpr (dim == 2) {
76 auto modified_derivative = get<DERIVATIVE>(u) / detJ_;
79 if constexpr (dim == 3) {
80 auto modified_derivative =
dot(get<DERIVATIVE>(u),
transpose(J_));
97 template <
typename test_space,
typename q_func_type>
100 if constexpr (std::is_same_v<test_space, double>) {
103 if constexpr (test_space{}.family == Family::H1 || test_space{}.family == Family::L2) {
104 auto modified_flux =
dot(get<FLUX>(v), inv_JT_) * detJ_;
105 auto modified_source = get<SOURCE>(v) * detJ_;
109 if constexpr (test_space{}.family == Family::HCURL) {
110 auto modified_source =
dot(get<SOURCE>(v), inv_JT_) * detJ_;
111 if constexpr (dim == 3) {
112 auto modified_flux =
dot(get<FLUX>(v), J_);
123 using jacobian_type = std::remove_reference_t<decltype(get<DERIVATIVE>(std::declval<shape_type>()))>;
124 using detJ_type = decltype(
det(std::declval<jacobian_type>()));
125 using inv_J_type = decltype(
inv(std::declval<jacobian_type>()));
126 using inv_JT_type = decltype(
inv(
transpose(std::declval<jacobian_type>())));
154 template <
typename position_type,
typename shape_type>
157 auto x_prime = X + shape;
159 auto n =
cross(get<DERIVATIVE>(x_prime));
170 auto area_correction =
norm(n) /
norm(
cross(get<DERIVATIVE>(X)));
172 return area_correction;
199 template <
typename lambda,
typename coord_type,
typename shape_type,
typename space_types,
typename trial_types,
200 typename correction_type,
int... i>
202 const shape_type& shape,
const space_types& space_tuple,
203 const trial_types& arg_tuple,
const correction_type& correction,
204 std::integer_sequence<int, i...>)
207 "Argument and finite element space tuples are not the same size.");
209 auto x =
serac::tuple{get<VALUE>(position) + get<VALUE>(shape),
214 get<DERIVATIVE>(position) + get<DERIVATIVE>(shape) * get<DERIVATIVE>(position)};
216 return qf(t, x, correction.modify_trial_argument(serac::get<i>(space_tuple), serac::get<i>(arg_tuple))...);
245 template <
typename lambda,
typename coord_type,
typename state_type,
typename shape_type,
typename space_types,
246 typename trial_types,
typename correction_type,
int... i>
248 state_type& state,
const shape_type& shape,
249 const space_types& space_tuple,
250 const trial_types& arg_tuple,
251 const correction_type& correction,
252 std::integer_sequence<int, i...>)
255 "Argument and finite element space tuples are not the same size.");
257 auto x =
serac::tuple{get<VALUE>(position) + get<VALUE>(shape),
262 get<DERIVATIVE>(position) + get<DERIVATIVE>(shape) * get<DERIVATIVE>(position)};
264 return qf(t, x, state, correction.modify_trial_argument(serac::get<i>(space_tuple), serac::get<i>(arg_tuple))...);
270 template <
typename T1,
typename T2, ExecutionSpace exec = serac::default_execution_space>
271 class ShapeAwareFunctional;
291 template <
typename test,
typename shape,
typename... trials,
ExecutionSpace exec>
292 class ShapeAwareFunctional<shape, test(trials...), exec> {
294 static constexpr
tuple<trials...> trial_spaces{};
297 static constexpr test test_space{};
300 static constexpr shape shape_space{};
303 static constexpr uint32_t num_trial_spaces =
sizeof...(trials);
316 template <
typename test_type = test,
typename = std::enable_if_t<!std::is_same_v<
double, test_type>>>
317 ShapeAwareFunctional(
const mfem::ParFiniteElementSpace* shape_fes,
const mfem::ParFiniteElementSpace* test_fes,
318 std::array<const mfem::ParFiniteElementSpace*, num_trial_spaces> trial_fes)
320 static_assert(shape_space.family == Family::H1,
"Only H1 spaces allowed for shape displacements");
322 std::array<const mfem::ParFiniteElementSpace*, num_trial_spaces + 1> prepended_spaces;
324 prepended_spaces[0] = shape_fes;
326 for (uint32_t i = 0; i < num_trial_spaces; ++i) {
327 prepended_spaces[1 + i] = trial_fes[i];
330 functional_ = std::make_unique<Functional<test(shape, trials...), exec>>(test_fes, prepended_spaces);
342 template <
typename test_type = test,
typename = std::enable_if_t<std::is_same_v<
double, test_type>>>
344 std::array<const mfem::ParFiniteElementSpace*, num_trial_spaces> trial_fes)
346 static_assert(shape_space.family == Family::H1,
"Only H1 spaces allowed for shape displacements");
348 std::array<const mfem::ParFiniteElementSpace*, num_trial_spaces + 1> prepended_spaces;
350 prepended_spaces[0] = shape_fes;
352 for (uint32_t i = 0; i < num_trial_spaces; ++i) {
353 prepended_spaces[1 + i] = trial_fes[i];
356 functional_ = std::make_unique<Functional<double(shape, trials...), exec>>(prepended_spaces);
375 template <
int dim,
int... args,
typename lambda,
typename domain_type,
typename qpt_data_type =
Nothing>
379 if constexpr (std::is_same_v<qpt_data_type, Nothing>) {
380 functional_->AddDomainIntegral(
382 [integrand](
double time,
auto x,
auto shape_val,
auto... qfunc_args) {
384 auto reduced_trial_space_tuple =
make_tuple(get<args>(trial_spaces)...);
388 auto unmodified_qf_return = detail::apply_shape_aware_qf_helper(
389 integrand, time, x, shape_val, reduced_trial_space_tuple, qfunc_tuple, shape_correction,
390 std::make_integer_sequence<
int,
sizeof...(qfunc_args)>{});
395 functional_->AddDomainIntegral(
397 [integrand](
double time,
auto x,
auto& state,
auto shape_val,
auto... qfunc_args) {
399 auto reduced_trial_space_tuple =
make_tuple(get<args>(trial_spaces)...);
403 auto unmodified_qf_return = detail::apply_shape_aware_qf_helper_with_state(
404 integrand, time, x, state, shape_val, reduced_trial_space_tuple, qfunc_tuple, shape_correction,
405 std::make_integer_sequence<
int,
sizeof...(qfunc_args)>{});
426 template <
int dim,
int... args,
typename lambda,
typename domain_type>
429 functional_->AddBoundaryIntegral(
431 [integrand](
double time,
auto x,
auto shape_val,
auto... qfunc_args) {
432 auto unmodified_qf_return = integrand(time, x + shape_val, qfunc_args...);
434 return unmodified_qf_return * detail::compute_boundary_area_correction(x, shape_val);
454 template <uint32_t wrt,
typename... T>
473 template <
typename... T>
476 return (*functional_)(t, args...);
487 void updateQdata(
bool update_flag) { functional_->updateQdata(update_flag); }
491 std::unique_ptr<Functional<test(shape, trials...), exec>> functional_;
#define SERAC_HOST_DEVICE
Macro that evaluates to __host__ __device__ when compiling with nvcc and does nothing on a host compi...
auto operator()(double t, const T &... args)
This function lets the user evaluate the serac::ShapeAwareFunctional with the given trial space value...
auto operator()(DifferentiateWRT< wrt >, double t, const T &... args)
This function lets the user evaluate the serac::ShapeAwareFunctional with the given trial space value...
ShapeAwareFunctional(const mfem::ParFiniteElementSpace *shape_fes, const mfem::ParFiniteElementSpace *test_fes, std::array< const mfem::ParFiniteElementSpace *, num_trial_spaces > trial_fes)
Constructs using mfem::ParFiniteElementSpace objects corresponding to the test/trial spaces.
void AddBoundaryIntegral(Dimension< dim >, DependsOn< args... >, lambda &&integrand, domain_type &domain)
Adds a boundary integral term to the weak formulation of the PDE.
void AddDomainIntegral(Dimension< dim >, DependsOn< args... >, lambda &&integrand, domain_type &domain, std::shared_ptr< QuadratureData< qpt_data_type >> qdata=NoQData)
Adds a domain integral term to the weak formulation of the PDE.
void updateQdata(bool update_flag)
A flag to update the quadrature data for this operator following the computation.
ShapeAwareFunctional(const mfem::ParFiniteElementSpace *shape_fes, std::array< const mfem::ParFiniteElementSpace *, num_trial_spaces > trial_fes)
Constructs a QOI functional using mfem::ParFiniteElementSpace objects corresponding to the trial spac...
Implementation of the quadrature-function-based functional enabling rapid development of FEM formulat...
Accelerator functionality.
constexpr SERAC_HOST_DEVICE auto dot(const isotropic_tensor< S, m, m > &I, const tensor< T, m, n... > &A)
dot product between an isotropic and (nonisotropic) tensor
std::shared_ptr< QuadratureData< Nothing > > NoQData
a single instance of a QuadratureData container of Nothings, since they are all interchangeable
constexpr T & get(variant< T0, T1 > &v)
Returns the variant member of specified type.
SERAC_HOST_DEVICE tuple< T... > make_tuple(const T &... args)
helper function for combining a list of values into a tuple
constexpr SERAC_HOST_DEVICE auto det(const isotropic_tensor< T, m, m > &I)
compute the determinant of an isotropic tensor
constexpr SERAC_HOST_DEVICE auto norm(const isotropic_tensor< T, m, m > &I)
compute the Frobenius norm (sqrt(tr(dot(transpose(I), I)))) of an isotropic tensor
auto cross(const tensor< T, 3, 2 > &A)
compute the cross product of the columns of A: A(:,1) x A(:,2)
constexpr SERAC_HOST_DEVICE auto inv(const isotropic_tensor< T, m, m > &I)
return the inverse of an isotropic tensor
constexpr SERAC_HOST_DEVICE auto transpose(const isotropic_tensor< T, m, m > &I)
return the transpose of an isotropic tensor
ExecutionSpace
enum used for signalling whether or not to perform certain calculations on the CPU or GPU
constexpr SERAC_HOST_DEVICE isotropic_tensor< double, m, m > Identity()
return the identity matrix of the specified size
SERAC_HOST_DEVICE auto apply_shape_aware_qf_helper_with_state(lambda &&qf, double t, const coord_type &position, state_type &state, const shape_type &shape, const space_types &space_tuple, const trial_types &arg_tuple, const correction_type &correction, std::integer_sequence< int, i... >)
A helper function to modify all of the trial function input derivatives according to the given shape ...
SERAC_HOST_DEVICE auto apply_shape_aware_qf_helper(lambda &&qf, double t, const coord_type &position, const shape_type &shape, const space_types &space_tuple, const trial_types &arg_tuple, const correction_type &correction, std::integer_sequence< int, i... >)
A helper function to modify all of the trial function input derivatives according to the given shape ...
SERAC_HOST_DEVICE auto compute_boundary_area_correction(const position_type &X, const shape_type &shape)
Compute the boundary area correction term for boundary integrals with a shape displacement field.
Compile-time alias for a dimension.
these classes are a little confusing. These two special types represent the similar (but different) c...
A class for storing and access user-defined types at quadrature points.
A helper struct that contains the appropriate parent-to-physical and physical-to-parent transformatio...
SERAC_HOST_DEVICE auto modify_trial_argument(space_type, const trial_type &u) const
Modify the trial argument using the correct physical to reference to shape-adjusted transformation fo...
ShapeCorrection(Dimension< dim >, shape_type p)
Construct a new Shape Correction object with the appropriate transformations for a shape field.
SERAC_HOST_DEVICE auto modify_shape_aware_qf_return(test_space, const q_func_type &v)
Modify the quadrature function return value using the correct shape-adjusted to reference transformat...
This is a class that mimics most of std::tuple's interface, except that it is usable in CUDA kernels ...