
.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "auto_examples/02_eddy-lifetime_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_02_eddy-lifetime_fit.py>`
        to download the full example code

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

.. _sphx_glr_auto_examples_02_eddy-lifetime_fit.py:


=============================
Example 2: Synthetic Data Fit
=============================

In this example, we compare the DRD model to the Mann model, using the three IEC-recommended Mann model
parameters: :math:`L/\text{zref}=0.59, Γ=3.9, αϵ^{2/3}=3.2 * (\text{zref}^{2/3} / \text{ustar}^2)`.
In this example, the exponent :math:`\nu=-\frac{1}{3}` is fixed so that :math:`\tau(\boldsymbol{k})`
matches the slope of :math:`\tau^{IEC}` for in the energy-containing range, :math:`k \rightarrow 0`.

The following example is also discussed in the `original DRD paper <https://arxiv.org/abs/2107.11046>`_.

.. GENERATED FROM PYTHON SOURCE LINES 15-20

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

First, we import the packages we need for this example. Additionally, we choose to use
CUDA if it is available.

.. GENERATED FROM PYTHON SOURCE LINES 20-38

.. code-block:: Python


    import torch
    import torch.nn as nn

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

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

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








.. GENERATED FROM PYTHON SOURCE LINES 39-45

Setting Physical Parameters
---------------------------
The following cell sets the necessary physical parameters

:math:`L` is our characteristic length scale, :math:`\Gamma` is our characteristic
time scale, and :math:`\sigma = \alpha\epsilon^{2/3}` is the spectrum amplitude.

.. GENERATED FROM PYTHON SOURCE LINES 45-61

.. code-block:: Python


    zref = 90  # reference height
    z0 = 0.02
    zref = 90
    uref = 11.4
    ustar = 0.556  # friction velocity

    # Scales associated with Kaimal spectrum
    L = 0.593 * zref  # length scale
    Gamma = 3.89  # time scale
    sigma = 3.2 * ustar**2.0 / zref ** (2.0 / 3.0)  # magnitude (σ = αϵ^{2/3})

    print(f"Physical Parameters: {L,Gamma,sigma}")

    k1 = torch.logspace(-1, 2, 20) / zref





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

 .. code-block:: none

    Physical Parameters: (53.37, 3.89, 0.04925737023046032)




.. GENERATED FROM PYTHON SOURCE LINES 62-82

``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.


.. GENERATED FROM PYTHON SOURCE LINES 82-102

.. code-block:: Python

    pb = CalibrationProblem(
        nn_params=NNParameters(
            nlayers=2,
            # Specifying the hidden layer sizes is done by passing a list of integers, as seen here.
            hidden_layer_sizes=[10, 10],
            # Specifying the activations is done similarly.
            activations=[nn.ReLU(), nn.ReLU()],
        ),
        prob_params=ProblemParameters(
            nepochs=10, learn_nu=False, eddy_lifetime=EddyLifetimeType.TAUNET
        ),
        # Note that we have not activated the first order term, but this can be done by passing a value for ``alpha_pen1``
        loss_params=LossParameters(alpha_pen2=1.0, beta_reg=1.0e-5),
        phys_params=PhysicalParameters(
            L=L, Gamma=Gamma, sigma=sigma, ustar=ustar, domain=k1
        ),
        logging_directory="runs/synthetic_fit",
        device=device,
    )








.. GENERATED FROM PYTHON SOURCE LINES 103-108

Data Generation
---------------
We now collect ``Data = (<data points>, <data values>)`` and specify the
reference height (``zref``) to be used during calibration. Note that ``DataType.KAIMAL``
is used by default.

.. GENERATED FROM PYTHON SOURCE LINES 108-110

.. code-block:: Python

    Data = OnePointSpectraDataGenerator(data_points=k1, zref=zref, ustar=ustar).Data








.. GENERATED FROM PYTHON SOURCE LINES 111-115

Calibration
-----------
Now, we fit our model. ``CalibrationProblem.calibrate`` takes the tuple ``Data``
which we just constructed and performs a typical training loop.

.. GENERATED FROM PYTHON SOURCE LINES 115-120

.. code-block:: Python


    optimal_parameters = pb.calibrate(data=Data)

    pb.print_calibrated_params()





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

 .. code-block:: none

    ========================================
    Initial loss: 0.04550837641441142
    ========================================

      0%|          | 0/10 [00:00<?, ?it/s]
     10%|█         | 1/10 [00:03<00:32,  3.64s/it]
     20%|██        | 2/10 [00:05<00:21,  2.69s/it]
     30%|███       | 3/10 [00:07<00:16,  2.39s/it]
     40%|████      | 4/10 [00:09<00:13,  2.22s/it]
     50%|█████     | 5/10 [00:11<00:10,  2.15s/it]
     60%|██████    | 6/10 [00:13<00:08,  2.08s/it]
     70%|███████   | 7/10 [00:15<00:06,  2.06s/it]
     80%|████████  | 8/10 [00:17<00:04,  2.05s/it]
     90%|█████████ | 9/10 [00:19<00:02,  2.02s/it]
    100%|██████████| 10/10 [00:21<00:00,  2.02s/it]
    100%|██████████| 10/10 [00:21<00:00,  2.17s/it]
    ========================================
    Spectra fitting concluded with final loss: 0.005957930162854974
    ========================================
    Optimal calibrated L        :  51.9619 
    Optimal calibrated Γ        :   1.4863 
    Optimal calibrated αϵ^{2/3} :   0.0473 
    ========================================




.. GENERATED FROM PYTHON SOURCE LINES 121-128

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 the fit.

.. GENERATED FROM PYTHON SOURCE LINES 128-130

.. code-block:: Python

    pb.plot()




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





.. GENERATED FROM PYTHON SOURCE LINES 131-135

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 135-136

.. code-block:: Python

    pb.plot_losses(run_number=0)



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





.. GENERATED FROM PYTHON SOURCE LINES 137-143

Save Model with Problem Metadata
--------------------------------
Here, we'll make use of the model saving utilities,
which make saving the ``DRDMannTurb`` fit very straightforward. The following line
automatically pickles and writes out a trained model along with the various
parameter dataclasses in ``../results``.

.. GENERATED FROM PYTHON SOURCE LINES 143-145

.. code-block:: Python

    pb.save_model("./outputs/")








.. GENERATED FROM PYTHON SOURCE LINES 146-149

Loading Model and Problem Metadata
----------------------------------
Lastly, we load our model back in.

.. GENERATED FROM PYTHON SOURCE LINES 151-164

.. code-block:: Python

    import pickle

    path_to_parameters = "./outputs/EddyLifetimeType.TAUNET_DataType.KAIMAL.pkl"

    with open(path_to_parameters, "rb") as file:
        (
            nn_params,
            prob_params,
            loss_params,
            phys_params,
            model_params,
        ) = pickle.load(file)








.. GENERATED FROM PYTHON SOURCE LINES 165-168

### Recovering Old Model Configuration and Old Parameters
We can also load the old model configuration from file and create a new ``CalibrationProblem`` object from the
stored network parameters and metadata.

.. GENERATED FROM PYTHON SOURCE LINES 168-180

.. code-block:: Python

    pb_new = CalibrationProblem(
        nn_params=nn_params,
        prob_params=prob_params,
        loss_params=loss_params,
        phys_params=phys_params,
        device=device,
    )

    pb_new.parameters = model_params

    import numpy as np

    assert np.ma.allequal(pb.parameters, pb_new.parameters)







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

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


.. _sphx_glr_download_auto_examples_02_eddy-lifetime_fit.py:

.. only:: html

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

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

      :download:`Download Jupyter notebook: 02_eddy-lifetime_fit.ipynb <02_eddy-lifetime_fit.ipynb>`

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

      :download:`Download Python source code: 02_eddy-lifetime_fit.py <02_eddy-lifetime_fit.py>`


.. only:: html

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

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