Skip to content

Commit 90b1500

Browse files
committed
Refactor the Newton line search.
1 parent f6d314e commit 90b1500

File tree

3 files changed

+105
-71
lines changed

3 files changed

+105
-71
lines changed

include/aspect/simulator.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,16 @@ namespace aspect
13371337
void interpolate_onto_velocity_system(const TensorFunction<1,dim> &func,
13381338
LinearAlgebra::Vector &vec) const;
13391339

1340+
/**
1341+
* Perform a Newton line search to determine the optimal step length
1342+
* along the search direction.
1343+
*
1344+
* This function is implemented in
1345+
* <code>source/simulator/helper_functions.cc</code>
1346+
*/
1347+
double perform_line_search(const DefectCorrectionResiduals &dcr,
1348+
const bool use_picard,
1349+
LinearAlgebra::BlockVector &search_direction);
13401350

13411351
/**
13421352
* Add constraints to the given @p constraints object that are required

source/simulator/helper_functions.cc

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2629,6 +2629,92 @@ namespace aspect
26292629
return initial_newton_residual;
26302630
}
26312631

2632+
/**
2633+
* Performs a Newton line search for the do_one_defect_correction_Stokes_step function
2634+
*/
2635+
template <int dim>
2636+
double Simulator<dim>::perform_line_search(const DefectCorrectionResiduals &dcr,
2637+
const bool use_picard,
2638+
LinearAlgebra::BlockVector &search_direction)
2639+
{
2640+
LinearAlgebra::BlockVector backup_linearization_point(introspection.index_sets.stokes_partitioning, mpi_communicator);
2641+
double step_length_factor = 1.0;
2642+
unsigned int line_search_iteration = 0;
2643+
// Many parts of the solver depend on the block layout (velocity = 0,
2644+
// pressure = 1). For example the linearized_stokes_initial_guess vector or the StokesBlock matrix
2645+
// wrapper. Let us make sure that this holds (and shorten their names):
2646+
const unsigned int pressure_block_index = (parameters.include_melt_transport) ?
2647+
introspection.variable("fluid pressure").block_index
2648+
: introspection.block_indices.pressure;
2649+
const unsigned int velocity_block_index = introspection.block_indices.velocities;
2650+
Assert(velocity_block_index == 0, ExcNotImplemented());
2651+
Assert(pressure_block_index == 1, ExcNotImplemented());
2652+
(void) pressure_block_index;
2653+
// Do the loop for the line search at least once with the full step length.
2654+
// If line search is disabled we will exit the loop in the first iteration.
2655+
2656+
do
2657+
{
2658+
if (line_search_iteration == 0)
2659+
{
2660+
// backup our starting point for the line search
2661+
backup_linearization_point.block(pressure_block_index) = current_linearization_point.block(pressure_block_index);
2662+
backup_linearization_point.block(velocity_block_index) = current_linearization_point.block(velocity_block_index);
2663+
}
2664+
else
2665+
{
2666+
// undo the last iteration and try again with smaller step length
2667+
current_linearization_point.block(pressure_block_index) = backup_linearization_point.block(pressure_block_index);
2668+
current_linearization_point.block(velocity_block_index) = backup_linearization_point.block(velocity_block_index);
2669+
search_direction.block(pressure_block_index) *= step_length_factor;
2670+
search_direction.block(velocity_block_index) *= step_length_factor;
2671+
}
2672+
2673+
// Update the current linearization point with the search direction
2674+
current_linearization_point.block(pressure_block_index) += search_direction.block(pressure_block_index);
2675+
current_linearization_point.block(velocity_block_index) += search_direction.block(velocity_block_index);
2676+
2677+
// Rebuild the rhs to determine the new residual.
2678+
assemble_newton_stokes_matrix = rebuild_stokes_preconditioner = false;
2679+
rebuild_stokes_matrix = !boundary_velocity_manager.get_prescribed_boundary_velocity_indicators().empty();
2680+
2681+
assemble_stokes_system();
2682+
2683+
const double test_velocity_residual = system_rhs.block(velocity_block_index).l2_norm();
2684+
const double test_pressure_residual = system_rhs.block(pressure_block_index).l2_norm();
2685+
const double test_residual = std::sqrt(test_velocity_residual * test_velocity_residual
2686+
+ test_pressure_residual * test_pressure_residual);
2687+
2688+
// Determine if the residual has decreased sufficiently.
2689+
const double alpha = 1e-4;
2690+
if (test_residual < (1.0 - alpha * step_length_factor) * dcr.residual
2691+
||
2692+
line_search_iteration >= newton_handler->parameters.max_newton_line_search_iterations
2693+
||
2694+
use_picard)
2695+
{
2696+
pcout << " Newton system information: Norm of the rhs: " << test_residual
2697+
<< ", Derivative scaling factor: " << newton_handler->parameters.newton_derivative_scaling_factor << std::endl;
2698+
return test_residual;
2699+
}
2700+
else
2701+
{
2702+
pcout << " Line search iteration " << line_search_iteration << ", with norm of the rhs "
2703+
<< test_residual << " and going to " << (1.0 - alpha * step_length_factor) * dcr.residual
2704+
<< ", relative residual: " << test_residual/dcr.initial_residual << std::endl;
2705+
2706+
// The current search direction has not decreased the residual
2707+
// enough, so we take a smaller step and try again.
2708+
// TODO: make a parameter out of this.
2709+
step_length_factor = 2.0/3.0;
2710+
}
2711+
2712+
++line_search_iteration;
2713+
Assert(line_search_iteration <= newton_handler->parameters.max_newton_line_search_iterations,
2714+
ExcInternalError());
2715+
}
2716+
while (true);
2717+
}
26322718

26332719

26342720
template <int dim>
@@ -2779,6 +2865,9 @@ namespace aspect
27792865
template void Simulator<dim>::restore_outflow_boundary_ids(const unsigned int boundary_id_offset); \
27802866
template void Simulator<dim>::check_consistency_of_boundary_conditions() const; \
27812867
template double Simulator<dim>::compute_initial_newton_residual(); \
2868+
template double Simulator<dim>::perform_line_search(const DefectCorrectionResiduals &dcr, \
2869+
const bool use_picard, \
2870+
LinearAlgebra::BlockVector &search_direction); \
27822871
template double Simulator<dim>::compute_Eisenstat_Walker_linear_tolerance(const bool EisenstatWalkerChoiceOne, \
27832872
const double maximum_linear_stokes_solver_tolerance, \
27842873
const double linear_stokes_solver_tolerance, \

source/simulator/solver_schemes.cc

Lines changed: 6 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,7 @@ namespace aspect
530530
}
531531

532532

533+
533534
template <int dim>
534535
void Simulator<dim>::do_one_defect_correction_Stokes_step(DefectCorrectionResiduals &dcr,
535536
const bool use_picard)
@@ -702,7 +703,9 @@ namespace aspect
702703
dcr.residual,
703704
dcr.residual_old);
704705

705-
pcout << " The linear solver tolerance is set to " << parameters.linear_stokes_solver_tolerance << std::endl;
706+
pcout << " The linear solver tolerance is set to "
707+
<< parameters.linear_stokes_solver_tolerance
708+
<< ". ";
706709
}
707710
}
708711

@@ -737,79 +740,11 @@ namespace aspect
737740
dcr.residual_old = dcr.residual;
738741

739742
// We have computed an update. Prepare for a line search.
740-
LinearAlgebra::BlockVector backup_linearization_point(introspection.index_sets.stokes_partitioning, mpi_communicator);
741-
742-
double step_length_factor = 1.0;
743-
unsigned int line_search_iteration = 0;
744-
745-
// Do the loop for the line search at least once with the full step length.
746-
// If line search is disabled we will exit the loop in the first iteration.
747-
do
748-
{
749-
if (line_search_iteration == 0)
750-
{
751-
// backup our starting point for the line search
752-
backup_linearization_point.block(pressure_block_index) = current_linearization_point.block(pressure_block_index);
753-
backup_linearization_point.block(velocity_block_index) = current_linearization_point.block(velocity_block_index);
754-
}
755-
else
756-
{
757-
// undo the last iteration and try again with smaller step length
758-
current_linearization_point.block(pressure_block_index) = backup_linearization_point.block(pressure_block_index);
759-
current_linearization_point.block(velocity_block_index) = backup_linearization_point.block(velocity_block_index);
760-
search_direction.block(pressure_block_index) *= step_length_factor;
761-
search_direction.block(velocity_block_index) *= step_length_factor;
762-
}
763-
764-
// Update the current linearization point with the search direction
765-
current_linearization_point.block(pressure_block_index) += search_direction.block(pressure_block_index);
766-
current_linearization_point.block(velocity_block_index) += search_direction.block(velocity_block_index);
767-
768-
// Rebuild the rhs to determine the new residual.
769-
assemble_newton_stokes_matrix = rebuild_stokes_preconditioner = false;
770-
rebuild_stokes_matrix = !boundary_velocity_manager.get_prescribed_boundary_velocity_indicators().empty();
771-
772-
assemble_stokes_system();
773-
774-
const double test_velocity_residual = system_rhs.block(velocity_block_index).l2_norm();
775-
const double test_pressure_residual = system_rhs.block(pressure_block_index).l2_norm();
776-
const double test_residual = std::sqrt(test_velocity_residual * test_velocity_residual
777-
+ test_pressure_residual * test_pressure_residual);
778-
779-
// Determine if the residual has decreased sufficiently.
780-
const double alpha = 1e-4;
781-
if (test_residual < (1.0 - alpha * step_length_factor) * dcr.residual
782-
||
783-
line_search_iteration >= newton_handler->parameters.max_newton_line_search_iterations
784-
||
785-
use_picard)
786-
{
787-
pcout << " Newton system information: Norm of the rhs: " << test_residual
788-
<< ", Derivative scaling factor: " << newton_handler->parameters.newton_derivative_scaling_factor << std::endl;
789-
dcr.residual = test_residual;
790-
break;
791-
}
792-
else
793-
{
794-
pcout << " Line search iteration " << line_search_iteration << ", with norm of the rhs "
795-
<< test_residual << " and going to " << (1.0 - alpha * step_length_factor) * dcr.residual
796-
<< ", relative residual: " << test_residual/dcr.initial_residual << std::endl;
797-
798-
// The current search direction has not decreased the residual
799-
// enough, so we take a smaller step and try again.
800-
// TODO: make a parameter out of this.
801-
step_length_factor = 2.0/3.0;
802-
}
803-
804-
++line_search_iteration;
805-
Assert(line_search_iteration <= newton_handler->parameters.max_newton_line_search_iterations,
806-
ExcInternalError());
807-
}
808-
while (true);
743+
dcr.residual = perform_line_search(dcr, use_picard, search_direction);
809744
}
810745

811746

812-
if (use_picard == true)
747+
if (use_picard)
813748
{
814749
// When we are using (defect corrected) Picard, keep the
815750
// newton_derivative_scaling_factor at zero. The newton_derivative_scaling_factor

0 commit comments

Comments
 (0)