.. _periodicBoundaryCondition:
.. |deg|    unicode:: U+000B0 .. DEGREE SIGN
.. role:: red

.. currentmodule:: flow360

TU Berlin TurboLab Stator simulation using periodic boundary conditions
==========================================================================================


Description
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The "TurboLab Stator" is a stator enclosed in a measurement rig in the `TU Berlin TurboLab <https://www.tu.berlin/en/la/research/technical-facilities>`__. This geometry has been used in the past for `CFD validation and optimization studies <https://www.aboutflow.sems.qmul.ac.uk/events/munich2016/benchmark/testcase3/>`__. 


.. figure:: Figures/Stator3DView.png
    :width: 600px
    :align: center
    :alt: TU Berlin TurboLab Stator

    TU Berlin TurboLab Stator
   
This stator has 15 blades and because of its circular symmetry we can take advantage of the periodicity in the circumferential direction by simulating only 1 blade. This drastically reduces the meshing requirements and computing times. To do that we will use :class:`Periodic` and :class:`Rotational` to define :code:`rotationallyPeriodic` boundary conditions. :code:`rotationallyPeriodic` boundaries need to come in pairs, each is assigned the other as a match and the flow values of one are assigned to the other and vice versa. This ensures periodicity of the flow across those two boundaries.  

:code:`rotationallyPeriodic` boundaries are perfectly suited anytime the flow is axiperiodic and we can get away with simulating only a subset of the whole circular domain. 

.. note::

    This technique requires that both the flow conditions and geometry be axiperiodic. In this example, even though the geometry is axiperiodic, if the inflow had some alpha or beta value for example then this technique wouldn't work. The same can be said if flow separation or unsteadiness makes the flow no longer axiperiodic. 

Meshing the geometry
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When meshing a set of periodic boundaries it is important that both matched boundaries have the same shape and mesh topology so that the flow information from one boundary can be exactly copied to the other. 

Because the TurboLab Stator CAD geometry is commonly available, it is easy to mesh but for this tutorial we have provided you with a `ready made mesh <https://simcloud-public-1.s3.amazonaws.com/tutorials/periodic_boundary_condition/periodic_boundary_condition_tu_berlin_stator_mesh.cgns.gz>`__.

Once you have the mesh file, you can upload it either by using the :ref:`Web UI <quick_start_geometry>` or the :ref:`Python API <quick_start_pyAPI>`.




.. figure:: Figures/blade_hub_shroud.png
    :width: 600px
    :align: center
    :alt: blade_hub_shroud

    TU Berlin Stator slice showing the blade, hub and shroud

As you can see above, we have the blade, hub and shroud boundaries which are going to be :code:`noSlipWall`.



.. figure:: Figures/isometric2.png
    :width: 600px
    :align: center
    :alt: isometric2

    Isometric view of the slice we will use as a flow domain



.. figure:: Figures/isometric.png
    :width: 600px
    :align: center
    :alt: isometric2

    Isometric view of the back of the slice we will use as a flow domain



.. figure:: Figures/topView.png
    :width: 600px
    :align: center
    :alt: topView

    top view of the slice we will use as a flow domain

As you can see in the above top view of the flow domain, we have setup a slip wall buffer region (in green) in front of the CAD geometry (in yellow). This is a technique used to allow for better convergence. Since we have a given velocity at the inlet, when that velocity meets the :code:`noSlipWall` at the hub and shroud then there will be a very large local gradient. That buffer region in green is set as a :code:`SlipWall` boundary condition and it gives the code a little room to spread that large gradient and thus converge better.


    
    

Defining the boundary conditions.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

A realistic scenario would be to define a given velocity distribution across the inlet using the :py:attr:`Freestream.velocity` option but for the sake of this tutorial we will assume that the inflow is constant across the whole inlet. To that end we will simply assign the following Boundary conditions to the various regions:

.. code-block:: python

    operating_condition = fl.operating_condition_from_mach_reynolds(
        mach=0.13989,
        reynolds=3200,
        project_length_unit=1 * fl.u.m,
        temperature=298.25 * fl.u.K,
    )
    fl.SimulationParams(
        models = 
        [
            fl.Wall(
                surfaces=[
                    volume_mesh["fluid/vane_ss"],
                    volume_mesh["fluid/vane_ps"],
                    volume_mesh["fluid/bladeFillet_ss"],
                    volume_mesh["fluid/bladeFillet_ps"],
                    volume_mesh["fluid/shroud"],
                    volume_mesh["fluid/hub"],
                ]
            ),
            fl.Freestream(
                surfaces=[
                    volume_mesh["fluid/inlet"],
                ]
            ),
            fl.Outflow(
                surfaces=[
                    volume_mesh["fluid/outlet"],
                ],
                spec=fl.Pressure(1.0032 * operating_condition.thermal_state.pressure),
            ),
            fl.SlipWall(
                surfaces=[
                    volume_mesh["fluid/bottomFront"],
                    volume_mesh["fluid/topFront"],
                ]
            ),
            fl.Periodic(
                surface_pairs=[(volume_mesh["fluid/periodic-1"], volume_mesh["fluid/periodic-2"])],
                spec=fl.Rotational(axis_of_rotation=(1, 0, 0)),
            ),
        ]
    )

As you can see we have simply assigned a :class:`Freestream` boundary condition at the inlet. The :code:`noSlipWall` boundary condition is defined using :class:`Wall`. Notice how :code:`fluid/bottomFront` and :code:`fluid/topFront` are set as :class:`SlipWall` boundaries and how we have a small :code:`staticPressureRatio` across the outlet.
Notice also how the two :code:`RotationallyPeriodic` boundaries are across from each other in the above images and that we have set them as a :code:`RotationallyPeriodic` pair in :py:attr:`Periodic.surface_pairs`.

The :py:attr:`Rotational.axis_of_rotation` is optional. If you know the value then it is a good idea to include it.  If it is not included then the software tries to calculate the value based on the geometry of the mesh. Including it guarantees that the correct values will be used.

Once we have set the boundary conditions setting up the rest of the simulation parameters is trivial.

Case running
~~~~~~~~~~~~~~~~~~~~~~

After launching the case using the provided  `mesh <https://simcloud-public-1.s3.amazonaws.com/tutorials/periodic_boundary_condition/periodic_boundary_condition_tu_berlin_stator_mesh.cgns.gz>`__ and :download:`Python Script <../../../../Flow360/examples/advanced_simulations/turbomachinery/periodic_BC.py>`, in a few minutes, you will see the run converge and the forces quickly stabilize


.. figure:: Figures/TU_berlin_convergence.png
    :width: 600px
    :align: center
    :alt: convergence of residuals

    Convergence plot showing more then 3 orders of magnitude decrease in the residuals.

.. figure:: Figures/TU_berlin_forces.png
    :width: 600px
    :align: center
    :alt: convergence of forces

    Force history plot showing good convergence.

Congratulations, you can now scale those forces and moments by 15 to get the forces and moments on all 15 blades of the TU Berlin stator. 

Translational periodic boundary conditions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Another periodic boundary condition that functions like the :code:`rotationallyPeriodic` boundary condition is the :code:`translationallyPeriodic` boundary condition, which can be defined using :class:`Periodic` and :class:`Translational`. This is useful when the periodicity is not rotational but translational. An example would be a 2D airfoil. By using a  :code:`translationallyPeriodic` boundary condition you could mesh a small subsection of the span and simulate an infinite span 2D section. 

This is particularly useful when you want to model 3D flow structures emanating from a 2D geometry. You can see this breakdown from 2D vortices into 3D vortices in our validation study on :ref:`Scale-Resolving Simulations Past a Circular Cylinder<cylinder2dValidationStudy>`; specifically :ref:`this image<cylinder_qCriterion>` 
