15 #include "gretl/double_state.hpp"
23 template <
typename DispSpace,
typename DensitySpace>
25 const mfem::ParFiniteElementSpace& density_space)
27 static constexpr
int dim = DispSpace::components;
28 auto ke_integrator = std::make_shared<smith::Functional<double(DispSpace, DispSpace, DensitySpace)>>(
29 std::array<const mfem::ParFiniteElementSpace*, 3>{&velocity_space, &velocity_space, &density_space});
30 ke_integrator->AddDomainIntegral(
32 [&](
auto ,
auto ,
auto U,
auto V,
auto Rho) {
33 auto rho = get<VALUE>(Rho);
34 auto v = get<VALUE>(V);
35 auto ke = 0.5 * rho *
inner(v, v);
36 auto dx_dX = get<DERIVATIVE>(U) + Identity<dim>();
45 template <
typename DispSpace,
typename DensitySpace>
47 const std::shared_ptr<smith::Functional<
double(DispSpace, DispSpace, DensitySpace)>>& energy_func,
50 return gretl::create_state<double, double>(
52 [](
double forwardVal) {
return 0 * forwardVal; },
55 return (*energy_func)(0.0, *Disp, *Velo, *Density) * scaling;
62 auto de_ddisp = assemble(smith::get<smith::DERIVATIVE>(ddisp));
65 auto de_dvelo = assemble(smith::get<smith::DERIVATIVE>(dvelo));
68 auto de_ddensity = assemble(smith::get<smith::DERIVATIVE>(ddens));
70 Disp_dual->Add(scaling * ke_dual, *de_ddisp);
71 Velo_dual->Add(scaling * ke_dual, *de_dvelo);
72 Density_dual->Add(scaling * ke_dual, *de_ddensity);
80 FiniteElementDual& inputDual,
double objectiveBase, gretl::DataStore& dataStore,
double eps)
88 for (
int i = 0; i < sz; ++i) {
89 pert[i] = -1.2 + 2.02 * (double(i) / sz);
90 input[i] += eps * pert[i];
93 double objectivePlus = objectiveState.get();
95 double directionDeriv = 0.0;
96 for (
int i = 0; i < sz; ++i) {
97 directionDeriv += pert[i] * inputDual[i];
100 *inputState.get() = inputSave;
102 return std::make_pair(directionDeriv, (objectivePlus - objectiveBase) / eps);
106 inline auto checkGradients(
const gretl::State<double>& objectiveState, gretl::State<double, double>& inputState,
107 double& inputDual,
double objectiveBase, gretl::DataStore& dataStore,
double eps)
109 double inputSave = inputState.get();
111 inputState.set(inputSave + eps);
112 double objectivePlus = objectiveState.get();
113 inputState.set(inputSave);
114 return std::make_pair(inputDual, (objectivePlus - objectiveBase) / eps);
121 size_t num_fd_steps = 4,
bool printmore =
false)
123 auto& graph = objective.data_store();
129 double objectiveBase = objective.get();
132 gretl::set_as_objective(objective);
135 auto dual_vec = input.get_dual();
137 std::vector<double> grad_errors;
138 auto [grad, grad_fd] =
checkGradients(objective, input, *dual_vec, objectiveBase, graph, eps);
139 grad_errors.push_back(
std::abs(grad - grad_fd));
141 for (
size_t step = 1; step < num_fd_steps; ++step) {
143 std::tie(grad, grad_fd) =
checkGradients(objective, input, *dual_vec, objectiveBase, graph, eps);
144 if (printmore) std::cout <<
"grad = " << grad <<
"\ngrad fd = " << grad_fd << std::endl;
145 grad_errors.push_back(
std::abs(grad - grad_fd));
148 for (
size_t step = 0; step < num_fd_steps; ++step) {
149 std::cout <<
"grad error " << step <<
" = " << grad_errors[step] << std::endl;
152 if (num_fd_steps >= 2) {
153 return std::log2(grad_errors[0] / grad_errors[num_fd_steps - 1]) /
static_cast<double>(num_fd_steps - 1);
162 inline double checkGradWrt(
const gretl::State<double>& objective, gretl::State<double, double>& input,
double eps,
163 size_t num_fd_steps = 4,
bool printmore =
false)
165 auto& graph = objective.data_store();
171 double objectiveBase = objective.get();
174 gretl::set_as_objective(objective);
177 auto dual = input.get_dual();
179 std::vector<double> grad_errors;
180 auto [grad, grad_fd] =
checkGradients(objective, input,
dual, objectiveBase, graph, eps);
181 grad_errors.push_back(
std::abs(grad - grad_fd));
183 for (
size_t step = 1; step < num_fd_steps; ++step) {
185 std::tie(grad, grad_fd) =
checkGradients(objective, input,
dual, objectiveBase, graph, eps);
186 if (printmore) std::cout <<
"grad = " << grad <<
"\ngrad fd = " << grad_fd << std::endl;
187 grad_errors.push_back(
std::abs(grad - grad_fd));
190 for (
size_t step = 0; step < num_fd_steps; ++step) {
191 std::cout <<
"grad error " << step <<
" = " << grad_errors[step] << std::endl;
194 if (num_fd_steps >= 2) {
195 return std::log2(grad_errors[0] / grad_errors[num_fd_steps - 1]) /
static_cast<double>(num_fd_steps - 1);
This file contains the declaration of the boundary condition manager class.
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)