-
Notifications
You must be signed in to change notification settings - Fork 2
Nonlinear Gauss-Seidel #164
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
JHopeCollins
wants to merge
21
commits into
master
Choose a base branch
from
gauss_siedel
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 2 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
70e7ab9
nonlinear gauss siedel for galewsky
JHopeCollins 1202047
correct tolerances for nonlinear gs
JHopeCollins 75da08c
Merge branch 'master' into gauss_siedel
JHopeCollins 2624c02
converge multiple chunks for nonlinear gauss siedel and output block …
JHopeCollins 26c43e6
switch for nonlinear jacobi or gauss-siedel switch
JHopeCollins d3f710c
split serial/parallel gauss-siedel galewsky
JHopeCollins 0180e04
dg_advection with aaos gauss-siedel
JHopeCollins 4404d45
split_ensemble functions from JacobiPC branch
JHopeCollins dd275b7
continuing gauss_seidel parallelisation
JHopeCollins 0242daa
I can't spell German
JHopeCollins 384ec50
add ensemble file to asQ/__init__
JHopeCollins fcacf56
initialisation loop for gauss-seidel
JHopeCollins d32e9eb
parallel gauss-seidel?
JHopeCollins 7c1aa26
Merge branch 'master' into gauss_siedel
JHopeCollins e24161d
switch between serial and parallel gauss-seidel sweeps
JHopeCollins 5768808
remove duplicate asQ.ensemble import
JHopeCollins 1a5db26
advection gs example
JHopeCollins ddd6383
update EnsembleConnector with new pyop2.internal_comm interface
JHopeCollins 707f6d9
advection gauss-seidel script with error check vs serial
JHopeCollins 00704a4
chunk snes outputs to seperate files
JHopeCollins 8f69ccc
Merge branch 'master' into gauss_siedel
JHopeCollins File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,279 @@ | ||
| from firedrake.petsc import PETSc | ||
|
|
||
| import asQ | ||
| import firedrake as fd # noqa: F401 | ||
| from utils import units | ||
| from utils.planets import earth | ||
| import utils.shallow_water as swe | ||
| from utils.shallow_water import galewsky | ||
|
|
||
| from functools import partial | ||
| from math import sqrt | ||
|
|
||
| PETSc.Sys.popErrorHandler() | ||
|
|
||
| # get command arguments | ||
| import argparse | ||
| parser = argparse.ArgumentParser( | ||
| description='Galewsky testcase for ParaDiag solver using fully implicit SWE solver.', | ||
| formatter_class=argparse.ArgumentDefaultsHelpFormatter | ||
| ) | ||
|
|
||
| parser.add_argument('--ref_level', type=int, default=2, help='Refinement level of icosahedral grid.') | ||
| parser.add_argument('--base_level', type=int, default=2, help='Refinement level of coarse grid.') | ||
| parser.add_argument('--nwindows', type=int, default=1, help='Total number of time-windows.') | ||
| parser.add_argument('--nlmethod', type=str, default='gs', choices=['gs', 'jac'], help='Nonlinear method. "gs" for Gauss-Siedel or "jac" for Jacobi.') | ||
| parser.add_argument('--nchunks', type=int, default=4, help='Number of chunks to solve simultaneously.') | ||
| parser.add_argument('--nsweeps', type=int, default=4, help='Number of nonlinear sweeps.') | ||
| parser.add_argument('--nsmooth', type=int, default=1, help='Number of nonlinear iterations per chunk at each sweep.') | ||
| parser.add_argument('--nchecks', type=int, default=1, help='Maximum number of chunks allowed to converge after each sweep.') | ||
| parser.add_argument('--ninitialise', type=int, default=0, help='Number of sweeps before checking convergence.') | ||
| parser.add_argument('--atol', type=float, default=1e0, help='Average atol of each timestep.') | ||
| parser.add_argument('--nslices', type=int, default=2, help='Number of time-slices per time-window.') | ||
| parser.add_argument('--slice_length', type=int, default=2, help='Number of timesteps per time-slice.') | ||
| parser.add_argument('--alpha', type=float, default=1e-4, help='Circulant coefficient.') | ||
| parser.add_argument('--dt', type=float, default=0.5, help='Timestep in hours.') | ||
| parser.add_argument('--filename', type=str, default='galewsky', help='Name of output vtk files') | ||
| parser.add_argument('--metrics_dir', type=str, default='metrics', help='Directory to save paradiag metrics to.') | ||
| parser.add_argument('--print_res', action='store_true', help='Print the residuals of each timestep at each iteration.') | ||
| parser.add_argument('--show_args', action='store_true', help='Output all the arguments.') | ||
|
|
||
| args = parser.parse_known_args() | ||
| args = args[0] | ||
|
|
||
| if args.show_args: | ||
| PETSc.Sys.Print(args) | ||
|
|
||
| PETSc.Sys.Print('') | ||
| PETSc.Sys.Print('### === --- Setting up --- === ###') | ||
| PETSc.Sys.Print('') | ||
|
|
||
| # time steps | ||
|
|
||
| time_partition = tuple((args.slice_length for _ in range(args.nslices))) | ||
| chunk_length = sum(time_partition) | ||
|
|
||
| dt = args.dt*units.hour | ||
|
|
||
|
|
||
| # alternative operator to precondition blocks | ||
|
|
||
| def aux_form_function(u, h, v, q, t): | ||
| mesh = v.ufl_domain() | ||
| coords = fd.SpatialCoordinate(mesh) | ||
|
|
||
| gravity = earth.Gravity | ||
| coriolis = swe.earth_coriolis_expression(*coords) | ||
|
|
||
| H = galewsky.H0 | ||
|
|
||
| return swe.linear.form_function(mesh, gravity, H, coriolis, | ||
| u, h, v, q, t) | ||
|
|
||
|
|
||
| block_appctx = { | ||
| 'aux_form_function': aux_form_function | ||
| } | ||
|
|
||
| # parameters for the implicit diagonal solve in step-(b) | ||
| factorisation_params = { | ||
| 'ksp_type': 'preonly', | ||
| # 'pc_factor_mat_ordering_type': 'rcm', | ||
| 'pc_factor_reuse_ordering': None, | ||
| 'pc_factor_reuse_fill': None, | ||
| } | ||
|
|
||
| lu_params = {'pc_type': 'lu', 'pc_factor_mat_solver_type': 'mumps'} | ||
| lu_params.update(factorisation_params) | ||
|
|
||
| aux_pc = { | ||
| 'snes_lag_preconditioner': -2, | ||
| 'snes_lag_preconditioner_persists': None, | ||
| 'pc_type': 'python', | ||
| 'pc_python_type': 'asQ.AuxiliaryBlockPC', | ||
| 'aux': lu_params, | ||
| } | ||
|
|
||
| sparameters = { | ||
| 'mat_type': 'matfree', | ||
| 'ksp_type': 'fgmres', | ||
| 'ksp': { | ||
| 'atol': 1e-5, | ||
| 'rtol': 1e-5, | ||
| 'max_it': 30, | ||
| 'converged_maxits': None, | ||
| }, | ||
| } | ||
| sparameters.update(aux_pc) | ||
|
|
||
| atol = args.atol | ||
| patol = sqrt(chunk_length)*atol | ||
| sparameters_diag = { | ||
| 'snes': { | ||
| 'linesearch_type': 'basic', | ||
| 'monitor': None, | ||
| 'converged_reason': None, | ||
| 'atol': patol, | ||
| 'rtol': 1e-10, | ||
| 'stol': 1e-12, | ||
| # 'ksp_ew': None, | ||
| # 'ksp_ew_version': 1, | ||
| # 'ksp_ew_threshold': 1e-2, | ||
| 'max_it': args.nsmooth, | ||
| 'convergence_test': 'skip', | ||
| }, | ||
| 'mat_type': 'matfree', | ||
| 'ksp_type': 'preonly', | ||
| 'ksp': { | ||
| # 'monitor': None, | ||
| # 'converged_reason': None, | ||
| # 'max_it': 2, | ||
| # 'converged_maxits': None, | ||
| 'rtol': 1e-2, | ||
| 'atol': patol, | ||
| }, | ||
| 'pc_type': 'python', | ||
| 'pc_python_type': 'asQ.DiagFFTPC', | ||
| 'diagfft_alpha': args.alpha, | ||
| 'diagfft_state': 'window', | ||
| 'aaos_jacobian_state': 'current' | ||
| } | ||
|
|
||
| for i in range(chunk_length): | ||
| sparameters_diag['diagfft_block_'+str(i)+'_'] = sparameters | ||
|
|
||
| create_mesh = partial( | ||
| swe.create_mg_globe_mesh, | ||
| ref_level=args.ref_level, | ||
| base_level=args.base_level, | ||
| coords_degree=1) # remove coords degree once UFL issue with gradient of cell normals fixed | ||
|
|
||
| # check convergence of each timestep | ||
|
|
||
|
|
||
| def post_function_callback(aaosolver, X, F): | ||
| if args.print_res: | ||
| residuals = asQ.SharedArray(time_partition, | ||
| comm=aaosolver.ensemble.ensemble_comm) | ||
| # all-at-once residual | ||
| res = aaosolver.aaoform.F | ||
| for i in range(res.nlocal_timesteps): | ||
| with res[i].dat.vec_ro as vec: | ||
| residuals.dlocal[i] = vec.norm() | ||
| residuals.synchronise() | ||
| PETSc.Sys.Print('') | ||
| PETSc.Sys.Print([f"{r:.4e}" for r in residuals.data()]) | ||
| PETSc.Sys.Print('') | ||
|
|
||
|
|
||
| PETSc.Sys.Print('### === --- Calculating parallel solution --- === ###') | ||
|
|
||
| appctx = {'block_appctx': block_appctx} | ||
|
|
||
| miniapp = swe.ShallowWaterMiniApp(gravity=earth.Gravity, | ||
| topography_expression=galewsky.topography_expression, | ||
| velocity_expression=galewsky.velocity_expression, | ||
| depth_expression=galewsky.depth_expression, | ||
| reference_depth=galewsky.H0, | ||
| reference_state=True, | ||
| create_mesh=create_mesh, | ||
| dt=dt, theta=0.5, | ||
| time_partition=time_partition, | ||
| appctx=appctx, | ||
| paradiag_sparameters=sparameters_diag, | ||
| file_name='output/'+args.filename, | ||
| post_function_callback=post_function_callback, | ||
| record_diagnostics={'cfl': True, 'file': False}) | ||
|
|
||
| paradiag = miniapp.paradiag | ||
| aaosolver = paradiag.solver | ||
| aaofunc = aaosolver.aaofunc | ||
| aaoform = aaosolver.aaoform | ||
|
|
||
| chunks = tuple(aaofunc.copy() for _ in range(args.nchunks)) | ||
|
|
||
| nconverged = 0 | ||
| PETSc.Sys.Print('') | ||
| for j in range(args.nsweeps): | ||
| PETSc.Sys.Print(f'### === --- Calculating nonlinear sweep {j} --- === ###') | ||
| PETSc.Sys.Print('') | ||
|
|
||
| # 1) set ics from previous iteration of previous chunk | ||
| if (args.nlmethod == 'jac'): | ||
| for i in range(1, args.nchunks): | ||
| chunks[i-1].bcast_field(-1, chunks[i].initial_condition) | ||
|
|
||
| for i in range(args.nchunks): | ||
| PETSc.Sys.Print(f' --- Calculating chunk {i} --- ') | ||
|
|
||
| # 1) set ic from current iteration of previous chunk | ||
| if (args.nlmethod == 'gs'): | ||
| if i > 0: | ||
| chunks[i-1].bcast_field(-1, chunks[i].initial_condition) | ||
|
|
||
| # 2) load chunk i solution | ||
| aaofunc.assign(chunks[i]) | ||
|
|
||
| # 3) one iteration of chunk i | ||
| aaosolver.solve() | ||
| PETSc.Sys.Print("") | ||
|
|
||
| # 4) save chunk i solution | ||
| chunks[i].assign(aaofunc) | ||
|
|
||
| # check if first chunks have converged | ||
| for i in range(args.nchecks): | ||
| if j < args.ninitialise: | ||
| break | ||
|
|
||
| aaoform.assemble(chunks[0]) | ||
| with aaoform.F.global_vec_ro() as rvec: | ||
| res = rvec.norm() | ||
|
|
||
| if res < patol: | ||
| PETSc.Sys.Print(f">>> Chunk {str(i).rjust(2)} converged with function norm = {res:.6e} <<<") | ||
| nconverged += 1 | ||
|
|
||
| # make sure we calculate the most up to date residual for the next chunk | ||
| chunks[0].bcast_field(-1, chunks[1].initial_condition) | ||
|
|
||
| # shuffle chunks down | ||
| for i in range(args.nchunks-1): | ||
| chunks[i].assign(chunks[i+1]) | ||
|
|
||
| # reset last chunk to start from end of series | ||
| chunks[-1].bcast_field(-1, chunks[-1].initial_condition) | ||
| chunks[-1].assign(chunks[-1].initial_condition) | ||
|
|
||
| else: # stop checking at first unconverged chunk | ||
| break | ||
|
|
||
| PETSc.Sys.Print('') | ||
| PETSc.Sys.Print(f">>> Converged chunks: {int(nconverged)}.") | ||
| converged_time = nconverged*chunk_length*args.dt | ||
| PETSc.Sys.Print(f">>> Converged time: {converged_time} hours.") | ||
| PETSc.Sys.Print('') | ||
|
|
||
| if nconverged >= args.nwindows: | ||
| PETSc.Sys.Print(f"Finished iterating to {args.nwindows}.") | ||
| break | ||
|
|
||
| nsweeps = j | ||
|
|
||
| pc_block_its = aaosolver.jacobian.pc.block_iterations | ||
| pc_block_its.synchronise() | ||
| pc_block_its = pc_block_its.data(deepcopy=True) | ||
| pc_block_its = pc_block_its/args.nchunks | ||
|
|
||
| niterations = nsweeps*args.nsmooth | ||
|
|
||
| PETSc.Sys.Print(f"Number of chunks: {args.nchunks}") | ||
| PETSc.Sys.Print(f"Maximum number of sweeps: {args.nsweeps}") | ||
| PETSc.Sys.Print(f"Actual number of sweeps: {nsweeps}") | ||
| PETSc.Sys.Print(f"Number of chunks converged: {int(nconverged)}") | ||
| PETSc.Sys.Print(f"Number of chunks converged per sweep: {nconverged/nsweeps}") | ||
| PETSc.Sys.Print(f"Number of sweeps per converged chunk: {nsweeps/nconverged if nconverged else 'n/a'}") | ||
| PETSc.Sys.Print(f"Number of iterations per converged chunk: {niterations/nconverged if nconverged else 'n/a'}") | ||
| PETSc.Sys.Print(f"Number of timesteps per iteration: {nconverged*chunk_length/niterations}") | ||
| PETSc.Sys.Print(f'Block iterations: {pc_block_its}') | ||
| PETSc.Sys.Print(f'Block iterations per block solve: {pc_block_its/niterations}') | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.