.. _examples_neutral_abl_test:
Neutral ABL Example
-------------------
The *tests/NeutralABLTest* example case shows how to simulate a conventionally neutral atmospheric boundary
layer (CNBL) in TOSCA. CNBLs are characterized by a strong capping inversion layer of
thickness :math:`\Delta h`, across which a potential temperature jump :math:`\Delta \theta`
is observed. Stratification is neutral below the inversion layer, while it is
characterized by a linear lapse rate :math:`\gamma` aloft.
These types of flows are simulated using lateral periodic boundary conditions,
while the flow driven by a large-scale driving pressure gradient imposed using TOSCA's
velocity controller. In this example, the pressure controller is used, which controls
the large-scale horizontal pressure gradient in order to obtain a wind speed of 8 m/s at
the height of 90 m.
The flow is initialized using a logarithmic profile below the inversion height :math:`H`,
and a uniform wind above. As the simulation progressess, turbulence is created and starts
developing inside the flow domain. To accelerate this process, spanwise fluctuations can be
imposed in the initial flow to anticipate turbulence onset.
All the above aspects can be controlled from the ``ABLProperties.dat`` file
(see Sec. :ref:`ablProperties-section` for a detailed description of all entries).
In particular, entries controlling the initial temperature and velocity profile are defined by
the following parameters:
.. code-block:: bash
uRef 8.0 # wind speed at hRef in m/s
hRef 90.0 # reference height in m
tRef 300.0 # ground potential temperature in K
hRough 0.003 # equivalent roughness length in m
hInv 750.0 # height of the inversion center in m
dInv 100.0 # width of the inversion center in m
gInv 5.0 # potential temperature jump in K across inversion
gTop 0.003 # gradient of the linear lapse rate above inversion in K/m
gABL 0.0 # gradient of the linear lapse rate below inversion in K/m (zero for neutral)
vkConst 0.4 # value of the Von Karman constant
smearT 0.33 # defines the smearing of the initial potential temperature profile
Then, the following flags are set in order to activate the velocity controller, the temperature controller
(which maintains constant the horizontally averaged potential temperature profile, preventing the inversion
layer to displace upwards), the Coriolis force and the initial flow perturbations in the velocity field:
.. code-block:: bash
controllerActive 1 # activates velocity controller
controllerActiveT 1 # activates temperature controller
controllerTypeT initial # target temperature is the initial temperature
coriolisActive 1 # activates Coriolis force
fCoriolis 5.156303966e-5 # 2 times the Coriolis parameter
perturbations 1 # flow perturbations
Notably, the ``fCoriolis`` should be set to :math:`7.272205217\cdot 10^{-5} \sin(\phi)` (2 times the Coriolis parameter),
where :math:`\phi` is the latitude. This is a TOSCA convention and other codes do the multiplication by 2 internally.
Finally, the parameters defining the velocity controller must be specified in the *controllerProperties* dictionary, namely
.. code-block:: bash
controllerProperties
{
controllerAction write # controller writes the momentumSource inside
# postProcessing/
controllerType pressure # controller tries to maintain uRef at hRef
relaxPI 0.7 # proportional gain
alphaPI 0.9 # proportional over integral ratio
timeWindowPI 3600 # time constant of the controller low-pass filter
geostrophicDamping 1 # only for pressure controller, eliminates inertial
# oscillations
geoDampingAlpha 1.0 # alpha 1 corresponds to critical damping
geoDampingStartTime 5000 # should start damping after turbulence has developed
geoDampingTimeWindow 4500 # should be large (ideally one inertial oscillation)
controllerMaxHeight 100000.0 # the controller is applied in the entire domain
}
In order to tell TOSCA to initialize the flow using the parameters defined within the ``ABLProperties.dat`` file, the
``internalField`` keyword inside the boundary condition files ``boundary/U``, ``boundary/T`` and ``boundary/nut``
should be set to *ABLFlow*. More details regarding the optimal setup for these types of simulations in the context of
larger cases can be found `here `_ .
Checking the case
~~~~~~~~~~~~~~~~~
In order to check that everything is correct, we run TOSCA for just one second and check the resulting fields in *ParaView*.
In order to do so, the following entries should be edited in the ``control.dat`` file
.. code-block:: bash
-startFrom startTime
-startTime 0
-endTime 1
-adjustTimeStep 0
-timeStep 0.5
-timeInterval 1
-sections 0
This will stop the simulation after 2 iterations of 0.5 s each (i.e. 1 s of simulation).
Notably, the flow sections are also deactivated, as two seconds of simulation will not produce any with the specific settings
defined in the ``sampling`` directory of this example case.
Once TOSCA executables ``tosca`` and ``tosca2PV`` are copied inside the case directory, TOSCA can be run in serial using
.. code-block:: bash
./tosca
or in parallel (using 4 processors) with
.. code-block:: bash
mpirun -np 4 ./tosca
Once the initial test completes, the user should first check that the entry ``-postProcessFields`` is active in the ``control.dat``
file, then run
.. code-block:: bash
./tosca2PV
The last executable creates an new ``XMF`` directory in which the solution fields are stored in *.hdf* format. The
log file gives information about what fields are written, and should look as follows:
.. image:: ./images/neutral_abl_test_log_1.png
:width: 100%
.. raw:: html
In order to visualize the data, the user should navigate inside the ``XMF`` directory and open the *.xmf* file e.g. using *ParaView*.
The following image shows the result of this operation. In particular, velocity and potential temperature fields are depicted on
the left and right panels, respectively.
.. image:: ./images/neutral_abl_test_initial_field.png
:width: 100%
.. raw:: html
Turbulence spinup phase
~~~~~~~~~~~~~~~~~~~~~~~
Now the actual simulation can be started. In particular, the turbilence spinup phase should be first carried out.
This is required to reach statistical independence of the turbulent fluctuations and, although it does not produce any
meaningful data, it is required before one can start to gather flow statistics and sampling sections.
To this end, the following parameters should be edited in the ``control.dat`` file:
.. code-block:: bash
-startFrom startTime
-startTime 0
-endTime 10000
-adjustTimeStep 1
-timeInterval 500
-sections 0
-probes 0
-averageABL 1
-average3LM 0
-avgABLPeriod 10
-avgABLStartTime 0
-averaging 0
-avgPeriod 50
-avgStartTime 1000
After launching ``tosca``, the simulation will restart from time 0, and run for 10000 s. The time step will be adjusted based on
the CFL value and in order to average ABL fields every 10 s. The user can notice that every 500 s a new time directory is created
inside the ``fields`` directory. Here, checkpoint files are saved for post processing or simulation restart.
Moreover, ABL averages (planar averages of different flow quantities at every height) are stored every 10 s inside the
``postProcessing/averaging/`` directory. The figure below shows the velocity (left) and temperature fields (right)
at the end of the spinup phase.
.. image:: ./images/neutral_abl_test_spinup_field.png
:width: 100%
.. raw:: html
Data acquisition phase
~~~~~~~~~~~~~~~~~~~~~~
At this point, the simulation can be restarted from 10000 s and flow statistics can be gathered. Usually, precursor simulations are
used to save flow sections of velocity, temperature and effective viscosity at each time step, which are then assembled into an
inflow database and later used as inlet boundary condition for a subsequent simulation, e.g. with wind turbines.
If this is the case, or if the user simply desires to visualize flow planes, sampling planes should be activated in the
``control.dat`` file by setting the ``-sections`` flag to 1. Saving sections is also useful for large cases, when the domain is too
large to be visualized in its entirety as it does not fit in the available RAM memory of a laptop (or even a single
supercomputer node).
When sampling planes are later used as inlet boundary conditions, this will happen in TOSCA at the ``kLeft`` boundary, as it is the
only boundary that features special inlet functions (see Sec. :ref:`inlet-functions-subsubsection` for details). Hence, the settings
of *kSections* have to be such that these are written with the highest possible frequency to reduce the error of their interpolation
in time when used as inflow. Hence, the ``sampling/surfaces/kSections`` file is usually defined with the following syntax:
.. code-block:: bash
surfaceNumber 1 # one k-surface
timeStart 10000 # acquisition starts at 10000
intervalType timeStep # writes every timeInterval iterations
timeInterval 1 # writes every iteration
coordinates 10.0 # plane located at x = 10 m
Conversely, sections used for visualization (usually *iSections* and *jSections*, but also *kSections* can be visualized) are
sampled less frequently. For example, a possible syntax for the ``sampling/surfaces/jSections`` file is given below.
.. code-block:: bash
surfaceNumber 2 # two j-surface
timeStart 1000 # acquisition starts at 10000
intervalType adjustableTime # writes every timeInterval seconds
timeInterval 10 # writes every 10 seconds
coordinates 90.0 500.0 # flow section at hub and inversion heights
In is important now to tell TOSCA to read the saved checkpoint file at the latest time, otherwise it will re-initialize the flow using
the input parameters defined in ``ABLProperties.dat``. To this end, and in order to terminate the simulation at 12000 s, the
``control.dat`` can be edited as follows:
.. code-block:: bash
-startFrom latestTime # reads the latest time inside the fields directory
-endTime 12000 # simulate 2000 more s with data acquisition
In addition, the ``internalField`` entry in the boundary files has to be changed to ``readField`` (in all ``U``, ``p`` and
``nut`` files). The simulation is now set up for restart, and subsequent restarts will not require
further editing until the final time is reached. Finally, 3D field averaging and the sampling sections are activated by setting
.. code-block:: bash
-sections 1
-averageABL 1
-avgABLPeriod 10
-avgABLStartTime 0
-averaging 1
-avgPeriod 5
-avgStartTime 10000
in the ``control.dat`` file. Once TOSCA is submitted, the user can verify from the log file (see below) that *kSections* are stored
every iteration inside the ``postProcessing/kSurfaces/k-ID`` directory, where ``k-ID`` corresponds to the k-index of the
plane of cells intercepts by the sampling surface . Notably, the name of each section file corresponds to the time at which
the section has been taken, where the number of decimal places can be controlled with the ``-timePrecision`` keyword in the
``control.dat`` file.
.. image:: ./images/neutral_abl_test_log_2.png
:width: 100%
.. raw:: html
Once that the simulation completes, all data except from the 3D fields
are stored inside the ``postProcessing`` directory. In particular, *iSections*, *jSections*, *kSections* and ABL averages at
different levels are stored in the here, while 3D field averages and checkpoint variables are located in the corresponding
checkpoint time inside the ``fields`` directory. As this test case is small, the user can decide to
visualize them in e.g. *ParaView* by running ``tosca2PV``. For large simulations, these files are usually
kept for hypotetically restarting the simulation at a later phase, if needed. However, 3D field averages can be sliced after the
simulation using TOSCA's post processor ``tosca2PV``. This is done by leaving both the ``-averaging`` and the ``-sections`` flags
activated ``control.dat`` file, prompting the code to re-read the definition of the sampling sections and then slice the average fields.
Currently, no additional sections can be added *a-posteriori* if instantaneous sections (generated during the simulations) are found inside the ``postProcessing`` directory.
In order force ``tosca2PV`` to re-read the section definitions inside ``sampling`` (i.e. after adding more sections) and re-slice the 3D
average fields, it is sufficient to rename the directories ``postProcessing/iSurfaces``, ``postProcessing/jSurfaces`` or
``postProcessing/kSurfaces`` to something else, depending if ``sampling/surfaces/iSections``, ``sampling/surfaces/jSections`` or
``sampling/surfaces/kSections`` have been edited, respectively. This procedure is identified in TOSCA as on-the-fly section
re-acquisition, and it is printed in the terminal (or the log file) when running ``tosca2PV``.
Regarding the data contained in the ``postProcessing`` directory - except from sections, which are read using ``tosca2PV`` - this is
usually post processed using *ad-hoc* Python or Matlab scripts.
Creating the inflow database
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In order to create an inflow database that can be later used by TOSCA, the workflow is the following.
1. Create a directory named ``inflowDatabase``.
2. Copy the directories ``U``, ``T`` (if present) and ``nut``, contained inside the directory ``postProcessing/kSurfaces/k-ID/``, where the *k-ID* corresponds to the *kSurface* selected for sampling the inflow data, inside the ``inflowDatabase`` directory.
3. Create a new file named ``momentumSource`` inside the ``inflowDatabase`` directory. Then copy the content of each ``postProcessing/momentumSource_`` file inside the ``momentumSource`` file, eliminating the overlapping portion of each source file's time history (as if source files were tiled together).
4. Copy the ``mesh.xyz`` file inside the ``inflowDatabase`` directory, renaming it ``inflowMesh.xyz``. In this file, eliminate the lines *-iPeriodicType*, *-jPeriodicType* and *-kPeriodicType*, if present.
The ``inflowDatabase`` is now a standalone inflow database that can be used as inlet boundary condition for several different
successor simulations.