PolyFEM
Loading...
Searching...
No Matches
DirichletNodesVariableToSimulation.cpp
Go to the documentation of this file.
2
3#include <polyfem/Common.hpp>
11
12#include <Eigen/Core>
13
14#include <cassert>
15#include <string>
16#include <utility>
17#include <vector>
18
19namespace polyfem::solver
20{
21
23 VarFormPtrs varforms,
24 DiffCachePtrs diff_caches,
25 CompositeParametrization parametrizations,
26 Eigen::VectorXi active_geom_nodes)
27 : dim_(varforms[0]->get_mesh().dimension()),
28 vertex_num_(varforms[0]->get_mesh().n_vertices()),
29 varforms_(std::move(varforms)),
30 diff_caches_(std::move(diff_caches)),
31 parametrization_(std::move(parametrizations)),
32 active_geom_nodes_(std::move(active_geom_nodes))
33 {
34 assert(!varforms_.empty());
35 assert(varforms_.size() == diff_caches_.size());
36
37 // Quasistatic only.
38 for (auto &varform : varforms_)
39 {
40 if (varform->get_problem().is_time_dependent())
41 {
42 log_and_throw_adjoint_error("Fail to construct dirichlet nodes variable to simulation. Reason: only quasistatic simulations supported.");
43 }
44 }
45
46 // Expand implicit all-active node selection.
47 if (active_geom_nodes_.size() == 0)
48 {
49 auto &varform = *varforms_[0];
50 std::vector<int> tmp;
51 for (int v_in = 0; v_in < vertex_num_; ++v_in)
52 {
53 int v = varform.primary_space().space_in_node_to_node(v_in);
54 int tag = varform.get_mesh().get_node_id(v);
55 if (varform.get_problem().is_nodal_dirichlet_boundary(v, tag))
56 {
57 tmp.push_back(v_in);
58 }
59 }
60 std::sort(tmp.begin(), tmp.end());
61 active_geom_nodes_ = Eigen::Map<Eigen::VectorXi>(tmp.data(), tmp.size());
62 }
63
64 // Validate the expanded node selection against every varform.
65 std::string reason;
67 {
68 log_and_throw_adjoint_error("Fail to construct dirichlet nodes variable to simulation. Reason: {}", reason);
69 }
70 }
71
73 {
74 return "dirichlet-nodes";
75 }
76
81
83 {
84 for (auto &varform : varforms_)
85 {
86 if (varform.get() == &target)
87 {
88 return true;
89 }
90 }
91 return false;
92 }
93
94 void DirichletNodesVariableToSimulation::update(const Eigen::VectorXd &x)
95 {
96 Eigen::VectorXd y = parametrization_.eval(x);
97 assert(y.size() == para_out_dof());
98
99 Eigen::MatrixXd nodal_dirichlet = utils::unflatten(y, dim_);
100
101 for (auto &varform : varforms_)
102 varform->set_dirichlet_nodes(active_geom_nodes_, nodal_dirichlet);
103 }
104
105 void DirichletNodesVariableToSimulation::update_state_variables(const Eigen::VectorXd &x, Eigen::VectorXd &state_variables) const
106 {
107 assert(state_variables.size() == para_out_dof());
108 state_variables = parametrization_.eval(x);
109 }
110
111 Eigen::VectorXd DirichletNodesVariableToSimulation::compute_adjoint_term(const Eigen::VectorXd &x) const
112 {
113 Eigen::VectorXd term = Eigen::VectorXd::Zero(para_out_dof());
114
115 for (int si = 0; si < varforms_.size(); ++si)
116 {
117 auto &varform = varforms_[si];
118 auto &diff_cache = diff_caches_[si];
119
120 Eigen::MatrixXd adjoint_p = get_adjoint_mat(*varform, *diff_cache, 0);
121
122 Eigen::VectorXd full_term;
123 AdjointTools::dJ_dirichlet_static_adjoint_term(*varform, *diff_cache, adjoint_p, full_term);
124
125 assert(full_term.size() == vertex_num_ * dim_);
126
127 for (int i = 0; i < active_geom_nodes_.size(); ++i)
128 {
129 term.segment(i * dim_, dim_) += full_term.segment(active_geom_nodes_(i) * dim_, dim_);
130 }
131 }
132
133 assert(term.size() == para_out_dof());
134 return parametrization_.apply_jacobian(term, x);
135 }
136
141
143 {
144 logger().warn("Inverse eval is not implemented in {}; falling back to zero.", name());
145 return parametrization_.inverse_eval(Eigen::VectorXd::Zero(para_out_dof()));
146 }
147
148 Eigen::VectorXd DirichletNodesVariableToSimulation::apply_parametrization_jacobian(const Eigen::VectorXd &, const Eigen::VectorXd &) const
149 {
150 // Not implemented because there's no user
151 log_and_throw_adjoint_error("apply_parametrization_jacobian is not implemented in {} variable to simulation.", name());
152 }
153
158} // namespace polyfem::solver
int y
int x
Eigen::VectorXd apply_jacobian(const Eigen::VectorXd &grad_full, const Eigen::VectorXd &x) const override
Apply jacobian for chain rule.
Eigen::VectorXd inverse_eval(const Eigen::VectorXd &y) const override
Eval x = f^-1 (y).
int inverse_size(int y_size) const override
Compute DOF of x given DOF of y.
Eigen::VectorXd eval(const Eigen::VectorXd &x) const override
Eval y = f(x).
Eigen::VectorXd apply_parametrization_jacobian(const Eigen::VectorXd &term, const Eigen::VectorXd &x) const override
Apply parametrization jacobian to compute the gradient w.r.t.
void update(const Eigen::VectorXd &x) override
Update forward simulation varforms from optimization variables.
int inverse_dof() const override
Compute optimization variables dof.
std::vector< std::shared_ptr< varform::DifferentiableVarForm > > VarFormPtrs
Eigen::VectorXd compute_adjoint_term(const Eigen::VectorXd &x) const override
Compute adjoint contribution of objective gradient.
void update_state_variables(const Eigen::VectorXd &x, Eigen::VectorXd &state_variables) const override
Update varform variables from optimization variables.
Eigen::VectorXd inverse_eval() const override
Compute optimization variables from forward simulation varform::DifferentiableVarForm.
DirichletNodesVariableToSimulation(VarFormPtrs varforms, DiffCachePtrs diff_caches, CompositeParametrization parametrizations, Eigen::VectorXi active_geom_nodes)
Construct DirichletNodesVariableToSimulation.
bool affects_varform(const varform::DifferentiableVarForm &target) const override
Return true if current var2sim maps to target varform.
Optimization-facing interface implemented by differentiated VarForm adapters.
void dJ_dirichlet_static_adjoint_term(const varform::DifferentiableVarForm &varform, const DiffCache &diff_cache, const Eigen::MatrixXd &adjoint, Eigen::VectorXd &one_form)
bool is_active_dirichlet_node_valid(const Eigen::VectorXi &active_dirichlet_nodes, const std::vector< std::shared_ptr< varform::DifferentiableVarForm > > &varforms, std::string &reason)
Validate active Dirichlet node ids selection given varforms.
Eigen::MatrixXd unflatten(const Eigen::VectorXd &x, int dim)
Unflatten rowwises, so every dim elements in x become a row.
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:44
void log_and_throw_adjoint_error(const std::string &msg)
Definition Logger.cpp:79
Eigen::MatrixXd get_adjoint_mat(const varform::DifferentiableVarForm &varform, const DiffCache &diff_cache, int type)
Get adjoint parameter nu or p.