PolyFEM
Loading...
Searching...
No Matches
SmoothingForms.cpp
Go to the documentation of this file.
2
3#include <polyfem/State.hpp>
6
7#include <Eigen/Core>
8
9#include <cassert>
10#include <memory>
11#include <set>
12#include <utility>
13#include <vector>
14
15namespace polyfem::solver
16{
18 const VariableToSimulationGroup &variable_to_simulations,
19 std::shared_ptr<const State> state,
20 const bool scale_invariant,
21 const int power,
22 const std::vector<int> &surface_selections,
23 const std::vector<int> &active_dims) : AdjointForm(variable_to_simulations), state_(std::move(state)), scale_invariant_(scale_invariant), power_(power), active_dims_(active_dims)
24 {
25 const auto &mesh = *(state_->mesh);
26 const int dim = mesh.dimension();
27 const int n_verts = mesh.n_vertices();
28 assert(mesh.is_simplicial());
29
30 surface_ids_ = std::set(surface_selections.begin(), surface_selections.end());
31
32 // collect active nodes
33 std::vector<bool> active_mask;
34 active_mask.assign(n_verts, false);
35 std::vector<Eigen::Triplet<bool>> T_adj;
36
37 for (int b = 0; b < mesh.n_boundary_elements(); b++)
38 {
39 const int boundary_id = mesh.get_boundary_id(b);
40 if (!surface_ids_.empty() && surface_ids_.find(boundary_id) == surface_ids_.end())
41 continue;
42
43 for (int lv = 0; lv < dim; lv++)
44 {
45 active_mask[mesh.boundary_element_vertex(b, lv)] = true;
46 }
47
48 for (int lv1 = 0; lv1 < dim; lv1++)
49 for (int lv2 = 0; lv2 < lv1; lv2++)
50 {
51 const int v1 = mesh.boundary_element_vertex(b, lv1);
52 const int v2 = mesh.boundary_element_vertex(b, lv2);
53 T_adj.emplace_back(v2, v1, true);
54 T_adj.emplace_back(v1, v2, true);
55 }
56 }
57
58 adj.setZero();
59 adj.resize(n_verts, n_verts);
60 adj.setFromTriplets(T_adj.begin(), T_adj.end());
61
62 std::vector<int> degrees(n_verts, 0);
63 for (int k = 0; k < adj.outerSize(); ++k)
64 for (Eigen::SparseMatrix<bool, Eigen::RowMajor>::InnerIterator it(adj, k); it; ++it)
65 degrees[k]++;
66
67 L.setZero();
68 L.resize(n_verts, n_verts);
70 {
71 std::vector<Eigen::Triplet<double>> T_L;
72 for (int k = 0; k < adj.outerSize(); ++k)
73 {
74 if (!active_mask[k])
75 continue;
76 T_L.emplace_back(k, k, 1);
77 for (Eigen::SparseMatrix<bool, Eigen::RowMajor>::InnerIterator it(adj, k); it; ++it)
78 {
79 assert(it.row() == k);
80 T_L.emplace_back(it.row(), it.col(), -1. / degrees[k]);
81 }
82 }
83 L.setFromTriplets(T_L.begin(), T_L.end());
84 L.prune([](int i, int j, double val) { return abs(val) > 1e-12; });
85 }
86 }
87
88 double BoundarySmoothingForm::value_unweighted(const Eigen::VectorXd &x) const
89 {
90 const auto &mesh = *(state_->mesh);
91 const int dim = mesh.dimension();
92 const int n_verts = mesh.n_vertices();
93
94 double val = 0;
96 {
97 for (int b = 0; b < adj.rows(); b++)
98 {
100 s.setZero(dim);
101 double sum_norm = 0;
102 int valence = 0;
103 for (Eigen::SparseMatrix<bool, Eigen::RowMajor>::InnerIterator it(adj, b); it; ++it)
104 {
105 assert(it.col() != b);
106 polyfem::RowVectorNd x = mesh.point(b) - mesh.point(it.col());
107 s += x;
108 sum_norm += x.norm();
109 valence += 1;
110 }
111 if (valence)
112 {
113 s = s / sum_norm;
114 val += pow(s.norm(), power_);
115 }
116 }
117 }
118 else
119 {
120 Eigen::MatrixXd V;
121 state_->get_vertices(V);
122
123 val = (L * V(Eigen::all, active_dims_)).squaredNorm();
124 }
125
126 return val;
127 }
128
129 void BoundarySmoothingForm::compute_partial_gradient(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
130 {
131 const auto &mesh = *(state_->mesh);
132 const int dim = mesh.dimension();
133 const int n_verts = mesh.n_vertices();
134
135 Eigen::VectorXd grad;
137 {
138 grad.setZero(n_verts * dim);
139 for (int b = 0; b < adj.rows(); b++)
140 {
142 s.setZero(dim);
143 double sum_norm = 0;
144 polyfem::RowVectorNd sum_normalized = s;
145 int valence = 0;
146 for (Eigen::SparseMatrix<bool, Eigen::RowMajor>::InnerIterator it(adj, b); it; ++it)
147 {
148 assert(it.col() != b);
149 polyfem::RowVectorNd x = mesh.point(b) - mesh.point(it.col());
150 s += x;
151 sum_norm += x.norm();
152 sum_normalized += x.normalized();
153 valence += 1;
154 }
155 if (valence)
156 {
157 s = s / sum_norm;
158 const double coeff = power_ * pow(s.norm(), power_ - 2.) / sum_norm;
159
160 grad.segment(b * dim, dim) += (s * valence - s.squaredNorm() * sum_normalized) * coeff;
161 for (Eigen::SparseMatrix<bool, Eigen::RowMajor>::InnerIterator it(adj, b); it; ++it)
162 grad.segment(it.col() * dim, dim) -= (s + s.squaredNorm() * (mesh.point(it.col()) - mesh.point(b)).normalized()) * coeff;
163 }
164 }
165 }
166 else
167 {
168 Eigen::MatrixXd V;
169 state_->get_vertices(V);
170
171 Eigen::MatrixXd grad_mat = 2 * (L.transpose() * (L * V));
172 for (int d = 0; d < dim; d++)
173 if (std::find(active_dims_.begin(), active_dims_.end(), d) == active_dims_.end())
174 grad_mat.col(d).setZero();
175 grad = utils::flatten(grad_mat);
176 }
177
179 return grad;
180 });
181 }
182} // namespace polyfem::solver
int V
double val
Definition Assembler.cpp:86
int x
const VariableToSimulationGroup variable_to_simulations_
Eigen::SparseMatrix< bool, Eigen::RowMajor > adj
BoundarySmoothingForm(const VariableToSimulationGroup &variable_to_simulations, std::shared_ptr< const State > state, const bool scale_invariant, const int power, const std::vector< int > &surface_selections, const std::vector< int > &active_dims)
std::shared_ptr< const State > state_
double value_unweighted(const Eigen::VectorXd &x) const override
Compute the value of the form.
void compute_partial_gradient(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const override
Eigen::SparseMatrix< double, Eigen::RowMajor > L
virtual double weight() const
Get the form's multiplicative constant weight.
Definition Form.hpp:128
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.
Eigen::VectorXd flatten(const Eigen::MatrixXd &X)
Flatten rowwises.
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Definition Types.hpp:13