PolyFEM
Loading...
Searching...
No Matches
AMIPSForm.cpp
Go to the documentation of this file.
2
4
7
16
17#include <cmath>
18
19namespace polyfem::solver
20{
21 namespace
22 {
23 void scaled_jacobian(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, Eigen::VectorXd &quality)
24 {
25 const int dim = F.cols() - 1;
26
27 quality.setZero(F.rows());
28 if (dim == 2)
29 {
30 for (int i = 0; i < F.rows(); i++)
31 {
32 Eigen::RowVector3d e0;
33 e0(2) = 0;
34 e0.head(2) = V.row(F(i, 2)) - V.row(F(i, 1));
35 Eigen::RowVector3d e1;
36 e1(2) = 0;
37 e1.head(2) = V.row(F(i, 0)) - V.row(F(i, 2));
38 Eigen::RowVector3d e2;
39 e2(2) = 0;
40 e2.head(2) = V.row(F(i, 1)) - V.row(F(i, 0));
41
42 double l0 = e0.norm();
43 double l1 = e1.norm();
44 double l2 = e2.norm();
45
46 double A = 0.5 * (e0.cross(e1)).norm();
47 double Lmax = std::max(l0 * l1, std::max(l1 * l2, l0 * l2));
48
49 quality(i) = 2 * A * (2 / sqrt(3)) / Lmax;
50 }
51 }
52 else
53 {
54 for (int i = 0; i < F.rows(); i++)
55 {
56 Eigen::RowVector3d e0 = V.row(F(i, 1)) - V.row(F(i, 0));
57 Eigen::RowVector3d e1 = V.row(F(i, 2)) - V.row(F(i, 1));
58 Eigen::RowVector3d e2 = V.row(F(i, 0)) - V.row(F(i, 2));
59 Eigen::RowVector3d e3 = V.row(F(i, 3)) - V.row(F(i, 0));
60 Eigen::RowVector3d e4 = V.row(F(i, 3)) - V.row(F(i, 1));
61 Eigen::RowVector3d e5 = V.row(F(i, 3)) - V.row(F(i, 2));
62
63 double l0 = e0.norm();
64 double l1 = e1.norm();
65 double l2 = e2.norm();
66 double l3 = e3.norm();
67 double l4 = e4.norm();
68 double l5 = e5.norm();
69
70 double J = std::abs((e0.cross(e3)).dot(e2));
71
72 double a1 = l0 * l2 * l3;
73 double a2 = l0 * l1 * l4;
74 double a3 = l1 * l2 * l5;
75 double a4 = l3 * l4 * l5;
76
77 double a = std::max({a1, a2, a3, a4, J});
78 quality(i) = J * sqrt(2) / a;
79 }
80 }
81 }
82 } // namespace
83
84 double MinJacobianForm::value_unweighted(const Eigen::VectorXd &x) const
85 {
86 const bool is_volume = varform_->get_mesh().is_volume();
87 double min_jacs = std::numeric_limits<double>::max();
88 for (size_t e = 0; e < varform_->primary_space().geometry_basis_list().size(); ++e)
89 {
90 if (varform_->get_mesh().is_polytope(e))
91 continue;
92
93 const auto &gbasis = varform_->primary_space().geometry_basis_list()[e];
94 const int n_local_bases = int(gbasis.bases.size());
95
97 gbasis.compute_quadrature(quad);
98
99 std::vector<assembler::AssemblyValues> tmp;
100
101 Eigen::MatrixXd dx = Eigen::MatrixXd::Zero(quad.points.rows(), quad.points.cols());
102 Eigen::MatrixXd dy = Eigen::MatrixXd::Zero(quad.points.rows(), quad.points.cols());
103 Eigen::MatrixXd dz;
104 if (is_volume)
105 dz = Eigen::MatrixXd::Zero(quad.points.rows(), quad.points.cols());
106
107 gbasis.evaluate_grads(quad.points, tmp);
108
109 for (int j = 0; j < n_local_bases; ++j)
110 {
111 const basis::Basis &b = gbasis.bases[j];
112
113 for (std::size_t ii = 0; ii < b.global().size(); ++ii)
114 {
115 dx += tmp[j].grad.col(0) * b.global()[ii].node * b.global()[ii].val;
116 dy += tmp[j].grad.col(1) * b.global()[ii].node * b.global()[ii].val;
117 if (is_volume)
118 dz += tmp[j].grad.col(2) * b.global()[ii].node * b.global()[ii].val;
119 }
120 }
121
122 for (long i = 0; i < dx.rows(); ++i)
123 {
124 if (is_volume)
125 {
126 Eigen::Matrix3d tmp;
127 tmp << dx.row(i), dy.row(i), dz.row(i);
128 min_jacs = std::min(min_jacs, tmp.determinant());
129 }
130 else
131 {
132 Eigen::Matrix2d tmp;
133 tmp << dx.row(i), dy.row(i);
134 min_jacs = std::min(min_jacs, tmp.determinant());
135 }
136 }
137 }
138
139 return min_jacs;
140 }
141
142 void MinJacobianForm::compute_partial_gradient(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
143 {
144 log_and_throw_adjoint_error("{} is not differentiable!", name());
145 }
146
147 AMIPSForm::AMIPSForm(const VariableToSimulationGroup &variable_to_simulation, std::shared_ptr<const varform::DifferentiableVarForm> varform)
148 : AdjointForm(variable_to_simulation),
149 varform_(std::move(varform))
150 {
152 amips_energy_->set_size(varform_->get_mesh().dimension());
153
154 json use_rest = {};
155 use_rest["use_rest_pose"] = true;
156 amips_energy_->add_multimaterial(0, use_rest, varform_->get_units(), varform_->get_root_path());
157
158 Eigen::MatrixXd V;
159 varform_->get_vertices(V);
160 varform_->get_elements(F);
162 init_geom_bases_ = varform_->primary_space().geometry_basis_list();
163 }
164
165 double AMIPSForm::value_unweighted(const Eigen::VectorXd &x) const
166 {
167 Eigen::VectorXd X = get_updated_mesh_nodes(x);
168
169 return amips_energy_->assemble_energy(varform_->get_mesh().is_volume(), init_geom_bases_, init_geom_bases_, init_ass_vals_cache_, 0, 0, AdjointTools::map_primitive_to_node_order(*varform_, X - X_rest), Eigen::VectorXd());
170 }
171
172 void AMIPSForm::compute_partial_gradient(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
173 {
175 const Eigen::VectorXd X = get_updated_mesh_nodes(x);
176 Eigen::MatrixXd grad;
177 amips_energy_->assemble_gradient(varform_->get_mesh().is_volume(), varform_->primary_space().geometry->n_bases, init_geom_bases_, init_geom_bases_, init_ass_vals_cache_, 0, 0, AdjointTools::map_primitive_to_node_order(*varform_, X - X_rest), Eigen::VectorXd(), grad); // grad wrt. gbases
179 });
180 }
181
182 bool AMIPSForm::is_step_valid(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const
183 {
184 Eigen::VectorXd X = get_updated_mesh_nodes(x1);
185 Eigen::MatrixXd V1 = utils::unflatten(X, varform_->get_mesh().dimension());
186 bool flipped = utils::is_flipped(V1, F);
187
188 if (flipped)
189 adjoint_logger().trace("[{}] Step flips elements.", name());
190
191 return !flipped;
192 }
193} // namespace polyfem::solver
int V
double J
int x
static std::shared_ptr< Assembler > make_assembler(const std::string &formulation)
Represents one basis function and its gradient.
Definition Basis.hpp:44
double value_unweighted(const Eigen::VectorXd &x) const override
Compute the value of the form.
AMIPSForm(const VariableToSimulationGroup &variable_to_simulation, std::shared_ptr< const varform::DifferentiableVarForm > varform)
virtual std::string name() const override
Definition AMIPSForm.hpp:45
bool is_step_valid(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const override
Determine if a step from solution x0 to solution x1 is allowed.
Eigen::VectorXd get_updated_mesh_nodes(const Eigen::VectorXd &x) const
Definition AMIPSForm.hpp:52
std::vector< polyfem::basis::ElementBases > init_geom_bases_
Definition AMIPSForm.hpp:63
void compute_partial_gradient(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const override
std::shared_ptr< assembler::Assembler > amips_energy_
Definition AMIPSForm.hpp:66
assembler::AssemblyValsCache init_ass_vals_cache_
Definition AMIPSForm.hpp:64
std::shared_ptr< const varform::DifferentiableVarForm > varform_
Definition AMIPSForm.hpp:59
const VariableToSimulationGroup variable_to_simulations_
virtual double weight() const
Get the form's multiplicative constant weight.
Definition Form.hpp:128
virtual std::string name() const override
Definition AMIPSForm.hpp:31
void compute_partial_gradient(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const override
double value_unweighted(const Eigen::VectorXd &x) const override
Compute the value of the form.
Definition AMIPSForm.cpp:84
std::shared_ptr< const varform::DifferentiableVarForm > varform_
Definition AMIPSForm.hpp:37
Eigen::VectorXd apply_parametrization_jacobian(ParameterType type, const varform::DifferentiableVarForm &target, const Eigen::VectorXd &x, const std::function< Eigen::VectorXd()> &grad) const
Compute parametrization jacobian for all var2sim matching parameter type and output to target varform...
int norm
Definition p_bases.py:265
bool scaled_jacobian(Mesh3DStorage &hmi, Mesh_Quality &mq)
Eigen::VectorXd map_node_to_primitive_order(const varform::DifferentiableVarForm &varform, const Eigen::VectorXd &nodes)
Eigen::VectorXd map_primitive_to_node_order(const varform::DifferentiableVarForm &varform, const Eigen::VectorXd &primitives)
bool is_flipped(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F)
Determine if any simplex is inverted or collapses.
Eigen::MatrixXd unflatten(const Eigen::VectorXd &x, int dim)
Unflatten rowwises, so every dim elements in x become a row.
Eigen::VectorXd flatten(const Eigen::MatrixXd &X)
Flatten rowwises.
spdlog::logger & adjoint_logger()
Retrieves the current logger for adjoint.
Definition Logger.cpp:30
nlohmann::json json
Definition Common.hpp:9
void log_and_throw_adjoint_error(const std::string &msg)
Definition Logger.cpp:79