20 Eigen::MatrixXd
extract_nodes(
const int dim,
const std::vector<basis::ElementBases> &bases,
const std::vector<basis::ElementBases> &gbases,
const Eigen::VectorXd &u,
int order,
int n_elem)
23 n_elem = bases.size();
24 Eigen::MatrixXd local_pts;
29 const int n_basis_per_cell = local_pts.rows();
30 Eigen::MatrixXd cp = Eigen::MatrixXd::Zero(n_elem * n_basis_per_cell, dim);
31 for (
int e = 0; e < n_elem; ++e)
34 vals.
compute(e, dim == 3, local_pts, bases[e], gbases[e]);
38 cp.middleRows(e * n_basis_per_cell, n_basis_per_cell) += g.val *
vals.
basis_values[j].val * u.segment(g.index * dim, dim).transpose();
40 Eigen::MatrixXd mapped;
41 gbases[e].eval_geom_mapping(local_pts, mapped);
42 cp.middleRows(e * n_basis_per_cell, n_basis_per_cell) += mapped;
69 const Eigen::MatrixXd &cp,
70 const Eigen::MatrixXd &uv)
72#ifdef POLYFEM_WITH_MISO
73 const int dim = cp.cols();
74 Eigen::VectorXd result(uv.rows());
77 std::vector<Eigen::MatrixXd> grads(cp.rows(), Eigen::MatrixXd::Zero(uv.rows(), dim));
78 for (
int bid = 0; bid < cp.rows(); bid++)
85 for (
int k = 0; k < uv.rows(); k++)
87 Eigen::MatrixXd jac_mat = Eigen::MatrixXd::Zero(dim, dim);
88 for (
int bid = 0; bid < cp.rows(); bid++)
89 jac_mat += cp.row(bid).transpose() * grads[bid].row(k);
90 result(k) = jac_mat.determinant();
95 return Eigen::VectorXd::Zero(uv.rows());
124 const std::vector<basis::ElementBases> &bases,
125 const std::vector<basis::ElementBases> &gbases,
126 const Eigen::VectorXd &u,
127 const unsigned max_iter)
129 std::vector<int> invalidList;
130#ifdef POLYFEM_WITH_MISO
131 RealInterval::init();
132 const int order = std::max(bases[0].bases.front().order(), gbases[0].bases.front().order());
133 const int n_per = std::max(bases[0].bases.size(), gbases[0].bases.size());
134 const Eigen::MatrixXd cp =
extract_nodes(dim, bases, gbases, u, order);
135 const int n_elem =
static_cast<int>(bases.size());
137 auto run_solve = [&](
auto problem,
int e) {
139 params.constraintEpsilon = {0.0};
140 params.maxIter = max_iter;
141 params.findOne =
true;
143 auto sols = solve(std::move(problem), params, &info);
145 logger().warn(
"Jacobian solve gave up at element {} after {} iterations", e, info.numIterations);
146 return !sols.empty();
149 for (
int e = 0; e < n_elem; ++e)
151 const int o = e * n_per;
152 bool invalid =
false;
158 invalid = JacEval_P1Tri(rv<3>(cp, o, 0, tri1_perm), rv<3>(cp, o, 1, tri1_perm)) <= 0;
161 invalid = run_solve(make_p2tri_val(cp, o), e);
164 invalid = run_solve(make_p3tri_val(cp, o), e);
167 invalid = run_solve(make_p4tri_val(cp, o), e);
170 throw std::invalid_argument(
"Order not supported");
178 invalid = JacEval_P1Tet(rv<4>(cp, o, 0, tet1_perm), rv<4>(cp, o, 1, tet1_perm), rv<4>(cp, o, 2, tet1_perm)) <= 0;
181 invalid = run_solve(make_p2tet_val(cp, o), e);
184 invalid = run_solve(make_p3tet_val(cp, o), e);
187 throw std::invalid_argument(
"Order not supported");
191 invalidList.push_back(e);
193 RealInterval::deinit();
203 const std::vector<basis::ElementBases> &bases,
204 const std::vector<basis::ElementBases> &gbases,
205 const Eigen::VectorXd &u,
206 const double threshold,
207 const unsigned max_iter)
209#ifdef POLYFEM_WITH_MISO
210 RealInterval::init();
211 const int order = std::max(bases[0].bases.front().order(), gbases[0].bases.front().order());
212 const int n_per = std::max(bases[0].bases.size(), gbases[0].bases.size());
213 const Eigen::MatrixXd cp =
extract_nodes(dim, bases, gbases, u, order);
214 const int n_elem =
static_cast<int>(bases.size());
216 auto run_solve = [threshold, max_iter](
auto problem,
int e) {
218 params.constraintEpsilon = {threshold};
219 params.maxIter = max_iter;
220 params.findOne =
true;
222 auto sols = solve(std::move(problem), params, &info);
225 logger().warn(
"Jacobian solve gave up at element {} after {} iterations", e, info.numIterations);
228 return !sols.empty();
231 for (
int e = 0; e < n_elem; ++e)
233 const int o = e * n_per;
234 bool invalid =
false;
240 invalid = JacEval_P1Tri(rv<3>(cp, o, 0, tri1_perm), rv<3>(cp, o, 1, tri1_perm)) <= 0;
243 invalid = run_solve(make_p2tri_val(cp, o), e);
246 invalid = run_solve(make_p3tri_val(cp, o), e);
249 invalid = run_solve(make_p4tri_val(cp, o), e);
252 throw std::invalid_argument(
"Order not supported");
260 invalid = JacEval_P1Tet(rv<4>(cp, o, 0, tet1_perm), rv<4>(cp, o, 1, tet1_perm), rv<4>(cp, o, 2, tet1_perm)) <= 0;
263 invalid = run_solve(make_p2tet_val(cp, o), e);
266 invalid = run_solve(make_p3tet_val(cp, o), e);
269 throw std::invalid_argument(
"Order not supported");
274 RealInterval::deinit();
275 return {
false, e,
Tree{}};
278 RealInterval::deinit();
279 return {
true, -1,
Tree{}};
282 return {
false, -1,
Tree{}};
288 const std::vector<basis::ElementBases> &bases,
289 const std::vector<basis::ElementBases> &gbases,
290 const Eigen::VectorXd &u1,
291 const Eigen::VectorXd &u2,
294 const unsigned max_iter)
296#ifdef POLYFEM_WITH_MISO
297 RealInterval::init();
298 const int order = std::max(bases[0].bases.front().order(), gbases[0].bases.front().order());
299 const int n_per = std::max(bases[0].bases.size(), gbases[0].bases.size());
300 const Eigen::MatrixXd cp1 =
extract_nodes(dim, bases, gbases, u1, order);
301 const Eigen::MatrixXd cp2 =
extract_nodes(dim, bases, gbases, u2, order);
302 const int n_elem =
static_cast<int>(bases.size());
306 double invalid_step = 1.0;
310 const unsigned n_children = (dim == 2) ? 4u : 8u;
314 auto run_batch = [&](
auto factory) {
315 using ProblemType =
decltype(factory(0));
316 std::vector<ProblemType> problems;
317 problems.reserve(n_elem);
318 for (
int e = 0; e < n_elem; ++e)
319 problems.push_back(factory(e * n_per));
322 params.targetPrecision = precision;
323 params.constraintEpsilon = {threshold};
324 params.maxIter = max_iter;
325 params.requiredMinimum = 0.;
326 params.minBoxWidth = 0.;
328 auto result = batch_minimize(std::move(problems), params, &info);
329 const double t_lo = lower(result);
333 logger().error(
"Jacobian batch_minimize gave up with step size 0 after {} iterations", info.numIterations);
335 logger().warn(
"Jacobian batch_minimize gave up after {} iterations (step={})", info.numIterations, t_lo);
340 invalid_id =
static_cast<int>(info.pathToFeasibleId);
341 invalid_step = upper(result);
343 build_tree(tree, info.pathToFeasible, n_children);
352 run_batch([&](
int o) {
return make_p1tri_cgv(cp1, cp2, o); });
355 run_batch([&](
int o) {
return make_p2tri_cgv(cp1, cp2, o); });
358 run_batch([&](
int o) {
return make_p3tri_cgv(cp1, cp2, o); });
361 run_batch([&](
int o) {
return make_p4tri_cgv(cp1, cp2, o); });
364 throw std::invalid_argument(
"Order not supported");
372 run_batch([&](
int o) {
return make_p1tet_cgv(cp1, cp2, o); });
375 run_batch([&](
int o) {
return make_p2tet_cgv(cp1, cp2, o); });
378 run_batch([&](
int o) {
return make_p3tet_cgv(cp1, cp2, o); });
381 throw std::invalid_argument(
"Order not supported");
385 RealInterval::deinit();
386 return {step, invalid_id, invalid_step, tree};
389 return {1.0, -1, 1.0,
Tree{}};
void compute(const int el_index, const bool is_volume, const Eigen::MatrixXd &pts, const basis::ElementBases &basis, const basis::ElementBases &gbasis)
computes the per element values at the local (ref el) points (pts) sets basis_values,...
std::tuple< bool, int, Tree > is_valid(const int dim, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const Eigen::VectorXd &u, const double threshold, const unsigned max_iter)
std::tuple< double, int, double, Tree > max_time_step(const int dim, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const Eigen::VectorXd &u1, const Eigen::VectorXd &u2, double precision, double threshold, const unsigned max_iter)
Eigen::MatrixXd extract_nodes(const int dim, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const Eigen::VectorXd &u, int order, int n_elem)