PolyFEM
Loading...
Searching...
No Matches
TargetForms.cpp
Go to the documentation of this file.
1#include "TargetForms.hpp"
5
6#include <polyfem/State.hpp>
10
12
13using namespace polyfem::utils;
14
15namespace polyfem::solver
16{
17 namespace
18 {
19 class LocalThreadScalarStorage
20 {
21 public:
22 double val;
24
25 LocalThreadScalarStorage()
26 {
27 val = 0;
28 }
29 };
30 } // namespace
31
33 {
35 if (target_state_)
36 {
37 assert(target_state_->diff_cached.size() > 0);
38
39 auto j_func = [this](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
40 int e_ref = params.elem;
41 if (auto search = e_to_ref_e_.find(params.elem); search != e_to_ref_e_.end())
42 e_ref = search->second;
43
44 Eigen::MatrixXd pts_ref;
45 target_state_->geom_bases()[e_ref].eval_geom_mapping(local_pts, pts_ref);
46
47 Eigen::MatrixXd u_ref, grad_u_ref;
48 const Eigen::VectorXd &sol_ref = target_state_->diff_cached.u(target_state_->problem->is_time_dependent() ? params.step : 0);
49 io::Evaluator::interpolate_at_local_vals(*(target_state_->mesh), target_state_->problem->is_scalar(), target_state_->bases, target_state_->geom_bases(), e_ref, local_pts, sol_ref, u_ref, grad_u_ref);
50
51 val = (u_ref + pts_ref - u - pts).rowwise().squaredNorm();
52 };
53
54 auto djdu_func = [this](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
55 int e_ref = params.elem;
56 if (auto search = e_to_ref_e_.find(params.elem); search != e_to_ref_e_.end())
57 e_ref = search->second;
58
59 Eigen::MatrixXd pts_ref;
60 target_state_->geom_bases()[e_ref].eval_geom_mapping(local_pts, pts_ref);
61
62 Eigen::MatrixXd u_ref, grad_u_ref;
63 const Eigen::VectorXd &sol_ref = target_state_->diff_cached.u(target_state_->problem->is_time_dependent() ? params.step : 0);
64 io::Evaluator::interpolate_at_local_vals(*(target_state_->mesh), target_state_->problem->is_scalar(), target_state_->bases, target_state_->geom_bases(), e_ref, local_pts, sol_ref, u_ref, grad_u_ref);
65
66 val = 2 * (u + pts - u_ref - pts_ref);
67 };
68
69 j.set_j(j_func);
70 j.set_dj_du(djdu_func);
71 j.set_dj_dx(djdu_func); // only used for shape derivative
72 }
73 else if (have_target_func)
74 {
75 auto j_func = [this](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
76 val.setZero(u.rows(), 1);
77
78 const Eigen::MatrixXd X = u + pts;
79 for (int q = 0; q < u.rows(); q++)
80 val(q) = target_func(X(q, 0), X(q, 1), X.cols() == 2 ? 0 : X(q, 2), 0, params.elem);
81 };
82
83 auto djdu_func = [this](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
84 val.setZero(u.rows(), u.cols());
85
86 const Eigen::MatrixXd X = u + pts;
87 for (int q = 0; q < u.rows(); q++)
88 for (int d = 0; d < val.cols(); d++)
89 val(q, d) = target_func_grad[d](X(q, 0), X(q, 1), X.cols() == 2 ? 0 : X(q, 2), 0, params.elem);
90 };
91
92 j.set_j(j_func);
93 j.set_dj_du(djdu_func);
94 j.set_dj_dx(djdu_func); // only used for shape derivative
95 }
96 else // error wrt. a constant displacement
97 {
98 if (target_disp.size() == state_.mesh->dimension())
99 {
100 auto j_func = [this](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
101 val.setZero(u.rows(), 1);
102
103 for (int q = 0; q < u.rows(); q++)
104 {
105 Eigen::VectorXd err = u.row(q) - this->target_disp.transpose();
106 for (int d = 0; d < active_dimension_mask.size(); d++)
107 if (!active_dimension_mask[d])
108 err(d) = 0;
109 val(q) = err.squaredNorm();
110 }
111 };
112 auto djdu_func = [this](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
113 val.setZero(u.rows(), u.cols());
114
115 for (int q = 0; q < u.rows(); q++)
116 {
117 Eigen::VectorXd err = u.row(q) - this->target_disp.transpose();
118 for (int d = 0; d < active_dimension_mask.size(); d++)
119 if (!active_dimension_mask[d])
120 err(d) = 0;
121 val.row(q) = 2 * err;
122 }
123 };
124
125 j.set_j(j_func);
126 j.set_dj_du(djdu_func);
127 }
128 else
129 log_and_throw_adjoint_error("[{}] Only constant target displacement is supported!", name());
130 }
131
132 return j;
133 }
134
135 void TargetForm::set_reference(const std::shared_ptr<const State> &target_state, const std::set<int> &reference_cached_body_ids)
136 {
137 target_state_ = target_state;
138
139 std::map<int, std::vector<int>> ref_interested_body_id_to_e;
140 int ref_count = 0;
141 for (int e = 0; e < target_state_->bases.size(); ++e)
142 {
143 int body_id = target_state_->mesh->get_body_id(e);
144 if (reference_cached_body_ids.size() > 0 && reference_cached_body_ids.count(body_id) == 0)
145 continue;
146 if (ref_interested_body_id_to_e.find(body_id) != ref_interested_body_id_to_e.end())
147 ref_interested_body_id_to_e[body_id].push_back(e);
148 else
149 ref_interested_body_id_to_e[body_id] = {e};
150 ref_count++;
151 }
152
153 std::map<int, std::vector<int>> interested_body_id_to_e;
154 int count = 0;
155 for (int e = 0; e < state_.bases.size(); ++e)
156 {
157 int body_id = state_.mesh->get_body_id(e);
158 if (reference_cached_body_ids.size() > 0 && reference_cached_body_ids.count(body_id) == 0)
159 continue;
160 if (interested_body_id_to_e.find(body_id) != interested_body_id_to_e.end())
161 interested_body_id_to_e[body_id].push_back(e);
162 else
163 interested_body_id_to_e[body_id] = {e};
164 count++;
165 }
166
167 if (count != ref_count)
168 adjoint_logger().error("[{}] Number of interested elements in the reference and optimization examples do not match! {} {}", name(), count, ref_count);
169 else
170 adjoint_logger().trace("[{}] Found {} matching elements.", name(), count);
171
172 for (const auto &kv : interested_body_id_to_e)
173 {
174 for (int i = 0; i < kv.second.size(); ++i)
175 {
176 e_to_ref_e_[kv.second[i]] = ref_interested_body_id_to_e[kv.first][i];
177 }
178 }
179 }
180
181 void TargetForm::set_reference(const json &func, const json &grad_func)
182 {
183 target_func.init(func);
184 for (size_t k = 0; k < grad_func.size(); k++)
185 target_func_grad[k].init(grad_func[k]);
186 have_target_func = true;
187 }
188
189 NodeTargetForm::NodeTargetForm(const State &state, const VariableToSimulationGroup &variable_to_simulations, const json &args) : StaticForm(variable_to_simulations), state_(state)
190 {
191 std::string target_data_path = args["target_data_path"];
192 if (!std::filesystem::is_regular_file(target_data_path))
193 {
194 throw std::runtime_error("Marker path invalid!");
195 }
196 Eigen::MatrixXd tmp;
197 io::read_matrix(target_data_path, tmp);
198
199 // markers to nodes
200 Eigen::VectorXi nodes = tmp.col(0).cast<int>();
201 target_vertex_positions.setZero(nodes.size(), state_.mesh->dimension());
202 active_nodes.reserve(nodes.size());
203 for (int s = 0; s < nodes.size(); s++)
204 {
205 const int node_id = state_.in_node_to_node(nodes(s));
206 target_vertex_positions.row(s) = tmp.block(s, 1, 1, tmp.cols() - 1);
207 active_nodes.push_back(node_id);
208 }
209 }
210
211 NodeTargetForm::NodeTargetForm(const State &state, const VariableToSimulationGroup &variable_to_simulations, const std::vector<int> &active_nodes_, const Eigen::MatrixXd &target_vertex_positions_) : StaticForm(variable_to_simulations), state_(state), target_vertex_positions(target_vertex_positions_), active_nodes(active_nodes_)
212 {
213 }
214
215 Eigen::VectorXd NodeTargetForm::compute_adjoint_rhs_step(const int time_step, const Eigen::VectorXd &x, const State &state) const
216 {
217 Eigen::VectorXd rhs;
218 rhs.setZero(state.diff_cached.u(0).size());
219
220 const int dim = state_.mesh->dimension();
221
222 if (&state == &state_)
223 {
224 int i = 0;
225 Eigen::VectorXd disp = state_.diff_cached.u(time_step);
226 for (int v : active_nodes)
227 {
228 RowVectorNd cur_pos = state_.mesh_nodes->node_position(v) + disp.segment(v * dim, dim).transpose();
229
230 rhs.segment(v * dim, dim) = 2 * (cur_pos - target_vertex_positions.row(i++));
231 }
232 }
233
234 return rhs * weight();
235 }
236
237 double NodeTargetForm::value_unweighted_step(const int time_step, const Eigen::VectorXd &x) const
238 {
239 const int dim = state_.mesh->dimension();
240 double val = 0;
241 int i = 0;
242 Eigen::VectorXd disp = state_.diff_cached.u(time_step);
243 for (int v : active_nodes)
244 {
245 RowVectorNd cur_pos = state_.mesh_nodes->node_position(v) + disp.segment(v * dim, dim).transpose();
246 val += (cur_pos - target_vertex_positions.row(i++)).squaredNorm();
247 }
248 return val;
249 }
250
251 void NodeTargetForm::compute_partial_gradient_step(const int time_step, const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
252 {
253 gradv.setZero(x.size());
255 log_and_throw_adjoint_error("[{}] Doesn't support derivatives wrt. shape!", name());
256 return Eigen::VectorXd::Zero(0).eval();
257 });
258 }
259
260 BarycenterTargetForm::BarycenterTargetForm(const VariableToSimulationGroup &variable_to_simulations, const json &args, const std::shared_ptr<State> &state1, const std::shared_ptr<State> &state2) : StaticForm(variable_to_simulations)
261 {
262 dim = state1->mesh->dimension();
263 json tmp_args = args;
264 for (int d = 0; d < dim; d++)
265 {
266 tmp_args["dim"] = d;
267 center1.push_back(std::make_unique<PositionForm>(variable_to_simulations, *state1, tmp_args));
268 center2.push_back(std::make_unique<PositionForm>(variable_to_simulations, *state2, tmp_args));
269 }
270 }
271
272 Eigen::VectorXd BarycenterTargetForm::compute_adjoint_rhs_step(const int time_step, const Eigen::VectorXd &x, const State &state) const
273 {
274 Eigen::VectorXd term;
275 term.setZero(state.ndof());
276 for (int d = 0; d < dim; d++)
277 {
278 double value = center1[d]->value_unweighted_step(time_step, x) - center2[d]->value_unweighted_step(time_step, x);
279 term += (2 * value) * (center1[d]->compute_adjoint_rhs_step(time_step, x, state) - center2[d]->compute_adjoint_rhs_step(time_step, x, state));
280 }
281 return term * weight();
282 }
283 void BarycenterTargetForm::compute_partial_gradient_step(const int time_step, const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
284 {
285 gradv.setZero(x.size());
286 Eigen::VectorXd tmp1, tmp2;
287 for (int d = 0; d < dim; d++)
288 {
289 double value = center1[d]->value_unweighted_step(time_step, x) - center2[d]->value_unweighted_step(time_step, x);
290 center1[d]->compute_partial_gradient_step(time_step, x, tmp1);
291 center2[d]->compute_partial_gradient_step(time_step, x, tmp2);
292 gradv += (2 * value) * (tmp1 - tmp2);
293 }
294 gradv *= weight();
295 }
296 double BarycenterTargetForm::value_unweighted_step(const int time_step, const Eigen::VectorXd &x) const
297 {
298 double dist = 0;
299 for (int d = 0; d < dim; d++)
300 dist += std::pow(center1[d]->value_unweighted_step(time_step, x) - center2[d]->value_unweighted_step(time_step, x), 2);
301
302 return dist;
303 }
304} // namespace polyfem::solver
double val
Definition Assembler.cpp:86
ElementAssemblyValues vals
Definition Assembler.cpp:22
int x
void set_dj_du(const functionalType &dj_du)
void set_j(const functionalType &j)
void set_dj_dx(const functionalType &dj_dx)
main class that contains the polyfem solver and all its state
Definition State.hpp:79
Eigen::VectorXi in_node_to_node
Inpute nodes (including high-order) to polyfem nodes, only for isoparametric.
Definition State.hpp:450
std::unique_ptr< mesh::Mesh > mesh
current mesh, it can be a Mesh2D or Mesh3D
Definition State.hpp:466
std::shared_ptr< polyfem::mesh::MeshNodes > mesh_nodes
Mapping from input nodes to FE nodes.
Definition State.hpp:193
solver::DiffCache diff_cached
Definition State.hpp:669
std::vector< basis::ElementBases > bases
FE bases, the size is #elements.
Definition State.hpp:171
int ndof() const
Definition State.hpp:673
stores per element basis values at given quadrature points and geometric mapping
static void interpolate_at_local_vals(const mesh::Mesh &mesh, const bool is_problem_scalar, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const int el_index, const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &fun, Eigen::MatrixXd &result, Eigen::MatrixXd &result_grad)
interpolate solution and gradient at element (calls interpolate_at_local_vals with sol)
double value(const Eigen::VectorXd &x) const override
Compute the value of the form multiplied with the weigth.
const VariableToSimulationGroup variable_to_simulations_
std::vector< std::unique_ptr< PositionForm > > center1
std::vector< std::unique_ptr< PositionForm > > center2
Eigen::VectorXd compute_adjoint_rhs_step(const int time_step, const Eigen::VectorXd &x, const State &state) const override
void compute_partial_gradient_step(const int time_step, const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const override
double value_unweighted_step(const int time_step, const Eigen::VectorXd &x) const override
BarycenterTargetForm(const VariableToSimulationGroup &variable_to_simulations, const json &args, const std::shared_ptr< State > &state1, const std::shared_ptr< State > &state2)
Eigen::VectorXd u(int step) const
virtual void init(const Eigen::VectorXd &x)
Initialize the form.
Definition Form.hpp:19
virtual double weight() const
Get the form's multiplicative constant weight.
Definition Form.hpp:126
NodeTargetForm(const State &state, const VariableToSimulationGroup &variable_to_simulations, const json &args)
double value_unweighted_step(const int time_step, const Eigen::VectorXd &x) const override
void compute_partial_gradient_step(const int time_step, const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const override
Eigen::MatrixXd target_vertex_positions
std::vector< int > active_nodes
Eigen::VectorXd compute_adjoint_rhs_step(const int time_step, const Eigen::VectorXd &x, const State &state) const override
virtual std::string name() const override
std::shared_ptr< const State > target_state_
void set_reference(const std::shared_ptr< const State > &target_state, const std::set< int > &reference_cached_body_ids)
IntegrableFunctional get_integral_functional() const override
std::array< utils::ExpressionValue, 3 > target_func_grad
utils::ExpressionValue target_func
std::map< int, int > e_to_ref_e_
std::vector< bool > active_dimension_mask
virtual std::string name() const override
A collection of VariableToSimulation.
Eigen::VectorXd apply_parametrization_jacobian(const ParameterType type, const State *state_ptr, const Eigen::VectorXd &x, const std::function< Eigen::VectorXd()> &grad) const
Maps the partial gradient wrt.
bool read_matrix(const std::string &path, Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &mat)
Reads a matrix from a file. Determines the file format based on the path's extension.
Definition MatrixIO.cpp:18
spdlog::logger & adjoint_logger()
Retrieves the current logger for adjoint.
Definition Logger.cpp:28
nlohmann::json json
Definition Common.hpp:9
void log_and_throw_adjoint_error(const std::string &msg)
Definition Logger.cpp:77
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Definition Types.hpp:11
Parameters for the functional evaluation.