User's Manual
- Definition of terms
- Theory
- Input and output files
- Link to ADCIRC-2DDI
1. Definition of terms
Node: A vertex in a grid.
Element: a collection of 3 nodes.
Edge: a side of a triangular element.
Foreground grid: also referred to as edit grid or simply grid, it is an
unstructured 2D
grid that is to be optimized. Initially it is stored in fort.14.
Background grid: sometimes also referred to as 1st background grid, it contains
the errors at each node in it (fort.13). It is also an unstructured grid, but
unlike the foreground grid, it remains the same throughout the optimization.
Search grid: a structured grid used to speed up the interpolation,
which is fequently necessary during the optimization process. See the illustration in Theory on how it is used. It also remains unchanged throughout the
optimization.
Internal edge: any edge that is shared by 2 elements.
Boundary edge (or interval): an edge that can only be found in one element.
Negative element area: element area < 0. But in practice, a small positive
number is used in lieu of zero to prevent underflow problem, i.e., if an
element's area falls below this positive number, the operation in the 5
optimization modules is then aborted.
Skewness of an element: defined as the ratio between the longest edge
of the triangular element and its equivalent radius (=sqrt(area/pi)).
2. Theory
AGrid is a 2D grid optimization code that seeks to
equi-distribute edge errors in the foreground grid, given an error field associated
with every node in the background grid. The edge error is defined as
the integration of nodal errors along an edge. It utilizes five core modules to achieve the
error equi-distribution: move node, refine, coarsen and swap edge,
and snap node to an edge. These 5 modules are iterated in the way illustrated below:
The clean-up loop consists of move-node, swap-edge, coarsen-edge and snap-node
modules written in the Euclidean space to eliminate skew elements (in
Euclidean space), which are detrimental to a number of circulation packages.
AGrid is also iterated with the solver to produce a final optimized grid in
the following fashion:
2.1 Five optimization modules
1) Move-node module:
In this module, a node (i_0) is moved in order to
better equidistribute edge errors for the edges around it.
2) Swap-edge module:
In this module,
an internal edge, shared by 2 elements, is swapped to the other diagonal of
the quadrilateral formed by the 2 elements, in order to improve aspect
ratios (or skewness)
of the 2 elements in the Riemann space.
3) Refine-edge module:
In
this module, an edge is refined whenever its error exceeds a pre-given threshold
lambda_1.
4) Coarsen-edge module:
In this
module, an edge is removed from the grid if its error is smaller than a
pre-given threshold lambda_2.
5) Snap-node module:
In this
module, a node is snapped to its opposing edge if the "snapping distance"
in Riemann space falls below a certain threshold lambda_3. There are two
distinctive
cases in this module: snapping to a boundary edge or an internal edge, which
are shown respectively above and below this sentence.
2.2 Second background grid ("search grid")
The code has been made very efficient to handle very large grids, but
it was found that the interpolation of errors on the background grid
took considerable amount of time (more than 90%). Therefore to
maximize efficiency, it is highly recommended to create a search grid,
which is a structured grid.
The way the search grid is constructed and utilized is as follows. The
entire domain is divided into small rectangles (which may not be equal in
size), and each rectangle intersects some elements in the 1st background
grid (see the diagram below). Note that this information can be computed
and stored once and for all as the two background grids do not change
during the optimization.
During the process of optimization, it is frequently necessary to find
error for a given point in space via interpolation from its parent triangle
in the 1st background grid. Instead of searching through all elements
in the 1st background grid to find the parent triagnle, we first find its
parent rectangle in the search grid (which is trivial), and then
search through all the intersecting triangles of this rectangle.
AGrid supports three options for the construction of search grid, but
only two are most useful. The easiest way is to evenly divide the domain
into nxx times nyy small rectangles (nxx and nyy are specified in agrid.h),
and this corresponds to a flag 1 for iflag2bg on the 6th line of fort.15.
On the other hand, a flag of 2 entails a user-defined search grid
and the x,y values used for the division in x,y directions are specified
in fort.18. This option is useful for highly uneven 1st background grids.
In any case, there is a cap on the maximum number of intersecting elements
allowed for a rectangle (mie in agrid.h), and the smaller this parameter is,
the faster the code will run, but possibly at the expense of larger memory required.
A good choice of this parameter is around 70. Should the code fail to construct
the search grid due to too many intersecting elements,
the error message contains the required mie.
2.3 The issue of reserving boundary nodes
It's essential to reserve some of the boundary nodes to preserve its
integrity. AGrid automatically reserves those boundary nodes near which
the curvature is high. Cubic spline is used to compute the curvature. Then
starting from the maximum curvature point on a boundary, the code will go
through the boundary and select reserved
nodes in such a way that the change of slope angle/tangent (which is the integration
of curvature along the boundary) is always below a pre-given constant (degrm
on the 8th line of fort.15). Reserved nodes are never moved, deleted or
snapped in the optimization process. However, in order to reduce the number
of skew elements left after the geometric run, the reserved nodes are allowed
to be deleted in this run. This may
cause the boundary to be self-looped. Therefore a check is made at the end of this run to indicate problematic boundary nodes and the user can easily fix it
with Gredit.
2.4 Automatic search for thresholds lambda_1-3
A bi-section method is used to automaticlly search for proper thresholds
lambda_1-3 in order that the number of nodes after the first refinement
falls into the prescribed interval [ndmin,ndmax] (the 11th line of fort.15).
Currently, the upper bound used in the bi-section method is the larger of
5*A.E. and A.E.+2*S.D. (A.E. is the initial averaged error and S.D. is the
standard deviation), and the lower bound is either A.E.-S.D.
(if it's positive) or 0.2*A.E. Therefore this option may not be
robust and the bi-section method
may fail. Also the final number of nodes is less than ndmax, but may be
less than ndmin due to later iterations. Obviously,
the larger the interval [ndmin,ndmax] is, the faster the search becomes.
Automatic search option should not be used from the 2nd solver-adaptor
iteration onwards; instead, set lambda_1-3 to be the values found in
the first iteration, in order to guarentee the exactly the same set of parameters
is used for every iteration for convergence check purpose.
2.5 Hot start
The user can hot start AGrid anywhere except within the geometric run (the
clean-up loop). Also the hot start cannot be made when the following flags
are set as:
- icstflag=0;
- ibifur=1;
- icsflag=2.
For hot start, first move save.dat to save0.dat, turn on the hot start option
in fort.15, and then place statement 999 to where you want to restart from.
3. Input and output files
3.1 Input files:
Grid file (fort.14), background grid file (fort.13),
boundary nodes file (fort.16),
main parameter input file (fort.15), search grid file (fort.18).
Description of input files
- fort.13 and fort.14:
- standard grid file in Gredit format,
with the depth being the error at the node in fort.13 (for
fort.14, the depth is not used).
- fort.16:
- in Gredit format (edit boundary nodes).
- fort.18 (enabled when iflag2bg>=2 in fort.15):
-
- ndivx: no. of divisions in x;
- xmin: minimum x (leave as it is);
- xmid(i), i=1,ndivx: x values defining each division;
- xmax: maximum x (leave as it is);
- mx(i), i=1,ndivx: no. of subdivisions in each interval. The sum of
mx(i) must be equal to nxx-2!
- ndivy: no. of divisions in y;
- ymin: minimum y (leave as it is);
- ymid(i), i=1,ndivy: y values defining each division;
- ymax: maximum y (leave as it is);
- my(i), i=1,ndivy: no. of subdivisions in each interval. The sum of
my(i) must be equal to nyy-2!
- fort.15 (parameter file):
-
- warning message;
- ics, slam0,sfea0: coorsinates system. ics=1: cartesian; =2:
lat/long. slam0 and sfea0 are center of projection.
- ihot, nstep: hot start option; =0: cold start; =1: hot start and
nstep is the new starting step. The code cannot be restarted
within the geometric run;
- icoflag, emin, emax: flag; =0: error cutoff disabled; =1: enabled,
and emin and emax are lower and upper error cutoff values (ignored
when icoflag=0);
- ismflag, it_sm: flag; =0: no error field smoothing; =1: error
smoothing using least square method, and
and it_sm is the no. of iterations in smoothing (ignored when
ismflag=0);
- iflag2bg: flag; =0: no search grid; =1: uniform
structured grid as search grid; =2:
user-defined search grid (fort.18); =3: use
strips in x and y directions defined in fort.18 (user needs
to comment out two lines and uncomment two lines in agrid.h).
The search grid
determines efficiency.
- icstflag, cst_neg: flag and a constant to determine
negative area during the optimization process. If icstflag=0,
cst_neg
is a ratio to the smallest element area in the inital grid;
if icstflag=1, use absolute value for cst_neg.
- degrm: maximum change of slope angle (in degrees) within a
boundary interval. Used to reserve boundary nodes.
- ivsflag: flag; =0: virus scan of the grid disabled; =1: enabled.
- ibifur: flag to use automatic search for thresholds rlam1-3. =0:
disabled; =1: enabled.
if ibifur=0, next line will be:
- icsflag, rlam1, rlam2, rlam3: flag; =0: relative thresholds rlam1-3
for refine, coarsen and snap
modules; =1: absolute thresholds; =2: absolute thresholds as
ratios to the averaged error for the initial grid
(the user is not allowed to hot start with flag 2);
if ibifur=1, next line will be:
- ndmin, ndmax: target interval for # of nodes.
- iconflag: flag for convergence criterion used in optimization;
=0: absolute convergence; =1: relative convergence.
- dn_r, an_r, se_r: used when iconflag=1. The three
tolerances give the
maximum ratios of deleted nodes, added nodes and swapped
edges allowed for convergence.
- iflaggeo: flag for geometric optimization to get rid of very
skew elements; =0: disabled (then the remaining
parameters are all ignored); =1: enabled.
- askew: acceptable skewness.
- it_geo: no. of iterations for geometric run.
3.2 Output files:
screen output, main output file (fort.10), edge error
distribution file (err_dis.dat), reserved nodes (rsv.dat),
intermediate grid and output files (debug.dat and save.dat),
optimized grid (op.gr and op.ll), optimized grid after geometric
correction (converged.gr and converged.ll), and error message output files
(fort.11).
Appendix: Compressed sample input and output files
4. Trouble shooting
It is quite common to encounter fatal errors during the run, but most of those
errors are caused by improper dimensioning in the header file (agrid.h) or
improper threshold used in the refinement (rlam1), and can be easily rectified.
Below is a list of commonly encountered error messages and the remedy.
- Errors in generating search grid
Solution: if iflag2bg=1, a uniform grid is generated, and you may need to
increase nxx and nyy (no. of divisions in x and y) or increase mie (maximum
no. of intersecting triangles for any rectangle). Try to keep mie as small as
possible to maximize the speed. For highly irregular domains, uniform grid
may not be sufficient, and you may consider using a non-uniform grid by changing
the flag to 2 and prepare a fort.18. Put more divisions around "crowed" areas.
The error message helps you estimate mie required.
- Too many nodes/elements during the refinement
Solution:
The 3 thresholds are related by rlam1=4*rlam2, and
rlam3=0.8*rlam2. Since
most added/deleted nodes are done during the very first iteration,
the number of nodes in the final grid is smaller than that after
the first iteration.
If the refinement cannot go through due to too many added
nodes/elements, raise rlam1 (and adjust
rlam2-3 accordingly) and retry. It is a good idea
to start with rlam1= 2 times the initial average edge error
(there is an option to specify rlam1-3 as ratios).
An easier way is to use the automatic search utility to automatically
adjust rlam1-3.
- How to adjust emin, emax and cst_neg to obtain a desired grid?
Solution: Set cst_neg to be of the same order as the smallest
area in the initial foreground grid so that most elements
will have a chance
to be altered by the optimizer. For example, you may set the flag=0,
cst_neg=2.0 etc. Remember the smallest element size in the final grid is
also related to the time
step admissible to a solver.
The 2 cut-off values emin and emax serves to change the smoothness or contrast
of the optimized grid. Often it's necessary to impose these 2 cut-offs for
the initial error field because otherwise overflow or over-coarsening would occur due to the
"noise" in the field. If the low-error region is over-coarsened
after the first iteration, raise emin; if the high-error
region is over-refined, lower emax.
- Flow solver blows up even if a smaller time step is used.
Solution: For Adcirc, it should be able to run if the maximum skewness
in the grid is less than 6. However, the smallest element size also affects
the run. The user can try to raise the minimum element size in the final grid by
increasing cst_neg.
- Too many neighbors during refinement when using auto search for rlam1-3.
Solution: Automatic search is not robust, and it can fail due to
the following reasons: # of iterations in bi-section method exceeding 20;
inadequate maximum and minimum rlam1 used in bi-section method, which are
currently being set at 5 and 0.2 times the initial averaged error; # of
neighbors exceeding maxnei during the refinement. The last problem is often an
indication that the initial error field is too uneven and thus closing up
the gap between emin and emax would help. But the user may also try to
manually set rlam1-3 to avoid the problem.
5. Link to ADCIRC-2DDI
The Columbia River estuary is used here as an example to illustrate the solver-optimizer loop.
Starting with an initial grid, ADCIRC-2DDI (2D depth integrated model) is
used to calculate an error norm (e.g., mass conservation errors).
After the ADCIRC run, fort.13 and fort.14 are therefore eventually
generated (and they are actually identical in this case).
Fort.16 can be easily generated by using
Gredit.
After setting all parameters in fort.15, agrid.f can be compiled and run.
A new optimized grid is generated at the end of the geometric run
(which is needed in this case as ADCIRC is sensitive to skew elements).
Most likely there are still a few skew elements in the grid, and
Gredit can be
used to fix them directly. The resultant grid is then
used as new grid in ADCIRC.
To generate fort.15 in ADCIRC run, the user needs to re-compute the
open boundary condition of tidal forcing. A series of Perl and FORTRAN
codes need to be run to achieve this (spcs.pl, ecp.f, genbcs.f, intel_deg.f).
The grid file in ADCIRC, fort.14 is used as input to these programs.
The bottom friction file (fort.21) can be generated by a simple FORTRAN
code friction.f, the wind file (fort.22) can be generated by data obtained from
the web, and the river open-boundary forcing file (fort.17) can be generated
from a database (LOADMAX). Then ADCIRC is run and the process repeated until
converged.