17 double triangle_jacobian(
const Eigen::VectorXd &v1,
const Eigen::VectorXd &v2,
const Eigen::VectorXd &v3)
19 Eigen::VectorXd a = v2 - v1, b = v3 - v1;
20 return a(0) * b(1) - b(0) * a(1);
23 double tet_determinant(
const Eigen::VectorXd &v1,
const Eigen::VectorXd &v2,
const Eigen::VectorXd &v3,
const Eigen::VectorXd &v4)
26 mat.col(0) << v2 - v1;
27 mat.col(1) << v3 - v1;
28 mat.col(2) << v4 - v1;
29 return mat.determinant();
32 void scaled_jacobian(
const Eigen::MatrixXd &
V,
const Eigen::MatrixXi &
F, Eigen::VectorXd &quality)
34 const int dim =
F.cols() - 1;
36 quality.setZero(
F.rows());
39 for (
int i = 0; i <
F.rows(); i++)
41 Eigen::RowVector3d e0;
43 e0.head(2) =
V.row(
F(i, 2)) -
V.row(
F(i, 1));
44 Eigen::RowVector3d e1;
46 e1.head(2) =
V.row(
F(i, 0)) -
V.row(
F(i, 2));
47 Eigen::RowVector3d e2;
49 e2.head(2) =
V.row(
F(i, 1)) -
V.row(
F(i, 0));
51 double l0 = e0.norm();
52 double l1 = e1.norm();
53 double l2 = e2.norm();
55 double A = 0.5 * (e0.cross(e1)).
norm();
56 double Lmax = std::max(l0 * l1, std::max(l1 * l2, l0 * l2));
58 quality(i) = 2 * A * (2 / sqrt(3)) / Lmax;
63 for (
int i = 0; i <
F.rows(); i++)
65 Eigen::RowVector3d e0 =
V.row(
F(i, 1)) -
V.row(
F(i, 0));
66 Eigen::RowVector3d e1 =
V.row(
F(i, 2)) -
V.row(
F(i, 1));
67 Eigen::RowVector3d e2 =
V.row(
F(i, 0)) -
V.row(
F(i, 2));
68 Eigen::RowVector3d e3 =
V.row(
F(i, 3)) -
V.row(
F(i, 0));
69 Eigen::RowVector3d e4 =
V.row(
F(i, 3)) -
V.row(
F(i, 1));
70 Eigen::RowVector3d e5 =
V.row(
F(i, 3)) -
V.row(
F(i, 2));
72 double l0 = e0.norm();
73 double l1 = e1.norm();
74 double l2 = e2.norm();
75 double l3 = e3.norm();
76 double l4 = e4.norm();
77 double l5 = e5.norm();
79 double J = std::abs((e0.cross(e3)).dot(e2));
81 double a1 = l0 * l2 * l3;
82 double a2 = l0 * l1 * l4;
83 double a3 = l1 * l2 * l5;
84 double a4 = l3 * l4 * l5;
86 double a = std::max({a1, a2, a3, a4, J});
87 quality(i) = J * sqrt(2) / a;
92 bool is_flipped(
const Eigen::MatrixXd &
V,
const Eigen::MatrixXi &
F)
96 for (
int i = 0; i <
F.rows(); i++)
97 if (triangle_jacobian(
V.row(
F(i, 0)),
V.row(
F(i, 1)),
V.row(
F(i, 2))) <= 0)
100 else if (
F.cols() == 4)
102 for (
int i = 0; i <
F.rows(); i++)
103 if (tet_determinant(
V.row(
F(i, 0)),
V.row(
F(i, 1)),
V.row(
F(i, 2)),
V.row(
F(i, 3))) <= 0)
115 class AMIPSForm :
public AdjointForm
125 json transform_params = {};
126 transform_params[
"canonical_transformation"] = json::array();
127 if (!state.
mesh->is_volume())
129 Eigen::MatrixXd regular_tri(3, 3);
130 regular_tri << 0, 0, 1,
132 1. / 2., std::sqrt(3) / 2., 1;
133 regular_tri.transposeInPlace();
134 Eigen::MatrixXd regular_tri_inv = regular_tri.inverse();
137 for (
int e = 0; e < state.
mesh->n_elements(); e++)
139 Eigen::MatrixXd transform;
141 transform_params[
"canonical_transformation"].push_back(
json({
155 Eigen::MatrixXd regular_tet(4, 4);
156 regular_tet << 0, 0, 0, 1,
158 1. / 2., std::sqrt(3) / 2., 0, 1,
159 1. / 2., 1. / 2. / std::sqrt(3), std::sqrt(3) / 2., 1;
160 regular_tet.transposeInPlace();
161 Eigen::MatrixXd regular_tet_inv = regular_tet.inverse();
164 for (
int e = 0; e < state.
mesh->n_elements(); e++)
166 Eigen::MatrixXd transform;
168 transform_params[
"canonical_transformation"].push_back(
json({
187 transform_params[
"solve_displacement"] =
true;
197 virtual std::string
name()
const override {
return "AMIPS"; }
210 Eigen::MatrixXd grad;
211 amips_energy_->assemble_gradient(
state_.
mesh->is_volume(),
state_.
n_geom_bases,
init_geom_bases_,
init_geom_bases_,
init_ass_vals_cache_, 0, 0,
AdjointTools::map_primitive_to_node_order(
state_, X -
X_init), Eigen::VectorXd(), grad);
216 bool is_step_valid(
const Eigen::VectorXd &x0,
const Eigen::VectorXd &x1)
const override
220 bool flipped = is_flipped(
V1,
F);
231 Eigen::VectorXd X =
X_init;
main class that contains the polyfem solver and all its state
void get_vertices(Eigen::MatrixXd &vertices) const
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
void get_elements(Eigen::MatrixXi &elements) const
int n_geom_bases
number of geometric bases
static std::shared_ptr< Assembler > make_assembler(const std::string &formulation)
Caches basis evaluation and geometric mapping at every element.
void compute_face_jacobian(const int el_id, const Eigen::MatrixXd &reference_map, Eigen::MatrixXd &jacobian) const
void compute_cell_jacobian(const int el_id, const Eigen::MatrixXd &reference_map, Eigen::MatrixXd &jacobian) const
A collection of VariableToSimulation.
void compute_state_variable(const ParameterType type, const State *state_ptr, const Eigen::VectorXd &x, Eigen::VectorXd &state_variable) const
Evaluate the variable to simulations and overwrite the state_variable based on x.
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 scaled_jacobian(Mesh3DStorage &hmi, Mesh_Quality &mq)
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.