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

.. only:: html

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

        :ref:`Go to the end <sphx_glr_download_auto_examples_05_custom_noisy_data_fit.py>`
        to download the full example code

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

.. _sphx_glr_auto_examples_05_custom_noisy_data_fit.py:


==========================
Example 5: Custom Data Fit
==========================

In this example, we use ``drdmannturb`` to fit a simple neural network model to real-world
data without any preprocessing. This involves data that are observed in the real world,
specifically near a North Sea wind turbine farm. The physical parameters are determined
from those measurements. Additionally, the :math:`\nu` parameter is also learned.
is learned for the rational function for :math:`\tau` given by

.. math::
        \tau(\boldsymbol{k})=\frac{T|\boldsymbol{a}|^{\nu-\frac{2}{3}}}{\left(1+|\boldsymbol{a}|^2\right)^{\nu / 2}}, \quad \boldsymbol{a}=\boldsymbol{a}(\boldsymbol{k}).

.. GENERATED FROM PYTHON SOURCE LINES 18-23

Import packages
---------------

First, we import the packages needed for this example, obtain the current
working directory and dataset path, and choose to use CUDA if it is available.

.. GENERATED FROM PYTHON SOURCE LINES 23-52

.. code-block:: Python

    from pathlib import Path

    import numpy as np
    import torch
    import torch.nn as nn

    from drdmannturb.enums import DataType
    from drdmannturb.parameters import (
        LossParameters,
        NNParameters,
        PhysicalParameters,
        ProblemParameters,
    )
    from drdmannturb.spectra_fitting import CalibrationProblem, OnePointSpectraDataGenerator

    path = Path().resolve()

    device = "cuda" if torch.cuda.is_available() else "cpu"

    if torch.cuda.is_available():
        torch.set_default_tensor_type("torch.cuda.FloatTensor")


    spectra_file = (
        path / "./inputs/Spectra.dat"
        if path.name == "examples"
        else path / "../data/Spectra.dat"
    )








.. GENERATED FROM PYTHON SOURCE LINES 53-57

Setting Physical Parameters
---------------------------
Here, we define our characteristic scales :math:`L, \Gamma, \alpha\epsilon^{2/3}`, the
log-scale domain, and the reference height `zref` and velocity `Uref`.

.. GENERATED FROM PYTHON SOURCE LINES 57-67

.. code-block:: Python


    domain = torch.logspace(-1, 3, 40)

    L = 70  # length scale
    Gamma = 3.7  # time scale
    sigma = 0.04  # magnitude (σ = αϵ^{2/3})

    Uref = 21  # reference velocity
    zref = 1  # reference height








.. GENERATED FROM PYTHON SOURCE LINES 68-89

``CalibrationProblem`` construction
-----------------------------------

We'll use a simple neural network consisting of two layers with :math:`10` neurons each,
connected by a ReLU activation function. The parameters determining the network
architecture can conveniently be set through the ``NNParameters`` dataclass.

Using the ``ProblemParameters`` dataclass, we indicate the eddy lifetime function
:math:`\tau` substitution, that we do not intend to learn the exponent :math:`\nu`,
and that we would like to train for 10 epochs, or until the tolerance ``tol`` loss (0.001 by default),
whichever is reached first.

Having set our physical parameters above, we need only pass these to the
``PhysicalParameters`` dataclass just as is done below.

Lastly, using the ``LossParameters`` dataclass, we introduce a second-order
derivative penalty term with weight :math:`\alpha_2 = 1` and a
network parameter regularization term with weight
:math:`\beta=10^{-5}` to our MSE loss function.

Note that :math:`\nu` is learned here.

.. GENERATED FROM PYTHON SOURCE LINES 89-111

.. code-block:: Python


    pb = CalibrationProblem(
        nn_params=NNParameters(
            nlayers=2, hidden_layer_sizes=[10, 10], activations=[nn.ReLU(), nn.ReLU()]
        ),
        prob_params=ProblemParameters(
            data_type=DataType.CUSTOM, tol=1e-9, nepochs=5, learn_nu=True
        ),
        loss_params=LossParameters(alpha_pen2=1.0, beta_reg=1e-5),
        phys_params=PhysicalParameters(
            L=L,
            Gamma=Gamma,
            sigma=sigma,
            domain=domain,
            Uref=Uref,
            zref=zref,
        ),
        logging_directory="runs/custom_data",
        device=device,
    )









.. GENERATED FROM PYTHON SOURCE LINES 112-117

Data from File
--------------
The data are provided in a CSV format with the first column determining the frequency domain, which must be non-dimensionalized by the reference velocity.
The different spectra are provided in the order ``uu, vv, ww, uw`` where the last is the u-w cospectra (the convention for 3D velocity vector components being u, v, w for x, y, z).
The ``k1_data_points`` key word argument is needed here to define the domain over which the spectra are defined.

.. GENERATED FROM PYTHON SOURCE LINES 117-129

.. code-block:: Python

    CustomData = torch.tensor(np.genfromtxt(spectra_file, skip_header=1, delimiter=","))
    f = CustomData[:, 0]
    k1_data_pts = 2 * torch.pi * f / Uref
    Data = OnePointSpectraDataGenerator(
        zref=zref,
        data_points=k1_data_pts,
        data_type=DataType.CUSTOM,
        spectra_file=spectra_file,
        k1_data_points=k1_data_pts.data.cpu().numpy(),
    ).Data









.. GENERATED FROM PYTHON SOURCE LINES 130-136

Calibration
-----------
Now, we fit our model. ``CalibrationProblem.calibrate`` takes the tuple ``Data``
which we just constructed and performs a typical training loop. The resulting
fit for :math:`\nu` is close to :math:`\nu \approx - 1/3`, which can be improved
with further training.

.. GENERATED FROM PYTHON SOURCE LINES 136-140

.. code-block:: Python

    optimal_parameters = pb.calibrate(data=Data)

    pb.print_calibrated_params()





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    ========================================
    Initial loss: 5.186083324959
    ========================================

      0%|          | 0/5 [00:00<?, ?it/s]
     20%|██        | 1/5 [00:05<00:20,  5.16s/it]
     40%|████      | 2/5 [00:10<00:15,  5.11s/it]
     60%|██████    | 3/5 [00:15<00:10,  5.37s/it]
     80%|████████  | 4/5 [00:21<00:05,  5.33s/it]
    100%|██████████| 5/5 [00:26<00:00,  5.38s/it]
    100%|██████████| 5/5 [00:26<00:00,  5.33s/it]
    ========================================
    Spectra fitting concluded with final loss: 0.15160002859971103
    Learned nu value: 3.5242151866494558
    ========================================
    Optimal calibrated L        : 397.3070 
    Optimal calibrated Γ        : 113.7880 
    Optimal calibrated αϵ^{2/3} :   0.0037 
    ========================================




.. GENERATED FROM PYTHON SOURCE LINES 141-150

Plotting
--------
``DRDMannTurb`` offers built-in plotting utilities and Tensorboard integration
which make visualizing results and various aspects of training performance
very simple.

The following will plot our fit. As can be seen, the spectra is fairly noisy,
which suggests that a better fit may be obtained from pre-processing the data, which
we will explore in the next example.

.. GENERATED FROM PYTHON SOURCE LINES 150-152

.. code-block:: Python

    pb.plot()




.. image-sg:: /auto_examples/images/sphx_glr_05_custom_noisy_data_fit_001.png
   :alt: One-point spectra, Eddy lifetime
   :srcset: /auto_examples/images/sphx_glr_05_custom_noisy_data_fit_001.png
   :class: sphx-glr-single-img





.. GENERATED FROM PYTHON SOURCE LINES 153-157

This plots out the loss function terms as specified, each multiplied by the
respective coefficient hyperparameter. The training logs can be accessed from the logging directory
with Tensorboard utilities, but we also provide a simple internal utility for a single
training log plot.

.. GENERATED FROM PYTHON SOURCE LINES 157-158

.. code-block:: Python

    pb.plot_losses(run_number=0)



.. image-sg:: /auto_examples/images/sphx_glr_05_custom_noisy_data_fit_002.png
   :alt: Total Loss, Regularization, 2nd Order Penalty, MSE Loss
   :srcset: /auto_examples/images/sphx_glr_05_custom_noisy_data_fit_002.png
   :class: sphx-glr-single-img






.. rst-class:: sphx-glr-timing

   **Total running time of the script:** (0 minutes 27.631 seconds)


.. _sphx_glr_download_auto_examples_05_custom_noisy_data_fit.py:

.. only:: html

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

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

      :download:`Download Jupyter notebook: 05_custom_noisy_data_fit.ipynb <05_custom_noisy_data_fit.ipynb>`

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

      :download:`Download Python source code: 05_custom_noisy_data_fit.py <05_custom_noisy_data_fit.py>`


.. only:: html

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

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