Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion gusto/solvers/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
"""
from gusto.core.function_spaces import is_cg

__all__ = ['mass_parameters', 'hydrostatic_parameters']
__all__ = [
'mass_parameters', 'hydrostatic_parameters',
'conservative_tracer_parameters'
]


def mass_parameters(V, spaces=None, ignore_vertical=True):
Expand Down Expand Up @@ -120,3 +123,56 @@
}
}
}


def conservative_tracer_parameters(V, num_fields=2):
"""
Returns PETSc solver settings for conservative tracer transport, in which
a tracer is transported simultaneously with a reference density field in a
discontinuous space.

As the density does not depend upon the tracer, we solve this with a
multiplicative fieldsplit, in which the density is solved for first.

Parameters
----------
V : :class:`FunctionSpace`
The (sub)function space of the density/tracer.
num_fields : int, optional
The number of fields in the mixed function space. Default is 2.

Returns
-------
settings : dict
A dictionary containing the PETSc solver settings.
"""
fs_name = V.name
settings = {
"mat_type": "aij",
"snes_type": "ksponly",
"ksp_type": "preonly",
"pc_type": "fieldsplit",
"ksp_monitor_true_residual": None,
"ksp_converged_reason": None,
"snes_monitor": None,
"snes_converged_reason": None,
"pc_fieldsplit_type": "multiplicative",
"pc_fieldsplit_0_fields": "0",
"pc_fieldsplit_1_fields": "1",

f"fieldsplit_{fs_name}_ksp_type": "preonly",
"fieldsplit_0_pc_type": "lu",
f"fieldsplit_{fs_name}_ksp_converged_reason": None,
f"fieldsplit_{fs_name}_ksp_monitor_true_residual": None,
}

if num_fields < 2:
raise ValueError(
"The number of fields used for conservative tracer transport must "
+ f"be at least 2, but got {num_fields}."
)
elif num_fields > 2:
for i in range(2, num_fields):
settings[f"pc_fieldsplit_{i}_fields"] = str(i)

return settings

Check failure on line 178 in gusto/solvers/parameters.py

View workflow job for this annotation

GitHub Actions / Run linter

W292

gusto/solvers/parameters.py:178:20: W292 no newline at end of file
37 changes: 25 additions & 12 deletions gusto/time_discretisation/time_discretisation.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@
self.courant_max = None
self.augmentation = augmentation
self.subcycling_options = subcycling_options
self.solver_parameters = solver_parameters
self.default_solver_parameters = (solver_parameters is None)

if self.subcycling_options is not None:
self.subcycling_options.check_options()
Expand Down Expand Up @@ -136,15 +138,8 @@
self.wrapper = None
self.wrapper_name = None

# get default solver options if none passed in
if solver_parameters is None:
self.solver_parameters = {'ksp_type': 'gmres',
'pc_type': 'bjacobi',
'sub_pc_type': 'ilu'}
else:
self.solver_parameters = solver_parameters

def setup(self, equation, apply_bcs=True, *active_labels):

Check failure on line 142 in gusto/time_discretisation/time_discretisation.py

View workflow job for this annotation

GitHub Actions / Run linter

E303

gusto/time_discretisation/time_discretisation.py:142:5: E303 too many blank lines (2)
"""
Set up the time discretisation based on the equation.

Expand Down Expand Up @@ -351,7 +346,14 @@
)

self.residual = self.wrapper.label_terms(self.residual)
if self.solver_parameters is None:

# Use wrapper solver parameters if they are specified
if (self.solver_parameters is None
and self.wrapper.solver_parameters is not None):

Check failure on line 352 in gusto/time_discretisation/time_discretisation.py

View workflow job for this annotation

GitHub Actions / Run linter

E129

gusto/time_discretisation/time_discretisation.py:352:21: E129 visually indented line with same indent as next logical line
logger.info(
'Using default solver parameters for'
+ f'{self.wrapper_name} wrapper'
)
self.solver_parameters = self.wrapper.solver_parameters

# -------------------------------------------------------------------- #
Expand Down Expand Up @@ -384,6 +386,14 @@
self.x_out = Function(self.fs)
self.x1 = Function(self.fs)

# Finally, set solver parameters to default
if self.solver_parameters is None:
self.solver_parameters = {
'ksp_type': 'gmres',
'pc_type': 'bjacobi',
'sub_pc_type': 'ilu'
}

@property
def nlevels(self):
return 1
Expand Down Expand Up @@ -490,6 +500,7 @@
this time discretisation to be augmented, for instances with
extra terms of another auxiliary variable. Defaults to None.
"""

super().__init__(domain, field_name,
subcycling_options=subcycling_options,
solver_parameters=solver_parameters,
Expand All @@ -509,10 +520,12 @@
"""
super().setup(equation, apply_bcs, *active_labels)

# get default solver options if none passed in
self.solver_parameters.update(mass_parameters(
self.fs, equation.domain.spaces))
self.solver_parameters['snes_type'] = 'ksponly'
# Set default solver params for explicit schemes, if none were passed in
Comment thread
jshipton marked this conversation as resolved.
if self.default_solver_parameters:
self.solver_parameters = mass_parameters(
self.fs, equation.domain.spaces
)
self.solver_parameters['snes_type'] = 'ksponly'

# if user has specified a number of fixed subcycles, then save this
# and rescale dt accordingly; else perform just one cycle using dt
Expand Down
Loading