-
Notifications
You must be signed in to change notification settings - Fork 50
Description
For discussion, fleshing out an idea we've discussed briefly in the past...
See also http://www.clawpack.org/refinement.html
Current flagging strategy in amrclaw:
(ignoring adjoint flagging to start)
setrun.py sets values:
amrdata.flag_richardson = boolean (stored as flag_richardson in Fortran)
amrdata.flag_richardson_tol = scalar (stored as tol in Fortran)
amrdata.flag2refine = boolean (stored as flag_gradient in Fortran)
amrdata.flag2refine_tol = scalar (stored as tolsp in Fortran)
If it is regrid time on level L, the following is done in flagger.f,
looping over all patches on this level:
-
set amrflag(i,j) = UNSET for all cells on patch.
-
call flagregions2 to set some values to DONTFLAG if forbidden or
DOFLAG if required to refine further, done as follows:
If the cell center is in the union of some set of regions then the
cell is markedDOFLAG if L < max(minlevel) DONTFLAG if L >= max(maxlevel)where the max is over these regions in both cases (yes, both are max).
The cell remains UNSET if it does not lie in any region, or ifmax(minlevel) <= L < max(maxlevel)in which case refinement is neither required nor forbidden
-
If any cells on this patch are still UNSET and flag_gradient==True, then
call flag2refine and possibly mark some of these cells as DOFLAG
if tolerance tolsp is exceeded by the undivided gradient estimate or user's
criterion in flag2refine.
(Does not change cells already marked, does not mark more cells as DONTFLAG) -
If any cells are still UNSET and flag_richardson==True,
call errest to possibly mark some of these cells as DOFLAG
if tolerance tol is exceeded by Richardson error estimate.
(Does not change cells already marked, does not mark more cells as DONTFLAG) -
If any cells are still UNSET, mark them as DONTFLAG.
Then buffer flagged points and cluster into rectanglar level L+1 patches.
If adjoint_flagging == True then the above is still done, but now:
- flag2refine computes inner product with adjoint snapshots over some
time range and compares max amplitude of this to tolsp to mark DOFLAG, - errest computes inner product of error estimate with adjoint snapshots
and uses tol as tolerance to mark DOFLAG.
Proposed modification (ignoring adjoint):
setrun.py sets values:
amrdata.flag_richardson = boolean or array
amrdata.flag_richardson_tol = scalar or array
amrdata.flag2refine = boolean or array
amrdata.flag2refine_tol = scalar or array
In each case, a scalar value means that value applies to all levels L,
while an array such as
amrdata.flag_richardson = [True, True, False]
would mean use Richardson flagging on levels L = 1 and 2 but not on level 3
or above, and the tolerance could also vary by level.
The above algorithm would be unchanged except that on level L the values of
flag_richardson, richardson_tol, etc. would be the ones specified for that
level. This should be a very minor change.
Note that flag_richardson and flag2refine can each be True or False independent
of the other. If both True, then if a cell is UNSET by regions we first check
flag2refine and if it remains UNSET then it is checked by flag_richardson.
So it will end up flagged if either criterion says it should be flagged
(unless the regions already determined it as DOFLAG or DONTFLAG).
Adjoint flagging:
Currently if adjoint_flagging = True then either flag2refine and/or
flag_richardson can be applied, with the tolerance applied to the
adjoint inner product rather than directly to q or the error estimate.
This could be extended to arrays as above by letting adjoint_flagging be an
array and apply the current approach on each level based on adjoint_flagging[L].
A more general approach would be to allow adjoint_flagging in addition to one
or both of flag2refine (based on gradient of q) and flag_richardson (error
estimates of q). Ideally we would allow two new possibilities, adjoint_flagging
based on magnitude of inner product of q and the adjoint, and adjoint_flagging
based on the inner product of the error estimate with the adjoint.
This does not seem worth fully implementing at this time because doing both
Richardson flagging on q and on the adjoint simultaneously would require more
refactoring and probably would not be used.
But I do suggest we introduce:
amrdata.flag_adjoint = boolean or array
amrdata.flag_adjoint_tol = scalar or array
amrdata.flag_adjoint_richardson = boolean or array
amrdata.flag_adjoint_richardson_tol = scalar or array
for more clarity of what is being done in setrun.py, and with the requirement
that flag_adjoint_richardson and flag_richardson cannot both
be True on the same level.
In particular, allow both flag2refine and flag_adjoint to be True on the same
level, and remove the code that computes the adjoint inner product from
flag2refine since it does not belong there anyway -- the original idea was
that flag2refine.f90 should be a simple routine for gradient flagging that
the user could easily modify to implement some other desired flagging based
directly on q.
This set of modifications would in particular allow setting, e.g.
amrdata.flag_adjoint = [True, True, False]
amrdata.flag_adjoint_tol = 0.001
amrdata.flag2refine = [False, False, True]
amrdata.flag2refine_tol = 0.1
in order to use adjoint flagging only on levels L=1 and 2, and flagging based
on q in all finer levels. This is a common use case in GeoClaw where we
want to use adjoint flagging to track waves over the ocean on levels up to
L+1=3, but not on the finer grids near the coastal location of interest, where
wave_tolerance flagging is both much cheaper to apply and also properly
identifies onshore locations that are flooded (whereas the adjoint of
the linearized ocean at rest is identically 0 onshore).