Turbidity Current in Axisymmetric Configuration

Turbidity Current in Axisymmetric Configuration#

image info

import matplotlib.pyplot as plt
import numpy as np
import xarray as xr  # noqa: F401

import xcompact3d_toolbox as x3d

Parameters#

  • Numerical precision

Use np.float64 if Xcompact3d was compiled with the flag -DDOUBLE_PREC, use np.float32 otherwise.

x3d.param["mytype"] = np.float32
  • Xcompact3d’s parameters

For more information about them, checkout the API reference.

prm = x3d.Parameters(
    filename="input.i3d",
    # BasicParam
    itype=12,
    nx=501,
    ny=73,
    nz=501,
    xlx=20.0,
    yly=2.0,
    zlz=20.0,
    nclx1=1,
    nclxn=1,
    ncly1=2,
    nclyn=1,
    nclz1=1,
    nclzn=1,
    re=3500.0,
    init_noise=0.0125,
    dt=5e-4,
    ifirst=1,
    ilast=80000,
    numscalar=1,
    # ScalarParam
    nclxS1=1,
    nclxSn=1,
    nclyS1=1,
    nclySn=1,
    nclzS1=1,
    nclzSn=1,
    sc=[1.0],
    ri=[0.5],
    uset=[0.0],
    cp=[1.0],
)

Setup#

Everything needed is in one Dataset (see API reference):

ds = x3d.init_dataset(prm)

Let’s see it, data and attributes are attached, try to interact with the icons:

ds
<xarray.Dataset> Size: 293MB
Dimensions:  (x: 501, y: 73, z: 501, n: 1)
Coordinates:
  * x        (x) float32 2kB 0.0 0.04 0.08 0.12 0.16 ... 19.88 19.92 19.96 20.0
  * y        (y) float32 292B 0.0 0.02778 0.05556 0.08333 ... 1.944 1.972 2.0
  * z        (z) float32 2kB 0.0 0.04 0.08 0.12 0.16 ... 19.88 19.92 19.96 20.0
  * n        (n) int64 8B 1
Data variables:
    ux       (x, y, z) float32 73MB 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0
    uy       (x, y, z) float32 73MB 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0
    uz       (x, y, z) float32 73MB 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0
    phi      (n, x, y, z) float32 73MB 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0

Initial Condition#

A random noise will be applied to the initial velocity field, we start creating a modulation function mod, to apply it just near the fresh/turbidity interface:

# Position of the initial interface in the polar coordinate
r0 = 4.0

# Random noise with fixed seed,
# important for reproducibility, development and debugging
if prm.iin == 2:
    np.random.seed(seed=67)

radius = np.sqrt(ds.x**2 + ds.z**2.0)

mod = np.exp(-25.0 * (radius - r0) ** 2.0)

# This attribute will be shown at the colorbar
mod.attrs["long_name"] = "Noise modulation"

mod.plot()
<matplotlib.collections.QuadMesh at 0x7f947c174fe0>
../_images/1ecdf966373b7cd4c978f06de7acc62cb60b00844b2bc919e8666ebd048a1384.png

Now we reset velocity fields ds[key] *= 0.0, just to guarantee consistency in the case of multiple executions of this cell. Notice that ds[key] = 0.0 may overwrite all the metadata contained in the array, so it should be avoided.

We then add a random number array with the right shape and multiply by the noise amplitude at the initial condition init_noise and multiply again by our modulation function mod, defined previously.

Plotting a xarray.DataArray is as simple as da.plot() (see its user guide), I’m adding extra options just to exemplify how easily we can slice the vertical coordinate and produce multiple plots:

for key in "ux uy uz".split():
    #
    print(ds[key].attrs["name"])
    #
    ds[key] *= 0.0
    #
    ds[key] += prm.init_noise * (np.random.random(ds[key].shape) - 0.5)
    ds[key] *= mod
    #
    ds[key].sel(y=slice(None, None, ds.y.size // 3)).plot(x="x", y="z", col="y", col_wrap=2)
    plt.show()

plt.close("all")
Initial Condition for Streamwise Velocity
../_images/fc6ea8a270d12ba4c446e4c2e09c832af19ff7dea649673376e300f6c25ed2ae.png
Initial Condition for Vertical Velocity
../_images/c12c3031ee8e08a1644154cf1193e73b00f923ceb6ed70ea9e5a70a4bcfdfb50.png
Initial Condition for Spanwise Velocity
../_images/a12314749a108834133fa3aa90541734a031f64779ee55cc22959b66f5802456.png

A smooth transition at the interface fresh/turbidity fluid is used for the initial concentration(s) field(s), it is defined in the polar coordinates as:

\[ \varphi_n = c_{0,n} \dfrac{1}{2} \left( 1 - \tanh \left( (r - r_0) \sqrt{Sc_n Re} \right) \right). \]

The code block includes the same procedures, we reset the scalar field ds['phi'] *= 0.0, just to guarantee consistency, we compute the equation above, we add it to the array and make a plot:

# Concentration

print(ds["phi"].attrs["name"])

ds["phi"] *= 0.0

for n in range(prm.numscalar):
    #
    fun = 0.5 * prm.cp[n] * (1.0 - np.tanh((radius - r0) * (prm.sc[n] * prm.re) ** 0.5))
    #
    ds["phi"][{"n": n}] += fun
    #
    ds.phi.isel(n=n).sel(y=prm.yly / 2.0).T.plot()
    plt.show()

plt.close("all")
Initial Condition for Scalar field(s)
../_images/4863ec2c9d06a8196a28048fe94ff993e674721b5362a285b6a6355079b59796.png

Writing to disc#

is as simple as:

prm.dataset.write(ds)
prm.write()

Running the Simulation#

It was just to show the capabilities of xcompact3d_toolbox.sandbox, keep in mind the aspects of numerical stability of our Navier-Stokes solver. It is up to the user to find the right set of numerical and physical parameters.

Make sure that the compiling flags and options at Makefile are what you expect. Then, compile the main code at the root folder with make.

And finally, we are good to go:

mpirun -n [number of cores] ./xcompact3d |tee log.out