Skip to content

Commit 9ca0ffc

Browse files
authored
Merge pull request #68 from polyfem/extra-stop
extra stopping condition
2 parents 73d9800 + cce9a19 commit 9ca0ffc

File tree

3 files changed

+16
-3
lines changed

3 files changed

+16
-3
lines changed

nonlinear-solver-spec.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,7 @@
697697
"optional": [
698698
"f_delta",
699699
"f_delta_step_tol",
700+
"derivative_along_delta_x_tol",
700701
"apply_gradient_fd",
701702
"gradient_fd_eps"
702703
],
@@ -715,6 +716,13 @@
715716
"type": "int",
716717
"doc": "Dangerous Option: Quit the optimization if the solver reduces the energy by less than f_delta for consecutive f_delta_step_tol steps."
717718
},
719+
{
720+
"pointer": "/advanced/derivative_along_delta_x_tol",
721+
"default": 0,
722+
"min": 0,
723+
"type": "float",
724+
"doc": "Quit the optimization if the directional derivative along the descent direction is smaller than this tolerance."
725+
},
718726
{
719727
"pointer": "/advanced/apply_gradient_fd",
720728
"default": "None",

src/polysolve/nonlinear/Solver.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ namespace polysolve::nonlinear
224224

225225
gradient_fd_strategy = solver_params["advanced"]["apply_gradient_fd"];
226226
gradient_fd_eps = solver_params["advanced"]["gradient_fd_eps"];
227+
derivative_along_delta_x_tol = solver_params["advanced"]["derivative_along_delta_x_tol"];
227228
}
228229

229230
void Solver::set_strategies_iterations(const json &solver_params)
@@ -357,8 +358,9 @@ namespace polysolve::nonlinear
357358
// Compute a Δx to update the variable
358359
//
359360
bool ok = compute_update_direction(objFunc, x, grad, delta_x);
361+
const double derivative_along_delta_x = delta_x.dot(grad);
360362

361-
if (!ok || std::isnan(grad_norm) || (m_strategies[m_descent_strategy]->is_direction_descent() && grad_norm != 0 && delta_x.dot(grad) >= 0))
363+
if (!ok || std::isnan(grad_norm) || (m_strategies[m_descent_strategy]->is_direction_descent() && grad_norm != 0 && derivative_along_delta_x >= 0))
362364
{
363365
const auto current_name = descent_strategy_name();
364366

@@ -369,13 +371,13 @@ namespace polysolve::nonlinear
369371
this->m_status = cppoptlib::Status::UserDefined;
370372
log_and_throw_error(m_logger, "[{}][{}] direction is not a descent direction on last strategy (‖Δx‖={:g}; ‖g‖={:g}; Δx⋅g={:g}≥0); stopping",
371373
current_name, m_line_search->name(),
372-
delta_x.norm(), compute_grad_norm(x, grad), delta_x.dot(grad));
374+
delta_x.norm(), compute_grad_norm(x, grad), derivative_along_delta_x);
373375
}
374376

375377
m_logger.debug(
376378
"[{}][{}] direction is not a descent direction (‖Δx‖={:g}; ‖g‖={:g}; Δx⋅g={:g}≥0); reverting to {}",
377379
current_name, m_line_search->name(),
378-
delta_x.norm(), compute_grad_norm(x, grad), delta_x.dot(grad), descent_strategy_name());
380+
delta_x.norm(), compute_grad_norm(x, grad), derivative_along_delta_x, descent_strategy_name());
379381
this->m_status = cppoptlib::Status::Continue;
380382
continue;
381383
}
@@ -404,6 +406,8 @@ namespace polysolve::nonlinear
404406
this->m_current.xDelta = delta_x_norm;
405407
xDelta = this->m_current.xDelta;
406408
this->m_status = checkConvergence(this->m_stop, this->m_current);
409+
if (this->m_status == cppoptlib::Status::Continue && derivative_along_delta_x > -derivative_along_delta_x_tol)
410+
this->m_status = cppoptlib::Status::XDeltaTolerance;
407411
if (this->m_status != cppoptlib::Status::Continue)
408412
break;
409413

src/polysolve/nonlinear/Solver.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ namespace polysolve::nonlinear
118118

119119
double use_grad_norm_tol;
120120
double first_grad_norm_tol;
121+
double derivative_along_delta_x_tol;
121122

122123
const double characteristic_length;
123124

0 commit comments

Comments
 (0)