PolyFEM
Loading...
Searching...
No Matches
ShapeVariableToSimulation.cpp
Go to the documentation of this file.
2
8
9#include <Eigen/Core>
10
11#include <string>
12#include <cassert>
13
14namespace polyfem::solver
15{
16
18 DiffCachePtrs diff_caches,
19 CompositeParametrization parametrizations,
20 Eigen::VectorXi active_dimensions,
21 Eigen::VectorXi active_geom_nodes)
22 : dim_(varforms[0]->get_mesh().dimension()),
23 vertex_num_(varforms[0]->get_mesh().n_vertices()),
24 varforms_(std::move(varforms)),
25 diff_caches_(std::move(diff_caches)),
26 parametrization_(std::move(parametrizations)),
27 active_dimensions_(std::move(active_dimensions)),
28 active_geom_nodes_(std::move(active_geom_nodes))
29 {
30 assert(!varforms_.empty());
31 assert(varforms_.size() == diff_caches_.size());
32
33 // Validates active selections.
34 std::string reason;
36 {
37 log_and_throw_adjoint_error("Fail to construct shape variable to simulation. Reason: {}", reason);
38 }
40 {
41 log_and_throw_adjoint_error("Fail to construct shape variable to simulation. Reason: {}", reason);
42 }
43
44 // Expand implicit all active selection.
45 if (active_dimensions_.size() == 0)
46 {
47 active_dimensions_ = Eigen::VectorXi::LinSpaced(dim_, 0, dim_ - 1);
48 }
49 if (active_geom_nodes_.size() == 0)
50 {
51 active_geom_nodes_ = Eigen::VectorXi::LinSpaced(vertex_num_, 0, vertex_num_ - 1);
52 }
53 }
54
56 {
57 return "shape";
58 }
59
64
66 {
67 for (auto &varform : varforms_)
68 {
69 if (varform.get() == &target)
70 {
71 return true;
72 }
73 }
74 return false;
75 }
76
77 void ShapeVariableToSimulation::update(const Eigen::VectorXd &x)
78 {
79 Eigen::VectorXd y = parametrization_.eval(x);
80 assert(y.size() == para_out_dof());
81
82 int active_dim_num = active_dimensions_.size();
83 for (auto &varform : varforms_)
84 {
85 Eigen::MatrixXd vertices;
86 varform->get_vertices(vertices);
87 for (int ni = 0; ni < active_geom_nodes_.size(); ++ni)
88 {
89 int node_id = active_geom_nodes_(ni);
90 for (int di = 0; di < active_dimensions_.size(); ++di)
91 {
92 int d = active_dimensions_(di);
93 vertices(node_id, d) = y(ni * active_dim_num + di);
94 }
95 }
96 varform->set_vertex_positions(vertices);
97 }
98 }
99
100 void ShapeVariableToSimulation::update_state_variables(const Eigen::VectorXd &x, Eigen::VectorXd &state_variables) const
101 {
102 assert(state_variables.size() == dim_ * vertex_num_);
103
104 Eigen::VectorXd y = parametrization_.eval(x);
105 assert(y.size() == para_out_dof());
106
107 int active_dim_num = active_dimensions_.size();
108 for (int ni = 0; ni < active_geom_nodes_.size(); ++ni)
109 {
110 int vertex_id = active_geom_nodes_(ni);
111 for (int di = 0; di < active_dimensions_.size(); ++di)
112 {
113 int d = active_dimensions_(di);
114 state_variables(vertex_id * dim_ + d) = y(ni * active_dim_num + di);
115 }
116 }
117 }
118
119 Eigen::VectorXd ShapeVariableToSimulation::compute_adjoint_term(const Eigen::VectorXd &x) const
120 {
121 Eigen::VectorXd term, cur_term;
122 for (int i = 0; i < varforms_.size(); ++i)
123 {
124 auto &varform = varforms_[i];
125 auto &diff_cache = diff_caches_[i];
126
127 if (varform->get_problem().is_time_dependent())
128 {
129 Eigen::MatrixXd adjoint_p = get_adjoint_mat(*varform, *diff_cache, 0);
130 Eigen::MatrixXd adjoint_nu = get_adjoint_mat(*varform, *diff_cache, 1);
131 AdjointTools::dJ_shape_transient_adjoint_term(*varform, *diff_cache, adjoint_nu, adjoint_p, cur_term);
132 }
133 else if (varform->is_homogenization())
134 {
135 Eigen::MatrixXd adjoint_p = get_adjoint_mat(*varform, *diff_cache, 0);
137 *diff_cache,
138 diff_cache->u(0),
139 adjoint_p,
140 cur_term);
141 }
142 else
143 {
144 Eigen::MatrixXd adjoint_p = get_adjoint_mat(*varform, *diff_cache, 0);
146 *diff_cache,
147 diff_cache->u(0),
148 adjoint_p,
149 cur_term);
150 }
151
152 if (term.size() != cur_term.size())
153 {
154 term = cur_term;
155 }
156 else
157 {
158 term += cur_term;
159 }
160 }
161
162 assert(term.size() == vertex_num_ * dim_);
163
164 Eigen::VectorXd active_term(para_out_dof());
165 int active_dim_num = active_dimensions_.size();
166 for (int i = 0; i < active_geom_nodes_.size(); ++i)
167 {
168 int vertex_id = active_geom_nodes_(i);
169 for (int di = 0; di < active_dimensions_.size(); ++di)
170 {
171 int d = active_dimensions_(di);
172 active_term(i * active_dim_num + di) = term(vertex_id * dim_ + d);
173 }
174 }
175
176 assert(active_term.size() == para_out_dof());
177 return parametrization_.apply_jacobian(active_term, x);
178 }
179
184
186 {
187 Eigen::VectorXd x = Eigen::VectorXd::Zero(para_out_dof());
188 int active_dim_num = active_dimensions_.size();
189 for (int i = 0; i < active_geom_nodes_.size(); ++i)
190 {
191 Eigen::VectorXd p = varforms_[0]->get_mesh().point(active_geom_nodes_(i));
192 for (int di = 0; di < active_dimensions_.size(); ++di)
193 {
194 int d = active_dimensions_(di);
195 x(i * active_dim_num + di) = p(d);
196 }
197 }
198
200 }
201
202 Eigen::VectorXd ShapeVariableToSimulation::apply_parametrization_jacobian(const Eigen::VectorXd &term, const Eigen::VectorXd &x) const
203 {
204 // Forms expect term to be full dof before any selection.
205 assert(term.size() == vertex_num_ * dim_);
206
207 Eigen::VectorXd active_term(para_out_dof());
208 int active_dim_num = active_dimensions_.size();
209 for (int i = 0; i < active_geom_nodes_.size(); ++i)
210 {
211 int vertex_id = active_geom_nodes_(i);
212 for (int di = 0; di < active_dimensions_.size(); ++di)
213 {
214 int d = active_dimensions_(di);
215 active_term(i * active_dim_num + di) = term(vertex_id * dim_ + d);
216 }
217 }
218 return parametrization_.apply_jacobian(active_term, x);
219 }
220
222 {
223 return active_dimensions_.size() * active_geom_nodes_.size();
224 }
225
226} // 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).
bool affects_varform(const varform::DifferentiableVarForm &target) const override
Return true if current var2sim maps to target varform.
void update_state_variables(const Eigen::VectorXd &x, Eigen::VectorXd &state_variables) const override
Update varform variables from optimization variables.
ShapeVariableToSimulation(VarFormPtrs varforms, DiffCachePtrs diff_caches, CompositeParametrization parametrizations, Eigen::VectorXi active_dimensions, Eigen::VectorXi active_geom_nodes)
Construct ShapeVariableToSimulation.
std::vector< std::shared_ptr< varform::DifferentiableVarForm > > VarFormPtrs
int inverse_dof() const override
Compute optimization variables dof.
std::vector< std::shared_ptr< DiffCache > > DiffCachePtrs
Eigen::VectorXd compute_adjoint_term(const Eigen::VectorXd &x) const override
Compute adjoint contribution of objective gradient.
Eigen::VectorXd inverse_eval() const override
Compute optimization variables from forward simulation varform::DifferentiableVarForm.
int para_out_dof() const
Return variable dof after parametrization mapping.
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.
Optimization-facing interface implemented by differentiated VarForm adapters.
void dJ_shape_transient_adjoint_term(const varform::DifferentiableVarForm &varform, const DiffCache &diff_cache, const Eigen::MatrixXd &adjoint_nu, const Eigen::MatrixXd &adjoint_p, Eigen::VectorXd &one_form)
void dJ_shape_static_adjoint_term(const varform::DifferentiableVarForm &varform, const DiffCache &diff_cache, const Eigen::MatrixXd &sol, const Eigen::MatrixXd &adjoint, Eigen::VectorXd &one_form)
void dJ_shape_homogenization_adjoint_term(const varform::DifferentiableVarForm &varform, const DiffCache &diff_cache, const Eigen::MatrixXd &sol, const Eigen::MatrixXd &adjoint, Eigen::VectorXd &one_form)
bool is_active_dims_valid(const Eigen::VectorXi &active_dimensions, const std::vector< std::shared_ptr< varform::DifferentiableVarForm > > &varforms, std::string &reason)
Validate active dimensions selection given varforms.
bool is_active_geom_nodes_valid(const Eigen::VectorXi &active_geom_nodes, const std::vector< std::shared_ptr< varform::DifferentiableVarForm > > &varforms, std::string &reason)
Validate active geometry nodes selection given varforms.
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.