

\section{Unstructured Meshes And Tagging}\label{UNSTRUCTURED SEC}
This section provides a simple example of how to use
an unstructured mesh generated by \gmshextern, including the use of tagging.
The use of unstructured meshes offers a high degree of geometrical flexibility. For detailed information, we refer to the \textit{Gmsh} documentation at \url{https://gmsh.info}.

\begin{figure}
\centerline{\includegraphics[width=0.8\textwidth]{unstructgeo.png}}
\caption{Rectangular Domain with Circular Inclusion.}
\label{FIG:UNSTRUCT:GEO}
\end{figure}
\begin{figure}
\centerline{\includegraphics[width=0.8\textwidth]{unstructmsh.png}}
\caption{Mesh for Rectangular Domain with Circular Inclusion.}
\label{FIG:UNSTRUCT:MSH}
\end{figure}
As an example, we revisit the temperature diffusion already introduced
in Section~\ref{DIFFUSION TEMP SEC} but at steady state and with different boundary conditions.
The domain is again a 2D rectangle, as shown in Figure~\ref{FIG:UNSTRUCT:GEO}.
The unknown temperature $T$ is given as
The governing equation in the interior of the domain is given by
\begin{equation}
- (\kappa T_{,i})_{,i} = q_H
\label{UNSTRUCTURED EQ 1}
\end{equation}
where $\kappa$ is given material constants - again assumed to be constant.
As before, the source term $q_H$ is assumed to be
$q^{c}$ over an inclusion defined as a circle with center $x^c$ and radius $r$, and $0$ elsewhere.
In contrast to the approach in Section~\ref{DIFFUSION TEMP SEC}, we will use element tagging
to set the value of $q_H$. On the bottom edge, we set $T=T_{ref}$.
On all other edges, we specify the normal heat flux as $q_{S}$:
\begin{equation}
 \kappa T_{,i} n_i = q_{S}
\label{UNSTRUCTURED TEMP EQ 2}
\end{equation}
As usual, $n_i$ is the $i$-th component of the outer normal field\index{outer normal field} at the surface of the domain. $q_{S}$ takes the value $q_out$ on the left and the right edge of the domain and zero at the top edge.
Although this is not specifically stated, it is assumed that the temperature and the normal heat flux across the circular inclusion and the outer region are continuous.

For the mesh generation, the domain is defined in \textit{gmsh} geometry file, typically with file extension \texttt{geo}. The geometry file for the case discussed here is available as \file{inclusion.geo}.

The geometry is set up by first defining the corner points of the outer boundary:
\begin{verbatim}
// ... Points: Outer Boundary
Point(1) = {0., 0., 0., SizeOuter};
Point(2) = {L0, 0., 0., SizeOuter};
Point(3) = {0., L1, 0., SizeOuter};
Point(4) = {L0, L1, 0., SizeOuter};
\end{verbatim}
where \texttt{L0} and \texttt{L!} are the horizontal and vertical extensions of the outer domain. \texttt{SizeOuter} is the mesh size to be set at these points. These points are then connected to define lines of the outer edges of the domain, which are then connected to form the outer boundary, see also Figure~\ref{FIG:UNSTRUCT:GEO}:
\begin{verbatim}
// ... Outer Boundary
Line(1) = {1, 2};
Line(2) = {2, 4};
Line(3) = {4, 3};
Line(4) = {3, 1};
Curve Loop(1) = {1, 2, 3, 4};
\end{verbatim}
For the circular inclusion, one follows the analogous process to first define relevant points, which are the circle centre at \texttt{(X0_c, X1_c)} and four points on the
perimeter of the circle:
\begin{verbatim}
// ..... Center of Circle:
Point(5) = {X0_c , X1_c, 0., SizeInter};
// ..... Points on the perimeter:
Point(6) = {X0_c, X1_c - R_c, 0., SizeInter};
Point(7) = {X0_c + R_c, X1_c, 0., SizeInter};
Point(8) = {X0_c, X1_c + R_c, 0., SizeInter};
Point(9) = {X0_c - R_c, X1_c, 0., SizeInter};
\end{verbatim}
The local element size is \texttt{SizeInter}. These points are then connected by four circular segments, which in turn are connected to form the interface edge between the inclusion and the rest of the domain:
\begin{verbatim}
// ...  Circle segments for the inclusion
Circle(5) = {6, 5, 7};
Circle(6) = {7, 5, 8};
Circle(7) = {8, 5, 9};
Circle(8) = {9, 5, 6};
Curve Loop(2) = {5, 6, 7, 8};
\end{verbatim}
The domain of the inclusion is introduced by its edge \texttt{Curve Loop(2)}:
\begin{verbatim}
Plane Surface(1) = {2};
\end{verbatim}
Analogously, the outer edge \texttt{Curve Loop(1)} defines the rest of the domain
but we need to take out the inclusion bounded by \texttt{Curve Loop(2)} to define a hole:
\begin{verbatim}
Plane Surface(2) = {1, 2};
\end{verbatim}
We label the inclusion and the rest of the domain using appropriate tags:
\begin{verbatim}
// Label the subdomain:
Physical Surface("Inclusion") = {1};
Physical Surface("Rest") = {2};
\end{verbatim}
We do the same for the outer edge:
\begin{verbatim}
Physical Curve("Top") = {3};
Physical Curve("Left") = {4};
Physical Curve("Right") = {2};
Physical Curve("Bottom") = {1};
\end{verbatim}
At the beginning of the geometry file, we need to add the geometry dimensions
\begin{verbatim}
L0 = 200.;
L1 = 100.;
X0_c = 80;
X1_c = 60;
R_c = 20.;
\end{verbatim}
and the local element sizes
\begin{verbatim}
SizeInter = 2.;
SizeOuter = 10.;
\end{verbatim}
Mesh generation is then run for instance, from the command line as
\begin{verbatim}
gmsh -2 -format msh22 -o inclusion.msh inclusion.geo
\end{verbatim}
The mesh is written \texttt{inclusion.msh} in the format version 2.2, which can be read by \finley.

\begin{figure}
\centerline{\includegraphics[width=0.8\textwidth]{unstructresult.png}}
\caption{Result for Rectangular Domain with Circular Inclusion.}
\label{FIG:UNSTRUCT:RESULT}
\end{figure}

The \textit{gmsh} file is read to define a 2-dimensional PDE domain using the \function{ReadGmsh}, see \Chap{chap:finley}:
\begin{python}
from esys.finley import ReadGmsh
domain = ReadGmsh("inclusion.msh", 2, optimize=True)
\end{python}
The argument \texttt{optimize=True} allows for a relabeling of the FEM nodes to optimise performance in the iterative solvers. The PDE~\eqref{UNSTRUCTURED EQ 1}
is set up and solved in the usual way:
\begin{python}
mypde = LinearPDE(domain)
mypde.setSymmetryOn()
mypde.setValue(A=kappa * kronecker(domain), Y=q_H, y=q_S, q=fixedT, r=T_ref)
T = mypde.getSolution()
print("Temperature is ", T)
saveVTK("T.vtu", temperature=T)
\end{python}
where \texttt{T_ref=15.} and \texttt{kappa = 1.}. We still need to define the heat source \texttt{q_H}, heat influx \texttt{q_S} and mask of locations of fixed temperature \texttt{fixedT}. As we have marked the circular inclusion
with label \texttt{Inclusion} during mesh generation, tagging can be used to
define easily:
\begin{python}
q_H=Scalar(0., Function(domain))
q_H.setTaggedValue("Inclusion", q_c)
\end{python}
The first statement is initialising \texttt{q_H} as a scalar quantity with associated representation \texttt{Function(domain)} (= on quadrature point in the elements of the mesh). The second statement is replacing the initial value \texttt{0.} by \texttt{q_c} for all element that are tagged with the label \texttt{Inclusion}, which are the elements that are located within the circular inclusion defined in the geometry file \file{inclusion.geo}. We apply the same strategy for heat influx \texttt{q_S} and set the outgoing fluxes to \texttt{q_out} on the left and right edges of the domain:
\begin{python}
q_S=Scalar(0., FunctionOnBoundary(domain))
q_S.setTaggedValue("Left", q_out)
q_S.setTaggedValue("Right", q_out)
\end{python}
For all other edges, the flux is set to zero. The mask for fix the temperature at the bottom can be set in the following way as discussed before:
\begin{python}
y=domain.getX()[1]
fixedT = whereZero(y - inf(y))
\end{python}
Note that the use of \text{inf(y)} rather then just $0.$ as set in the geometry makes the script independent from the location of the domain with the $x,y$-plane. An alternative way is the use of tagging with the help of the function \function{MaskFromBoundaryTag}:
\begin{python}
from esys.escript.pdetools import MaskFromBoundaryTag
fixedT = MaskFromBoundaryTag(domain, *('Bottom', ))
\end{python}
This function returns a mask with the \texttt{Solution(domain)} representation attribute that is one for all nodes that touch a boundary segment that is tagged with one of the given boundary tags - in this case, these are the FEM nodes located at the bottom of the domain. The full script is available as \file{inclusion.py}. For the result, see Figure\ref{FIG:UNSTRUCT:RESULT} created using \VisIt.

We finish this section with some useful hints and commends:
\begin{itemize}
\item The method \function{setTaggedValue} accepts tags that are not used in the associated mesh. This rule ensures better script portability.
\item Only elements - if they are internal or on the boundary - that are in regions tagged in the \gmshextern geometry file appear in the mesh file.
\item Using tagging in defining \Data objects is computationally very efficient in comparison to expanded \Data as they are typically generated when using functions
such as \function{whereZero} or \function{whereNoneNegative}.
\item The procedure presented here extends into 3D for \gmshextern, including the use \OpenCASCADE. \textbf{Mesh files need to be generated in} \texttt{MshFileVersion} 2.2.
\end{itemize}