.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "examples/00-fluent/tyler_sofrin_modes.py"
.. LINE NUMBERS ARE GIVEN BELOW.

.. only:: html

    .. note::
        :class: sphx-glr-download-link-note

        :ref:`Go to the end <sphx_glr_download_examples_00-fluent_tyler_sofrin_modes.py>`
        to download the full example code.

.. rst-class:: sphx-glr-example-title

.. _sphx_glr_examples_00-fluent_tyler_sofrin_modes.py:

.. _ref_ts_mode_calculator:

Tyler-Sofrin Compressor Modes Post-Processing
---------------------------------------------

.. GENERATED FROM PYTHON SOURCE LINES 30-76

Objective
~~~~~~~~~

This example demonstrates PyFluent API's for

* Read a case and data file
* Create monitor points to calculate Fourier coefficients
* Write Fourier coefficients to a file
* Tyler-Sofrin mode Plot using the matplotlib library

Background
~~~~~~~~~~

Tyler and Sofrin (1961) demonstrated that interactions between a rotor and a
stator result in an infinite set of spinning modes. Each Tyler-Sofrin (TS)
mode exhibits an m-lobed pattern and rotates at a speed given by the
following equation:

:math:`\text{speed} = \frac{BnΩ}{m}`
Where:

* m is the Tyler-Sofrin mode number, defined as 'm = nB + kV'
* n is the impeller frequency harmonic
* k is the vane harmonic
* B is the number of rotating blades
* V is the number of stationary vanes
* Ω is the Rotor shaft speed, rad/s

Example:

        * 8-blade rotor interacting with a 6-vane stator
        * 2-lobed pattern turning at (8)(1)/(2) = 4 times shaft speed


Example Table
~~~~~~~~~~~~~

.. image:: ../../_static/ExampleTable.jpg
   :alt: Example Table


Tyler-Sofrin Modes
~~~~~~~~~~~~~~~~~~

.. image:: ../../_static/TSmode.jpg
   :alt: Tyler-Sofrin Modes

.. GENERATED FROM PYTHON SOURCE LINES 79-99

Example Note: Discrete Fourier Transform (DFT)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  + In order to calculate the pressure related to each TS-mode, extend the
    simulation and perform the DFT of pressure at the desired blade passing
    frequency harmonics.

  + Disable the Hanning windowing (specifically for periodic flows like
    this one) to avoid getting half the expected magnitudes for periodic flows.
    Make sure to set the windowing parameter to 'None' when specifying
    the Discrete Fourier Transform (DFT) in the graphical user interface (GUI).

  + The DFT data will only be accurate if the sampling is done across the
    entire specified sampling period.


.. note::
  The .cas/.dat file provided with this example is for demonstration purposes only.
  A finer mesh is necessary for accurate acoustic analysis. This example uses data
  sets generated with Ansys Fluent V2023R2.

.. GENERATED FROM PYTHON SOURCE LINES 101-103

Post-Processing Implementation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. GENERATED FROM PYTHON SOURCE LINES 106-108

Import required libraries/modules
=====================================================================================

.. GENERATED FROM PYTHON SOURCE LINES 108-118

.. code-block:: Python

    import math
    from pathlib import Path
    import random

    import matplotlib.pyplot as plt
    import numpy as np

    import ansys.fluent.core as pyfluent
    from ansys.fluent.core import examples


.. GENERATED FROM PYTHON SOURCE LINES 119-126

Specifying save path
=====================================================================================
save_path can be specified as:

  +   Path("E:/", "pyfluent-examples-tests") or
  +   Path("E:/pyfluent-examples-tests") in a Windows machine for example, or
  +   Path("~/pyfluent-examples-tests") in Linux.

.. GENERATED FROM PYTHON SOURCE LINES 126-129

.. code-block:: Python


    save_path = Path(pyfluent.EXAMPLES_PATH)


.. GENERATED FROM PYTHON SOURCE LINES 130-132

Downloading cas/dat file
=====================================================================================

.. GENERATED FROM PYTHON SOURCE LINES 132-144

.. code-block:: Python

    import_filename = examples.download_file(
        "axial_comp_fullWheel_DFT_23R2.cas.h5",
        "pyfluent/examples/Tyler-Sofrin-Modes-Compressor",
        save_path=save_path,
    )

    examples.download_file(
        "axial_comp_fullWheel_DFT_23R2.dat.h5",
        "pyfluent/examples/Tyler-Sofrin-Modes-Compressor",
        save_path=save_path,
    )


.. GENERATED FROM PYTHON SOURCE LINES 145-147

Launch Fluent session and print Fluent version
=====================================================================================

.. GENERATED FROM PYTHON SOURCE LINES 147-152

.. code-block:: Python

    session = pyfluent.launch_fluent(
        ui_mode="gui", processor_count=4, product_version="25.1.0"
    )
    print(session.get_fluent_version())


.. GENERATED FROM PYTHON SOURCE LINES 153-158

Reading case and data file
=====================================================================================

.. note::
  The dat file should correspond to the already completed DFT simulation.

.. GENERATED FROM PYTHON SOURCE LINES 158-161

.. code-block:: Python


    session.file.read(file_type="case-data", file_name=import_filename)


.. GENERATED FROM PYTHON SOURCE LINES 162-171

Define User constant/variables
=====================================================================================

.. note::
  The variable names should match the ones written from the DFT and can be
  identified by manually examining the solution variables as shown below:

.. image:: ../../_static/var_names.jpg
   :alt: variable names

.. GENERATED FROM PYTHON SOURCE LINES 171-187

.. code-block:: Python


    varname = [
        "mean-static-pressure-dataset",
        "dft-static-pressure_10.00kHz-ta",
        "dft-static-pressure-1_21.43kHz-ta",
        "dft-static-pressure-2_30.00kHz-ta",
    ]
    n_mode = [0, 1, 2, 3]  # Impeller frequency harmonics
    r = 0.082  # meters
    z = -0.037  # meters
    d_theta = 5  # degrees
    m_max = 50  # maximum TS mode number

    # Plot will be from -m_max to +m_max, incremented by m_inc
    m_inc = 2  # TS mode increment


.. GENERATED FROM PYTHON SOURCE LINES 188-190

Create monitor points
=====================================================================================

.. GENERATED FROM PYTHON SOURCE LINES 190-197

.. code-block:: Python

    for angle in range(0, 360, d_theta):
        x = math.cos(math.radians(angle)) * r
        y = math.sin(math.radians(angle)) * r
        pt_name = "point-" + str(angle)
        session.results.surfaces.point_surface[pt_name] = {}
        session.results.surfaces.point_surface[pt_name].point = [x, y, z]


.. GENERATED FROM PYTHON SOURCE LINES 198-200

Compute Fourier coefficients at each monitor point (An, Bn)
=====================================================================================

.. GENERATED FROM PYTHON SOURCE LINES 200-240

.. code-block:: Python

    An = np.zeros((len(varname), int(360 / d_theta)))
    Bn = np.zeros((len(varname), int(360 / d_theta)))

    for angle_ind, angle in enumerate(range(0, 360, d_theta)):
        for n_ind, variable in enumerate(varname):
            if len(variable) >= 4 and variable[:4] == "mean":
                session.solution.report_definitions.surface["mag-report"] = {
                    "report_type": "surface-vertexavg",
                    "surface_names": ["point-" + str(angle)],
                    "field": str(variable),
                }
                mag = session.solution.report_definitions.compute(
                    report_defs=["mag-report"]
                )
                mag = mag[0]["mag-report"][0]
                An[n_ind][angle_ind] = mag
                Bn[n_ind][angle_ind] = 0
            else:
                session.solution.report_definitions.surface["mag-report"] = {
                    "report_type": "surface-vertexavg",
                    "surface_names": ["point-" + str(angle)],
                    "field": str(variable) + "-mag",
                }
                mag = session.solution.report_definitions.compute(
                    report_defs=["mag-report"]
                )
                mag = mag[0]["mag-report"][0]
                session.solution.report_definitions.surface["phase-report"] = {
                    "report_type": "surface-vertexavg",
                    "surface_names": ["point-" + str(angle)],
                    "field": str(variable) + "-phase",
                }
                phase = session.solution.report_definitions.compute(
                    report_defs=["phase-report"]
                )
                phase = phase[0]["phase-report"][0]
                An[n_ind][angle_ind] = mag * math.cos(phase)
                Bn[n_ind][angle_ind] = -mag * math.sin(phase)



.. GENERATED FROM PYTHON SOURCE LINES 241-247

Write Fourier coefficients to file
=====================================================================================

.. note::
  This step is only required if data is to be processed with other standalone
  tools. Update the path to the file accordingly.

.. GENERATED FROM PYTHON SOURCE LINES 247-266

.. code-block:: Python


    fourier_coefficients_file = Path(save_path, "FourierCoefficients.txt")
    with open(fourier_coefficients_file, "w") as f:
        f.write("n theta An Bn \n")

        for n_ind, variable in enumerate(varname):
            for ind, x in enumerate(An[n_ind, :]):
                f.write(
                    str(n_mode[n_ind])
                    + ","
                    + str(ind * d_theta)
                    + ","
                    + str(An[n_ind, ind])
                    + ","
                    + str(Bn[n_ind, ind])
                    + "\n"
                )



.. GENERATED FROM PYTHON SOURCE LINES 267-274

Calculate Resultant Pressure Field
=====================================================================================

Create list of m values based on m_max and m_inc

.. image:: ../../_static/TS_formulas.jpg
   :alt: variable names

.. GENERATED FROM PYTHON SOURCE LINES 274-301

.. code-block:: Python


    m_mode = range(-m_max, m_max + m_inc, m_inc)

    # Initialize solution matrices with zeros
    Anm = np.zeros((len(varname), len(m_mode)))
    Bnm = np.zeros((len(varname), len(m_mode)))
    Pnm = np.zeros((len(varname), len(m_mode)))

    for n_ind, variable in enumerate(varname):  # loop over n modes
        for m_ind, m in enumerate(m_mode):  # loop over m modes
            for angle_ind, angle in enumerate(
                np.arange(0, math.radians(360), math.radians(d_theta))
            ):  # loop over all angles, in radians
                Anm[n_ind][m_ind] += An[n_ind][angle_ind] * math.cos(m * angle) - Bn[n_ind][
                    angle_ind
                ] * math.sin(m * angle)
                Bnm[n_ind][m_ind] += An[n_ind][angle_ind] * math.sin(m * angle) + Bn[n_ind][
                    angle_ind
                ] * math.cos(m * angle)
            Anm[n_ind][m_ind] = Anm[n_ind][m_ind] / (2 * math.pi) * math.radians(d_theta)
            Bnm[n_ind][m_ind] = Bnm[n_ind][m_ind] / (2 * math.pi) * math.radians(d_theta)
            Pnm[n_ind][m_ind] = math.sqrt(Anm[n_ind][m_ind] ** 2 + Bnm[n_ind][m_ind] ** 2)

    # P_00 is generally orders of magnitude larger than that of other modes.
    # Giving focus to other modes by setting P_00 equal to zero
    Pnm[0][int(len(m_mode) / 2)] = 0


.. GENERATED FROM PYTHON SOURCE LINES 302-305

Plot Tyler-Sofrin modes
=====================================================================================


.. GENERATED FROM PYTHON SOURCE LINES 305-319

.. code-block:: Python

    fig = plt.figure()
    ax = plt.axes(projection="3d")
    ax.set_xlabel("Tyler-Sofrin Mode, m")
    ax.set_ylabel("Imp Freq Harmonic, n")
    ax.set_zlabel("Pnm [Pa]")
    plt.yticks(n_mode)
    for n_ind, n in enumerate(n_mode):
        x = m_mode
        y = np.full(Pnm.shape[1], n)
        z = Pnm[n_ind]
        rgb = (random.random(), random.random(), random.random())
        ax.plot3D(x, y, z, c=rgb)
    plt.show()


.. GENERATED FROM PYTHON SOURCE LINES 320-324

Tyler-Sofrin modes
=====================================================================================
.. image:: ../../_static/ts_modes.png
   :alt: Tyler-Sofrin modes

.. GENERATED FROM PYTHON SOURCE LINES 327-329

Close the session
=====================================================================================

.. GENERATED FROM PYTHON SOURCE LINES 329-332

.. code-block:: Python

    session.exit()



.. GENERATED FROM PYTHON SOURCE LINES 333-338

References
=====================================================================================

[1] J.M. Tyler and  T. G. Sofrin, Axial Flow Compressor Noise Studies,1961 Manly
Memorial Award.


.. _sphx_glr_download_examples_00-fluent_tyler_sofrin_modes.py:

.. only:: html

  .. container:: sphx-glr-footer sphx-glr-footer-example

    .. container:: sphx-glr-download sphx-glr-download-jupyter

      :download:`Download Jupyter notebook: tyler_sofrin_modes.ipynb <tyler_sofrin_modes.ipynb>`

    .. container:: sphx-glr-download sphx-glr-download-python

      :download:`Download Python source code: tyler_sofrin_modes.py <tyler_sofrin_modes.py>`

    .. container:: sphx-glr-download sphx-glr-download-zip

      :download:`Download zipped: tyler_sofrin_modes.zip <tyler_sofrin_modes.zip>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_