Skip to content

Commit

Permalink
Merge pull request #6125 from gassmoeller/simplify_newton_stokes
Browse files Browse the repository at this point in the history
Simplify Newton solver function arguments
  • Loading branch information
MFraters authored Nov 5, 2024
2 parents 6d46ffd + e8aae7f commit 4d576b2
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 67 deletions.
20 changes: 3 additions & 17 deletions include/aspect/simulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -1300,14 +1300,6 @@ namespace aspect
* "physical" pressure so that all following postprocessing
* steps can use the latter.
*
* In the case of the surface average, whether a face is part of
* the surface is determined by asking whether its depth of its
* midpoint (as determined by the geometry model) is less than
* 1/3*1/sqrt(dim-1)*diameter of the face. For reasonably curved
* boundaries, this rules out side faces that are perpendicular
* to the surface boundary but includes those faces that are
* along the boundary even if the real boundary is curved.
*
* Whether the pressure should be normalized based on the
* surface or volume average is decided by a parameter in the
* input file.
Expand Down Expand Up @@ -1352,12 +1344,7 @@ namespace aspect
* come out of GMRES, namely the one on which we later called
* normalize_pressure().
*
* This function modifies @p vector in-place. In some cases, we need
* locally_relevant values of the pressure. To avoid creating a new vector
* and transferring data, this function uses a second vector with relevant
* dofs (@p relevant_vector) for accessing these pressure values. Both
* @p vector and @p relevant_vector are expected to already contain
* the correct pressure values.
* This function modifies @p vector in-place.
*
* @note The adjustment made in this function is done using the
* negative of the @p pressure_adjustment function argument that
Expand All @@ -1371,8 +1358,7 @@ namespace aspect
* <code>source/simulator/helper_functions.cc</code>.
*/
void denormalize_pressure(const double pressure_adjustment,
LinearAlgebra::BlockVector &vector,
const LinearAlgebra::BlockVector &relevant_vector) const;
LinearAlgebra::BlockVector &vector) const;

/**
* Apply the bound preserving limiter to the discontinuous Galerkin solutions:
Expand Down Expand Up @@ -1780,7 +1766,7 @@ namespace aspect
* Computes the initial Newton residual.
*/
double
compute_initial_newton_residual (const LinearAlgebra::BlockVector &linearized_stokes_initial_guess);
compute_initial_newton_residual ();

/**
* This function computes the Eisenstat Walker linear tolerance used for the Newton iterations
Expand Down
76 changes: 46 additions & 30 deletions source/simulator/helper_functions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1085,8 +1085,7 @@ namespace aspect
void
Simulator<dim>::
denormalize_pressure (const double pressure_adjustment,
LinearAlgebra::BlockVector &vector,
const LinearAlgebra::BlockVector &relevant_vector) const
LinearAlgebra::BlockVector &vector) const
{
if (parameters.pressure_normalization == "no")
return;
Expand All @@ -1106,6 +1105,17 @@ namespace aspect
finite_element.base_element(introspection.variable("fluid pressure").base_index).dofs_per_cell
: finite_element.base_element(introspection.base_elements.pressure).dofs_per_cell);

// We may touch the same DoF multiple times, so we need to copy the
// vector before modifying it to have access to the original value.
LinearAlgebra::BlockVector vector_backup;
vector_backup.reinit(vector, /* omit_zeroing_entries = */ true);
const unsigned int pressure_block_index =
parameters.include_melt_transport ?
introspection.variable("fluid pressure").block_index
:
introspection.block_indices.pressure;
vector_backup.block(pressure_block_index) = vector.block(pressure_block_index);

std::vector<types::global_dof_index> local_dof_indices (finite_element.dofs_per_cell);
for (const auto &cell : dof_handler.active_cell_iterators())
if (cell->is_locally_owned())
Expand All @@ -1117,11 +1127,15 @@ namespace aspect
= finite_element.component_to_system_index(pressure_component,
/*dof index within component=*/ j);

// then adjust its value. Note that because we end up touching
// Then adjust its value. vector could be a vector with ghost elements
// or a fully distributed vector. In the latter case only access dofs that are
// locally owned. Note that because we end up touching
// entries more than once, we are not simply incrementing
// distributed_vector but copy from the unchanged vector.
vector(local_dof_indices[local_dof_index])
= relevant_vector(local_dof_indices[local_dof_index]) - pressure_adjustment;
// vector but copy from the vector_backup copy.
if (vector.has_ghost_elements() ||
dof_handler.locally_owned_dofs().is_element(local_dof_indices[local_dof_index]))
vector(local_dof_indices[local_dof_index])
= vector_backup(local_dof_indices[local_dof_index]) - pressure_adjustment;
}
}
vector.compress(VectorOperation::insert);
Expand All @@ -1144,7 +1158,20 @@ namespace aspect
ExcInternalError());
Assert(!parameters.include_melt_transport, ExcNotImplemented());
const unsigned int pressure_component = introspection.component_indices.pressure;

// We may touch the same DoF multiple times, so we need to copy the
// vector before modifying it to have access to the original value.
LinearAlgebra::BlockVector vector_backup;
vector_backup.reinit(vector, /* omit_zeroing_entries = */ true);
const unsigned int pressure_block_index =
parameters.include_melt_transport ?
introspection.variable("fluid pressure").block_index
:
introspection.block_indices.pressure;
vector_backup.block(pressure_block_index) = vector.block(pressure_block_index);

std::vector<types::global_dof_index> local_dof_indices (finite_element.dofs_per_cell);

for (const auto &cell : dof_handler.active_cell_iterators())
if (cell->is_locally_owned())
{
Expand All @@ -1154,12 +1181,11 @@ namespace aspect
= finite_element.component_to_system_index (pressure_component, 0);

// make sure that this DoF is really owned by the current processor
// and that it is in fact a pressure dof
Assert (dof_handler.locally_owned_dofs().is_element(local_dof_indices[first_pressure_dof]),
ExcInternalError());

// then adjust its value
vector (local_dof_indices[first_pressure_dof]) = relevant_vector(local_dof_indices[first_pressure_dof])
vector (local_dof_indices[first_pressure_dof]) = vector_backup(local_dof_indices[first_pressure_dof])
- pressure_adjustment;
}

Expand Down Expand Up @@ -1341,15 +1367,7 @@ namespace aspect
else
linearized_stokes_variables.block (pressure_block_index) = current_linearization_point.block (pressure_block_index);

// TODO: we don't have .stokes_relevant_partitioning so I am creating a much
// bigger vector here, oh well.
LinearAlgebra::BlockVector ghosted (introspection.index_sets.system_partitioning,
introspection.index_sets.system_relevant_partitioning,
mpi_communicator);
// TODO for Timo: can we create the ghost vector inside of denormalize_pressure
// (only in cases where we need it)
ghosted.block(pressure_block_index) = linearized_stokes_variables.block(pressure_block_index);
denormalize_pressure (this->last_pressure_normalization_adjustment, linearized_stokes_variables, ghosted);
denormalize_pressure (this->last_pressure_normalization_adjustment, linearized_stokes_variables);
current_constraints.set_zero (linearized_stokes_variables);

linearized_stokes_variables.block (pressure_block_index) /= pressure_scaling;
Expand Down Expand Up @@ -2586,23 +2604,22 @@ namespace aspect

template <int dim>
double
Simulator<dim>::compute_initial_newton_residual(const LinearAlgebra::BlockVector &linearized_stokes_initial_guess)
Simulator<dim>::compute_initial_newton_residual()
{
// Store the values of the current_linearization_point and linearized_stokes_initial_guess so we can reset them again.
// Store the values of current_linearization_point to be able to restore it later.
LinearAlgebra::BlockVector temp_linearization_point = current_linearization_point;
LinearAlgebra::BlockVector temp_linearized_stokes_initial_guess = linearized_stokes_initial_guess;

// Set the velocity initial guess to zero, but we use the initial guess for the pressure.
// Set the velocity initial guess to zero.
current_linearization_point.block(introspection.block_indices.velocities) = 0;
temp_linearized_stokes_initial_guess.block (introspection.block_indices.velocities) = 0;

denormalize_pressure (last_pressure_normalization_adjustment,
temp_linearized_stokes_initial_guess,
current_linearization_point);

// rebuild the whole system to compute the rhs.
// Rebuild the whole system to compute the rhs.
assemble_newton_stokes_system = true;
rebuild_stokes_preconditioner = false;

// Technically we only need the rhs, but we have asserts in place that check if
// the system is assembled correctly when boundary conditions are prescribed, so we assemble the whole system.
// TODO: This is a waste of time in the first nonlinear iteration. Check if we can modify the asserts in the
// assemble_stokes_system() function to only assemble the RHS.
rebuild_stokes_matrix = boundary_velocity_manager.get_active_boundary_velocity_conditions().size()!=0;
assemble_newton_stokes_matrix = boundary_velocity_manager.get_active_boundary_velocity_conditions().size()!=0;

Expand Down Expand Up @@ -2740,8 +2757,7 @@ namespace aspect
template struct Simulator<dim>::AdvectionField; \
template double Simulator<dim>::normalize_pressure(LinearAlgebra::BlockVector &vector) const; \
template void Simulator<dim>::denormalize_pressure(const double pressure_adjustment, \
LinearAlgebra::BlockVector &vector, \
const LinearAlgebra::BlockVector &relevant_vector) const; \
LinearAlgebra::BlockVector &vector) const; \
template double Simulator<dim>::compute_pressure_scaling_factor () const; \
template double Simulator<dim>::get_maximal_velocity (const LinearAlgebra::BlockVector &solution) const; \
template std::pair<double,double> Simulator<dim>::get_extrapolated_advection_field_range (const AdvectionField &advection_field) const; \
Expand All @@ -2766,7 +2782,7 @@ namespace aspect
template void Simulator<dim>::replace_outflow_boundary_ids(const unsigned int boundary_id_offset); \
template void Simulator<dim>::restore_outflow_boundary_ids(const unsigned int boundary_id_offset); \
template void Simulator<dim>::check_consistency_of_boundary_conditions() const; \
template double Simulator<dim>::compute_initial_newton_residual(const LinearAlgebra::BlockVector &linearized_stokes_initial_guess); \
template double Simulator<dim>::compute_initial_newton_residual(); \
template double Simulator<dim>::compute_Eisenstat_Walker_linear_tolerance(const bool EisenstatWalkerChoiceOne, \
const double maximum_linear_stokes_solver_tolerance, \
const double linear_stokes_solver_tolerance, \
Expand Down
6 changes: 2 additions & 4 deletions source/simulator/solver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -855,8 +855,7 @@ namespace aspect
// initial residual we could skip all of this stuff.
distributed_stokes_solution.block(velocity_and_pressure_block) = solution.block(velocity_and_pressure_block);
denormalize_pressure (this->last_pressure_normalization_adjustment,
distributed_stokes_solution,
solution);
distributed_stokes_solution);
current_stokes_constraints.set_zero (distributed_stokes_solution);

// Undo the pressure scaling:
Expand Down Expand Up @@ -973,8 +972,7 @@ namespace aspect
linearized_stokes_initial_guess.block (pressure_block_index) = current_linearization_point.block (pressure_block_index);

denormalize_pressure (this->last_pressure_normalization_adjustment,
linearized_stokes_initial_guess,
current_linearization_point);
linearized_stokes_initial_guess);
}
else
{
Expand Down
16 changes: 2 additions & 14 deletions source/simulator/solver_schemes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -437,19 +437,13 @@ namespace aspect
: introspection.block_indices.pressure;
Assert(introspection.block_indices.velocities == 0, ExcNotImplemented());
Assert(pressure_block_index == 1, ExcNotImplemented());
(void) pressure_block_index;
Assert(!parameters.include_melt_transport
|| introspection.variable("compaction pressure").block_index == 1, ExcNotImplemented());

// create a completely distributed vector that will be used for
// the scaled and denormalized solution and later used as a
// starting guess for the linear solver
LinearAlgebra::BlockVector linearized_stokes_initial_guess(introspection.index_sets.stokes_partitioning, mpi_communicator);
linearized_stokes_initial_guess.block(introspection.block_indices.velocities) = current_linearization_point.block(introspection.block_indices.velocities);
linearized_stokes_initial_guess.block(pressure_block_index) = current_linearization_point.block(pressure_block_index);

if (nonlinear_iteration == 0)
{
dcr.initial_residual = compute_initial_newton_residual(linearized_stokes_initial_guess);
dcr.initial_residual = compute_initial_newton_residual();
dcr.switch_initial_residual = dcr.initial_residual;
dcr.residual_old = dcr.initial_residual;
dcr.residual = dcr.initial_residual;
Expand All @@ -461,12 +455,6 @@ namespace aspect
{
assemble_newton_stokes_system = assemble_newton_stokes_matrix = false;
}
else
{
denormalize_pressure (last_pressure_normalization_adjustment,
linearized_stokes_initial_guess,
current_linearization_point);
}

if (nonlinear_iteration <= 1)
{
Expand Down
3 changes: 1 addition & 2 deletions source/simulator/stokes_matrix_free.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1919,8 +1919,7 @@ namespace aspect
linearized_stokes_initial_guess.block (block_p) = sim.current_linearization_point.block (block_p);

sim.denormalize_pressure (sim.last_pressure_normalization_adjustment,
linearized_stokes_initial_guess,
sim.current_linearization_point);
linearized_stokes_initial_guess);
}
else
{
Expand Down

0 comments on commit 4d576b2

Please sign in to comment.