Wildmeshing Toolkit
Loading...
Searching...
No Matches
AMIPSOptimizationSmoothing.cpp
Go to the documentation of this file.
2
3#include <polysolve/nonlinear/Problem.hpp>
4#include <wmtk/Mesh.hpp>
5#include <wmtk/Types.hpp>
10#include <wmtk/utils/orient.hpp>
11
12#include <polysolve/nonlinear/Solver.hpp>
13
14#include <Eigen/Core>
15
16namespace wmtk::operations {
17
18template <int S>
19class AMIPSOptimizationSmoothing::WMTKAMIPSProblem : public polysolve::nonlinear::Problem
20{
21public:
22 using typename polysolve::nonlinear::Problem::Scalar;
23 using typename polysolve::nonlinear::Problem::THessian;
24 using typename polysolve::nonlinear::Problem::TVector;
25
26 WMTKAMIPSProblem(std::vector<std::array<double, S>>& cells);
27
28 TVector initial_value() const;
29
30 double value(const TVector& x) override;
31 void gradient(const TVector& x, TVector& gradv) override;
32 void hessian(const TVector& x, THessian& hessian) override
33 {
34 throw std::runtime_error("Sparse functions do not exist, use dense solver");
35 }
36 void hessian(const TVector& x, Eigen::MatrixXd& hessian) override;
37
38 void solution_changed(const TVector& new_x) override;
39
40 bool is_step_valid(const TVector& x0, const TVector& x1) override;
41
42private:
43 std::vector<std::array<double, S>> m_cells;
44// Enables the use of power of p to approximate minimizing max energy
45// #define WMTK_ENABLE_P
46#ifdef WMTK_ENABLE_P
47 const int p = 4;
48#endif
49};
50
51template <int S>
53 std::vector<std::array<double, S>>& cells)
54 : m_cells(cells)
55{}
56
57template <int S>
59{
60 constexpr int64_t size = S == 6 ? 2 : 3;
61 Eigen::Matrix<double, size, 1> tmp;
62
63 for (int64_t d = 0; d < size; ++d) {
64 tmp(d) = m_cells[0][d];
65 }
66
67 return tmp;
68}
69
70template <int S>
72{
73 double res = 0;
74 for (auto c : m_cells) {
75 if constexpr (S == 6) {
76 assert(x.size() == 2);
77 c[0] = x[0];
78 c[1] = x[1];
79#ifdef WMTK_ENABLE_P
80 res += std::pow(wmtk::function::Tri_AMIPS_energy(c), p);
81#else
83#endif
84 } else {
85 assert(x.size() == 3);
86 c[0] = x[0];
87 c[1] = x[1];
88 c[2] = x[2];
89#ifdef WMTK_ENABLE_P
90 res += std::pow(wmtk::function::Tet_AMIPS_energy(c), p);
91#else
93#endif
94 }
95 }
96
97 // std::cout << res << std::endl;
98 return res;
99}
100
101template <int S>
103{
104 constexpr int64_t size = S == 6 ? 2 : 3;
105 gradv.resize(size);
106 gradv.setZero();
107 Eigen::Matrix<double, size, 1> tmp(size);
108#ifdef WMTK_ENABLE_P
109 double tmp2 = 0;
110#endif
111
112 for (auto c : m_cells) {
113 if constexpr (S == 6) {
114 assert(x.size() == 2);
115 c[0] = x[0];
116 c[1] = x[1];
118#ifdef WMTK_ENABLE_P
120#endif
121 } else {
122 assert(x.size() == 3);
123 c[0] = x[0];
124 c[1] = x[1];
125 c[2] = x[2];
127#ifdef WMTK_ENABLE_P
129#endif
130 }
131#ifdef WMTK_ENABLE_P
132 gradv += double(p) * pow(tmp2, p - 1) * tmp;
133#else
134 gradv += tmp;
135#endif
136 }
137}
138
139template <int S>
141 const TVector& x,
142 Eigen::MatrixXd& hessian)
143{
144 // std::cout << "error here !!! Hessian used" << std::endl;
145 constexpr int64_t size = S == 6 ? 2 : 3;
146 hessian.resize(size, size);
147 hessian.setZero();
148 Eigen::Matrix<double, size, size> tmp;
149#ifdef WMTK_ENABLE_P
150 double tmp2 = 0;
151 Eigen::Matrix<double, size, 1> tmpj(size);
152#endif
153
154 for (auto c : m_cells) {
155 if constexpr (S == 6) {
156 assert(x.size() == 2);
157 c[0] = x[0];
158 c[1] = x[1];
160#ifdef WMTK_ENABLE_P
163#endif
164 } else {
165 assert(x.size() == 3);
166 c[0] = x[0];
167 c[1] = x[1];
168 c[2] = x[2];
170#ifdef WMTK_ENABLE_P
173#endif
174 }
175#ifdef WMTK_ENABLE_P
176 hessian += (p) * (p - 1) * std::pow(tmp2, p - 2) * tmpj * tmpj.transpose() +
177 p * std::pow(tmp2, p - 1) * tmp;
178#else
179 hessian += tmp;
180#endif
181 // 12 f(x)^2 * f(x)'*f^T'(x) + 4 f(x)^3 * H
182 }
183}
184
185template <int S>
188
189template <int S>
191 const TVector& x0,
192 const TVector& x1)
193{
194 constexpr int64_t size = S == 6 ? 2 : 3;
195 Eigen::Matrix<double, size, 1> p0 = x1, p1, p2, p3;
196 if constexpr (S == 6) {
197 for (const auto& c : m_cells) {
198 p1 << c[2], c[3];
199 p2 << c[4], c[5];
200
201 if (wmtk::utils::wmtk_orient2d(p0, p1, p2) <= 0) return false;
202 }
203 } else {
204 for (const auto& c : m_cells) {
205 p1 << c[3], c[4], c[5];
206 p2 << c[6], c[7], c[8];
207 p3 << c[9], c[10], c[11];
208
209 // Eigen::Matrix<double, size, 1> x0m = x0;
210 // assert(wmtk::utils::wmtk_orient3d(x0m, p1, p2, p3) > 0);
211 // if (wmtk::utils::wmtk_orient3d(p0, p1, p2, p3) <= 0) {
212 // // std::cout << wmtk::utils::wmtk_orient3d(x0m, p1, p2, p3) << std::endl;
213 // return false;
214 // }
215
216 Eigen::Matrix<double, size, 1> x0m = x0;
217 assert(wmtk::utils::wmtk_orient3d(p3, x0m, p1, p2) > 0);
218 if (wmtk::utils::wmtk_orient3d(p3, p0, p1, p2) <= 0) {
219 // std::cout << wmtk::utils::wmtk_orient3d(p3, x0m, p1, p2) << std::endl;
220 return false;
221 }
222 }
223 }
224 return true;
225}
226
227
229 Mesh& mesh,
230 const attribute::MeshAttributeHandle& coords)
232 , m_coordinate_handle(coords)
233 , m_amips(mesh, coords)
234{
235 // assert(m_coordinate_handle.holds<Rational>());
236
237 m_linear_solver_params = R"({"solver": "Eigen::LDLT"})"_json;
238 m_nonlinear_solver_params = R"({"solver": "DenseNewton", "max_iterations": 10})"_json;
239 // m_nonlinear_solver_params = R"({"solver": "L-BFGS", "max_iterations": 100,
240 // "advanced":{"apply_gradient_fd": "FullFiniteDiff"}})"_json;
241 // m_nonlinear_solver_params = R"({"solver": "GradientDescent", "max_iterations": 100})"_json;
242
243
245}
246
248{
249 m_solver = polysolve::nonlinear::Solver::create(
252 1,
253 opt_logger());
254}
255
256
257std::vector<simplex::Simplex> AMIPSOptimizationSmoothing::execute(const simplex::Simplex& simplex)
258{
260 auto accessor = mesh().create_accessor(m_coordinate_handle.as<Rational>());
261
263 mesh(),
264 simplex,
265 mesh().top_simplex_type());
266
267 if (mesh().top_simplex_type() == PrimitiveType::Triangle) {
268 std::vector<std::array<double, 6>> cells;
269
270 for (const simplex::Simplex& cell : neighs) {
271 cells.emplace_back(m_amips.get_raw_coordinates<3, 2>(cell, simplex));
272 }
273 WMTKAMIPSProblem<6> problem(cells);
274
275 auto x = problem.initial_value();
276 try {
277 m_solver->minimize(problem, x);
278
279 for (int64_t d = 0; d < m_coordinate_handle.dimension(); ++d) {
280 accessor.vector_attribute(simplex.tuple())[d] = Rational(x[d], true);
281 }
282 } catch (const std::exception&) {
283 return {};
284 }
285 } else {
286 assert(mesh().top_simplex_type() == PrimitiveType::Tetrahedron);
287
288 std::vector<std::array<double, 12>> cells;
289
290 for (simplex::Simplex cell : neighs) {
291 // auto vertices = mesh().orient_vertices(cell.tuple());
292 // int idx = -1;
293 // for (int i = 0; i < 4; ++i) {
294 // if (simplex::Simplex::vertex(mesh(), vertices[i]) == simplex) {
295 // idx = i;
296 // break;
297 // }
298 // }
299 // if (idx == -1) {
300 // std::cout << "idx not found" << std::endl;
301 // }
302
303 // std::rotate(vertices.begin(), vertices.begin() + idx, vertices.end());
304
305
306 // assert(vertices.size() == 4);
307 // if (!simplex::utils::SimplexComparisons::equal(
308 // mesh(),
309 // simplex::Simplex::vertex(mesh(), vertices[0]),
310 // simplex)) {
311 // std::cout << "error here" << std::endl;
312 // }
313
314 if (!mesh().is_ccw(cell.tuple())) {
315 // switch any local id but NOT the vertex
316 cell = simplex::Simplex(
317 mesh(),
318 cell.primitive_type(),
319 mesh().switch_tuple(cell.tuple(), PrimitiveType::Edge));
320 }
321 assert(mesh().is_ccw(cell.tuple()));
322
323 const auto vertices =
325
326
327 assert(vertices.size() == 4);
329 mesh(),
330 vertices.simplex_vector()[0],
331 simplex)) {
332 std::cout << "error here" << std::endl;
333 }
334
335
336 std::array<double, 12> single_cell;
337 std::vector<Vector3r> ps;
338 for (size_t i = 0; i < 4; ++i) {
339 const simplex::Simplex& v = vertices.simplex_vector()[i];
340 // const auto p = accessor.const_vector_attribute(vertices[i]);
341 const auto p = accessor.const_vector_attribute(v);
342 ps.push_back(p);
343 single_cell[3 * i + 0] = p[0].to_double();
344 single_cell[3 * i + 1] = p[1].to_double();
345 single_cell[3 * i + 2] = p[2].to_double();
346
347 if (!p[0].is_rounded() || !p[1].is_rounded() || !p[2].is_rounded()) return {};
348 }
349 // if (wmtk::utils::wmtk_orient3d(ps[3], ps[0], ps[1], ps[2]) <= 0) {
350 // std::cout << "this is wrong" << std::endl;
351 // }
352
353 cells.emplace_back(single_cell);
354
355 // cells.emplace_back(m_amips.get_raw_coordinates<4, 3>(cell, simplex));
356 }
357 WMTKAMIPSProblem<12> problem(cells);
358
359 {
360 Eigen::Vector3d x1(cells[0][0], cells[0][1], cells[0][2]);
361 if (!problem.is_step_valid(x1, x1)) {
362 std::cout << "step is not valid!!!!!!!!!!!!!!!!" << std::endl;
363 }
364 }
365
366 auto x = problem.initial_value();
367 auto x0 = problem.initial_value();
368
369 try {
370 m_solver->minimize(problem, x);
371
372 } catch (const std::exception&) {
373 }
374
375 // Hack for surface only
376
377 auto child_meshes = mesh().get_child_meshes();
378
379
380 double alpha = 1.00;
381 // for (auto child_mesh : child_meshes) {
382 // if (!mesh().map_to_child(*child_mesh, simplex).empty()) {
383 // alpha = 0.01;
384 // break;
385 // }
386 // }
387
388
389 for (int64_t d = 0; d < m_coordinate_handle.dimension(); ++d) {
390 // accessor.vector_attribute(simplex.tuple())[d] = Rational(x[d], true);
391 accessor.vector_attribute(simplex.tuple())[d] =
392 Rational((1 - alpha) * x0[d] + alpha * x[d], true);
393 }
394 }
395
396 // assert(attribute_handle() == m_function.attribute_handle());
397
398 double res = 0;
399 } else {
400 auto accessor = mesh().create_accessor(m_coordinate_handle.as<double>());
401
403 mesh(),
404 simplex,
405 mesh().top_simplex_type());
406
407 if (mesh().top_simplex_type() == PrimitiveType::Triangle) {
408 std::vector<std::array<double, 6>> cells;
409
410 for (const simplex::Simplex& cell : neighs) {
411 cells.emplace_back(m_amips.get_raw_coordinates<3, 2>(cell, simplex));
412 }
413 WMTKAMIPSProblem<6> problem(cells);
414
415 auto x = problem.initial_value();
416 try {
417 m_solver->minimize(problem, x);
418
419 for (int64_t d = 0; d < m_coordinate_handle.dimension(); ++d) {
420 accessor.vector_attribute(simplex.tuple())[d] = x[d];
421 }
422 } catch (const std::exception&) {
423 return {};
424 }
425 } else {
426 assert(mesh().top_simplex_type() == PrimitiveType::Tetrahedron);
427
428 std::vector<std::array<double, 12>> cells;
429
430 for (simplex::Simplex cell : neighs) {
431 if (!mesh().is_ccw(cell.tuple())) {
432 // switch any local id but NOT the vertex
433 cell = simplex::Simplex(
434 mesh(),
435 cell.primitive_type(),
436 mesh().switch_tuple(cell.tuple(), PrimitiveType::Edge));
437 }
438 assert(mesh().is_ccw(cell.tuple()));
439
440 const auto vertices =
442
443
444 assert(vertices.size() == 4);
446 mesh(),
447 vertices.simplex_vector()[0],
448 simplex)) {
449 std::cout << "error here" << std::endl;
450 }
451
452
453 std::array<double, 12> single_cell;
454 std::vector<Vector3d> ps;
455 for (size_t i = 0; i < 4; ++i) {
456 const simplex::Simplex& v = vertices.simplex_vector()[i];
457 // const auto p = accessor.const_vector_attribute(vertices[i]);
458 const auto p = accessor.const_vector_attribute(v);
459 ps.push_back(p);
460 single_cell[3 * i + 0] = p[0];
461 single_cell[3 * i + 1] = p[1];
462 single_cell[3 * i + 2] = p[2];
463 }
464 // if (wmtk::utils::wmtk_orient3d(ps[3], ps[0], ps[1], ps[2]) <= 0) {
465 // std::cout << "this is wrong" << std::endl;
466 // }
467
468 cells.emplace_back(single_cell);
469
470 // cells.emplace_back(m_amips.get_raw_coordinates<4, 3>(cell, simplex));
471 }
472 WMTKAMIPSProblem<12> problem(cells);
473
474 {
475 Eigen::Vector3d x1(cells[0][0], cells[0][1], cells[0][2]);
476 if (!problem.is_step_valid(x1, x1)) {
477 std::cout << "step is not valid!!!!!!!!!!!!!!!!" << std::endl;
478 }
479 }
480
481 auto x = problem.initial_value();
482 auto x0 = problem.initial_value();
483
484 try {
485 m_solver->minimize(problem, x);
486
487 } catch (const std::exception&) {
488 }
489
490 // Hack for surface only
491
492 auto child_meshes = mesh().get_child_meshes();
493
494
495 double alpha = 1.00;
496 // for (auto child_mesh : child_meshes) {
497 // if (!mesh().map_to_child(*child_mesh, simplex).empty()) {
498 // alpha = 0.01;
499 // break;
500 // }
501 // }
502
503
504 for (int64_t d = 0; d < m_coordinate_handle.dimension(); ++d) {
505 // accessor.vector_attribute(simplex.tuple())[d] = Rational(x[d], true);
506 accessor.vector_attribute(simplex.tuple())[d] = (1 - alpha) * x0[d] + alpha * x[d];
507 }
508 }
509
510 // assert(attribute_handle() == m_function.attribute_handle());
511
512 double res = 0;
513 }
514
515
516 return AttributesUpdate::execute(simplex);
517}
518
519} // namespace wmtk::operations
virtual bool is_ccw(const Tuple &tuple) const =0
TODO this needs dimension?
attribute::Accessor< T, Mesh, D > create_accessor(const attribute::MeshAttributeHandle &handle)
std::vector< std::shared_ptr< Mesh > > get_child_meshes() const
returns the direct multimesh child meshes for the current mesh
auto as() const -> const held_handle_type< held_type_from_primitive< T >()> &
std::array< double, NV *DIM > get_raw_coordinates(const simplex::Simplex &domain_simplex, const std::optional< simplex::Simplex > &variable_simplex={}) const
Definition AMIPS.cpp:638
bool is_step_valid(const TVector &x0, const TVector &x1) override
std::vector< simplex::Simplex > execute(const simplex::Simplex &simplex) override
returns an empty vector in case of failure
std::shared_ptr< polysolve::nonlinear::Solver > m_solver
const attribute::MeshAttributeHandle & m_coordinate_handle
AMIPSOptimizationSmoothing(Mesh &mesh, const attribute::MeshAttributeHandle &coords)
virtual std::vector< simplex::Simplex > execute(const simplex::Simplex &simplex) override
returns an empty vector in case of failure
const Mesh & mesh() const
Definition Operation.hpp:45
const Tuple & tuple() const
Definition Simplex.hpp:53
static bool equal(const Mesh &m, const Simplex &s0, const Simplex &s1)
bool is_ccw(PrimitiveType pt, const Tuple &t)
Definition is_ccw.cpp:8
void Tet_AMIPS_jacobian(const std::array< double, 12 > &T, Eigen::Vector3d &result_0)
Definition AMIPS.cpp:75
void Tri_AMIPS_hessian(const std::array< double, 6 > &T, Eigen::Matrix2d &result_0)
Definition AMIPS.cpp:542
void Tri_AMIPS_jacobian(const std::array< double, 6 > &T, Eigen::Vector2d &result_0)
Definition AMIPS.cpp:503
double Tet_AMIPS_energy(const std::array< double, 12 > &T)
Definition AMIPS.cpp:375
void Tet_AMIPS_hessian(const std::array< double, 12 > &T, Eigen::Matrix3d &result_0)
Definition AMIPS.cpp:172
double Tri_AMIPS_energy(const std::array< double, 6 > &T)
Definition AMIPS.cpp:473
std::vector< Simplex > cofaces_single_dimension_simplices(const Mesh &mesh, const Simplex &simplex, PrimitiveType cofaces_type)
SimplexCollection faces_single_dimension(const Mesh &mesh, const Simplex &simplex, const PrimitiveType face_type)
Returns a vector with all faces in the boundary of a simplex of the given dimension.
int wmtk_orient3d(const Eigen::Ref< const Eigen::Vector3< Rational > > &p0, const Eigen::Ref< const Eigen::Vector3< Rational > > &p1, const Eigen::Ref< const Eigen::Vector3< Rational > > &p2, const Eigen::Ref< const Eigen::Vector3< Rational > > &p3)
Definition orient.cpp:75
int wmtk_orient2d(double p0x, double p0y, double p1x, double p1y, double p2x, double p2y)
Definition orient.cpp:178
spdlog::logger & opt_logger()
Retrieves the logger for the optimization.
Definition Logger.cpp:75
Rational pow(const Rational &x, int p)
Definition Rational.cpp:166