https://wiki.openfoam.com/index.php?title=Special:NewPages&feed=atom&limit=50&offset=&namespace=0&username=&tagfilter=&size-mode=max&size=0OpenFOAM Wiki - New pages [en]2023-09-23T07:51:34ZFrom OpenFOAM WikiMediaWiki 1.33.1https://wiki.openfoam.com/Coupling_a_simple_nonlinear_membrane_to_point_displacement_Michael_AllettoCoupling a simple nonlinear membrane to point displacement Michael Alletto2023-09-05T10:20:04Z<p>Michael Alletto: /* Circular membrane subject to constant pressure */</p>
<hr />
<div>[[category:mesh]]<br />
[[category:programming]]<br />
<br />
* '''contributor''': Michael Alletto<br />
* '''affiliation''': WRD MS<br />
* '''contact''': <mail address='michael.alletto@gmx.de' description='author'>click here for email address</mail><br />
* '''OpenFOAM versions''': v2112<br />
* '''Published under''': CC BY-NC-ND license ([https://creativecommons.org/licenses creative commons licenses])<br />
<br />
Go back to [https://wiki.openfoam.com/Collection_by_authors Collection by authors].<br />
<br />
You can download the case https://gitlab.com/mAlletto/openfoamtutorials/-/tree/master/membranBCSend] here.<br />
<br />
==Introduction==<br />
<br />
In the tutorial https://wiki.openfoam.com/Coupling_a_membrane_with_pretension_to_point_displacement_Michael_Alletto we saw how to couple different physical models. In the before mentioned tutorial we coupled the equations of motion of a prestressed membrane with the displacement of the mesh. The membrane is deformed by the action of the pressure on the solid surface. The equations of motion for a prestressed membrane assume that the stress of the membrane is constant and does not change when the membrane is deformed. The question which arises is what is if we want to simulate a membrane which is in an initial undeformed and unstressed configuration and deforms by the action of the fluid pressure? How should we proceed to figure out what are the correct equations to be solved, what kind of assumptions has to be made to simplify the equation and how do we verify if our assumptions are correct? In this tutorial we will answer this question.<br />
<br />
== Equation of motion ==<br />
<br />
The equations of motion for a curved thick membrane under the action of<br />
external forces can be found in Reddy [3] p. 421:<br />
<br />
[[File:simple_nonlinear_membrane_alletto_equation1.png|400px|center|equation 1 of the derivation of the membrane equation of motion]]<br />
<br />
The above equation is described in a curvilinear coordinate system. x<sub>1</sub> and x<sub>1</sub> represent curved coordinates which follow the surface. N<sub>11</sub> and N<sub>11</sub> are the normal (membrane) forces per unit length. N<sub>12</sub> represents the shear force parallel to the curved surface and Q<sub>1</sub> and Q<sub>2</sub> represent the shear forces normal to curved surface. R<sub>1</sub> and R<sub>2</sub> are the curvature radii and f<sub>3</sub> is the external force acting normal to the plane. u<sub>1</sub> and u<sub>2</sub> are the displacements parallel to the curved surface and $w$ is the displacement normal to the curved surface. I<sub>0</sub> = &rho h is the mass per unit surface. a<sub>1</sub> and a<sub>2</sub> are the scale factors (see e.g. https://mathworld.wolfram.com/ScaleFactor.html). <br />
<br />
In our case we want only to consider the effect of the pressure on the membrane motion. Since the pressure always acts in surface normal direction, it reasonable to assume that the displacements parallel to the surface u<sub>1</sub> and u<sub>2</sub> can be neglected. For thin membranes the transverse shear forces Q<sub>1</sub> and Q<sub>2</sub> are usually set to zero (see \cite{reddy2006theory}). Since the pressure acts in surface normal direction is it also reasonable to assume that the membrane is not rotated parallel to the surface and hence also the shear force N<sub>12</sub> can be neglected. With this assumption we obtain the following equation:<br />
<br />
[[File:simple_nonlinear_membrane_alletto_equation2.png|400px|center|equation 2]]<br />
<br />
The first term in the above equation can be identified as the Laplacian in curvilinear grids (see e.g. http://sites.science.oregonstate.edu/~corinne/COURSES/ph461/laplacian.pdf). Therefore we can write down the above equation as:<br />
<br />
[[File:simple_nonlinear_membrane_alletto_equation3.png|400px|center|equation 3]]<br />
<br />
The matrix '''N''' is defined as:<br />
<br />
[[File:simple_nonlinear_membrane_alletto_equation4.png|400px|center|equation 4]]<br />
<br />
It evident that the term the first term on the left of the above equation can be seen as an diffusion equation with an anisotropic diffusion (see also [1])<br />
<br />
The constitutive relations for a thin shell can be found in [3] p. 429:<br />
<br />
[[File:simple_nonlinear_membrane_alletto_equation5.png|400px|center|equation 5]]<br />
<br />
&epsilon<sub>11</sub>, &epsilon<sub>22</sub> and &epsilon<sub>12</sub> are the longitudinal, the lateral and the shear strain, respectively. The constant A is defined as follows:<br />
<br />
[[File:simple_nonlinear_membrane_alletto_equation6.png|400px|center|equation 6]]<br />
<br />
E is the Young modolus, h is the thickness of the membrane and &nu is the Poisson ratio.<br />
<br />
==Implementation ==<br />
<br />
The algorithm proposed to solve the non-linear equation for the membrane (remember that the membrane force '''N''' is a function of the displacement w normal to the surface) is a simple predictor corrector algorithm. It is shown in the figure below. We start from the initial (undeformed) state. After that the time marching is started until the end time is reached. Within each time step the membrane equation can be solved several times by specifying a number of nOuterCorrectors in the fvSolution dictionary grater than 1. The solution procedure for the membrane equation is the following: 1) Update the membrane force: The membrane force depends on how much neighboring face centers are displaced relative to the initial stage. The magnitude of the displacement is retrieved from geometrical information, i.e. it is calculated from the distance between face centers adjacent to an edge and distances between the two points forming an edge. Since the mesh is moved at the end of the loop, the membrane force has to be updated at the beginning in order to retrieve the correct displacements. 2) Solve the membrane equation with the updated membrane force to get the displacement in surface normal direction w. 3) Move the mesh in the direction of the undeformed (initial) surface normal by the amount w calculated from the solution of the membrane equation. The three steps are repeated the number of times specified by the user in order to get a better estimation for the membrane force. Note that the flag MeshOuterCorrectors should be set to yes in the fvSolution dictionary in order to allow the mesh to move during the sub iterations within a time step. Otherwise the membrane force will not be updated during the sub iterations.<br />
<br />
<br />
[[File:simple_nonlinear_membrane_flow_chart_alletto.png|650px|center|equation 2 of the derivation of the membrane equation of motion]]<br />
<br />
After having described the algorithm as a whole, we start with the description implementation of our equation with the anisotropic diffusion equation. As we know OpenFOAM uses a finite volume or in our case a finite area method to discretize the governing equation. If we integrate the anisotropic diffusion equation over the finite area and apply the Gauss-Green theorem we get:<br />
<br />
[[File:simple_nonlinear_membrane_alletto_equation7.png|400px|center|equation 7]]<br />
<br />
In the above equation $dA$ represent the differential area element a $\mathbf{E}$ is the edge vector (in a finite volume discretization it corresponds to the surface area vector). The summation index $e$ means that we have to sum over the edges of the finite area element. With an additional manipulation of the above equation (see also \cite{moukalled2016} p. 255) we obtain the final discretized equation:<br />
<br />
[[File:simple_nonlinear_membrane_alletto_equation8.png|400px|center|equation 8]]<br />
<br />
It is evident that the term '''N'''<sup>T</sup> * '''E''' represent the projection of the membrane force in direction of the edge vector '''E'''<br />
<br />
The anisotropic diffusion equation is implemented as follows:<br />
<br />
<TT><br />
fam::laplacian(normalForcef_, w_) <br />
</TT><br />
<br />
The edgeScalarField normalForcef_ represent the projection of the membrane force vector in direction of the edge vector '''E'''. In order to understand the current implementation, it is useful to have a look at the following figure. It represent a general polygonal cell. The cell consists in the cell center (labeled as O) and various neighbors (labeled as N). The distance between the owner cell center and the neighbor cell center is labeled as L. The length of the edge delimited by the points 1 and 2 is labeled as T. N<sub>e</sub> represents the projection of the membrane force in direction normal to the cell edge.<br />
<br />
[[File:simple_nonlinear_membrane_alletto_cell.png|400px|center|cell]]<br />
<br />
In the following we assume that the vectors connecting two adjacent cell centers and the edge of the cell bounding this two cells are normal to each other. This will be true for high quality meshes. For the latter orthonormal system, we can use the constitutive relation to obtain an expression for N<sub>e</sub>:<br />
<br />
[[File:simple_nonlinear_membrane_alletto_equation9.png|400px|center|equation 9]]<br />
<br />
e<sub>e</sub> is the strain normal to the edge and e<sub>t</sub> is the strain parallel to the edge. The stain e<sub>t</sub> can be approximated as:<br />
<br />
<br />
[[File:simple_nonlinear_membrane_alletto_equation10.png|400px|center|equation 10]]<br />
<br />
T represents the length of the edge in the deformed and T<sub>0</sub> in the undeformed (initial) state. The Implementation of this relation looks like:<br />
<br />
<TT><br />
edgeScalarField ett("ett",(regionMesh().magLe() - initialEdgeLength_) / initialEdgeLength_ ); <br />
</TT><br />
<br />
The edgeScalarField initialEdgeLength_ is the initial edge length and is calculated by the constructor if it not present on the hard drive. <br />
<br />
The stain e<sub>e</sub> can be approximated as:<br />
<br />
[[File:simple_nonlinear_membrane_alletto_equation11.png|400px|center|equation 11]]<br />
<br />
L represents the distance between two adjacent cell centers in the deformed and L<sub>0</sub> in the undeformed (initial) state. <br />
<br />
<br />
The Implementation of this relation looks like the following code snippet for the internal field:<br />
<br />
<TT><br />
label edgeCounter = 0;<br />
<br />
forAll(ess,edgeI)<br />
{<br />
<br />
vector ownCenter (regionMesh().areaCentres()[regionMesh().edgeOwner()[edgeI]]);<br />
vector neiCenter (regionMesh().areaCentres()[regionMesh().edgeNeighbour()[edgeI]]);<br />
scalar distance (mag(ownCenter - neiCenter));<br />
ess[edgeI] = (distance - initialFaceCenterDistance_[edgeI]) / (initialFaceCenterDistance_[edgeI] + SMALL);<br />
edgeCounter += 1; <br />
}<br />
<br />
<br />
</TT><br />
<br />
The edgeScalarField initialFaceCenterDistance_ is the initial distance between the face centers of two neighboring finite area cells. It is calculated by the constructor if it is not present on the hard drive. <br />
<br />
The treatment of the boundary fields looks like the following code snippet:<br />
<br />
<br />
<TT><br />
<br />
auto& bfld = ess.boundaryFieldRef();<br />
const auto& infc = initialFaceCenterDistance_.boundaryFieldRef();<br />
<br />
<br />
forAll(bfld, patchi)<br />
{<br />
forAll(bfld[patchi],edgeI)<br />
{<br />
vector ownCenter (regionMesh().areaCentres()[regionMesh().edgeOwner()[edgeCounter]]);<br />
vector edgeCenter (regionMesh().edgeCentres().boundaryField()[patchi][edgeI]);<br />
scalar distance (mag(ownCenter - edgeCenter));<br />
bfld[patchi][edgeI] = (distance - infc[patchi][edgeI]) / (infc[patchi][edgeI] + SMALL);<br />
edgeCounter += 1;<br />
}<br />
<br />
}<br />
</TT><br />
<br />
<br />
Finally the calculation of the membrane force normal to the edge looks like this:<br />
<br />
<TT><br />
normalForcef_ = Ah() * (ess + solid().nu() * ett); <br />
</TT><br />
<br />
The whole code to for the calculation of the membrane force normal to the edge is represented in the following:<br />
<br />
<TT><br />
void linearElasticMembraneModel::updateNormalForce()<br />
{<br />
<br />
edgeScalarField ett("ett",(regionMesh().magLe() - initialEdgeLength_) / initialEdgeLength_ );<br />
edgeScalarField ess("ess", ett);<br />
label edgeCounter = 0;<br />
<br />
forAll(ess,edgeI)<br />
{<br />
<br />
vector ownCenter (regionMesh().areaCentres()[regionMesh().edgeOwner()[edgeI]]);<br />
vector neiCenter (regionMesh().areaCentres()[regionMesh().edgeNeighbour()[edgeI]]);<br />
scalar distance (mag(ownCenter - neiCenter));<br />
ess[edgeI] = (distance - initialFaceCenterDistance_[edgeI]) / (initialFaceCenterDistance_[edgeI] + SMALL);<br />
edgeCounter += 1;<br />
<br />
}<br />
<br />
auto& bfld = ess.boundaryFieldRef();<br />
const auto& infc = initialFaceCenterDistance_.boundaryFieldRef();<br />
<br />
<br />
forAll(bfld, patchi)<br />
{<br />
forAll(bfld[patchi],edgeI)<br />
{<br />
vector ownCenter (regionMesh().areaCentres()[regionMesh().edgeOwner()[edgeCounter]]);<br />
vector edgeCenter (regionMesh().edgeCentres().boundaryField()[patchi][edgeI]);<br />
scalar distance (mag(ownCenter - edgeCenter));<br />
bfld[patchi][edgeI] = (distance - infc[patchi][edgeI]) / (infc[patchi][edgeI] + SMALL);<br />
edgeCounter += 1;<br />
}<br />
<br />
}<br />
<br />
normalForcef_ = Ah() * (ess + solid().nu() * ett);<br />
<br />
}<br />
</TT><br />
The next point in this tutorial is how to calculate the external forces $f_3$. In our equations we will consider only the gravity force and the pressure:<br />
<br />
[[File:simple_nonlinear_membrane_alletto_equation12.png|400px|center|equation 12]]<br />
<br />
The pressure p is taken from the fluid domain. '''g''' * '''n''' is the scalar product of the gravitational acceleration '''g''' and unit normal face vector '''n'''. The gravity force is implemented as follows:<br />
<br />
<TT><br />
areaScalarField linearElasticMembraneModel::gravityForce()<br />
{<br />
<br />
return regionMesh().faceAreaNormals() & g_ * rho();<br />
} <br />
</TT><br />
<br />
<br />
The last point in the description of the implementation is how we treat the terms: N<sub>11</sub>/R<sub>1</sub> + N<sub>22</sub>/R<sub>2</sub>. Since the curvatures &kappa<sub>1</sub> = 1/R<sub>1</sub> and &kappa<sub>2</sub> = 1/R<sub>2</sub> we can write down the equations as:<br />
<br />
[[File:simple_nonlinear_membrane_alletto_equation13.png|400px|center|equation 13]]<br />
<br />
Let's recall that $N_{11}$ and $N_{22}$ are the membrane forces in direction of the curvilinear coordinates &xi<sub>1</sub> and &xi<sub>2</sub>. &kappa<sub>1</sub> and &kappa<sub>2</sub> are the corresponding curvatures. <br />
The faMesh class offers a build in function which return the face curvature &kappa<sub>f</sub>. In order to get a first very rough estimation for the term N<sub>11</sub> &kappa<sub>1</sub> + N<sub>22</sub> &kappa<sub>2</sub>, we first average the membrane force over the face edges and then multiply it by the face curvature &kappa<sub>f</sub>:<br />
<br />
<TT><br />
{ <br />
curvatureForce_ = -fac::average(normalForcef_)*regionMesh().faceCurvatures(); <br />
return curvatureForce_;<br />
}<br />
</TT><br />
<br />
A better estimation for the computation of the term N<sub>11</sub> &kappa<sub>1</sub> + N<sub>22</sub> &kappa<sub>2</sub> would be to compute the curvature at each cell edge &kappa<sub>e</sub>, multiply it with the membrane force normal to the corresponding edge $N_e$ and sum the this product over the cell edges. Unfortunately I did not find yet a working implementation for this.<br />
<br />
==Test cases ==<br />
<br />
===Cylinder with internal pressure ===<br />
<br />
The next figures shows a sketch of the first test case. This first test case consists in a circular cylinder with an undeformed radius r<sub>0</sub> = 1 m, a Young modolus of E = 2.1 x 10<sup>6</sup> N/m<sup>2</sup> and a thickness of h = 3 x 10<sup>-4</sup> m. The undeformed cylinder is subject to an internal pressure of p = 70Pa in radial direction. The ends of the cylinder a free to move (i.e. they are not clamped). For this configuration an analytical solution exists (see [4] p. 475): w = p r<sub>0</sub><sup>2</sup>/(E h) = 0.111 m.<br />
<br />
[[File:simple_nonlinear_membrane_alletto_cylinder_sketch.png|250px|center|equation 1 of the derivation of the membrane equation of motion]]<br />
<br />
The mesh topography is shown in the next figure. In order to generate the mesh for we use blockMes in order to get a hexaedral mesh and after the we use snappyHexmesh in order to obtain the cylindrical shape. The results of four different meshes are compared in order to check if the can get a grid independent solution. The meshes differ in the number of cells used in radial and circumferential direction. The number of cells in axial direction was kept unchanged. The figure below shows the mesh with approximately 50 cells in circumferential direction. The four meshes compared had approximately N = 25, 50, 100 and 200 cells in circumferential direction.<br />
<br />
[[File:simple_nonlinear_membrane_alletto_cylinder_meshN50.png|250px|center|equation 1 of the derivation of the membrane equation of motion]]<br />
<br />
<br />
The results of the mesh sensitivity study is shown in the table below. It is evident that we could not reach a grid independent solution with the maximum number of N = 200 cells in circumferential direction. The reason is probable that the curvature should be computed as function of the direction. In our simplification we used an average curvature for each finite area element. The agreement with the analytical solution is reasonable.<br />
<br />
[[File:simple_nonlinear_membrane_alletto_table_cylinder.png|250px|center|equation 1 of the derivation of the membrane equation of motion]]<br />
<br />
===Circular membrane subject to constant pressure ===<br />
<br />
The second test case consists in a circular membrane with a radius r = 0.08$ m, a Young modolus of E = 2.1 x 10<sup>6</sup> N/m<sup>2</sup> and a thickness of h = 3.4 x 10<sup>-4</sup> m. The pressure acts in this case normal to surface in y-direction. The same case was also studied by [2] experimentally and numerically. [2] measured and simulated the displacement of the membrane for different pressures. For the evaluation of our model we took the maximum and minimum pressure studied by [2]: p = 70 and p = 230 Pa. The membrane is clamped at the outer border. A sketch of the configuration is provided below.<br />
<br />
[[File:simple_nonlinear_membrane_alletto_circular_membrane_sketch.png|250px|center|equation 1 of the derivation of the membrane equation of motion]]<br />
<br />
In order to check if we can reach mesh independent results, we simulate two meshes with around 20 and 40 cells in radial direction.<br />
The coarser mesh in the deformed stage is shown in the figure below.<br />
<br />
[[File:simple_nonlinear_membrane_alletto_circular_membrane_mesh.png|250px|center|equation 1 of the derivation of the membrane equation of motion]]<br />
<br />
The result obtained for the current test case are shown in the figure below. The left figure shows the comparison with the experiments of [[2]. The first observation is that the two meshes deliver very similar results. This means that we could obtain fairly mesh independent results. The second observation is that the agreement with the experiment is acceptable especially keeping in mind the simplicity of the model. The maximum displacement is reproduce quite well. We can observe that the experiment show profile which is more curved respect to the current results. The reason is probably that we displace the membrane only in the initially undeformed direction. <br />
<br />
[[File:simple_nonlinear_membrane_alletto_circular_membrane_results.png|600px|center|equation 1 of the derivation of the membrane equation of motion]]<br />
<br />
== Lessons learned ==<br />
<br />
* By making a few assumption we could derive a simple expression which describes the non linear membrane displacement<br />
<br />
* When simplifying equation we need always the check the range of applicability by careful designed test cases <br />
<br />
* We could use geometrical relations stored in the mesh class to derive an expression for the membrane force<br />
<br />
* The results can probably be improved by implement an anisotropic expression for the curvature and displace the mesh in direction of the actual normal instead of the undeformed normal<br />
<br />
* The finite area method is a very elegant way to couple 2D physical models acting as boundary conditions for the 3D computational domain<br />
<br />
==References==<br />
<br />
[1] Fadl Moukalled, L Mangani, Marwan Darwish, et al. The finite volume<br />
method in computational fluid dynamics, volume 113. Springer, 2016.<br />
<br />
[2] Draga Pihler-Puzović, Anne Juel, Gunnar G Peng, John R Lister, and<br />
Matthias Heil. Displacement flows under elastic membranes. part 1. ex-<br />
periments and direct numerical simulations. Journal of Fluid Mechanics,<br />
784:487–511, 2015.<br />
<br />
[3] Junuthula Narasimha Reddy. Theory and analysis of elastic plates and<br />
shells. CRC press, 2006.<br />
<br />
[4] Stephen Timoshenko, Sergius Woinowsky-Krieger, et al. Theory of plates<br />
and shells, volume 2. McGraw-hill New York, 1959.</div>Michael Alletto