Skip to content

Commit

Permalink
Test Eikonal-NL
Browse files Browse the repository at this point in the history
Test Eikonal-NL
  • Loading branch information
ruansava committed Feb 4, 2025
1 parent f82c1b6 commit 408380d
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 24 deletions.
184 changes: 160 additions & 24 deletions fig8.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import ipdb
os.environ["OMP_NUM_THREADS"] = "1"
fire.parameters["loopy"] = {"silenced_warnings": ["v1_scheduler_fallback"]}
import warnings
warnings.filterwarnings("ignore", category=RuntimeWarning)


def test_eikonal_values_fig8():
Expand All @@ -19,7 +21,7 @@ def test_eikonal_values_fig8():
# (MLT/spectral_quadrilateral/DG_triangle/DG_quadrilateral)
# You can either specify a cell_type+variant or a method
# accepted_variants = ["lumped", "equispaced", "DG"]
"degree": 4, # p order
"degree": 2, # p order p=4 ok
"dimension": 2, # dimension
}

Expand Down Expand Up @@ -47,7 +49,7 @@ def test_eikonal_values_fig8():
# the helper function `create_transect`.
dictionary["acquisition"] = {
"source_type": "ricker",
# "source_locations": [(-0.5, 0.2), (-0.5, 0.25), (-0.5, 0.3)],
# "source_locations": [(-0.5, 0.25), (-0.5, 0.35), (-0.5, 0.5)],
"source_locations": [(-0.5, 0.25)],
"frequency": 5.0,
"delay": 1.5,
Expand Down Expand Up @@ -158,18 +160,118 @@ def assemble_eik(Wave, u, vy, dx):
'''
Eikonal with stabilizer term
'''
eps = fire.Constant(1.) * fire.CellDiameter(Wave.mesh) # Stabilizer

# delta = fire.Constant(float_info.min)
delta = fire.Constant(float_info.epsilon)
f = fire.Constant(1.0)
eps = fire.Constant(1.0) * fire.CellDiameter(Wave.mesh) # Stabilizer
delta = fire.Constant(float_info.min)
# delta = fire.Constant(float_info.epsilon)
grad_u_norm = fire.sqrt(fire.inner(fire.grad(u), fire.grad(u))) + delta
f = fire.Constant(1.0)
F = (grad_u_norm * vy * dx - f / Wave.c * vy * dx + eps * fire.inner(
fire.grad(u), fire.grad(vy)) * dx)
return F


def solve_eik(Wave, bcs_eik):
def solve_prop(nl_solver='newtonls', l_solver='preonly',
user_rtol=1e-16, user_iter=50, monitor=False):
'''
Solver Parameters
https://petsc.org/release/manualpages/SNES/SNESType/
https://petsc.org/release/manualpages/KSP/KSPType/
https://petsc.org/release/manualpages/PC/PCType/
'''

# Tolerances and iterations
user_atol = user_rtol**2
user_stol = user_rtol**2.5
ksp_max_it = user_iter

param_solver = {'snes_type': nl_solver, 'ksp_type': l_solver}

if nl_solver == 'newtontr': # newton, cauchy, dogleg
param_solver.update({'snes_tr_fallback_type': 'newton'})

if nl_solver == 'ngmres': # difference, none, linesearch
param_solver.update({'snes_ngmres_select_type': 'linesearch'})

if nl_solver == 'qn':
param_solver.update({'snes_qn_m_type': 5,
'snes_qn_powell_descent': True,
# lbfgs, broyden, badbroyden
'snes_qn_type': 'badbroyden',
# diagonal, none, scalar, jacobian
'snes_qn_scale_type': 'jacobian'})

if nl_solver == 'ngs':
param_solver.update({'snes_ngs_sweeps': 2,
'snes_ngs_atol': user_rtol,
'snes_ngs_rtol': user_atol,
'snes_ngs_stol': user_stol,
'snes_ngs_max_it': user_iter})

if nl_solver == 'ncg':
# fr, prp, dy, hs, cd
param_solver.update({'snes_ncg_type': 'cd'})

if nl_solver == 'anderson':
param_solver.update({'snes_anderson_m': 3,
'snes_anderson_beta': 0.3})

if l_solver == 'preonly':
ig_nz = False
pc_type = 'lu' # lu, cholesky

param_solver.update({'pc_factor_mat_solver_type': 'umfpack'}) # mumps
else:
ig_nz = True
pc_type = 'icc' # ilu, icc

if l_solver == 'gmres':
param_solver.update({'ksp_gmres_restart': 3,
'ksp_gmres_haptol': user_stol})

param_solver.update({
'snes_linesearch_type': 'l2', # l2, cp, basic
'snes_linesearch_damping': 0.25,
'snes_linesearch_maxstep': 1.0,
'snes_max_funcs': 1000,
'snes_linesearch_order': 3,
'snes_linesearch_alpha': 0.5,
'snes_max_it': user_iter,
'snes_linesearch_rtol': user_rtol,
'snes_linesearch_atol': user_atol,
'snes_rtol': user_atol,
'snes_atol': user_rtol,
'snes_stol': user_stol,
'ksp_max_it': ksp_max_it,
'ksp_rtol': user_rtol,
'ksp_atol': user_atol,
'ksp_initial_guess_nonzero': ig_nz,
'pc_type': pc_type,
'pc_factor_reuse_ordering': True,
'snes_monitor': None,
})

if monitor: # For debugging
param_solver.update({
'snes_view': None,
'snes_converged_reason': None,
'snes_linesearch_monitor': None,
'ksp_monitor_true_residual': None,
'ksp_converged_reason': None,
'report': True,
'error_on_nonconvergence': True})
return param_solver


def clean_inst_num(data_arr):
''''
Clean data: Set NaNs and negative values to zero
'''
data_arr[np.where(np.isnan(data_arr) | np.isinf(
data_arr) | (data_arr < 0.0))] = 0.0
return data_arr


def solve_eik(Wave, bcs_eik, tol=1e-16):
'''
Solve nonlinear eikonal
'''
Expand All @@ -182,27 +284,61 @@ def solve_eik(Wave, bcs_eik):
# Linear Eikonal
print('Solving Pre-Eikonal')
FeikL = linear_eik(Wave, u, vy, fire.dx)
fire.solve(fire.lhs(FeikL) == fire.rhs(FeikL), yp, bcs=bcs_eik)
J = fire.derivative(FeikL, yp)

# Initial guess
cell_diameter_function = fire.Function(Wave.function_space)
cell_diameter_function.interpolate(fire.CellDiameter(Wave.mesh))
yp.assign(cell_diameter_function.dat.data_with_halos.max()
/ Wave.c.dat.data_with_halos.min())

# Linear Eikonal
user_rtol = tol**0.5
# newtontr, nrichardson, qn, ngs, ncg, ngmres, anderson
nl_solver = 'newtontr'
l_solver = 'gmres' # gmres, bcgs, preonly
while True:
try:
pL = solve_prop(nl_solver=nl_solver, l_solver=l_solver,
user_rtol=user_rtol, user_iter=50)
fire.solve(fire.lhs(FeikL) == fire.rhs(FeikL), yp,
bcs=bcs_eik, solver_parameters=pL, J=J)
print(f"\nSolver Executed Successfully. Tol: {user_rtol:.1e}")
break
except Exception as e:
print(f"Error Solving: {e}")
user_rtol = user_rtol * 10 if user_rtol < 1e-3 \
else round(user_rtol + 1e-3, 3)
if user_rtol > 1e-2:
print("\nTolerance too high. Exiting.")
break

# Clean data: Set NaNs and negative values to zero
yp.dat.data_with_halos[:] = clean_inst_num(yp.dat.data_with_halos)

# Nonlinear Eikonal
print('Solving Post-Eikonal')
Feik = assemble_eik(Wave, yp, vy, fire.dx)
J = fire.derivative(Feik, yp)
user_tol = 1e-16
fire.solve(Feik == 0, yp, bcs=bcs_eik, solver_parameters={
'snes_type': 'vinewtonssls',
'snes_max_it': 1000,
'snes_atol': user_tol, # Increase the tolerance
'snes_rtol': 1e-20,
'snes_linesearch_type': 'l2',
'snes_linesearch_damping': 1.00,
'snes_linesearch_maxstep': 0.50,
'snes_linesearch_order': 2,
'pc_type': 'lu',
'ksp_type': 'gmres',
'ksp_max_it': 1000,
'ksp_atol': user_tol, # Increase the tolerance
}, J=J)
user_rtol = tol
# newtonls, newtontr, nrichardson, qn, ngs, ncg, ngmres, anderson
nl_solver = 'newtonls'
l_solver = 'preonly' # gmres, bcgs, preonly
while True:
try:
pNL = solve_prop(nl_solver=nl_solver, l_solver=l_solver,
user_rtol=user_rtol, user_iter=50)
fire.solve(Feik == 0, yp, bcs=bcs_eik, solver_parameters=pNL, J=J)
print(f"\nSolver Executed Successfully. Tol: {user_rtol:.1e}")
break
except Exception as e:
print(f"Error Solving: {e}")
user_rtol = user_rtol * 10 if user_rtol < 1e-3 \
else round(user_rtol + 1e-3, 3)
if user_rtol > 1e-2:
print('\nHigh Tolerance. Exiting!')
break
# yp.dat.data_with_halos[:] = clean_inst_num(yp.dat.data_with_halos)

return yp

Expand Down
Binary file modified output/Eik/Eik_0.vtu
Binary file not shown.

0 comments on commit 408380d

Please sign in to comment.