Adaptive sampling
Inherited | Non-negative integer |
Objects | AdaptiveMesh Default Values |
---|---|
plot::Function2d | 2 |
plot::Conformal , plot::Curve2d , plot::Curve3d , plot::Cylindrical , plot::Function3d , plot::Implicit3d , plot::Polar , plot::Spherical , plot::Surface , plot::Sweep , plot::XRotate , plot::ZRotate | 0 |
plot::Rootlocus | 4 |
AdaptiveMesh = n
controls the adaptive sampling
in the numerical evaluation of functions, curves and surfaces. With n =
0, adaptive sampling is disabled. With n >
0, adaptive sampling is enabled.
The "depth" n of the adaptive sampling should be a small integer such as 0, 1, 2, or 3.
Continuous graphical objects such as function graphs, parameterized curves and surfaces are approximated by a discrete mesh of numerical points.
This mesh may be controlled by the user via the attributes Mesh
, Submesh
,
and AdaptiveMesh
. (Depending on the object, the Mesh
attribute
splits into more specific versions such us UMesh
and VMesh
for
curve and surface plots, or XMesh
, YMesh
, ZMesh
for function and implicit plots.)
First, the object is evaluated numerically on an equidistant
"initial mesh" set via the attribute Mesh
(or the more specific
versions mentioned above).
With AdaptiveMesh = 0
, the numerical data
over the initial mesh are used to render the object without any further
adaptive refinement.
With AdaptiveMesh = n
, n >
0, further numerical data are computed before
the renderer is called. In particular, the data of neighboring points
on the initial mesh are investigated. If a point is not reasonably
represented by a straight line connecting the neighboring points,
the corresponding intervals of the initial mesh are sub-divided recursively.
The adaptive mechanism descends into the sub-intervals of the initial
mesh if consecutive line segments of the discretized plot object deviate
from a straight line by a "bend angle" of more than
10 degrees. The intervals involved in such a situation are split into
halves, recursively.
The value of n should be a small integer that determines the recursive depth of the adaptive refinement. In each direction, up to 2^{n} - 1 additional points are placed between the points of the initial mesh.
If the object looks smooth on the initial mesh set via the attribute Mesh
or
its more detailed variants, the adaptive mechanism does not descend
into the intervals of the initial mesh. If there are fine structures
hidden inside these intervals, specifying AdaptiveMesh =
n
with n > 0 will not help
to improve the plot. In such a case, the initial mesh should be refined
via the appropriate attribute for the initial mesh.
On the other hand, if the initial mesh is fine enough to indicate
finer internal structures via the "max bend angle" criterion,
it is often more efficient to use AdaptiveMesh = n
than
to refine the initial mesh, because the adaptive mechanism refines
only those parts of the object that do need refinement. This effect
can be seen in Example 3.
Note: Note that increasing the recursive depth n by 1 may increase the run time by a factor of 2 for line objects (2D function graphs and curves) and by a factor of 4 for surface objects (3D function graphs and surfaces). In most cases, a small value such as n ∈ {1, 2, 3} suffices to obtain a reasonably smooth plot object. |
Note:
Note that the adaptive algorithm for surface objects in 3D is very expensive! As an alternative to values n >
0 in |
The following function plot contains areas of high variation.
Without a specification of AdaptiveMesh
, the default
mode AdaptiveMesh = 0
is used and we clearly see
artifacts caused by the evaluation on a discrete mesh:
plot(plot::Function2d( sin(x) + exp(-5*(x - PI/2)^2)*sin(110*x)/10, x = 0..PI)):
We activate the adaptive refinement with a high level of 3:
plot(plot::Function2d( sin(x) + exp(-5*(x - PI/2)^2)*sin(110*x)/10, x = 0..PI, AdaptiveMesh = 3)):
We set the attribute PointsVisible = TRUE
so
that the points of the adaptive mesh become visible:
plot(plot::Function2d( sin(x) + exp(-5*(x - PI/2)^2)*sin(110*x)/10, x = 0..PI, AdaptiveMesh = 3, PointsVisible = TRUE)):
The default value of Mesh
does not provide a sufficient resolution
for the following spiral:
plot(plot::Curve2d([x*cos(x), x*sin(x)], x = 0..50*PI)):
Increasing the Mesh
value improves the plot:
plot(plot::Curve2d([x*cos(x), x*sin(x)], x = 0..50*PI, Mesh = 1000)):
Alternatively, adaptive plotting can be used:
plot(plot::Curve2d([x*cos(x), x*sin(x)], x = 0..50*PI, AdaptiveMesh = 3)):
In 3D the typical artifacts caused by the rectilinear initial
mesh are "dents" on surface features that are not parallel
to a parameter axis. Without a specification of AdaptiveMesh
,
the default mode AdaptiveMesh = 0
is used:
f := plot::Function3d(sin(x*y)/(abs(x*y) + 1), x = -4 .. 4, y = -4 .. 4): plot(f):
Activating the adaptive refinement, we get a much more accurate plot. However, the computation takes much longer:
plot(f, AdaptiveMesh = 2):
To see how local the refinement is, we set the attribute MeshVisible
= TRUE
so that the internal triangulation of the adaptive
mesh becomes visible:
plot(f, AdaptiveMesh = 2, MeshVisible = TRUE):
We use a non-adaptive evaluation, but refine the regular mesh
by setting Submesh
values 2^{n} -
1 that correspond to the adaptive depth n =
2 used above. The result is of a similar quality
as before:
plot(plot::Function3d(sin(x*y)/(abs(x*y) + 1), x = -4 .. 4, y = -4 .. 4, Submesh = [3, 3])):
delete f: