Commit b5474726 authored by Dave Moxey's avatar Dave Moxey
Browse files

Merge branch 'feature/bl_upgrade' into 'master'

Feature/boundary layer generation upgrade

This branch brings the first update to the Nekmesh mesh generation system.

The primary new feature is a complete overhaul of the boundary layer generation capability meaning boundary layers can be generated on much more complicated CAD than the convex only requirements of the old system.

It also adds new documentation to Nektar describing how to operate the mesh generator.

There is a modification to the nodal triangles in the reference elements to make the orderings consistent with what people believed nektar used. This will break some peoples meshes if they use NodalTriFekete or NodalTriElec curve face tags.

Regression tests have been added for the mesh generation.

Completed:
+ Boundary layer upgrade
+ Nodal triangle edit
+ Regression tests
+ Finish docs

See merge request !576
parents ff501d05 2b85bb06
......@@ -97,7 +97,9 @@ MARK_AS_ADVANCED(NEKTAR_BUILD_PACKAGES)
OPTION(NEKTAR_TEST_ALL "Include full set of regression tests to this build." OFF)
# Meshing utilities and library
OPTION(NEKTAR_USE_MESHGEN "Build mesh generation utilities." OFF)
IF (NOT WIN32)
OPTION(NEKTAR_USE_MESHGEN "Build mesh generation utilities." OFF)
ENDIF()
# Build options
OPTION(NEKTAR_FULL_DEBUG "Enable Full Debugging." OFF)
......@@ -180,15 +182,15 @@ INCLUDE (ThirdPartyScotch)
INCLUDE (ThirdPartyZlib)
INCLUDE (ThirdPartyBoost)
INCLUDE (ThirdPartyFFTW)
INCLUDE (ThirdPartyOCC)
INCLUDE (ThirdPartyArpack)
INCLUDE (ThirdPartyMPI)
INCLUDE (ThirdPartyPETSc)
INCLUDE (ThirdPartyVTK)
INCLUDE (ThirdPartyQT4)
INCLUDE (ThirdPartySMV)
INCLUDE (ThirdPartyTriangle)
INCLUDE (ThirdPartyOCC)
INCLUDE (ThirdPartyTetGen)
INCLUDE (ThirdPartyANN)
INCLUDE (ThirdPartyCCM)
INCLUDE (Doxygen)
......
# Try to find OCE / OCC
# Once done this will define
#
# OCC_FOUND - system has OCC - OpenCASCADE
# OCC_INCLUDE_DIR - where the OCC include directory can be found
# OCC_LIBRARY_DIR - where the OCC library directory can be found
# OCC_LIBRARIES - Link this to use OCC
# OCC_OCAF_LIBRARIES - Link this to use OCC OCAF framework
#
# Adapted from FreeCAD: http://free-cad.sf.net
set(TEST_ENV $ENV{OCE_ROOT})
if(NOT DEFINED OCE_DIR AND DEFINED TEST_ENV)
file(GLOB OCE_DIR $ENV{OCE_ROOT}/lib/oce-*)
endif()
# First try to find OpenCASCADE Community Edition
if(NOT DEFINED OCE_DIR)
# Check for OSX needs to come first because UNIX evaluates to true on OSX
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
if(DEFINED MACPORTS_PREFIX)
find_package(OCE HINTS ${MACPORTS_PREFIX}/Library/Frameworks)
elseif(DEFINED HOMEBREW_PREFIX)
find_package(OCE HINTS ${HOMEBREW_PREFIX}/Cellar/oce/*)
endif()
elseif(UNIX)
set(OCE_DIR "/usr/local/share/cmake/")
elseif(WIN32)
set(OCE_DIR "c:/OCE-0.4.0/share/cmake")
endif()
endif()
find_package(OCE QUIET)
if(OCE_FOUND)
message(STATUS "-- OpenCASCADE Community Edition has been found.")
# Disable this define. For more details see bug #0001872
#add_definitions (-DHAVE_CONFIG_H)
set(OCC_INCLUDE_DIR ${OCE_INCLUDE_DIRS})
#set(OCC_LIBRARY_DIR ${OCE_LIBRARY_DIR})
else(OCE_FOUND) #look for OpenCASCADE
if(WIN32)
if(CYGWIN OR MINGW)
FIND_PATH(OCC_INCLUDE_DIR Standard_Version.hxx
/usr/include/opencascade
/usr/local/include/opencascade
/usr/local/opt/opencascade/include
/opt/opencascade/include
/opt/opencascade/inc
)
FIND_LIBRARY(OCC_LIBRARY TKernel
/usr/lib
/usr/local/lib
/usr/local/opt/opencascade/lib
/opt/opencascade/lib
)
else(CYGWIN OR MINGW)
FIND_PATH(OCC_INCLUDE_DIR Standard_Version.hxx
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\SIM\\OCC\\2;Installation Path]/include"
)
FIND_LIBRARY(OCC_LIBRARY TKernel
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\SIM\\OCC\\2;Installation Path]/lib"
)
endif(CYGWIN OR MINGW)
else(WIN32)
FIND_PATH(OCC_INCLUDE_DIR Standard_Version.hxx
/usr/include/opencascade
/usr/local/include/opencascade
/usr/local/opt/opencascade/include
/opt/opencascade/include
/opt/opencascade/inc
/opt/local/include/oce
)
FIND_LIBRARY(OCC_LIBRARY TKernel
/usr/lib
/usr/local/lib
/usr/local/opt/opencascade/lib
/opt/opencascade/lib
opt/local/lib
)
endif(WIN32)
if(OCC_LIBRARY)
GET_FILENAME_COMPONENT(OCC_LIBRARY_DIR ${OCC_LIBRARY} PATH)
IF(NOT OCC_INCLUDE_DIR)
FIND_PATH(OCC_INCLUDE_DIR Standard_Version.hxx
${OCC_LIBRARY_DIR}/../inc
)
ENDIF()
endif(OCC_LIBRARY)
endif(OCE_FOUND)
if(OCC_INCLUDE_DIR)
file(STRINGS ${OCC_INCLUDE_DIR}/Standard_Version.hxx OCC_MAJOR
REGEX "#define OCC_VERSION_MAJOR.*"
)
string(REGEX MATCH "[0-9]+" OCC_MAJOR ${OCC_MAJOR})
file(STRINGS ${OCC_INCLUDE_DIR}/Standard_Version.hxx OCC_MINOR
REGEX "#define OCC_VERSION_MINOR.*"
)
string(REGEX MATCH "[0-9]+" OCC_MINOR ${OCC_MINOR})
file(STRINGS ${OCC_INCLUDE_DIR}/Standard_Version.hxx OCC_MAINT
REGEX "#define OCC_VERSION_MAINTENANCE.*"
)
string(REGEX MATCH "[0-9]+" OCC_MAINT ${OCC_MAINT})
set(OCC_VERSION_STRING "${OCC_MAJOR}.${OCC_MINOR}.${OCC_MAINT}")
endif(OCC_INCLUDE_DIR)
# handle the QUIETLY and REQUIRED arguments and set OCC_FOUND to TRUE if
# all listed variables are TRUE
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(OCC REQUIRED_VARS OCC_INCLUDE_DIR VERSION_VAR OCC_VERSION_STRING)
if(OCC_FOUND)
set(OCC_LIBRARIES
TKFillet
TKMesh
TKernel
TKG2d
TKG3d
TKMath
TKIGES
TKSTL
TKShHealing
TKXSBase
TKBool
TKBO
TKBRep
TKTopAlgo
TKGeomAlgo
TKGeomBase
TKOffset
TKPrim
TKSTEP
TKSTEPBase
TKSTEPAttr
TKHLR
TKFeat
)
set(OCC_OCAF_LIBRARIES
TKCAF
TKXCAF
TKLCAF
TKXDESTEP
TKXDEIGES
TKMeshVS
)
if(OCC_VERSION_STRING VERSION_LESS 6.7.3)
list(APPEND OCC_OCAF_LIBRARIES TKAdvTools)
endif(OCC_VERSION_STRING VERSION_LESS 6.7.3)
message(STATUS "-- Found OCE/OpenCASCADE version: ${OCC_VERSION_STRING}")
message(STATUS "-- OCE/OpenCASCADE include directory: ${OCC_INCLUDE_DIR}")
message(STATUS "-- OCE/OpenCASCADE shared libraries directory: ${OCC_LIBRARY_DIR}")
else(OCC_FOUND)
#message(SEND_ERROR "Neither OpenCASCADE Community Edition nor OpenCasCade were found: will not build CAD modules!")
endif(OCC_FOUND)
########################################################################
#
# ThirdParty configuration for Nektar++
#
# libann partitioner
#
########################################################################
IF (NOT WIN32)
CMAKE_DEPENDENT_OPTION(NEKTAR_USE_ANN
"Use ANN routines for performing Approximate Nearest Neighbour searches." ON
"NEKTAR_USE_MESHGEN" OFF)
ENDIF(NOT WIN32)
IF (NEKTAR_USE_ANN)
# First search for system ANN installs. Hint /opt/local for MacPorts and
# /usr/local/opt/ann for Homebrew.
FIND_LIBRARY(ANN_LIBRARY NAMES ANN
PATHS /opt/local/lib /usr/local/opt/ann/lib $ENV{ANN_ROOT}/lib)
FIND_PATH (ANN_INCLUDE_DIR ANN.h
PATHS /opt/local/include /usr/local/opt/ann/include $ENV{ANN_ROOT}/include
PATH_SUFFIXES ANN)
GET_FILENAME_COMPONENT(ANN_LIBRARY_PATH ${ANN_LIBRARY} PATH)
IF (ANN_LIBRARY AND ANN_INCLUDE_DIR)
SET(BUILD_ANN OFF)
ELSE()
SET(BUILD_ANN ON)
ENDIF ()
OPTION(THIRDPARTY_BUILD_ANN "Build ANN library from ThirdParty" ${BUILD_ANN})
IF (THIRDPARTY_BUILD_ANN)
# Note that ANN is compiled in the source-tree, so we unpack the
# source code in the ThirdParty builds directory.
SET(ANN_DIR ${TPBUILD}/ann-1.1.2)
SET(ANN_SRC ${ANN_DIR}/src)
IF (APPLE)
SET(ANN_CFLAGS "-O3 -fPIC")
SET(ANN_MAKELIB "libtool -static -o")
ELSE ()
SET(ANN_CFLAGS "-O3 -fPIC")
SET(ANN_MAKELIB "ar ruv")
ENDIF ()
INCLUDE(ExternalProject)
EXTERNALPROJECT_ADD(
ann-1.1.2
PREFIX ${TPSRC}
URL ${TPURL}/ann_1.1.2.tar.gz
URL_MD5 "9f99653b76798ecb1cfadc88950c4707"
STAMP_DIR ${TPBUILD}/stamp
DOWNLOAD_DIR ${TPSRC}
SOURCE_DIR ${TPBUILD}/ann-1.1.2
BINARY_DIR ${TPBUILD}/ann-1.1.2
TMP_DIR ${TPBUILD}/ann-1.1.2-tmp
INSTALL_DIR ${TPDIST}
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E remove -f ${ANN_DIR}/Makefile
BUILD_COMMAND cd src
COMMAND $(MAKE) -C ${ANN_SRC} targets
"ANNLIB = libANN.a"
"C++ = ${CMAKE_CXX_COMPILER}"
"CFLAGS = ${ANN_CFLAGS}"
"MAKELIB = ${ANN_MAKELIB}"
"RANLIB = true"
INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${TPDIST}/lib
COMMAND ${CMAKE_COMMAND} -E copy ${ANN_DIR}/lib/libANN.a
${TPDIST}/lib
COMMAND ${CMAKE_COMMAND} -E copy_directory ${ANN_DIR}/include
${TPDIST}/include
)
SET(ANN_LIBRARY ANN CACHE FILEPATH
"ANN library" FORCE)
SET(ANN_INCLUDE_DIR ${TPDIST}/include CACHE FILEPATH
"ANN include directory" FORCE)
LINK_DIRECTORIES(${TPDIST}/lib)
MESSAGE(STATUS "Build ANN: ${TPDIST}/lib/lib${ANN_LIBRARY}.a")
SET(ANN_CONFIG_INCLUDE_DIR ${TPINC})
ELSE (THIRDPARTY_BUILD_ANN)
ADD_CUSTOM_TARGET(ann-1.1.2 ALL)
MESSAGE(STATUS "Found ANN: ${ANN_LIBRARY}")
SET(ANN_CONFIG_INCLUDE_DIR ${ANN_INCLUDE_DIR})
ENDIF (THIRDPARTY_BUILD_ANN)
INCLUDE_DIRECTORIES(${ANN_INCLUDE_DIR})
MARK_AS_ADVANCED(ANN_LIBRARY)
MARK_AS_ADVANCED(ANN_INCLUDE_DIR)
ENDIF()
......@@ -7,63 +7,66 @@
########################################################################
IF(NEKTAR_USE_MESHGEN)
SET(BUILD_OCC ON)
OPTION(THIRDPARTY_DOWNLOAD_OCC
"Download pre-compiled versions of OpenCascade." ${BUILD_OCC})
# Try to find installed version of OpenCascade
INCLUDE(FindOCC)
IF (THIRDPARTY_DOWNLOAD_OCC)
IF (OCC_FOUND)
SET(BUILD_OCC OFF)
ELSE()
SET(BUILD_OCC ON)
ENDIF()
OPTION(THIRDPARTY_BUILD_OCC "Build OpenCascade library from ThirdParty."
${BUILD_OCC})
IF (THIRDPARTY_BUILD_OCC)
INCLUDE(ExternalProject)
SET(OCC_LIBS_TMP PTKernel TKernel TKMath TKBRep TKIGES TKSTEP TKSTEPAttr
SET(OCC_LIBRARIES_TMP PTKernel TKernel TKMath TKBRep TKIGES TKSTEP TKSTEPAttr
TKSTEP209 TKSTEPBase TKShapeSchema TKGeomBase TKGeomAlgo TKG3d TKG2d
TKXSBase TKPShape TKTopAlgo)
FOREACH(OCC_LIB ${OCC_LIBS_TMP})
LIST(APPEND OCC_LIBS ${TPDIST}/lib/${CMAKE_SHARED_LIBRARY_PREFIX}${OCC_LIB}${CMAKE_SHARED_LIBRARY_SUFFIX})
TKXSBase TKPShape TKTopAlgo TKShHealing)
FOREACH(OCC_LIB ${OCC_LIBRARIES_TMP})
LIST(APPEND OCC_LIBRARIES ${TPDIST}/lib/${CMAKE_SHARED_LIBRARY_PREFIX}${OCC_LIB}${CMAKE_SHARED_LIBRARY_SUFFIX})
ENDFOREACH()
UNSET(OCC_LIBRARIES_TMP)
IF(WIN32)
MESSAGE(SEND_ERROR "Cannot currently use OpenCascade with Nektar++ on Windows")
ELSEIF(APPLE)
EXTERNALPROJECT_ADD(
opencascade-6.8
PREFIX ${TPSRC}
URL ${TPURL}/OCC680osx64.tgz
URL_MD5 626292523b0691304f0fa271989fbc44
STAMP_DIR ${TPBUILD}/stamp
BINARY_DIR ${TPBUILD}/opencascade-6.8
DOWNLOAD_DIR ${TPSRC}
SOURCE_DIR ${TPSRC}/opencascade-6.8
INSTALL_DIR ${TPDIST}
UPDATE_COMMAND ""
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND cp -a ${TPSRC}/opencascade-6.8/i686/lib/. ${TPDIST}/lib/ COMMAND cp -a ${TPSRC}/opencascade-6.8/i686/inc/. ${TPDIST}/include/
)
# Patch OS X libraries to fix install name problems.
EXTERNALPROJECT_ADD_STEP(opencascade-6.8 patch-install-path
COMMAND bash ${CMAKE_SOURCE_DIR}/cmake/scripts/patch-occ.sh ${TPSRC}/opencascade-6.8/i686/lib ${CMAKE_INSTALL_PREFIX}/${NEKTAR_LIB_DIR}
DEPENDEES build
DEPENDERS install)
ELSE()
EXTERNALPROJECT_ADD(
opencascade-6.8
PREFIX ${TPSRC}
URL ${TPURL}/OCC680lin64.tgz
URL_MD5 d655b6f50998bb9600e081907c247793
STAMP_DIR ${TPBUILD}/stamp
DOWNLOAD_DIR ${TPSRC}
SOURCE_DIR ${TPSRC}/opencascade-6.8
INSTALL_DIR ${TPDIST}
UPDATE_COMMAND ""
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND cp -a ${TPSRC}/opencascade-6.8/lib/. ${TPDIST}/lib/ COMMAND cp -a ${TPSRC}/opencascade-6.8/inc/. ${TPDIST}/include/
)
ENDIF()
EXTERNALPROJECT_ADD(
opencascade-6.9
PREFIX ${TPSRC}
URL http://ae-nektar.ae.ic.ac.uk/~dmoxey/OCE-0.17.2.tar.gz
URL_MD5 bf2226be4cd192606af677cf178088e5
STAMP_DIR ${TPBUILD}/stamp
BINARY_DIR ${TPBUILD}/opencascade-6.9
DOWNLOAD_DIR ${TPSRC}
SOURCE_DIR ${TPSRC}/opencascade-6.9
INSTALL_DIR ${TPBUILD}/opencascade-6.9/dist
CONFIGURE_COMMAND ${CMAKE_COMMAND}
-G ${CMAKE_GENERATOR}
-DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}
-DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER}
-DOCE_INSTALL_PREFIX:PATH=${TPDIST}
-DOCE_TESTING=OFF
-DOCE_VISUALISATION=OFF
-DOCE_DISABLE_X11=ON
${TPSRC}/opencascade-6.9
)
# Patch OS X libraries to fix install name problems.
EXTERNALPROJECT_ADD_STEP(opencascade-6.9 patch-install-path
COMMAND bash ${CMAKE_SOURCE_DIR}/cmake/scripts/patch-occ.sh ${TPDIST}/lib ${CMAKE_INSTALL_PREFIX}/${NEKTAR_LIB_DIR}
ALWAYS 1
DEPENDEES install)
MESSAGE(STATUS "Build OpenCascade: download binaries")
MESSAGE(STATUS "Build OpenCascade: ${TPDIST}/lib")
LINK_DIRECTORIES(${TPDIST}/lib)
INCLUDE_DIRECTORIES(SYSTEM ${TPDIST}/include)
ENDIF (THIRDPARTY_DOWNLOAD_OCC)
ENDIF(NEKTAR_USE_MESHGEN)
INCLUDE_DIRECTORIES(SYSTEM ${TPDIST}/include/oce)
ELSE()
ADD_CUSTOM_TARGET(opencascade-6.9 ALL)
SET(OPENCASCADE_CONFIG_INCLUDE_DIR ${OCC_INCLUDE_DIR})
INCLUDE_DIRECTORIES(SYSTEM ${OCC_INCLUDE_DIR})
ENDIF()
ENDIF()
########################################################################
#
# ThirdParty configuration for Nektar++
#
# Triangle
#
########################################################################
IF(NEKTAR_USE_MESHGEN)
SET(BUILD_TRIANGLE ON)
OPTION(THIRDPARTY_BUILD_TRIANGLE
"Build Triangle library from ThirdParty." ${BUILD_TRIANGLE})
IF (THIRDPARTY_BUILD_TRIANGLE)
INCLUDE(ExternalProject)
EXTERNALPROJECT_ADD(
triangle-1.6
PREFIX ${TPSRC}
URL ${TPURL}/triangle.zip
URL_MD5 357cb7107f51f3f89940c47435d4fa49
STAMP_DIR ${TPBUILD}/stamp
DOWNLOAD_DIR ${TPSRC}
SOURCE_DIR ${TPSRC}/triangle-1.6
BINARY_DIR ${TPBUILD}/triangle-1.6
TMP_DIR ${TPBUILD}/triangle-1.6-tmp
INSTALL_DIR ${TPDIST}
CONFIGURE_COMMAND ${CMAKE_COMMAND}
-G ${CMAKE_GENERATOR}
-DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}
-DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER}
-DCMAKE_INSTALL_PREFIX:PATH=${TPDIST}
${TPSRC}/triangle-1.6
)
SET(TRIANGLE_LIBRARY triangle CACHE FILEPATH
"Triangle library" FORCE)
SET(TRIANGLE_INCLUDE_DIR ${TPDIST}/include CACHE FILEPATH
"Triangle include" FORCE)
LINK_DIRECTORIES(${TPDIST}/lib)
IF (WIN32)
MESSAGE(STATUS
"Build Triangle: ${TPDIST}/${LIB_DIR}/${TRIANGLE_LIBRARY}.dll")
ELSE ()
MESSAGE(STATUS
"Build Triangle: ${TPDIST}/${LIB_DIR}/lib${TRIANGLE_LIBRARY}.a")
ENDIF ()
SET(TRIANGLE_CONFIG_INCLUDE_DIR ${TPINC})
ELSE()
ADD_CUSTOM_TARGET(triangle-1.6 ALL)
MESSAGE(STATUS "Found Triangle: ${TRIANGLE_LIBRARY}")
SET(TRIANGLE_CONFIG_INCLUDE_DIR ${TRIANGLE_INCLUDE_DIR})
ENDIF (THIRDPARTY_BUILD_TRIANGLE)
INCLUDE_DIRECTORIES(SYSTEM ${TRIANGLE_INCLUDE_DIR})
ENDIF(NEKTAR_USE_MESHGEN)
......@@ -6,6 +6,9 @@ install_path=$2
for file in $path/*.dylib
do
if [ -L $file ]; then
continue
fi
echo Repairing: $file
install_name_tool -id $install_path/`basename $file` $file
DYLIBS=`otool -L $file | grep -v "/" | awk -F' ' '{ print $1 }'`
......
......@@ -538,7 +538,7 @@ To extract a surface use the command:
where the integers are surface IDs to be extracted.
An optional arguemnt of \inltt{detectbnd} can be added to identify the boundary composites as part of the surface extraction.
An optional arguemnt of \inltt{detectbnd} can be added to identify the boundary composites as part of the surface extraction.
\subsection{Linearisation}
......@@ -603,6 +603,238 @@ may issue the command
module in combination with the splitting module described earlier.
\end{notebox}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Mesh generation}
In addition to the functionality described previously, \mc is capable of
generating high-order meshes directly from a CAD definition.
By default this functionality is not activated, a user wishing to utilise the
mesh generation capability of \mc must compile \nekpp with the MESHGEN option
on. As well as compiling the relevant routines into \mc it will also download
a number of other packages which are required.
As with all tasks within \mc the new mesh generation capability exists as its
own separate module which is of type Input. Due to the vast amount of code
associated with the generation of high-order meshes and the comparatively small
nature of modules in the \mc program a new library has been created for \nekpp
called {\em NekMeshUtils}, which contains all the core routines and classes for
the \mc mesh format as well as a series of classes for the generation of meshes.
This library also contains the CAD API for \nekpp which is used to generate the
meshes.
\subsection{Methodology}
This section outlines the approach taken by \mc to generate high-order meshes.
%
To simplify the sometimes very complicated high-order mesh generation processes
in other programs, \mc executes all the stages required to produce a high-order
mesh in one single pipeline which once started requires no interaction from the
user. In broad terms these stages are:
\begin{itemize}
\item Specification of the element sizes in the mesh,
\item Coarse linear mesh generation of the domain,
\item Generation of optimised high-order surface on the geometric boundary,
\end{itemize}
%
and are outlined in more detail in the following sections.
\subsubsection{CAD Interaction}
At the core of all the ideas in the \mc generator is that the final mesh is a
high quality representation of the underlying geometry. As such all of the
entities in the mesh must know where they are located with respect to the CAD
and the system to be able to query any geometric information at any point in the
domain easily and with accuracy. To handle this \mc has been interfaced with the
third-party suite of CAD libraries called OpenCascade. In its normal state
OpenCascade is a very large collection of libraries with tens of thousands of
functions which are simply not needed for our purposes, because of this its
installation is a very arduous and long process. Combine this with the fact that
there are dozens of versions and types of OpenCascade, such as OpenCascade
Community Edition, it is simply impossible for \mc to use already existing
OpenCascade installations on a given machine. To solve these issues, when
installing \nekpp with the mesh generator it will download pre-compiled binaries
for the relevant OS and link against those, any previously installed versions of
OpenCascade will not be searched for and therefore ignored.
%
To reduce the massively complex libraries in OpenCascade down to a manageable
set of functions to be used in \mc a set of interface classes have been created
which act as buffer between it and \nekpp. These CAD classes mean that
development of mesh generation routines is significantly easier and in the
future \nekpp developers will be able to utilise CAD information in all aspects
of the framework without having to learn OpenCascade. Another advantage with
this approach is that adding support for other CAD engines, as well as
OpenCascade, in the future should be relativity simple and will not require the
rewriting of any of the \mc code.
\subsubsection{Automatic specification of the mesh}
One of the key challenges of generating a high-order mesh is the creation of a
suitable coarse linear mesh. It is
quite difficult for a user to define a full set spacings over a whole domain
which will produce a good quality especially when aiming for coarseness. This
is tackled in \mc with a system for automatically defining a
set of smooth and coarse mesh spacings throughout the whole domain. This is
achieved using an octree description of the domain. The domain is recursively
subdivided into octants which each describe a small portion of the domain. The
level to which the domain subdivides is based on the curvature of the geometric
boundary. Higher curvature regions will subdivide to a finer level allowing for
increased control on the mesh specification and smoothness. The geometric
curvature is then related to a mesh sizing parameter and propagated throughout
the domain ensuring a smooth mesh. For those unfamiliar with octrees, it is
best to think of it as a non-conforming hexahedral mesh
\subsubsection{Linear Mesh Generation}
The first challenge mentioned in the previous section is addressed with the
\mc approach to linear mesh generation. Primarily because of the
difficulties in interfacing existing linear mesh generators for high-order
applications the decision was made to include a bespoke linear mesh generator
within the program. Compared with the mesh generators included in commercial
packages this linear mesh generator takes the quite unconventional and more
historic approach in building the mesh in a bottom up fashion from 0D to 3D.
Using this approach means it is possible to guarantee a level of boundary
conformity which direct to 3D approaches cannot at the desired level of
coarseness. In this approach, first mesh nodes are placed on the vertices of
the CAD model (0D), then the curves in the CAD are meshed in 1D using the
vertex nodes as boundaries, then the surfaces are meshed in their 2D parameter
plane using the curve meshes as boundaries and finally the 3D volume is meshed
using the surface mesh as the boundary to complete the linear mesh. In \mc, to
achieve greater robustness, the 2D mesh generation library Triangle is used and
the TetGen library for the 3D. Both of which are highly developed Delaunay based
mesh generators. As with all additional libraies in \nekpp these are
automatically downloaded and installed if needed.
\subsubsection{High-order Surface Generation}
Addition of the high-order nodes to and the curving of the mesh is very open
problem, no high-order mesh generator has solved this and while the methods
used in \mc are not 100\% full-proof, the system currently in place can create
good quality high-order curved meshes with a reasonable robustness. This area
will receive the greatest level of development in the future. The most critical
part of defining the high-order mesh is the addition of high-order nodes on the
geometric surface. The mesh generator must achieve the greatest level of
geometric accuracy as it can otherwise it will greatly affect the final flow
solutions. If the linear surface triangulation is taken to be fixed during this
process, the problem can be addressed in a element by element fashion. If the
high-order nodes are placed by simply using an affine mapping to the CAD surface
and back the resulting high-order triangle will inherit the same distortions as
the CAD surface. To solve this \mc uses a system node location optimisation in
the parameter plane of the CAD surface to ensure the high-order triangles have
as little distortion as possible while remaining exactly on the geometric
surface. To do this the system models the high-order edges and triangles as a
network of springs with an associated spring energy which is minimised using a
multidimensional Newton type optimisation procedure with a Gauss-Seidel matrix
solver.
\subsubsection{Mesh Correction}
Due to the fact that, for the time being, no consideration is given to the
curving of mesh interior entities, the curving the geometric surface can
produce meshes with invalid elements, especially in the case of Euler
type (Tetrahedra only) meshes. Two strategies exist within \nekpp to
correct these elements. Firstly killing the curvature, by removing the
curvature of invalid elements they become valid. However this has the
massive downside of compromising the geometric accuracy of the mesh but
is quick and effective, this can be enacted using the command:
\begin{lstlisting}[style=BashInputStyle]
NekMesh -m linearise:invalid invalidMesh.xml validMesh.xml
\end{lstlisting}
%
The alternative to this is to use the linear elastic solver within \nekpp to
deform the mesh interior entities. Its use is very computationally expensive,
as with all PDE solvers, and is also not particularly robust. It can be used
with the set of commands outlined in the FieldConvert deform and displacement
modules and the section on the Linear Elastic Solver