30 template <
int dim,
typename shape_type>
54 template <
typename trial_type,
typename space_type>
57 if constexpr (space_type{}.family == Family::H1 || space_type{}.family == Family::L2) {
62 auto trial_derivative =
dot(get<DERIVATIVE>(u), inv_J_);
67 if constexpr (space_type{}.family == Family::HCURL) {
68 auto modified_val =
dot(get<VALUE>(u), inv_J_);
69 if constexpr (dim == 2) {
70 auto modified_derivative = get<DERIVATIVE>(u) / detJ_;
73 if constexpr (dim == 3) {
74 auto modified_derivative =
dot(get<DERIVATIVE>(u),
transpose(J_));
91 template <
typename test_space,
typename q_func_type>
94 if constexpr (std::is_same_v<test_space, double>) {
97 if constexpr (test_space{}.family == Family::H1 || test_space{}.family == Family::L2) {
98 auto modified_flux =
dot(get<FLUX>(v), inv_JT_) * detJ_;
99 auto modified_source = get<SOURCE>(v) * detJ_;
103 if constexpr (test_space{}.family == Family::HCURL) {
104 auto modified_source =
dot(get<SOURCE>(v), inv_JT_) * detJ_;
105 if constexpr (dim == 3) {
106 auto modified_flux =
dot(get<FLUX>(v), J_);
117 using jacobian_type = std::remove_reference_t<decltype(get<DERIVATIVE>(std::declval<shape_type>()))>;
118 using detJ_type = decltype(
det(std::declval<jacobian_type>()));
119 using inv_J_type = decltype(
inv(std::declval<jacobian_type>()));
120 using inv_JT_type = decltype(
inv(
transpose(std::declval<jacobian_type>())));
148 template <
typename position_type,
typename shape_type>
151 auto x_prime = X + shape;
153 auto n =
cross(get<DERIVATIVE>(x_prime));
164 auto area_correction =
norm(n) /
norm(
cross(get<DERIVATIVE>(X)));
166 return area_correction;
193 template <
typename lambda,
typename coord_type,
typename shape_type,
typename space_types,
typename trial_types,
194 typename correction_type,
int... i>
196 const shape_type& shape,
const space_types& space_tuple,
197 const trial_types& arg_tuple,
const correction_type& correction,
198 std::integer_sequence<int, i...>)
201 "Argument and finite element space tuples are not the same size.");
203 auto x =
serac::tuple{get<VALUE>(position) + get<VALUE>(shape),
208 get<DERIVATIVE>(position) + get<DERIVATIVE>(shape) * get<DERIVATIVE>(position)};
210 return qf(t, x, correction.modify_trial_argument(serac::get<i>(space_tuple), serac::get<i>(arg_tuple))...);
239 template <
typename lambda,
typename coord_type,
typename state_type,
typename shape_type,
typename space_types,
240 typename trial_types,
typename correction_type,
int... i>
242 state_type& state,
const shape_type& shape,
243 const space_types& space_tuple,
244 const trial_types& arg_tuple,
245 const correction_type& correction,
246 std::integer_sequence<int, i...>)
249 "Argument and finite element space tuples are not the same size.");
251 auto x =
serac::tuple{get<VALUE>(position) + get<VALUE>(shape),
256 get<DERIVATIVE>(position) + get<DERIVATIVE>(shape) * get<DERIVATIVE>(position)};
258 return qf(t, x, state, correction.modify_trial_argument(serac::get<i>(space_tuple), serac::get<i>(arg_tuple))...);
264 template <
typename T1,
typename T2, ExecutionSpace exec = serac::ExecutionSpace::CPU>
265 class ShapeAwareFunctional;
285 template <
typename test,
typename shape,
typename... trials,
ExecutionSpace exec>
286 class ShapeAwareFunctional<shape, test(trials...), exec> {
288 static constexpr
tuple<trials...> trial_spaces{};
291 static constexpr test test_space{};
294 static constexpr shape shape_space{};
297 static constexpr uint32_t num_trial_spaces =
sizeof...(trials);
310 template <
typename test_type = test,
typename = std::enable_if_t<!std::is_same_v<
double, test_type>>>
311 ShapeAwareFunctional(
const mfem::ParFiniteElementSpace* shape_fes,
const mfem::ParFiniteElementSpace* test_fes,
312 std::array<const mfem::ParFiniteElementSpace*, num_trial_spaces> trial_fes)
314 static_assert(shape_space.family == Family::H1,
"Only H1 spaces allowed for shape displacements");
316 std::array<const mfem::ParFiniteElementSpace*, num_trial_spaces + 1> prepended_spaces;
318 prepended_spaces[0] = shape_fes;
320 for (uint32_t i = 0; i < num_trial_spaces; ++i) {
321 prepended_spaces[1 + i] = trial_fes[i];
324 functional_ = std::make_unique<Functional<test(shape, trials...), exec>>(test_fes, prepended_spaces);
336 template <
typename test_type = test,
typename = std::enable_if_t<std::is_same_v<
double, test_type>>>
338 std::array<const mfem::ParFiniteElementSpace*, num_trial_spaces> trial_fes)
340 static_assert(shape_space.family == Family::H1,
"Only H1 spaces allowed for shape displacements");
342 std::array<const mfem::ParFiniteElementSpace*, num_trial_spaces + 1> prepended_spaces;
344 prepended_spaces[0] = shape_fes;
346 for (uint32_t i = 0; i < num_trial_spaces; ++i) {
347 prepended_spaces[1 + i] = trial_fes[i];
350 functional_ = std::make_unique<Functional<double(shape, trials...), exec>>(prepended_spaces);
357 template <
typename Integrand,
int dim,
int... args>
358 struct ShapeAwareIntegrandWrapper {
375 template <
typename PositionType,
typename ShapeValueType,
typename... QFuncArgs>
377 QFuncArgs... qfunc_args)
const
380 auto reduced_trial_space_tuple =
make_tuple(get<args>(trial_spaces)...);
385 auto unmodified_qf_return = detail::apply_shape_aware_qf_helper(
386 integrand_, time, x, shape_val, reduced_trial_space_tuple, qfunc_tuple, shape_correction,
387 std::make_integer_sequence<
int,
sizeof...(qfunc_args)>{});
396 template <
typename Integrand,
int dim,
int... args>
397 struct ShapeAwareIntegrandWrapperWithState {
416 template <
typename PositionType,
typename StateType,
typename ShapeValueType,
typename... QFuncArgs>
418 QFuncArgs... qfunc_args)
const
421 auto reduced_trial_space_tuple =
make_tuple(get<args>(trial_spaces)...);
426 auto unmodified_qf_return = detail::apply_shape_aware_qf_helper_with_state(
427 integrand_, time, x, state, shape_val, reduced_trial_space_tuple, qfunc_tuple, shape_correction,
428 std::make_integer_sequence<
int,
sizeof...(qfunc_args)>{});
448 template <
int dim,
int... args,
typename lambda,
typename qpt_data_type =
Nothing>
452 if constexpr (std::is_same_v<qpt_data_type, Nothing>) {
454 ShapeAwareIntegrandWrapper<lambda, dim, args...>(integrand), domain, qdata);
457 ShapeAwareIntegrandWrapperWithState<lambda, dim, args...>(integrand), domain,
466 template <
typename test_type,
typename Integrand,
int dim,
int... args>
467 struct ShapeAwareInteriorBoundaryIntegrandWrapper {
484 template <
typename PositionType,
typename ShapeValueType,
typename... QFuncArgs>
486 QFuncArgs... qfunc_args)
const
488 auto unmodified_qf_returns = integrand_(time, x + shape_val, qfunc_args...);
489 auto correction = detail::compute_boundary_area_correction(x, shape_val);
490 return serac::tuple{correction * serac::get<0>(unmodified_qf_returns),
491 correction * serac::get<1>(unmodified_qf_returns)};
499 template <
typename Integrand,
int dim,
int... args>
500 struct ShapeAwareInteriorBoundaryIntegrandWrapper<double, Integrand, dim, args...> {
517 template <
typename PositionType,
typename ShapeValueType,
typename... QFuncArgs>
519 QFuncArgs... qfunc_args)
const
521 auto unmodified_qf_returns = integrand_(time, x + shape_val, qfunc_args...);
522 auto correction = detail::compute_boundary_area_correction(x, shape_val);
523 return correction * unmodified_qf_returns;
541 template <
int dim,
int... args,
typename lambda>
544 functional_->AddInteriorFaceIntegral(
546 ShapeAwareInteriorBoundaryIntegrandWrapper<test, lambda, dim, args...>(integrand), domain);
553 template <
typename Integrand,
int dim,
int... args>
554 struct ShapeAwareBoundaryIntegrandWrapper {
571 template <
typename PositionType,
typename ShapeValueType,
typename... QFuncArgs>
573 QFuncArgs... qfunc_args)
const
575 auto unmodified_qf_return = integrand_(time, x + shape_val, qfunc_args...);
576 return unmodified_qf_return * detail::compute_boundary_area_correction(x, shape_val);
594 template <
int dim,
int... args,
typename lambda>
598 ShapeAwareBoundaryIntegrandWrapper<lambda, dim, args...>(integrand), domain);
616 template <uint32_t wrt,
typename... T>
635 template <
typename... T>
638 return (*functional_)(t, args...);
649 void updateQdata(
bool update_flag) { functional_->updateQdata(update_flag); }
653 std::unique_ptr<Functional<test(shape, trials...), exec>> functional_;
This file contains the interface used for initializing/terminating any hardware accelerator-related f...
#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...
void AddBoundaryIntegral(Dimension< dim >, DependsOn< args... >, const lambda &integrand, Domain &domain)
Adds a boundary integral term to the weak formulationx of the PDE.
void AddDomainIntegral(Dimension< dim >, DependsOn< args... >, const lambda &integrand, Domain &domain, std::shared_ptr< QuadratureData< qpt_data_type >> qdata=NoQData)
Adds a domain integral term to the weak formulation of the PDE.
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 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...
void AddInteriorFaceIntegral(Dimension< dim >, DependsOn< args... >, const lambda &integrand, Domain &domain)
Adds an interior face integral term to the weak formulation of the PDE.
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(const 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(const 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.
a class for representing a geometric region that can be used for integration
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.
ShapeAwareInteriorBoundaryIntegrandWrapper(Integrand integrand)
Constructor for functor.
SERAC_HOST_DEVICE auto operator()(double time, PositionType x, ShapeValueType shape_val, QFuncArgs... qfunc_args) const
integrand call
Integrand integrand_
integrand
ShapeAwareInteriorBoundaryIntegrandWrapper(Integrand integrand)
Constructor for functor.
Integrand integrand_
integrand
SERAC_HOST_DEVICE auto operator()(double time, PositionType x, ShapeValueType shape_val, QFuncArgs... qfunc_args) const
integrand call
ShapeAwareBoundaryIntegrandWrapper(Integrand integrand)
Constructor for functor.
SERAC_HOST_DEVICE auto operator()(double time, PositionType x, ShapeValueType shape_val, QFuncArgs... qfunc_args) const
integrand call
Integrand integrand_
integrand
Integrand integrand_
integrand
ShapeAwareIntegrandWrapperWithState(Integrand integrand)
Constructor for functor.
SERAC_HOST_DEVICE auto operator()(double time, PositionType x, StateType &state, ShapeValueType shape_val, QFuncArgs... qfunc_args) const
integrand call
ShapeAwareIntegrandWrapper(Integrand integrand)
Constructor for functor.
SERAC_HOST_DEVICE auto operator()(double time, PositionType x, ShapeValueType shape_val, QFuncArgs... qfunc_args) const
integrand call
Integrand integrand_
Integrand.
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...
SERAC_HOST_DEVICE 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 ...