Download as pdf or txt
Download as pdf or txt
You are on page 1of 10

CODE DOCUMENTATION

Spring Analogy Method


Spring analogy method is one of the many techniques used to implement mesh deformation algorithms on unstructured
grids. In this method, each edge in the mesh is modeled as a spring with stiffness being a function of nodal coordinates
and internal angles in the mesh. Traditionally, spring analogy was implemented by assuming spring stiffness to depend
only on the nodal coordinates, as follows –

1
𝑘𝑖𝑗 = 2 2 [1]
[(𝑥𝑖 −𝑥𝑗 ) +(𝑦𝑖 −𝑦𝑗 ) ]0.5

From Equation [1], it can be seen that as the distance between the nodes i and j decrease to zero, spring stiffness kij
increases to unbounded values. This implementation of spring stiffness, also known as lineal spring stiffness thus prevents
node to node collision by assuming high values as node i tends to node j, in other words, the distance between the nodes
i and j tend to zero. However, a drawback with this lineal spring stiffness definition is the fact that this formulation only
ensures that there is no node to node collision in the mesh. This formulation does not prevent intersection of triangular
cells or the degeneration of a triangular cells into a straight lines.

This can be remedied by introduction of torsional spring stiffness component, which is a function of the internal angle of
the triangular cell, and is defined as –

1
𝐶𝑖𝑗 = 𝑠𝑖𝑛2 𝜃 [2]
𝑚

From Equation [2], it can be seen that as the internal angle 𝜃 tends to zero, the stiffness 𝐶𝑖𝑗 assumes highly indefinite
values and thus prevents these failure modes.

Hence, in the present attempt to model the spring stiffness of edges, the overall spring constant has been taken to be a
function of 𝑘𝑖𝑗 and 𝐶𝑖𝑗 as follows –

𝐾𝑖𝑗 = 𝑓(𝑘𝑖𝑗 , 𝐶𝑖𝑗 ) [3]

A similar formulation has been used by Zhang et. al.[1] on 2D and 3D unstructured meshes and is presented below-

1 1
𝐾𝑖𝑗 = 𝜆 [𝑙𝑛 + {∑𝑁
𝑚=1 𝑖𝑗 }𝜁 ] [4]
𝑖𝑗 𝑠𝑖𝑛2 𝜃𝑚

, where 𝜆 is the grid scale parameter and is defined as 𝑙0/ 𝑙ij, where 𝑙0 is the largest scale in the mesh. Also, the values
of the exponents 𝑛 and 𝜁 used in the paper is 2 and 4 respectively in the 2D problems.

However, implementation of this formulation in the present 2D unstructured Navier Stokes solver did not lead to fruitful
results. Various failure modes were observed in the deforming mesh including degeneration of a triangular cell into a
straight line, highly skewed cells and intersecting triangular cells. Few results after this implementation in the present 2D
unstructured solver have been presented below.
(a) (b) (c)
FIG. 1 Failure modes obtained using the spring stiffness formulation used by Zhang et. al.[1] in the present solver

From FIG. 1(a), it can be observed that, a few triangular cells in the immediate mesh layer adjacent to the cylinder have
degenerated into a straight line. From FIG. 1(b), it can be observed that the deformation is not smooth and is leading to
patchy deformation in the interior of the mesh, which is not a good sign. Also, from FIG. 1(c), it can be seen that some of
the cells are overlapping and intersecting and some others have become highly skewed, which is again not a good sign.

Hence, at this point, it was realized that there is a problem either in the spring stiffness formulation or the mesh update
scheme. Proceeding from this point onward, a different spring stiffness formulation based on the work by Zeng et. al.[2]
was implemented, which takes the following form –

1 1
𝐾𝑖𝑗 = [𝑙𝑛 + 𝜅 ∑𝑁
𝑚=1 𝑖𝑗 ] [5]
𝑖𝑗 𝑠𝑖𝑛2 𝜃𝑚

, where 𝑛 = 2 and 𝜅 = 1. So, initially, all the edges in the unstructured mesh were set spring stiffness values based on
the formulation in equation [5]. Few of the results have been presented below in order to investigate the effectiveness of
this formulation.

(a) (b)
FIG.2 Failure modes obtained by using spring stiffness formulation used by Zeng et. al. [2] in the present solver
(a) (b)
FIG.3 Improvements in grid deformation after implementation of spring stiffness formulation used by Zeng et. al.[2]

FIG. 2 shows the failure modes obtained after implementation of the spring stiffness formulation used by Zeng et. al. [2]
Essentially, FIG. 2(a) and FIG 2(b) refer to the same failure mode, except for the fact that FIG. 2(b) is a zoomed in view of
FIG. 2(a). From FIG. 2(b), the formation of negative volumes can be observed, which was also present during the
implementation of spring stiffness formulation used by Zhang et. al. [1] However, as it can be seen from FIG. 3(a) and FIG.
3(b), the issues pertaining to patchy grid deformation that was present in the earlier case (shown in FIG. 1(b)) and
overlapping, intersecting, highly-skewed elements (shown in FIG. 1(c)) seem have to decreased by a great degree, which
shows that the spring stiffness formulation used by Zeng et. al. [2] (Equation [5]) is more suitable to the current
unstructured mesh generation scheme, as compared to the formulation used by Zhang et. al. [1] (Equation [4]). In spite
of the improvement, still the failure modes shown in FIG. 2 exist, which need to be sorted out.

In order to achieve this, a spring stiffness formulation based on the following equation was implemented –

1 1
𝐾𝑖𝑗 = [𝛼 𝑙𝑛 + 𝛽 ∑𝑁
𝑚=1 𝑖𝑗 ] [6]
𝑖𝑗 𝑠𝑖𝑛2 𝜃𝑚

,where 𝛼, 𝛽 are parameters which control the contributions of lineal stiffness and torsional stiffness for the overall
stiffness and 𝑛 = 1.
From FIG. 2(a), it can be seen that there is a problem with mesh update only in the immediate vicinity of the solid object.
Hence, only for edges with one node on the solid object, i.e., the edges directly connected to the solid object, the value
of𝛼 was increased to 4 and the value of 𝛽 was retained at 1. However, for the rest of the edges, the values of both 𝛼
and 𝛽 was set to 1. FIG. 4 shows the deformation patterns obtained using this formulation –
(a) (b)
FIG.4 Improvements in mesh deformation using the modified Spring Stiffness formulation (a) After 5 iterations (b) After
20 iterations

As it can be seen from FIG. 4, the mesh deformation has become better than in the previous cases. However, as it can be
observed in FIG. 4(b), the second layer seems to be more skewed compared to the rest of the layers. This means that, over
a period of time, this layer will degenerate into a line and will lead to negative volume elements eventually, which is
undesirable.

Thus, at this point, since this Spring Stiffness formulation is able to sustain grid deformation without the formation of
negative volumes for a few iterations, it was realized that there could be some bug in the implementation overall. De-
bugging revealed that there was an error in the force formulation used in the code.

In the current code, the force formulation used is

Fxn = Spring Stiffness * Xn-1 [7]

Fyn = Spring Stiffness * Yn-1 [8]

which is erroneous! It is important to note that Fxn and Fyn refer to the force components in x- and y- directions at nth
iteration.

The correct force formulation should have been

Fxn = Spring Stiffness * (δxn-δxn-1) [9]

Fyn = Spring Stiffness * (δyn-δyn-1), [10]

where δxnand δyn represent the displacements in x- and y- directions at nth iteration.
The implementation of Equations [9] and [10] in the 2D Unstructured Navier Stokes solver is currently underway.
Successive Over-Relation has used to evaluate the nodal coordinates after each iteration within the admissible tolerance
value of 5e-05.
Since this patch is still in the de-bugging stage, the Successive Over-Relaxation (SOR) patch has been provided below
instead of a separate .txt file.

Patch which is being currently debugged to implement the corrected force


formulation in equations [9] and [10]
Note: The patch below is currently being de-bugged and is NOT ERROR-FREE !!!

/* SolveLinearEqn is a User-defined Function which has been implemented to solve the equation in consideration based
on the provided inputs */

int c = 0;
double disp=0.0;

/*Successive Over-Relaxation Iteration */

do
{
c++;
Maxerr=0.0;

for (i=0;i<NoOfNodes;i++)
{
if(Node[i].Type==DOM)
{
int NeighCount=0;
double NetForceX=0;
double NetForceY=0;
int NeighbourNode[10];
double bx,by;

for (j=0;j<NoOfEdges;j++)
{
if(i==Edge[j].Point1)
{
NeighbourNode[NeighCount] = Edge[j].Point2;
if(Node[NeighbourNode[NeighCount]].Type == BODY1)
{
ForceX[NeighCount] = Edge[j].SpringConst * (Node[i].xnext - Node[i].x);
ForceY[NeighCount] = Edge[j].SpringConst * ((Node[i].ynext - Node[i].y)- 0.5*sin(2*PI*0.1*Iter*DelT));
NeighCount++;
}
else
{
ForceX[NeighCount] = Edge[j].SpringConst * ((Node[i].xnext - Node[i].x));
ForceY[NeighCount] = Edge[j].SpringConst * ((Node[i].ynext - Node[i].y));
NeighCount++;
}
}

else if(i==Edge[j].Point2)
{
NeighbourNode[NeighCount] = Edge[j].Point1;
if(Node[NeighbourNode[NeighCount]].Type == BODY1)
{
ForceX[NeighCount] = Edge[j].SpringConst * (Node[i].xnext - Node[i].x);
ForceY[NeighCount] = Edge[j].SpringConst * ((Node[i].ynext - Node[i].y)- 0.5*sin(2*PI*0.1*Iter*DelT));
NeighCount++;
}
/*else if((Node[NeighbourNode[NeighCount]].Type == INLET) || (Node[NeighbourNode[NeighCount]].Type ==
OUTLET) || (Node[NeighbourNode[NeighCount]].Type == TOP) || (Node[NeighbourNode[NeighCount]].Type ==
BOTTOM))
{
ForceX[NeighCount] = Edge[j].SpringConst * (Node[i].xnext - Node[i].x);
ForceY[NeighCount] = Edge[j].SpringConst * ((Node[i].ynext - Node[i].y)));
NeighCount++;
}*/
else
{
ForceX[NeighCount] = Edge[j].SpringConst * ((Node[i].xnext - Node[i].x));
ForceY[NeighCount] = Edge[j].SpringConst * ((Node[i].ynext - Node[i].y));
NeighCount++;
}
}
}
printf("Neighbours=%lf",NeighCount);
for (k=0;k<NeighCount;k++)
{
NetForceX += ForceX[k];
NetForceY += ForceY[k];
a += Edge[k].SpringConst;
bx += Edge[k].SpringConst * Node[i].x ;
//by += Edge[k].SpringConst * Node[i].y ;
}

by = NetForceY - a*Node[i].ynext;

Node[i].xnext = SolveLinearEqn(a,bx);
Node[i].ynext = SolveLinearEqn(a,by);
}

//disp = sqrt(pow((Node[i].xnext-Node[i].x),2)+pow((Node[i].ynext-Node[i].y),2));
err1=fabs(Node[i].xnext-Node[i].x);
err2=fabs(Node[i].ynext-Node[i].y);
if(err1>Maxerr)
{
Maxerr=err1;
printf("\nerr1=%lf",Maxerr);
}
if(err2>Maxerr)
{
Maxerr=err2;
printf("\nerr2=%lf",Maxerr);
}
}
printf("\nc=%d, maxdiv=%lf",c,disp);
}while(Maxerr>0.00005);

Laplace Smoothing Algorithm


From the results obtained based on Spring Analogy method, it was realized that a situation might come up involving
highly skewed elements and hence Laplace Smoothing algorithm was pursued.

Laplace Smoothing Algorithm can be illustrated using FIG. 5 given below –

FIG. 5 The movement of node ‘i’ towards centroid ‘m’ computed based on the nodal coordinates j1, j2, j3, j4 and j5
(Adopted from the work by Liakopoulos et. al.[3])

Let us assume that a node ‘i’ in the unstructured mesh is surrounded by five neighbors j1, j2, j3, j4 and j5. Based on the
coordinates of the neighbor nodes j1-j5, the location of centroid ‘m’ can be computed as
𝑥𝑚 = ∑𝑁
𝑗=1 𝑥𝑗 [11]

𝑦𝑚 = ∑𝑁
𝑗=1 𝑦𝑗 [12]
,where N is the number of neighbor nodes.

i m based on the following update scheme-


Laplace Smoothing algorithm moves the interior node towards the centroid

𝑥𝑖 ′ = (1 − 𝜔)𝑥𝑖 + 𝜔𝑥𝑚 [13]

𝑦𝑖 ′ = (1 − 𝜔)𝑦𝑖 + 𝜔𝑦𝑚 [14]

However, an often reported failure mode with Laplace smoothing is the inversion of elements. In order to remedy this, a
modified version of Laplace Smoothing Algorithm can be used, which can be illustrating using FIG. 6 below.
FIG. 6 Modified version of Laplace smoothing algorithm which can remedy inversion of elements
(Adopted from the work by Liakopoulos et. al.[3])

This method, as reported by Liakopoulos et. al.[3] involves computing the minimum distance among i-j1, i-j2, i-j3, i-j4
and i-j5 and re-constructing a new polygon based on this minimum length as shown in FIG. 6. Now, Laplace smoothing
algorithm is applied on the newly constructed polygon j1-j2’, j1-j3’, j1-j4’, j1-j5’.

This modified Laplace Smoothing Algorithm is currently being implemented into the Spring Analogy method code and still
under development. The patch which has been written for this implementation is given below.

Patch which is being currently combined into Spring analogy method code
/* Patch for implementing a modified version of Laplace Smoothing algorithm */

/* This patch is yet to be included in the code */

for(i=0;i<NoOfNodes;i++)
{
count=0;
printf("Node=%d",Node[i]);

if((Node[i].Type==INLET)||(Node[i].Type==OUTLET)||(Node[i].Type==TOP)||(Node[i].Type==BOTTOM)||(Node[i].Type=
=BODY1))
{
printf("boundary");
Node[i].x = Node[i].x;
Node[i].y = Node[i].y;
}

else
{
printf("interior");
for(j=0;j<NoOfEdges;j++)
{
if(i==Edge[j].Point1)
{
Neighbour[count] = Edge[j].Point2;
count++;
}
else if(i==Edge[j].Point2)
{
Neighbour[count] = Edge[j].Point1;
count++;
}
}

Node[i].NoOfNeighbours=count;

for(j=0;j<count;j++)
{
Node[i].NeighDist[j] = pow((pow((Node[i].x-Node[Neighbour[j]].x),2) + pow((Node[i].y-
Node[Neighbour[j]].y),2)),0.5);
}

num = Node[i].NeighDist[0];

for(j=1;j<count;j++)
{
if(Node[i].NeighDist[j]<num)
num = Node[i].NeighDist[j];
}
mindist = num;

for(j=0;j<count;j++)
{
Node[Neighbour[j]].x = Node[i].x + (mindist/Node[i].NeighDist[j])*(Node[i].x - Node[Neighbour[j]].x);
Node[Neighbour[j]].y = Node[i].y + (mindist/Node[i].NeighDist[j])*(Node[i].y - Node[Neighbour[j]].y);
Xnew = Xnew + Node[Neighbour[j]].x;
Ynew = Ynew + Node[Neighbour[j]].y;
}
Xm = Xnew/NoOfNeighbours;
Ym = Ynew/NoOfNeighbours;

Temp1 = Node[i].x;
Temp2 = Node[i].y;
do
{
Node[i].x = (1-omega)*Node[i].x + omega*Xm;
Node[i].y = (1-omega)*Node[i].y + omega*Ym;

Err1 = fabs(Temp1-Node[i].x);
Err2 = fabs(Temp2-Node[i].y);

if(Err1>Err2)
MaxErr = Err1;
else
MaxErr = Err2;
}while(MaxErr<0.00005);
}
}
References

[1] Zhang Xia-Ping, Zhou Dai, Bao Yan, Mesh motion approach based on spring analogy method for unstructured
meshes, J. Shanghai Jiaotong Univ. (Sci.),2010, 15(2):138-146
[2] Dehong Zeng, C.Ross Ethier, A semi-torsional spring analogy model for updating unstructured meshes in 3D
moving domains, Finite Elements in Analysis and Design 41 (2005), 1118-1139
[3] Panagiotis I.K.Liakopoulos and Kyriakos C. Giannacoglou, Unstructured remeshing using an efficient
smoothing scheme, ECCOMAS CFD 2006

You might also like