Documentation |
Adaptive sampling
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 AdaptiveMesh = n, you may experiment with AdaptiveMesh = 0, Submesh = [2^{n}- 1, 2^{n}- 1] in 3D function graphs or surfaces. The granularity of the "initial mesh" generated with these attribute values is approximately of the same size as the adaptive mesh generated with AdaptiveMesh = n, Submesh = [0, 0]. The non-adaptive evaluation on the refined regular mesh may still be more efficient than the evaluation on the (irregular) non-adaptive mesh. |
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: