15 #include "gretl/double_state.hpp"
22 template <
typename DispSpace,
typename DensitySpace>
24 const mfem::ParFiniteElementSpace& density_space)
26 static constexpr
int dim = DispSpace::components;
27 auto ke_integrator = std::make_shared<smith::Functional<double(DispSpace, DispSpace, DensitySpace)>>(
28 std::array<const mfem::ParFiniteElementSpace*, 3>{&velocity_space, &velocity_space, &density_space});
29 ke_integrator->AddDomainIntegral(
31 [&](
auto ,
auto ,
auto U,
auto V,
auto Rho) {
32 auto rho = get<VALUE>(Rho);
33 auto v = get<VALUE>(V);
34 auto ke = 0.5 * rho *
inner(v, v);
35 auto dx_dX = get<DERIVATIVE>(U) + Identity<dim>();
44 template <
typename DispSpace,
typename DensitySpace>
46 const std::shared_ptr<smith::Functional<
double(DispSpace, DispSpace, DensitySpace)>>& energy_func,
49 return gretl::create_state<double, double>(
51 [](
double forwardVal) {
return 0 * forwardVal; },
54 return (*energy_func)(0.0, *Disp, *Velo, *Density) * scaling;
61 auto de_ddisp = assemble(smith::get<smith::DERIVATIVE>(ddisp));
64 auto de_dvelo = assemble(smith::get<smith::DERIVATIVE>(dvelo));
67 auto de_ddensity = assemble(smith::get<smith::DERIVATIVE>(ddens));
69 Disp_dual->Add(scaling * ke_dual, *de_ddisp);
70 Velo_dual->Add(scaling * ke_dual, *de_dvelo);
71 Density_dual->Add(scaling * ke_dual, *de_ddensity);
79 FiniteElementDual& inputDual,
double objectiveBase, gretl::DataStore& dataStore,
double eps)
87 for (
int i = 0; i < sz; ++i) {
88 pert[i] = -1.2 + 2.02 * (double(i) / sz);
89 input[i] += eps * pert[i];
92 double objectivePlus = objectiveState.get();
94 double directionDeriv = 0.0;
95 for (
int i = 0; i < sz; ++i) {
96 directionDeriv += pert[i] * inputDual[i];
99 *inputState.get() = inputSave;
101 return std::make_pair(directionDeriv, (objectivePlus - objectiveBase) / eps);
105 inline auto checkGradients(
const gretl::State<double>& objectiveState, gretl::State<double, double>& inputState,
106 double& inputDual,
double objectiveBase, gretl::DataStore& dataStore,
double eps)
108 double inputSave = inputState.get();
110 inputState.set(inputSave + eps);
111 double objectivePlus = objectiveState.get();
112 inputState.set(inputSave);
113 return std::make_pair(inputDual, (objectivePlus - objectiveBase) / eps);
120 size_t num_fd_steps = 4,
bool printmore =
false)
122 auto& graph = objective.data_store();
128 double objectiveBase = objective.get();
131 gretl::set_as_objective(objective);
134 auto dual_vec = *input.get_dual();
136 std::vector<double> grad_errors;
137 auto [grad, grad_fd] =
checkGradients(objective, input, dual_vec, objectiveBase, graph, eps);
138 grad_errors.push_back(
std::abs(grad - grad_fd));
140 for (
size_t step = 1; step < num_fd_steps; ++step) {
142 std::tie(grad, grad_fd) =
checkGradients(objective, input, dual_vec, objectiveBase, graph, eps);
143 if (printmore) std::cout <<
"grad = " << grad <<
"\ngrad fd = " << grad_fd << std::endl;
144 grad_errors.push_back(
std::abs(grad - grad_fd));
147 for (
size_t step = 0; step < num_fd_steps; ++step) {
148 std::cout <<
"grad error " << step <<
" = " << grad_errors[step] << std::endl;
151 if (num_fd_steps >= 2) {
152 return std::log2(grad_errors[0] / grad_errors[num_fd_steps - 1]) /
static_cast<double>(num_fd_steps - 1);
161 inline double checkGradWrt(
const gretl::State<double>& objective, gretl::State<double, double>& input,
double eps,
162 size_t num_fd_steps = 4,
bool printmore =
false)
164 auto& graph = objective.data_store();
170 double objectiveBase = objective.get();
173 gretl::set_as_objective(objective);
176 auto dual = input.get_dual();
178 std::vector<double> grad_errors;
179 auto [grad, grad_fd] =
checkGradients(objective, input,
dual, objectiveBase, graph, eps);
180 grad_errors.push_back(
std::abs(grad - grad_fd));
182 for (
size_t step = 1; step < num_fd_steps; ++step) {
184 std::tie(grad, grad_fd) =
checkGradients(objective, input,
dual, objectiveBase, graph, eps);
185 if (printmore) std::cout <<
"grad = " << grad <<
"\ngrad fd = " << grad_fd << std::endl;
186 grad_errors.push_back(
std::abs(grad - grad_fd));
189 for (
size_t step = 0; step < num_fd_steps; ++step) {
190 std::cout <<
"grad error " << step <<
" = " << grad_errors[step] << std::endl;
193 if (num_fd_steps >= 2) {
194 return std::log2(grad_errors[0] / grad_errors[num_fd_steps - 1]) /
static_cast<double>(num_fd_steps - 1);
Class for encapsulating the dual vector space of a finite element space (i.e. the space of linear for...
Class for encapsulating the critical MFEM components of a primal finite element field.
mfem::ParFiniteElementSpace & space()
Returns a non-owning reference to the internal FESpace.
std::string name() const
Returns the name of the FEState (field)
Accelerator functionality.
auto checkGradients(const gretl::State< double > &objectiveState, FieldState &inputState, FiniteElementDual &inputDual, double objectiveBase, gretl::DataStore &dataStore, double eps)
testing utility to confirm order of convergence of the finite differences relative to the backprop gr...
std::shared_ptr< FiniteElementState > FEFieldPtr
typedef
gretl::State< double > computeKineticEnergy(const std::shared_ptr< smith::Functional< double(DispSpace, DispSpace, DensitySpace)>> &energy_func, smith::FieldState disp, smith::FieldState velo, smith::FieldState density, double scaling)
Utility function which computes the kinetic energy and returns it as a gretl state (with its vjp defi...
double checkGradWrt(const gretl::State< double > &objective, smith::FieldState &input, double eps, size_t num_fd_steps=4, bool printmore=false)
Testing utility function which runs a gretl graph num_fd_steps (with increasingly smaller finite diff...
gretl::State< FEFieldPtr, FEDualPtr > FieldState
typedef
auto differentiate_wrt(const mfem::Vector &v)
this function is intended to only be used in combination with smith::Functional::operator(),...
auto createKineticEnergyIntegrator(smith::Domain &domain, const mfem::ParFiniteElementSpace &velocity_space, const mfem::ParFiniteElementSpace &density_space)
Utility function to construct a smith::functional which evaluates the total kinetic energy.
std::shared_ptr< FiniteElementDual > FEDualPtr
typedef
SMITH_HOST_DEVICE auto abs(dual< gradient_type > x)
Implementation of absolute value function for dual numbers.
constexpr SMITH_HOST_DEVICE auto det(const isotropic_tensor< T, m, m > &I)
compute the determinant of an isotropic tensor
constexpr SMITH_HOST_DEVICE auto inner(const dual< S > &A, const dual< T > &B)
Specifies interface for evaluating scalar objective from fields and their field gradients.
Compile-time alias for a dimension.
a class for representing a geometric region that can be used for integration
Dual number struct (value plus gradient)