Skip to content
Merged
5 changes: 2 additions & 3 deletions Benchmarks/ControlFiles/BlobAdapt.control
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@

\begin{RUN_PARAMETERS}
mesh file name = Benchmarks/MeshFiles/Tests/BlobAdapt.mesh
plot file name = Benchmarks/MeshFiles/Tests/BlobAdapt.tec
stats file name = none
error file name = Benchmarks/MeshFiles/Tests/BlobAdaptErrors.txt
plot file name = Benchmarks/PlotFiles/Tests/BlobAdapt.tec
stats file name = Benchmarks/StatsFiles/Tests/BlobAdapt.txt
test file name = Benchmarks/BenchmarkData/BlobAdapt.txt
mesh file format = ISM
polynomial order = 6
Expand Down
294 changes: 294 additions & 0 deletions Benchmarks/StatsFiles/Benchmarks/BlobAdapt.txt

Large diffs are not rendered by default.

94 changes: 49 additions & 45 deletions Documentation/docs/error-controlled-adaptive-meshing.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ It now can also adaptively mesh a model to provide optimal boundary approximatio
## How to Control the Boundary Errors
Error control is added chain-by-chain in the model by telling HOHQMesh what norm to optimize ($\mathbb L^2$ or $\mathbb H^1$), the error tolerance, and to what derivatives the resulting boundary approximation will be smooth. The syntax is

\begin{CHAIN}
optimize = L2Norm OR H1Norm OR none
tolerance = <real value>
continuity = <integer value> = highest derivative to be made smooth
connect = <see below>
.
.
.
\end{CHAIN}
\begin{CHAIN}
optimize = L2Norm OR H1Norm OR none
tolerance = <real value>
continuity = <integer value> = highest derivative to be made smooth
connect = <see below>
.
.
.
\end{CHAIN}

An `OUTER_BOUNDARY` implicitly includes a chain. So, the optimization keywords can directly
be added to a `\begin{OUTER_BOUNDARY} ... \end{OUTER_BOUNDARY}` block.
Expand All @@ -38,11 +38,11 @@ The options are:

The syntax is the following:

connect = crv_1-crv_2,crv_3-crv_4,...
connect = crv_1-crv_2,crv_3-crv_4,...

where the `crv_n` are the index of the curves in the chain. For example, if a chain contains ten curves and optimization is requested across the third and fourth curves in the list and across the sixth through ninth in the list, then

connect = 3-4,6-9
connect = 3-4,6-9

**Note Well:**

Expand All @@ -55,48 +55,52 @@ The options are:

Whether or not boundary optimization is chosen, HOHQMesh will write out the maximum $\mathbb L^2$ and $\mathbb H^1$ boundary edge errors. Running the [`Examples/2D/BlobAdapt/BlobAdapt.control`](https://github.com/trixi-framework/HOHQMesh/blob/main/Examples/2D/BlobAdapt/BlobAdapt.control) example and requesting an `H1Norm` tolerance of $10^{-4}$ and first derivative continuity by

\begin{OUTER_BOUNDARY}
optimize = H1Norm
continuity = 1
tolerance = 1.0e-4
\begin{PARAMETRIC_EQUATION_CURVE}
name = blob
xEqn = x(t) = 4*cos(2*pi*t) - 3/5*cos(8*pi*t)^3
yEqn = y(t) = 4*sin(2*pi*t) - 0.5*sin(11*pi*t)^2
zEqn = z(t) = 0.0
\end{PARAMETRIC_EQUATION_CURVE}
\end{OUTER_BOUNDARY}
\begin{OUTER_BOUNDARY}
optimize = H1Norm
continuity = 1
tolerance = 1.0e-4
\begin{PARAMETRIC_EQUATION_CURVE}
name = blob
xEqn = x(t) = 4*cos(2*pi*t) - 3/5*cos(8*pi*t)^3
yEqn = y(t) = 4*sin(2*pi*t) - 0.5*sin(11*pi*t)^2
zEqn = z(t) = 0.0
\end{PARAMETRIC_EQUATION_CURVE}
\end{OUTER_BOUNDARY}

produces the output:

*******************
2D Mesh Statistics:
*******************
Total time = 0.57661399999999996
Number of nodes = 570
Number of Edges = 1059
Number of Elements = 490
Number of Subdivisions = 4

Mesh Quality:
Measure Minimum Maximum Average Acceptable Low Acceptable High Reference
Signed Area 0.00122001 0.82263252 0.10243554 0.00000000 999.99900000 1.00000000
Aspect Ratio 1.02370049 2.84878712 1.32371594 1.00000000 999.99900000 1.00000000
Condition 1.00112287 3.80020102 1.21708413 1.00000000 4.00000000 1.00000000
Edge Ratio 1.02962316 6.00757565 1.63781443 1.00000000 4.00000000 1.00000000
Jacobian 0.00049569 0.75891397 0.07875994 0.00000000 999.99900000 1.00000000
Minimum Angle 34.57990654 87.89988997 68.98664291 40.00000000 90.00000000 90.00000000
Maximum Angle 91.84435669 150.95227640 114.13256251 90.00000000 135.00000000 90.00000000
Area Sign 1.00000000 1.00000000 1.00000000 1.00000000 1.00000000 1.00000000

Boundary Error Quality:
Boundary Name Max L2 Error Max H1Error
Outer Boundary 5.13545249E-08 5.45735801E-05
Total time = 0.89582899999999999
Number of nodes = 570
Number of Edges = 1059
Number of Elements = 490
Number of Subdivisions = 4

Mesh Quality:
Measure Minimum Maximum Average Acceptable Low Acceptable High Reference
Signed Area 0.00122001 0.82263252 0.10243554 0.00000000 999.99900000 1.00000000
Aspect Ratio 1.02370049 2.84878712 1.32371594 1.00000000 999.99900000 1.00000000
Condition 1.00112287 3.80020102 1.21708413 1.00000000 4.00000000 1.00000000
Edge Ratio 1.02962316 6.00757565 1.63781443 1.00000000 4.00000000 1.00000000
Jacobian 0.00049569 0.75891397 0.07875994 0.00000000 999.99900000 1.00000000
Minimum Angle 34.57990654 87.89988997 68.98664291 40.00000000 90.00000000 90.00000000
Maximum Angle 91.84435669 150.95227640 114.13256251 90.00000000 135.00000000 90.00000000
Area Sign 1.00000000 1.00000000 1.00000000 1.00000000 1.00000000 1.00000000

Boundary Error Quality:
Boundary Name Max L2 Error Max H1 Error
Outer Boundary 6.97837728E-08 5.63742411E-05

In addition to the usual element quality measures, one sees that the $\mathbb H^1$ error is indeed bounded by the requested tolerance. If there is more than one boundary, they are listed by boundary name.

HOHQMesh can optionally write out the boundary approximation errors to files for plotting and later analysis, whether or not the adaptive procedure is requested. Two files can be written prepended with the name of the control file. One contains the point-wise error along each boundary as a function of the chain curve parameter. The other contains the integrated ($\mathbb L^2$ or $\mathbb H^1$ norms), grouped by chain. To have these files written, include the following key in the [RUN_PARAMETERS](the-control-input.md#RunParameters) block:
HOHQMesh can optionally write out the boundary approximation errors to a file for plotting and later analysis, whether or not the adaptive procedure is requested. If the statistics file key is present in the [RUN_PARAMETERS](the-control-input.md#RunParameters) block, e.g.,

error file name = <path_to_desired_file>
stats file name = path/desiredFileName.txt

Choose the name to be `none` to turn off printing out the errors, or simply delete the line from the file.
then the boundary errors will be written to a separate file with the same name appended with `_ErrorNorms`.
It contains the integrated $\mathbb L^2$ and $\mathbb H^1$ norms, grouped by chain.
For the example above the boundary error file would be located in the same `path` as the statistics file
with the name `desiredFileName_ErrorNorms.txt`.
Choose the `stats file name` to be `none` to turn off printing out the errors, or simply delete the line from the control file.
34 changes: 17 additions & 17 deletions Documentation/docs/the-control-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,37 @@
The `MODEL` and the `CONTROL_INPUT` blocks described above are put into a single file called the **control file**, which is finished with a `\end{FILE}` command. An example of a full control file that meshes a model with a circular outer boundary and two inner circular boundaries, and writes out a plot file with spectral element resolution,
is shown below. There is also a template control file in the *Examples* directory.

Just some notes:
Just some notes:

1. Blocks do not have to be specified in any order (e.g. the `MODEL` could come first before the `CONTROL_INPUT`. `INNER_BOUNDARIES` could come before `OUTER_BOUNDARY`. Blocks must be defined within their appropriate block however, e.g. `OUTER_BOUNDARY` can only be defined in a `MODEL` block.
2. Keywords within a block can be specified in any order. The only ordering that is important is that within a `CHAIN`, the curves must be specified in order, counter-clockwise.
1. Blocks do not have to be specified in any order e.g. the `MODEL` could come first before the `CONTROL_INPUT` or `INNER_BOUNDARIES` could come before `OUTER_BOUNDARY`. Blocks must be defined within their appropriate block however, e.g. `OUTER_BOUNDARY` can only be defined in a `MODEL` block.
2. Keywords within a block can be specified in any order. The only ordering that is important is that within a `CHAIN`, the curves must be specified in order, counter-clockwise.
3. Spaces in keywords **are** significant, but not in any other contexts. For instance equals signs are aligned only for visual formatting.
4. Blank lines or lines starting with % are ignored.

---

\begin{CONTROL_INPUT}

\begin{RUN_PARAMETERS}
mesh file name = Circles3Mesh.mesh
plot file name = Circles3Plot.tec
statistics file name = Circles3Stats.txt
mesh file format = ISM
polynomial order = 6
plot file format = sem
mesh file name = Circles3Mesh.mesh
plot file name = Circles3Plot.tec
stats file name = Circles3Stats.txt
mesh file format = ISM
polynomial order = 6
plot file format = sem
\end{RUN_PARAMETERS}

\begin{BACKGROUND_GRID}
background grid size = [4.0,4.0]
\end{BACKGROUND_GRID}

\begin{SPRING_SMOOTHER}
smoothing type = LinearAndCrossbarSpring
number of iterations = 20
\end{SPRING_SMOOTHER}

\end{CONTROL_INPUT}

\begin{MODEL}

\begin{OUTER_BOUNDARY}
Expand All @@ -46,7 +46,7 @@ Just some notes:
\end{OUTER_BOUNDARY}

\begin{INNER_BOUNDARIES}

\begin{CHAIN}
name = Boundary 1
\begin{PARAMETRIC_EQUATION_CURVE}
Expand All @@ -56,7 +56,7 @@ Just some notes:
zEqn = z(t) = 0.0
\end{PARAMETRIC_EQUATION_CURVE}
\end{CHAIN}

\begin{CHAIN}
name = Boundary 2
\begin{PARAMETRIC_EQUATION_CURVE}
Expand All @@ -66,7 +66,7 @@ Just some notes:
zEqn = z(t) = 0.0
\end{PARAMETRIC_EQUATION_CURVE}
\end{CHAIN}

\begin{CHAIN}
name = Boundary 3
\begin{PARAMETRIC_EQUATION_CURVE}
Expand Down
54 changes: 46 additions & 8 deletions Source/BoundaryOptimization/BoundaryErrors.f90
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,35 @@ END SUBROUTINE ComputeBoundaryErrors
!////////////////////////////////////////////////////////////////////////
!
SUBROUTINE WriteBoundaryErrors(project)
!
! ----------------------------------------------------------------------------
! Write the L2 and H1 errors within each segment along each boundary.
! It writes to the path of the stats file name appended with the string
! "_ErrorNorms" provided in the control file unless the value for the
! stats file name is "none" or not included.
!
! The format is:
!
! "Number of boundary curves = " # boundary curves
! For each boundary curve
! Boundary name, # Segments
! For each segment
! t_{start} x_{start} y_{start} t_{end} x_{end} y_{end} L2Error H1Error
! end
! end
!
! where
! t_{start} = start parametrization for the segment
! t_{end} = end parametrization for the segment
! x_{start},y_{start} = physical space location of segment start
! x_{end},y_{end} = physical space location of segment end
! L2Error = L2Error of the segment
! H1Error = H1 Error of the segment
!
! The format is redundant in that it duplicates the start and end points,
! but should make it easier to read the file and draw from it.
! ----------------------------------------------------------------------------
!
IMPLICIT NONE
!
! ---------
Expand All @@ -215,11 +244,16 @@ SUBROUTINE WriteBoundaryErrors(project)

CHARACTER(DEFAULT_CHARACTER_LENGTH) :: str
REAL(KIND=RP) :: gTStart, gTEnd
REAL(KIND=RP) :: xs(3), xe(3)
REAL(KIND=RP) :: eL2Norm, eH1Norm
INTEGER :: normUnit
INTEGER :: m, j, c

IF ( project % runParams % errorFileName == "none" ) RETURN
!
! ----------------------------------------------------------------------
! If stats are not requested then boundary errors are not written either
! ----------------------------------------------------------------------
!
IF ( project % runParams % statsFileName == "none" ) RETURN
!
! -------
! Aliases
Expand All @@ -233,12 +267,12 @@ SUBROUTINE WriteBoundaryErrors(project)
! Where to write the results
! --------------------------
!
m = INDEX(STRING = project % runParams % errorFileName, SUBSTRING = ".")
m = INDEX(STRING = project % runParams % statsFileName, SUBSTRING = ".")
IF ( m == -1 ) THEN
OPEN(NEWUNIT = normUnit, FILE = project % runParams % errorFileName //"_Norms")
OPEN(NEWUNIT = normUnit, FILE = project % runParams % statsFileName //"_ErrorNorms")
ELSE
str = project % runParams % errorFileName
str = str(1:m-1) //"_Norms.txt"
str = project % runParams % statsFileName
str = str(1:m-1) //"_ErrorNorms.txt"
OPEN(NEWUNIT = normUnit, FILE = str)
END IF
!
Expand All @@ -252,21 +286,25 @@ SUBROUTINE WriteBoundaryErrors(project)
! Write them
! ----------
!
WRITE(normUnit,*) "Number of boundary curves = ", model % numberOfChains()
DO j = 1, model % numberOfChains()
obj => modelChains(j) % object
CALL castToSMChainedCurve(obj, modelChain)
WRITE(normUnit,*) TRIM(modelChain % curveName())

obj => boundaryPolynomials % objectAtIndex(j)
CALL castObjToMultiSegmentCurve(obj,boundaryPolynomial)

WRITE(normUnit,*) TRIM(modelChain % curveName()), ",", boundaryPolynomial % nSegments

DO c = 1, boundaryPolynomial % nSegments
gTStart = boundaryPolynomial % cuts(c-1)
gTEnd = boundaryPolynomial % cuts(c)
eL2Norm = project % L2BoundaryError(j) % array(c)
eH1Norm = project % H1BoundaryError(j) % array(c)
xs = boundaryPolynomial % positionAt(gTStart)
xe = boundaryPolynomial % positionAt(gTEnd)

WRITE(normUnit,*) 0.5_RP*(gTStart + gTEnd), LOG10(eL2Norm + 1.0d-15), LOG10(eH1Norm + 1.0d-15)
WRITE(normUnit,*) gTStart, xs(1:2), gTEnd, xe(1:2), eL2Norm, eH1Norm

END DO

Expand Down
2 changes: 1 addition & 1 deletion Source/HOHQMesh.f90
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ SUBROUTINE HOHQMesh(projectDict, project, stats, didGenerate3DMesh, test)
IF ( .NOT.test ) THEN
IF ( SIZE(project % L2ErrorMax) > 0 ) THEN
PRINT *, "Boundary Error Quality:"
WRITE(6,"(A32,4x,A12,A16)") "Boundary Name", "Max L2 Error", "Max H1Error"
WRITE(6,"(A32,4x,A12,A16)") "Boundary Name", "Max L2 Error", "Max H1 Error"
DO k = 1, SIZE(project % L2ErrorMax)
obj => project % model % allChains(k) % object
CALL castToSMCurve(obj,boundaryCurve)
Expand Down
17 changes: 1 addition & 16 deletions Source/Project/MeshProject.f90
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ Module MeshProjectClass
CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: MESH_FILE_NAME_KEY = "mesh file name"
CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: PLOT_FILE_NAME_KEY = "plot file name"
CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: STATS_FILE_NAME_KEY = "stats file name"
CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: ERROR_FILE_NAME_KEY = "error file name"
CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: MESH_FILE_FORMAT_NAME_KEY = "mesh file format"
CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: POLYNOMIAL_ORDER_KEY = "polynomial order"
CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH), PARAMETER :: PLOT_FORMAT_KEY = "plot file format"
Expand Down Expand Up @@ -101,7 +100,6 @@ Module MeshProjectClass
CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: MeshFileName
CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: plotFileName
CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: statsFileName
CHARACTER(LEN=DEFAULT_CHARACTER_LENGTH) :: errorFileName
INTEGER :: meshFileFormat
INTEGER :: polynomialOrder
INTEGER :: plotFileFormat ! = SKELETON_FORMAT OR = SEM_FORMAT
Expand Down Expand Up @@ -1517,7 +1515,7 @@ SUBROUTINE SetRunParametersBlock( params, controlDict )
poster = "SetRunParametersBlock")

params % statsFileName = "none"
msg = "Control file is missing the stats file name. Stats not written."
msg = "Control file is missing the stats file name. Stats and boundary errors are not written."
CALL SetStringValueFromDictionary(valueToSet = params % statsFileName, &
sourceDict = paramsDict, &
key = STATS_FILE_NAME_KEY, &
Expand All @@ -1532,19 +1530,6 @@ SUBROUTINE SetRunParametersBlock( params, controlDict )
errorLevel = FT_ERROR_WARNING, &
message = msg, &
poster = "SetRunParametersBlock")
!
! --------------------------------------------------------------------------------
! For now, no warnings or anything for not requesting the errors to be written out
! --------------------------------------------------------------------------------
!
params % errorFileName = "none"
msg = "Control file is missing the errors file name. Errors not written."
CALL SetStringValueFromDictionary(valueToSet = params % errorFileName, &
sourceDict = paramsDict, &
key = ERROR_FILE_NAME_KEY, &
errorLevel = FT_ERROR_NONE, &
message = msg, &
poster = "SetRunParametersBlock")

IF( fileFormat == "Basic" ) THEN
params % meshFileFormat = BASIC_MESH_FORMAT
Expand Down
Loading