19 class LocalThreadScalarStorage
25 LocalThreadScalarStorage()
40 int e_ref = params.elem;
42 e_ref = search->second;
44 Eigen::MatrixXd pts_ref;
45 target_state_->geom_bases()[e_ref].eval_geom_mapping(local_pts, pts_ref);
47 Eigen::MatrixXd u_ref, grad_u_ref;
51 val = (u_ref + pts_ref - u - pts).rowwise().squaredNorm();
55 int e_ref = params.elem;
57 e_ref = search->second;
59 Eigen::MatrixXd pts_ref;
60 target_state_->geom_bases()[e_ref].eval_geom_mapping(local_pts, pts_ref);
62 Eigen::MatrixXd u_ref, grad_u_ref;
66 val = 2 * (u + pts - u_ref - pts_ref);
76 val.setZero(u.rows(), 1);
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);
84 val.setZero(u.rows(), u.cols());
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);
101 val.setZero(u.rows(), 1);
103 for (
int q = 0; q < u.rows(); q++)
105 Eigen::VectorXd err = u.row(q) - this->
target_disp.transpose();
109 val(q) = err.squaredNorm();
113 val.setZero(u.rows(), u.cols());
115 for (
int q = 0; q < u.rows(); q++)
117 Eigen::VectorXd err = u.row(q) - this->
target_disp.transpose();
121 val.row(q) = 2 * err;
139 std::map<int, std::vector<int>> ref_interested_body_id_to_e;
144 if (reference_cached_body_ids.size() > 0 && reference_cached_body_ids.count(body_id) == 0)
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);
149 ref_interested_body_id_to_e[body_id] = {e};
153 std::map<int, std::vector<int>> interested_body_id_to_e;
158 if (reference_cached_body_ids.size() > 0 && reference_cached_body_ids.count(body_id) == 0)
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);
163 interested_body_id_to_e[body_id] = {e};
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);
172 for (
const auto &kv : interested_body_id_to_e)
174 for (
int i = 0; i < kv.second.size(); ++i)
176 e_to_ref_e_[kv.second[i]] = ref_interested_body_id_to_e[kv.first][i];
184 for (
size_t k = 0; k < grad_func.size(); k++)
197 LocalThreadScalarStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
199 Eigen::MatrixXd uv, samples, gtmp;
200 Eigen::MatrixXd points, normal;
201 Eigen::VectorXd weights;
203 Eigen::MatrixXd u, grad_u;
205 for (int lb_id = start; lb_id < end; ++lb_id)
207 const auto &lb = state_.total_local_boundary[lb_id];
208 const int e = lb.element_id();
210 for (int i = 0; i < lb.size(); i++)
212 const int global_primitive_id = lb.global_primitive_id(i);
213 if (ids_.size() != 0 && ids_.find(state_.mesh->get_boundary_id(global_primitive_id)) == ids_.end())
216 utils::BoundarySampler::boundary_quadrature(lb, state_.n_boundary_samples(), *state_.mesh, i, false, uv, points, normal, weights);
218 assembler::ElementAssemblyValues &vals = local_storage.vals;
219 vals.compute(e, state_.mesh->is_volume(), points, bases[e], gbases[e]);
220 io::Evaluator::interpolate_at_local_vals(e, dim, actual_dim, vals, state_.diff_cached.u(time_step), u, grad_u);
222 normal = normal * vals.jac_it[0];
224 for (int q = 0; q < u.rows(); q++)
225 interpolation_fn->cache_grid([this](const Eigen::MatrixXd &point, double &distance) { compute_distance(point, distance); }, vals.val.row(q) + u.row(q));
233 dim = control_points.cols();
240 nanospline::BSpline<double, 2, 3> curve;
241 curve.set_control_points(control_points);
242 curve.set_knots(knots);
250 Eigen::MatrixXi edges(
samples - 1, 2);
251 edges.col(0) = Eigen::VectorXi::LinSpaced(
samples - 1, 0,
samples - 2);
252 edges.col(1) = Eigen::VectorXi::LinSpaced(
samples - 1, 1,
samples - 1);
262 dim = control_points.cols();
269 nanospline::BSplinePatch<double, 3, 3, 3> patch;
270 patch.set_control_grid(control_points);
271 patch.set_knots_u(knots_u);
272 patch.set_knots_v(knots_v);
276 for (
int i = 0; i <
samples; ++i)
290 for (
int i = 0; i <
samples - 1; ++i)
291 for (
int j = 0; j <
samples - 1; ++j)
293 Eigen::MatrixXi F_local(2, 3);
296 F.block(f, 0, 2, 3) = F_local;
308 Eigen::MatrixXd p = point.transpose();
315 const double t = std::max(0., std::min(1., distance_to_perpendicular));
317 const double project_distance = (p - project).norm();
318 if (project_distance < distance)
319 distance = project_distance;
323 for (
int i = 0; i <
samples - 1; ++i)
324 for (
int j = 0; j <
samples - 1; ++j)
329 const double u = std::max(0., std::min(1., distance_to_perpendicular));
333 const double v = std::max(0., std::min(1., distance_to_perpendicular));
337 const double project_distance = (p - project).norm();
338 if (project_distance < distance)
339 distance = project_distance;
348 val.setZero(u.rows(), 1);
350 for (
int q = 0; q < u.rows(); q++)
353 Eigen::MatrixXd unused_grad;
355 val(q) = pow(distance, 2);
360 val.setZero(u.rows(), u.cols());
362 for (
int q = 0; q < u.rows(); q++)
365 Eigen::MatrixXd grad;
367 val.row(q) = 2 * distance * grad.transpose();
400 LocalThreadScalarStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
402 Eigen::MatrixXd uv, samples, gtmp;
403 Eigen::MatrixXd points, normal;
404 Eigen::VectorXd weights;
406 Eigen::MatrixXd u, grad_u;
408 for (int lb_id = start; lb_id < end; ++lb_id)
410 const auto &lb = state_.total_local_boundary[lb_id];
411 const int e = lb.element_id();
413 for (int i = 0; i < lb.size(); i++)
415 const int global_primitive_id = lb.global_primitive_id(i);
416 if (ids_.size() != 0 && ids_.find(state_.mesh->get_boundary_id(global_primitive_id)) == ids_.end())
419 utils::BoundarySampler::boundary_quadrature(lb, state_.n_boundary_samples(), *state_.mesh, i, false, uv, points, normal, weights);
421 assembler::ElementAssemblyValues &vals = local_storage.vals;
422 vals.compute(e, state_.mesh->is_volume(), points, bases[e], gbases[e]);
423 io::Evaluator::interpolate_at_local_vals(e, dim, actual_dim, vals, state_.diff_cached.u(time_step), u, grad_u);
425 normal = normal * vals.jac_it[0];
427 for (int q = 0; q < u.rows(); q++)
428 interpolation_fn->cache_grid([this](const Eigen::MatrixXd &point, double &distance) {
430 Eigen::Matrix<double, 1, 3> closest;
431 distance = pow(tree_.squared_distance(V_, F_, point.col(0), idx, closest), 0.5);
433 vals.val.row(q) + u.row(q));
443 val.setZero(u.rows(), 1);
445 for (
int q = 0; q < u.rows(); q++)
448 Eigen::MatrixXd unused_grad;
450 val(q) = pow(distance, 2);
455 val.setZero(u.rows(), u.cols());
457 for (
int q = 0; q < u.rows(); q++)
460 Eigen::MatrixXd grad;
462 val.row(q) = 2 * distance * grad.transpose();
475 const int dim = state.
mesh->dimension();
476 const std::string target_data_path = args[
"target_data_path"];
477 if (!std::filesystem::is_regular_file(target_data_path))
479 throw std::runtime_error(
"Marker path invalid!");
482 Eigen::MatrixXd data;
488 for (
int s = 0; s < data.rows(); s++)
493 bool not_found =
true;
494 double min_dist = std::numeric_limits<double>::max();
497 min_dist = std::min(min_dist, (
state_.
mesh_nodes->node_position(v) - node).norm());
498 if ((
state_.
mesh_nodes->node_position(v) - node).norm() < args[
"tolerance"])
553 gradv.setZero(
x.size());
556 return Eigen::VectorXd::Zero(0).eval();
562 dim = state1->mesh->dimension();
563 json tmp_args = args;
564 for (
int d = 0; d <
dim; d++)
567 center1.push_back(std::make_unique<PositionForm>(variable_to_simulations, *state1, tmp_args));
568 center2.push_back(std::make_unique<PositionForm>(variable_to_simulations, *state2, tmp_args));
574 Eigen::VectorXd term;
575 term.setZero(state.
ndof());
576 for (
int d = 0; d <
dim; d++)
578 double value =
center1[d]->value_unweighted_step(time_step,
x) -
center2[d]->value_unweighted_step(time_step,
x);
585 gradv.setZero(
x.size());
586 Eigen::VectorXd tmp1, tmp2;
587 for (
int d = 0; d <
dim; d++)
589 double value =
center1[d]->value_unweighted_step(time_step,
x) -
center2[d]->value_unweighted_step(time_step,
x);
590 center1[d]->compute_partial_gradient_step(time_step,
x, tmp1);
591 center2[d]->compute_partial_gradient_step(time_step,
x, tmp2);
592 gradv += (2 *
value) * (tmp1 - tmp2);
599 for (
int d = 0; d <
dim; d++)
606 :
AdjointForm(variable_to_simulations), steps_(steps), target_(target)
608 dim = state->mesh->dimension();
609 json tmp_args = args;
610 for (
int d = 0; d <
dim; d++)
613 objs.push_back(std::make_unique<PositionForm>(variable_to_simulations, *state, tmp_args));
615 objs.push_back(std::make_unique<VolumeForm>(variable_to_simulations, *state, args));
619 Eigen::VectorXd values(
steps_.size());
620 std::vector<Eigen::MatrixXd> grads(
steps_.size(), Eigen::MatrixXd::Zero(state.
ndof(),
objs.size()));
621 Eigen::MatrixXd g2(
steps_.size(),
objs.size());
625 Eigen::VectorXd input(
objs.size());
627 for (
int d = 0; d <
objs.size(); d++)
629 input(d) =
objs[d]->value_unweighted_step(s,
x);
630 grads[i].col(d) =
objs[d]->compute_adjoint_rhs_step(s,
x, state);
632 values[i] =
eval2(input);
641 terms.col(s) += g1(i) * grads[i] * g2.row(i).transpose();
649 Eigen::VectorXd values(
steps_.size());
650 std::vector<Eigen::MatrixXd> grads(
steps_.size(), Eigen::MatrixXd::Zero(
x.size(),
objs.size()));
651 Eigen::MatrixXd g2(
steps_.size(),
objs.size());
655 Eigen::VectorXd input(
objs.size());
657 for (
int d = 0; d <
objs.size(); d++)
659 input(d) =
objs[d]->value_unweighted_step(s,
x);
660 objs[d]->compute_partial_gradient_step(s,
x, tmp);
661 grads[i].col(d) = tmp;
663 values[i] =
eval2(input);
668 gradv.setZero(
x.size());
672 gradv += g1(i) * grads[i] * g2.row(i).transpose();
679 Eigen::VectorXd values(
steps_.size());
683 Eigen::VectorXd input(
objs.size());
684 for (
int d = 0; d <
objs.size(); d++)
685 input(d) =
objs[d]->value_unweighted_step(s,
x);
686 values[i++] =
eval2(input);
689 return eval1(values);
ElementAssemblyValues vals
void set_dj_du(const functionalType &dj_du)
void evaluate(const Eigen::MatrixXd &elastic_params, const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, ParameterType ¶ms, Eigen::MatrixXd &val) const
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
const std::vector< basis::ElementBases > & geom_bases() const
Get a constant reference to the geometry mapping bases.
std::unique_ptr< mesh::Mesh > mesh
current mesh, it can be a Mesh2D or Mesh3D
std::shared_ptr< polyfem::mesh::MeshNodes > mesh_nodes
Mapping from input nodes to FE nodes.
std::shared_ptr< assembler::Problem > problem
current problem, it contains rhs and bc
solver::DiffCache diff_cached
std::vector< basis::ElementBases > bases
FE bases, the size is #elements.
std::vector< mesh::LocalBoundary > total_local_boundary
mapping from elements to nodes for all mesh
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)
static bool write(const std::string &path, const Eigen::MatrixXd &v, const Eigen::MatrixXi &e, const Eigen::MatrixXi &f)
Eigen::VectorXd u(int step) const
A collection of VariableToSimulation.
virtual 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.
void init(const json &vals)
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.
auto create_thread_storage(const LocalStorage &initial_local_storage)
void maybe_parallel_for(int size, const std::function< void(int, int, int)> &partial_for)
spdlog::logger & adjoint_logger()
Retrieves the current logger for adjoint.
void log_and_throw_adjoint_error(const std::string &msg)
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
void log_and_throw_error(const std::string &msg)
Parameters for the functional evaluation.