Welcome to Xcompact3d-toolbox’s documentation!¶
It is a Python package designed to handle the pre and postprocessing of the high-order Navier-Stokes solver Xcompact3d. It aims to help users and code developers to build case-specific solutions with a set of tools and automated processes.
The physical and computational parameters are built on top of traitlets, a framework that lets Python classes have attributes with type checking, dynamically calculated default values, and ‘on change’ callbacks. In addition to ipywidgets for an user friendly interface.
Data structure is provided by xarray (see Why xarray?), that introduces labels in the form of dimensions, coordinates and attributes on top of raw NumPy-like arrays, which allows for a more intuitive, more concise, and less error-prone developer experience. It integrates tightly with dask for parallel computing and hvplot for interactive data visualization.
Finally, Xcompact3d-toolbox is fully integrated with the new Sandbox Flow Configuration. The idea is to easily provide everything that Xcompact3d needs from a Jupyter Notebook, like initial conditions, solid geometry, boundary conditions, and the parameters. It makes life easier for beginners, that can run any new flow configuration without worrying about Fortran and 2decomp. For developers, it works as a rapid prototyping tool, to test concepts and then compare results to validate any future Fortran implementations.
Useful links¶
Installation¶
It is possible to install using pip:
pip install xcompact3d-toolbox
There are other dependency sets for extra functionality:
pip install xcompact3d-toolbox[visu] # interactive visualization with hvplot and others
pip install xcompact3d-toolbox[doc] # dependencies to build the documentation
pip install xcompact3d-toolbox[dev] # tools for development
pip install xcompact3d-toolbox[test] # tools for testing
pip install xcompact3d-toolbox[all] # all the above
To install from source, clone de repository:
git clone https://github.com/fschuch/xcompact3d_toolbox.git
And then install it interactively with pip:
cd xcompact3d_toolbox
pip install -e .
You can install all dependencies as well:
pip install -e .[all]
Now, any change you make at the source code will be available at your local installation, with no need to reinstall the package every time.
Examples¶
Importing the package:
import xcompact3d_toolbox as x3d
Loading the parameters file (both
i3d
andprm
are supported, see #7) from the disc:prm = x3d.Parameters(loadfile="input.i3d") prm = x3d.Parameters(loadfile="incompact3d.prm")
Specifying how the binary fields from your simulations are named, for instance:
If the simulated fields are named like
ux-000.bin
:prm.dataset.filename_properties.set( separator = "-", file_extension = ".bin", number_of_digits = 3 )
If the simulated fields are named like
ux0000
:prm.dataset.filename_properties.set( separator = "", file_extension = "", number_of_digits = 4 )
There are many ways to load the arrays produced by your numerical simulation, so you can choose what best suits your post-processing application. All arrays are wrapped into xarray objects, with many useful methods for indexing, comparisons, reshaping and reorganizing, computations and plotting. See the examples:
Load one array from the disc:
ux = prm.dataset.load_array("ux-0000.bin")
Load the entire time series for a given variable:
ux = prm.dataset["ux"]
Load all variables from a given snapshot:
snapshot = prm.dataset[10]
Loop through all snapshots, loading them one by one:
for ds in prm.dataset: # compute something vort = ds.uy.x3d.first_derivative("x") - ds.ux.x3d.first_derivative("y") # write the results to the disc prm.dataset.write(data = vort, file_prefix = "w3")
Or simply load all snapshots at once (if you have enough memory):
ds = prm.dataset[:]
It is possible to produce a new xdmf file, so all data can be visualized on any external tool:
prm.dataset.write_xdmf()
User interface for the parameters with IPywidgets:
prm = x3d.ParametersGui() prm

Table of Content¶
API reference¶
Parameters¶
Tools to manipulate the physical and computational parameters. It contains variables and methods designed to be a link between XCompact3d and Python applications for pre and post-processing.
-
class
xcompact3d_toolbox.parameters.
Parameters
(raise_warning: bool = False, **kwargs)¶ Bases:
xcompact3d_toolbox.parameters.ParametersBasicParam
,xcompact3d_toolbox.parameters.ParametersNumOptions
,xcompact3d_toolbox.parameters.ParametersInOutParam
,xcompact3d_toolbox.parameters.ParametersScalarParam
,xcompact3d_toolbox.parameters.ParametersLESModel
,xcompact3d_toolbox.parameters.ParametersIbmStuff
,xcompact3d_toolbox.parameters.ParametersALMParam
,xcompact3d_toolbox.parameters.ParametersExtras
The physical and computational parameters are built on top of traitlets. It is a framework that lets Python classes have attributes with type checking, dynamically calculated default values, and ‘on change’ callbacks. In this way, many of the parameters are validated regarding the type, business rules, and the range of values supported by XCompact3d. There are methods to handle the parameters file (
.i3d
and.prm
).The parameters are arranged in different classes, but just for organization purposes, this class inherits from all of them.
In addition, there are ipywidgets for a friendly user interface, see
xcompact3d_toolbox.gui.ParametersGui
.After that, it is time to read the binary arrays produced by XCompact3d and also to write a new xdmf file, so the binary fields can be opened in any external visualization tool. See more details in
xcompact3d_toolbox.parameters.ParametersExtras.dataset
.Note
This is a work in progress, not all parameters are covered yet.
-
__init__
(raise_warning: bool = False, **kwargs)¶ Initializes the Parameters Class.
Parameters: - raise_warning (bool, optional) – Raise a warning instead of an error if an invalid parameter is found. By default False.
- **kwargs – Keyword arguments for valid attributes, like
nx
,re
and so on.
Raises: KeyError
– Exception is raised when an Keyword arguments is not a valid attribute.Examples
There are a few ways to initialize the class.
First, calling it with no arguments initializes all variables with default value:
>>> prm = xcompact3d_toolbox.Parameters()
It is possible to set any value afterwards:
>>> prm.re = 1e6 >>> prm.set( ... iibm = 0, ... p_row = 4, ... p_col = 2, ... )
Second, we can specify some values, and let the missing ones be initialized with default value:
>>> prm = x3d.Parameters( ... filename = 'example.i3d', ... itype = 12, ... nx = 257, ... ny = 129, ... nz = 32, ... xlx = 15.0, ... yly = 10.0, ... zlz = 3.0, ... nclx1 = 2, ... nclxn = 2, ... ncly1 = 1, ... nclyn = 1, ... nclz1 = 0, ... nclzn = 0, ... re = 300.0, ... init_noise = 0.0125, ... dt = 0.0025, ... ilast = 45000, ... ioutput = 200, ... iprocessing = 50 ... )
And finally, it is possible to read the parameters from the disc:
>>> prm = xcompact3d_toolbox.Parameters(loadfile = 'example.i3d')
It also supports the previous parameters file format (see #7):
>>> prm = xcompact3d_toolbox.Parameters(loadfile = 'incompact3d.prm')
-
__repr__
()¶ Return repr(self).
-
__str__
()¶ Representation of the parameters class, similar to the representation of the
.i3d
file.
-
from_file
(filename: str = None, raise_warning: bool = False) → None¶ Loads the attributes from the parameters file.
It also includes support for the previous format
prm
(see #7).Parameters: Raises: Examples
>>> prm = xcompact3d_toolbox.Parameters(filename = 'example.i3d') >>> prm.load()
>>> prm = xcompact3d_toolbox.Parameters() >>> prm.load('example.i3d')
or just:
>>> prm = xcompact3d_toolbox.Parameters(loadfile = 'example.i3d') >>> prm = xcompact3d_toolbox.Parameters(loadfile = 'incompact3d.prm')
-
from_string
(string: str, raise_warning: bool = False) → None¶ Loads the attributes from a string.
Parameters: Raises: KeyError
– Exception is raised when an attributes is invalid.
-
get_boundary_condition
(variable_name: str) → dict¶ This method returns the appropriate boundary parameters that are expected by the derivatives methods.
Parameters: variable_name (str) – Variable name. The supported options are ux
,uy
,uz
,pp
andphi
, otherwise the method returns the default option.Returns: A dict containing the boundary conditions for the variable specified. Return type: dict
ofdict
Examples
>>> prm = xcompact3d_toolbox.Parameters() >>> prm.get_boundary_condition('ux') {'x': {'ncl1': 1, 'ncln': 1, 'npaire': 0}, 'y': {'ncl1': 1, 'ncln': 2, 'npaire': 1, 'istret': 0, 'beta': 0.75}, 'z': {'ncl1': 0, 'ncln': 0, 'npaire': 1}}
It is possible to store this information as an attribute in any
xarray.DataArray
:>>> DataArray.attrs['BC'] = prm.get_boundary_condition('ux')
So the correct boundary conditions will be used to compute the derivatives:
>>> DataArray.x3d.first_derivative('x') >>> DataArray.x3d.second_derivative('x')
-
get_mesh
(refined_for_ibm: bool = False) → dict¶ Get mesh the three-dimensional coordinate system. The coordinates are stored in a dictionary. It supports mesh refinement in y when
ParametersBasicParam.istret
\(\ne\) 0.Parameters: refined_for_ibm (bool) – If True, it returns a refined mesh as a function of ParametersIbmStuff.nraf
(default is False).Returns: It contains the mesh point locations at three dictionary keys, for x, y and z. Return type: dict
ofnumpy.ndarray
Examples
>>> prm = xcompact3d_toolbox.Parameters() >>> prm.get_mesh() {'x': array([0. , 0.0625, 0.125 , 0.1875, 0.25 , 0.3125, 0.375 , 0.4375, 0.5 , 0.5625, 0.625 , 0.6875, 0.75 , 0.8125, 0.875 , 0.9375, 1. ]), 'y': array([0. , 0.0625, 0.125 , 0.1875, 0.25 , 0.3125, 0.375 , 0.4375, 0.5 , 0.5625, 0.625 , 0.6875, 0.75 , 0.8125, 0.875 , 0.9375, 1. ]), 'z': array([0. , 0.0625, 0.125 , 0.1875, 0.25 , 0.3125, 0.375 , 0.4375, 0.5 , 0.5625, 0.625 , 0.6875, 0.75 , 0.8125, 0.875 , 0.9375, 1. ])}
-
load
(*arg, **kwarg) → None¶ An alias for
Parameters.from_file
-
set
(raise_warning: bool = False, **kwargs) → None¶ Set a new value for any parameter after the initialization.
Parameters: - raise_warning (bool, optional) – Raise a warning instead of an error if an invalid parameter is found. By default False.
- **kwargs – Keyword arguments for valid attributes, like
nx
,re
and so on.
Raises: KeyError
– Exception is raised when an Keyword arguments is not a valid attribute.Examples
>>> prm = xcompact3d_toolbox.Parameters() >>> prm.set( ... iibm = 0, ... p_row = 4, ... p_col = 2, ... )
-
write
(filename: str = None) → None¶ Write all valid attributes to an
i3d
file.An attribute is considered valid if it has a
tag
namedgroup
, witch assigns it to the respective namespace at thei3d
file.Parameters: filename (str, optional) – The filename for the i3d
file. If None, it uses the filename specified in the class (default isNone
).Examples
>>> prm = xcompact3d_toolbox.Parameters( ... filename = 'example.i3d', ... nx = 101, ... ny = 65, ... nz = 11, ... # and so on... ... ) >>> prm.write()
or just:
>>> prm.write('example.i3d')
-
-
class
xcompact3d_toolbox.parameters.
ParametersALMParam
¶ Bases:
traitlets.traitlets.HasTraits
-
__init__
()¶ Initialize self. See help(type(self)) for accurate signature.
-
-
class
xcompact3d_toolbox.parameters.
ParametersBasicParam
¶ Bases:
traitlets.traitlets.HasTraits
-
__init__
()¶ Initialize self. See help(type(self)) for accurate signature.
-
iibm
¶ - 0 - Off (default);
- 1 - On with direct forcing method, i.e., it sets velocity to zero inside the solid body;
- 2 - On with alternating forcing method, i.e, it uses Lagrangian Interpolators to define the velocity inside the body and imposes no-slip condition at the solid/fluid interface;
- 3 - Cubic Spline Reconstruction;
Any option greater than zero activates the namespace ibmstuff, for variables like
ParametersIbmStuff.nobjmax
andParametersIbmStuff.nraf
.Type: int Type: Enables Immersed Boundary Method (IBM)
-
iin
¶ - 0 - No random noise (default);
- 1 - Random noise with amplitude of
init_noise
; - 2 - Random noise with fixed seed
(important for reproducibility, development and debugging)
and amplitude of
init_noise
; - 3 - Read inflow planes.
Notes
The exactly behavior may be different according to each flow configuration.
Type: int Type: Defines perturbation at the initial condition
-
ilesmod
¶ - 0 - No (also forces
ParametersNumOptions.nu0nu
andParametersNumOptions.cnu
to 4.0 and 0.44, respectively); - 1 - Yes (also activates the namespace LESModel (see
ParametersLESModel
).
Type: int Type: Enables Large-Eddy methodologies - 0 - No (also forces
-
inflow_noise
¶ Random number amplitude at inflow boundary (where \(x=0\)).
Notes
Only necessary if
nclx1
is equal to 2.Type: float
-
init_noise
¶ Random number amplitude at initial condition.
Notes
Only necessary if
iin
\(\ne\) 0. The exactly behavior may be different according to each flow configuration.Type: float
-
ipost
¶ - 0 - No;
- 1 - Yes (default).
Note
The computation for each case is specified at the
BC.<flow-configuration>.f90
file.Type: int Type: Enables online postprocessing at a frequency ParametersInOutParam.iprocessing
-
istret
¶ - 0 - No refinement (default);
- 1 - Refinement at the center;
- 2 - Both sides;
- 3 - Just near the bottom.
Notes
See
beta
.Type: int Type: Controls mesh refinement in y
-
itype
¶ Sets the flow configuration, each one is specified in a different
BC.<flow-configuration>.f90
file (see Xcompact3d/src), they are:- 0 - User configuration;
- 1 - Turbidity Current in Lock-Release;
- 2 - Taylor-Green Vortex;
- 3 - Periodic Turbulent Channel;
- 4 - Periodic Hill
- 5 - Flow around a Cylinder;
- 6 - Debug Schemes (for developers);
- 7 - Mixing Layer;
- 8 - Jet;
- 9 - Turbulent Boundary Layer;
- 10 - ABL;
- 11 - Uniform;
- 12 - Sandbox.
Type: int
-
ivisu
¶ - 0 - No;
- 1 - Yes (default).
Type: int Type: Enables store snapshots at a frequency ParametersInOutParam.ioutput
-
nclx1
¶ - 0 - Periodic;
- 1 - Free-slip;
- 2 - Inflow.
Type: int Type: Boundary condition for velocity field where \(x=0\), the options are
-
nclxn
¶ - 0 - Periodic;
- 1 - Free-slip;
- 2 - Convective outflow.
Type: int Type: Boundary condition for velocity field where \(x=L_x\), the options are
-
ncly1
¶ - 0 - Periodic;
- 1 - Free-slip;
- 2 - No-slip.
Type: int Type: Boundary condition for velocity field where \(y=0\), the options are
-
nclyn
¶ - 0 - Periodic;
- 1 - Free-slip;
- 2 - No-slip.
Type: int Type: Boundary condition for velocity field where \(y=L_y\), the options are
-
nclz1
¶ - 0 - Periodic;
- 1 - Free-slip;
- 2 - No-slip.
Type: int Type: Boundary condition for velocity field where \(z=0\), the options are
-
nclzn
¶ - 0 - Periodic;
- 1 - Free-slip;
- 2 - No-slip.
Type: int Type: Boundary condition for velocity field where \(z=L_z\), the options are
-
numscalar
¶ Number of scalar fraction, which can have different properties. Any option greater than zero activates the namespace
ParametersScalarParam
.Type: int
-
nx
¶ Number of mesh points.
Notes
See
xcompact3d_toolbox.mesh.Coordinate.possible_grid_size
for recommended grid sizes.Type: int
-
ny
¶ Number of mesh points.
Notes
See
xcompact3d_toolbox.mesh.Coordinate.possible_grid_size
for recommended grid sizes.Type: int
-
nz
¶ Number of mesh points.
Notes
See
xcompact3d_toolbox.mesh.Coordinate.possible_grid_size
for recommended grid sizes.Type: int
-
p_col
¶ Defines the domain decomposition for (large-scale) parallel computation.
Notes
The product
p_row * p_col
must be equal to the number of computational cores where XCompact3d will run. More information can be found at 2DECOMP&FFT.p_row = p_col = 0
activates auto-tunning.Type: int
-
p_row
¶ Defines the domain decomposition for (large-scale) parallel computation.
Notes
The product
p_row * p_col
must be equal to the number of computational cores where XCompact3d will run. More information can be found at 2DECOMP&FFT.p_row = p_col = 0
activates auto-tunning.Type: int
-
-
class
xcompact3d_toolbox.parameters.
ParametersExtras
¶ Bases:
traitlets.traitlets.HasTraits
Extra utilities that are not present at the parameters file, but are usefull for Python applications.
-
__init__
()¶ Initialize self. See help(type(self)) for accurate signature.
-
dataset
¶ An object that reads and writes the raw binary files from XCompact3d on-demand.
Notes
All arrays are wrapped into Xarray objects (
xarray.DataArray
orxarray.Dataset
), take a look at xarray’s documentation, specially, see Why xarray? Xarray has many useful methods for indexing, comparisons, reshaping and reorganizing, computations and plotting.Consider using hvPlot to explore your data interactively, see how to plot Gridded Data.
Examples
The first step is specify the filename properties. If the simulated fields are named like
ux-000.bin
, they are in the default configuration, there is no need to specify filename properties. But just in case, it would be like:>>> prm = xcompact3d_toolbox.Parameters() >>> prm.dataset.filename_properties.set( ... separator = "-", ... file_extension = ".bin", ... number_of_digits = 3 ... )
If the simulated fields are named like
ux0000
, the parameters are:>>> prm = xcompact3d_toolbox.Parameters() >>> prm.dataset.filename_properties.set( ... separator = "", ... file_extension = "", ... number_of_digits = 4 ... )
Data type is defined by
xcompact3d_toolbox.param
:>>> import numpy >>> xcompact3d_toolbox.param["mytype] = numpy.float64 # if double precision >>> xcompact3d_toolbox.param["mytype] = numpy.float32 # if single precision
Now it is possible to customize the way the dataset will be handled:
>>> prm.dataset.set( ... data_path = "./data/", ... drop_coords = "", ... set_of_variables = {"ux", "uy", "uz"}, ... snapshot_step = "ioutput", ... snapshot_counting = "ilast", ... stack_scalar = True, ... stack_velocity = False, ... )
Note
For convenience,
data_path
is set as"./data/"
relative to thefilename
of the parameters file when creating a new instance ofParameters
(i.g., iffilename = "./example/input.i3d"
thendata_path = "./example/data/"
).There are many ways to load the arrays produced by your numerical simulation, so you can choose what best suits your post-processing application. See the examples:
Load one array from the disc:
>>> ux = prm.dataset.load_array("ux-0000.bin")
Load the entire time series for a given variable:
>>> ux = prm.dataset.load_time_series("ux") >>> uy = prm.dataset.load_time_series("uy") >>> uz = prm.dataset.load_time_series("uz")
or just:
>>> ux = prm.dataset["ux"] >>> uy = prm.dataset["uy"] >>> uz = prm.dataset["uz"]
You can organize them using a dataset:
>>> dataset = xarray.Dataset() >>> for var in "ux uy uz".split(): ... dataset[var] = prm.dataset[var]
Load all variables from a given snapshot:
>>> snapshot = prm.dataset.load_snapshot(10)
or just:
>>> snapshot = prm.dataset[10]
Loop through all snapshots, loading them one by one:
>>> for ds in prm.dataset: ... vort = ds.uy.x3d.first_derivative("x") - ds.ux.x3d.first_derivative("y") ... prm.dataset.write(data = vort, file_prefix = "w3")
Loop through some snapshots, loading them one by one, with the same arguments of a classic Python
range
, for instance, from 0 to 100 with a step of 5:>>> for ds in prm.dataset(0, 101, 5): ... vort = ds.uy.x3d.first_derivative("x") - ds.ux.x3d.first_derivative("y") ... prm.dataset.write(data = vort, file_prefix = "w3")
Or simply load all snapshots at once (if you have enough memory):
>>> ds = prm.dataset[:]
And finally, it is possible to produce a new xdmf file, so all data can be visualized on any external tool:
>>> prm.dataset.write_xdmf()
Type: xcompact3d_toolbox.io.Dataset
-
mesh
¶ Mesh object.
Type: xcompact3d_toolbox.mesh.Mesh3D
-
-
class
xcompact3d_toolbox.parameters.
ParametersIbmStuff
¶ Bases:
traitlets.traitlets.HasTraits
-
__init__
()¶ Initialize self. See help(type(self)) for accurate signature.
-
izap
¶ How many points to skip for reconstruction ranging from 0 to 3, the recommended is 1.
Type: int
-
nobjmax
¶ Maximum number of objects in any direction. It is defined automatically at
gene_epsi_3D
.Type: int
-
nraf
¶ Level of refinement to find the surface of the immersed object, when
ParametersBasicParam.iibm
is equal to 2.Type: int
-
-
class
xcompact3d_toolbox.parameters.
ParametersInOutParam
¶ Bases:
traitlets.traitlets.HasTraits
-
__init__
()¶ Initialize self. See help(type(self)) for accurate signature.
-
-
class
xcompact3d_toolbox.parameters.
ParametersLESModel
¶ Bases:
traitlets.traitlets.HasTraits
-
__init__
()¶ Initialize self. See help(type(self)) for accurate signature.
-
iwall
¶ type: int
-
jles
¶ - 0 - No model (DNS);
- 1 - Phys Smag;
- 2 - Phys WALE;
- 3 - Phys dyn. Smag;
- 4 - iSVV.
Type: int Type: Chooses LES model, they are
-
maxdsmagcst
¶ type: float
-
nSmag
¶ type: float
-
smagcst
¶ type: float
-
smagwalldamp
¶ type: int
-
walecst
¶ type: float
-
-
class
xcompact3d_toolbox.parameters.
ParametersNumOptions
¶ Bases:
traitlets.traitlets.HasTraits
-
__init__
()¶ Initialize self. See help(type(self)) for accurate signature.
-
ifirstder
¶ - 1 - 2nd central;
- 2 - 4th central;
- 3 - 4th compact;
- 4 - 6th compact (default).
Type: int Type: Scheme for first order derivative
-
iimplicit
¶ - 0 - Off (default);
- 1 - With backward Euler for Y diffusion;
- 2 - With CN for Y diffusion.
Type: int Type: Time integration scheme
-
isecondder
¶ - 1 - 2nd central;
- 2 - 4th central;
- 3 - 4th compact;
- 4 - 6th compact (default);
- 5 - Hyperviscous 6th.
Type: int Type: Scheme for second order derivative
-
-
class
xcompact3d_toolbox.parameters.
ParametersScalarParam
¶ Bases:
traitlets.traitlets.HasTraits
-
__init__
()¶ Initialize self. See help(type(self)) for accurate signature.
-
nclxS1
¶ - 0 - Periodic;
- 1 - No-flux;
- 2 - Inflow.
Type: int Type: Boundary condition for scalar field(s) where \(x=0\), the options are
-
nclxSn
¶ - 0 - Periodic;
- 1 - No-flux;
- 2 - Convective outflow.
Type: int Type: Boundary condition for scalar field(s) where \(x=L_x\), the options are
-
nclyS1
¶ - 0 - Periodic;
- 1 - No-flux;
- 2 - Dirichlet.
Type: int Type: Boundary condition for scalar field(s) where \(y=0\), the options are
-
nclySn
¶ - 0 - Periodic;
- 1 - No-flux;
- 2 - Dirichlet.
Type: int Type: Boundary condition for scalar field(s) where \(y=L_y\), the options are
-
nclzS1
¶ - 0 - Periodic;
- 1 - No-flux;
- 2 - Dirichlet.
Type: int Type: Boundary condition for scalar field(s) where \(z=0\), the options are
-
Parameters - GUI¶
Manipulate the physical and computational parameters, just like xcompact3d_toolbox.parameters.Parameters
,
but with ipywidgets.
-
class
xcompact3d_toolbox.gui.
ParametersGui
(**kwargs)¶ Bases:
xcompact3d_toolbox.parameters.Parameters
This class is derivated from
xcompact3d_toolbox.parameters.Parameters
, including all its features. In addition, there is a two way link between the parameters and their widgets. Control them with code and/or with the graphical user interface.-
__call__
(*args) -> Type(widgets.VBox)¶ Returns widgets on demand.
Parameters: *args (str) – Name(s) for the desired widget(s). Returns: Widgets for an user friendly interface. Return type: ipywidgets.VBox
Examples
>>> prm = xcompact3d_toolbox.ParametersGui() >>> prm('nx', 'xlx', 'dx', 'nclx1', 'nclxn')
-
__init__
(**kwargs)¶ Initializes the Parameters Class.
Parameters: **kwargs – Keyword arguments for xcompact3d_toolbox.parameters.Parameters
.
-
link_widgets
() → None¶ Creates a two-way link between the value of an attribute and its widget. This method is called at initialization, but provides an easy way to link any new variable.
Examples
>>> prm = xcompact3d_toolbox.ParametersGui(loadfile = 'example.i3d') >>> prm.link_widgets()
-
Mesh¶
Objects to handle the coordinates and coordinate system.
Note they are an atribute at xcompact3d_toolbox.parameters.ParametersExtras
,
so they work together with all the other parameters. They are presented here for reference.
-
class
xcompact3d_toolbox.mesh.
Coordinate
(**kwargs)¶ Bases:
traitlets.traitlets.HasTraits
A coordinate.
Thanks to traitlets, the attributes can be type checked, validated and also trigger ‘on change’ callbacks. It means that:
grid_size
is validated to just accept the values expected by XCompact3d (seexcompact3d_toolbox.mesh.Coordinate.possible_grid_size
);delta
is updated after any change ongrid_size
orlength
;length
is updated after any change ondelta
(grid_size
remais constant);grid_size
is reduced automatically by 1 whenis_periodic
changes toTrue
and it is added by 1 whenis_periodic
changes back toFalse
(seexcompact3d_toolbox.mesh.Coordinate.possible_grid_size
);
All these functionalities aim to make a user-friendly interface, where the consistency between different coordinate parameters is ensured even when they change at runtime.
Parameters: Notes
There is no need to specify both
length
anddelta
, because they are a function of each other, the missing value is automatically computed from the other.Returns: Coordinate Return type: xcompact3d_toolbox.mesh.Coordinate
-
__array__
() -> Type(np.ndarray)¶ This method makes the coordinate automatically work as a numpy like array in any function from numpy.
Returns: A numpy array. Return type: numpy.ndarray
Examples
>>> from xcompact3d_toolbox.mesh import Coordinate >>> import numpy >>> coord = Coordinate(length = 1.0, grid_size = 9) >>> numpy.sin(coord) array([0. , 0.12467473, 0.24740396, 0.36627253, 0.47942554, 0.58509727, 0.68163876, 0.7675435 , 0.84147098]) >>> numpy.cos(coord) array([1. , 0.99219767, 0.96891242, 0.93050762, 0.87758256, 0.81096312, 0.73168887, 0.64099686, 0.54030231])
-
__init__
(**kwargs)¶ Initializes the Coordinate class.
Parameters: **kwargs – Keyword arguments for attributes, like grid_size
,length
and so on.Raises: KeyError
– Exception is raised when an Keyword arguments is not a valid attribute.Examples
>>> from xcompact3d_toolbox.mesh import Coordinate >>> coord = Coordinate(length = 1.0, grid_size = 9, is_periodic = False)
-
__len__
()¶ Make the coordinate work with the Python function
len
.Returns: Coordinate size ( grid_size
)Return type: int Examples
>>> from xcompact3d_toolbox.mesh import Coordinate >>> coord = Coordinate(grid_size = 9) >>> len(coord) 9
-
__repr__
()¶ Return repr(self).
-
possible_grid_size
¶ Possible values for grid size.
Due to restrictions at the FFT library, they must be equal to:
\[n = 2^{1+a} \times 3^b \times 5^c,\]if the coordinate is periodic, and:
\[n = 2^{1+a} \times 3^b \times 5^c + 1,\]otherwise, where \(a\), \(b\) and \(c\) are non negative integers.
Aditionally, the derivative’s stencil imposes that \(n \ge 8\) if periodic and \(n \ge 9\) otherwise.
Returns: Possible values for grid size Return type: list Notes
There is no upper limit, as long as the restrictions are satisfied.
Examples
>>> from xcompact3d_toolbox.mesh import Coordinate >>> coordinate(is_periodic = True).possible_grid_size [8, 10, 12, 16, 18, 20, 24, 30, 32, 36, 40, 48, 50, 54, 60, 64, 72, 80, 90, 96, 100, 108, 120, 128, 144, 150, 160, 162, 180, 192, 200, 216, 240, 250, 256, 270, 288, 300, 320, 324, 360, 384, 400, 432, 450, 480, 486, 500, 512, 540, 576, 600, 640, 648, 720, 750, 768, 800, 810, 864, 900, 960, 972, 1000, 1024, 1080, 1152, 1200, 1250, 1280, 1296, 1350, 1440, 1458, 1500, 1536, 1600, 1620, 1728, 1800, 1920, 1944, 2000, 2048, 2160, 2250, 2304, 2400, 2430, 2500, 2560, 2592, 2700, 2880, 2916, 3000, 3072, 3200, 3240, 3456, 3600, 3750, 3840, 3888, 4000, 4050, 4096, 4320, 4374, 4500, 4608, 4800, 4860, 5000, 5120, 5184, 5400, 5760, 5832, 6000, 6144, 6250, 6400, 6480, 6750, 6912, 7200, 7290, 7500, 7680, 7776, 8000, 8100, 8192, 8640, 8748, 9000] >>> coordinate(is_periodic = False).possible_grid_size [9, 11, 13, 17, 19, 21, 25, 31, 33, 37, 41, 49, 51, 55, 61, 65, 73, 81, 91, 97, 101, 109, 121, 129, 145, 151, 161, 163, 181, 193, 201, 217, 241, 251, 257, 271, 289, 301, 321, 325, 361, 385, 401, 433, 451, 481, 487, 501, 513, 541, 577, 601, 641, 649, 721, 751, 769, 801, 811, 865, 901, 961, 973, 1001, 1025, 1081, 1153, 1201, 1251, 1281, 1297, 1351, 1441, 1459, 1501, 1537, 1601, 1621, 1729, 1801, 1921, 1945, 2001, 2049, 2161, 2251, 2305, 2401, 2431, 2501, 2561, 2593, 2701, 2881, 2917, 3001, 3073, 3201, 3241, 3457, 3601, 3751, 3841, 3889, 4001, 4051, 4097, 4321, 4375, 4501, 4609, 4801, 4861, 5001, 5121, 5185, 5401, 5761, 5833, 6001, 6145, 6251, 6401, 6481, 6751, 6913, 7201, 7291, 7501, 7681, 7777, 8001, 8101, 8193, 8641, 8749, 9001]
-
set
(**kwargs) → None¶ Set a new value for any parameter after the initialization.
Parameters: **kwargs – Keyword arguments for attributes, like grid_size
,length
and so on.Raises: KeyError
– Exception is raised when an Keyword arguments is not a valid attribute.Examples
>>> from xcompact3d_toolbox.mesh import Coordinate >>> coord = Coordinate() >>> coord.set(length = 1.0, grid_size = 9, is_periodic = False)
-
vector
¶ Construct a vector with
numpy.linspace
and return it.Returns: Numpy array Return type: numpy.ndarray
-
class
xcompact3d_toolbox.mesh.
Mesh3D
(**kwargs)¶ Bases:
traitlets.traitlets.HasTraits
A three-dimensional coordinate system
Parameters: - x (
xcompact3d_toolbox.mesh.Coordinate
) – Streamwise coordinate - y (
xcompact3d_toolbox.mesh.StretchedCoordinate
) – Vertical coordinate - z (
xcompact3d_toolbox.mesh.Coordinate
) – Spanwise coordinate
Notes
mesh
is in fact an atribute ofxcompact3d_toolbox.parameters.ParametersExtras
, so there is no need to initialize it manually for most of the common use cases. The features of each coordinate are copled by a two-way link with their corresponding values at the Parameters class. For instance, the length of each of them is copled toxlx
,yly
andzlz
, grid size tonx
,ny
andnz
and so on.Returns: Coordinate system Return type: xcompact3d_toolbox.mesh.Mesh3D
-
__init__
(**kwargs)¶ Initializes the 3DMesh class.
Parameters: **kwargs – Keyword arguments for each coordinate (x, y and z), containing a dict
with the parameters for them, likegrid_size
,length
and so on.Raises: KeyError
– Exception is raised when an Keyword arguments is not a valid coordinate.Examples
>>> from xcompact3d_toolbox.mesh import Mesh3D >>> mesh = Mesh3D( ... x = dict(length = 4.0, grid_size = 65, is_periodic = False), ... y = dict(length = 1.0, grid_size = 17, is_periodic = False, istret = 0), ... z = dict(length = 1.0, grid_size = 16, is_periodic = True) ... )
-
__len__
()¶ Make the coordinate work with the Python function
len
.Returns: Mesh size is calculated by multiplying the size of the three coordinates Return type: int
-
__repr__
()¶ Return repr(self).
-
copy
()¶ Return a copy of the Mesh3D object.
-
drop
(*args) → dict¶ Get the coordinates in a dictionary, where the keys are their names and the values are their vectors. It is possible to drop any of the coordinates in case they are needed to process planes. For instance:
- Drop
x
if working withyz
planes; - Drop
y
if working withxz
planes; - Drop
z
if working withxy
planes.
Parameters: *args (str or list of str) – Name of the coordenate(s) to be dropped Raises: KeyError
– Exception is raised when an Keyword arguments is not a valid attribute.Returns: A dict containing the desired coordinates Return type: dict
ofnumpy.ndarray
- Drop
-
get
() → dict¶ Get the three coordinates in a dictionary, where the keys are their names (x, y and z) and the values are their vectors.
Raises: KeyError
– Exception is raised when an Keyword arguments is not a valid attribute.Returns: A dict containing the coordinates Return type: dict
ofnumpy.ndarray
Notes
It is an alias for
Mesh3D.drop(None)
.
-
set
(**kwargs) → None¶ Set new values for any of the coordinates after the initialization.
Parameters: **kwargs – Keyword arguments for each coordinate (x, y and z), containing a dict
with the parameters for them, likegrid_size
,length
and so on.Raises: KeyError
– Exception is raised when an Keyword arguments is not a valid attribute.Examples
>>> from xcompact3d_toolbox.mesh import Mesh3D >>> mesh = Mesh3D() >>> mesh.set( ... x = dict(length = 4.0, grid_size = 65, is_periodic = False), ... y = dict(length = 1.0, grid_size = 17, is_periodic = False, istret = 0), ... z = dict(length = 1.0, grid_size = 16, is_periodic = True) ... )
- x (
-
class
xcompact3d_toolbox.mesh.
StretchedCoordinate
(**kwargs)¶ Bases:
xcompact3d_toolbox.mesh.Coordinate
Another coordinate, as a subclass of
Coordinate
. It includes parameters and methods to handle stretched coordinates, which is employed by XCompact3d at the vertical dimensiony
.Parameters: - length (float) – Length of the coordinate (default is 1.0).
- grid_size (int) – Number of mesh points (default is 17).
- delta (float) – Mesh resolution (default is 0.0625).
- is_periodic (bool) – Specifies if the boundary condition is periodic (True) or not (False) (default is False).
- istret (int) –
Type of mesh refinement:
- 0 - No refinement (default);
- 1 - Refinement at the center;
- 2 - Both sides;
- 3 - Just near the bottom.
- beta (float) – Refinement parameter.
Notes
There is no need to specify both
length
anddelta
, because they are a function of each other, the missing value is automatically computed from the other.Returns: Stretched coordinate Return type: xcompact3d_toolbox.mesh.StretchedCoordinate
-
__array__
()¶ This method makes the coordinate automatically work as a numpy like array in any function from numpy.
Returns: A numpy array. Return type: numpy.ndarray
Examples
>>> from xcompact3d_toolbox.mesh import StretchedCoordinate >>> import numpy >>> coord = StretchedCoordinate(length = 1.0, grid_size = 9) >>> numpy.sin(coord) array([0. , 0.12467473, 0.24740396, 0.36627253, 0.47942554, 0.58509727, 0.68163876, 0.7675435 , 0.84147098]) >>> numpy.cos(coord) array([1. , 0.99219767, 0.96891242, 0.93050762, 0.87758256, 0.81096312, 0.73168887, 0.64099686, 0.54030231])
-
__repr__
()¶ Return repr(self).
Reading and writing files¶
Usefull objects to read and write the binary fields produced by XCompact3d.
-
class
xcompact3d_toolbox.io.
Dataset
(**kwargs)¶ Bases:
traitlets.traitlets.HasTraits
An object that reads and writes the raw binary files from XCompact3d on-demand.
Parameters: - data_path (str) –
The path to the folder where the binary fields are located (default is
"./data/"
). .. note :: the default"./data/"
is relative to the path to the parametersfile when initialized fromxcompact3d_toolbox.parameters.ParametersExtras
. - drop_coords (str) – If working with two-dimensional planes, specify which of the coordinates should be
dropped, i.e.,
"x"
,"y"
or"z"
, or leave it empty for 3D fields (default is""
). - filename_properties (
FilenameProperties
) – Specifies filename properties for the binary files, like the separator, file extension and number of digits. - set_of_variables (set) – The methods in this class will try to find all variables per snapshot, use this parameter to work with just a few specified variables if you need to speedup your application (default is an empty set).
- snapshot_counting (str) – The parameter that controls the number of timesteps used to produce the datasets
(default is
"ilast"
). - snapshot_step (str) – The parameter that controls the number of timesteps between each snapshot, it is often
"ioutput"
or"iprocessing"
(default is"ioutput"
). - stack_scalar (bool) – When
True
, the scalar fields will be stacked in a new coordinaten
, otherwise returns one array per scalar fraction (default isFalse
). - stack_velocity (bool) – When
True
, the velocity will be stacked in a new coordinatei
, otherwise returns one array per velocity component (default isFalse
).
Notes
Dataset
is in fact an atribute ofxcompact3d_toolbox.parameters.ParametersExtras
, so there is no need to initialize it manually for most of the common use cases.- All arrays are wrapped into Xarray objects (
xarray.DataArray
orxarray.Dataset
), take a look at xarray’s documentation, specially, see Why xarray? Xarray has many useful methods for indexing, comparisons, reshaping and reorganizing, computations and plotting. - Consider using hvPlot to explore your data interactively, see how to plot Gridded Data.
-
__call__
(*args) → Type[xarray.core.dataset.Dataset]¶ Yields selected snapshots, so the application can iterate over them, loading one by one, with the same arguments of a classic Python
range
.Parameters: *args (int) – Same arguments used for a range
.Yields: xarray.Dataset
– Dataset containing the arrays loaded from the disc with the appropriate dimensions, coordinates and attributes.Examples
Initial setup:
>>> prm = xcompact3d_toolbox.Parameters(loadfile="input.i3d") >>> prm.dataset.set( ... filename_properties=dict( ... separator="-", ... file_extension=".bin", ... number_of_digits=3 ... ), ... stack_scalar=True, ... stack_velocity=True, ... )
Iterate over some snapshots, loading them one by one, with the same arguments of a classic Python
range
, for instance, from 0 to 100 with a step of 5:>>> for ds in prm.dataset(0, 101, 5): ... vort = ds.uy.x3d.first_derivative("x") - ds.ux.x3d.first_derivative("y") ... prm.dataset.write(data = vort, file_prefix = "w3")
-
__getitem__
(arg: Union[int, slice, str]) → Union[Type[xarray.core.dataarray.DataArray], Type[xarray.core.dataset.Dataset]]¶ Get specified items from the disc.
Note
Make sure to have enough memory to load many files at the same time.
Parameters: arg ( int
orslice
orstr
) –Specifies the items to load from the disc, depending on the type of the argument:
int
returns the specified snapshot in axarray.Dataset
. It is equivalent toDataset.load_snapshot
;slice
returns the specified snapshots in axarray.Dataset
;str
returns the entire time series for a given variable in axarray.DataArray
. It is equivalent toDataset.load_time_series
;
Returns: Xarray objects containing values loaded from the disc with the appropriate dimensions, coordinates and attributes. Return type: xarray.Dataset
orxarray.DataArray
Raises: TypeError
– Raises type error if arg is not an interger, string or sliceExamples
Initial setup:
>>> prm = xcompact3d_toolbox.Parameters(loadfile="input.i3d") >>> prm.dataset.set( ... filename_properties=dict( ... separator="-", ... file_extension=".bin", ... number_of_digits=3 ... ), ... drop_coords="z", ... stack_scalar=True, ... stack_velocity=True, ... )
Load the entire time series for a given variable:
>>> ux = prm.dataset["ux"] >>> uy = prm.dataset["uy"] >>> uz = prm.dataset["uz"]
or organize them using a dataset:
>>> dataset = xarray.Dataset() >>> for var in "ux uy uz".split(): ... dataset[var] = prm.dataset[var]
Load all variables from a given snapshot:
>>> snapshot = prm.dataset[10]
Load many snapshots at once with a
slice
, for instance, from 0 to 100 with a step of 10:>>> snapshots = prm.dataset[0:101:10]
Or simply load all snapshots at once (if you have enough memory):
>>> snapshots = prm.dataset[:]
-
__init__
(**kwargs)¶ Initializes the Dataset class.
Parameters: - filename_properties (dict, optional) – Keyword arguments for
FilenamePropertie
, likeseparator
,file_extension
and so on. - **kwargs – Keyword arguments for the parameters, like
data_path
,drop_coords
and so on.
Raises: KeyError
– Exception is raised when an Keyword arguments is not a valid parameter.Returns: An object to read and write the raw binary files from XCompact3d on-demand.
Return type: - filename_properties (dict, optional) – Keyword arguments for
-
__iter__
()¶ Yields all the snapshots, so the application can iterate over them.
Yields: xarray.Dataset
– Dataset containing the arrays loaded from the disc with the appropriate dimensions, coordinates and attributes.Examples
Initial setup:
>>> prm = xcompact3d_toolbox.Parameters(loadfile="input.i3d") >>> prm.dataset.set( ... filename_properties=dict( ... separator="-", ... file_extension=".bin", ... number_of_digits=3 ... ), ... stack_scalar=True, ... stack_velocity=True, ... )
Iterate over all snapshots, loading them one by one:
>>> for ds in prm.dataset: ... vort = ds.uy.x3d.first_derivative("x") - ds.ux.x3d.first_derivative("y") ... prm.dataset.write(data = vort, file_prefix = "w3")
-
__len__
() → int¶ Make the dataset work with the Python function
len
.Returns: Total of snapshots as a function of snapshot_counting
andsnapshot_step
.Return type: int
-
__repr__
()¶ Return repr(self).
-
load_array
(filename: str, add_time: bool = True, attrs: Optional[dict] = None) → Type[xarray.core.dataarray.DataArray]¶ This method reads a binary field from XCompact3d with
numpy.fromfile
and wraps it into axarray.DataArray
with the appropriate dimensions, coordinates and attributes.Parameters: - filename (str) – Name of the file.
- add_time (bool, optional) – Add time as a coordinate (default is
True
). - attrs (dict_like, optional) – Attributes to assign to the new instance
xarray.DataArray
.
Returns: Data array containing values loaded from the disc.
Return type: Examples
Initial setup:
>>> prm = xcompact3d_toolbox.Parameters(loadfile="input.i3d") >>> prm.dataset.set( ... filename_properties=dict( ... separator="-", ... file_extension=".bin", ... number_of_digits=3 ... ), ... stack_scalar=True, ... stack_velocity=True, ... )
Load one array from the disc:
>>> ux = prm.dataset.load_array("ux-000.bin")
-
load_snapshot
(numerical_identifier: int, list_of_variables: Optional[list] = None, add_time: bool = True, stack_scalar: Optional[bool] = None, stack_velocity: Optional[bool] = None) → Type[xarray.core.dataset.Dataset]¶ Load the variables for a given snapshot.
Parameters: - numerical_identifier (int) – The number of the snapshot.
- list_of_variables (list, optional) – List of variables to be loaded, if None, it uses
Dataset.set_of_variables
, ifDataset.set_of_variables
is empty, it automatically loads all arrays from this snapshot, by default None. - add_time (bool, optional) – Add time as a coordinate, by default True.
- stack_scalar (bool, optional) – When true, the scalar fields will be stacked in a new coordinate
n
, otherwise returns one array per scalar fraction. If none, it usesDataset.stack_scalar
, by default None. - stack_velocity (bool, optional) – When true, the velocity will be stacked in a new coordinate
i
, otherwise returns one array per velocity component. If none, it usesDataset.stack_velocity
, by default None.
Returns: Dataset containing the arrays loaded from the disc with the appropriate dimensions, coordinates and attributes.
Return type: Raises: IOError
– Raises IO error if it does not find any variable for this snapshot.Examples
Initial setup:
>>> prm = xcompact3d_toolbox.Parameters(loadfile="input.i3d") >>> prm.dataset.set( ... filename_properties=dict( ... separator="-", ... file_extension=".bin", ... number_of_digits=3 ... ), ... stack_scalar=True, ... stack_velocity=True, ... )
Load all variables from a given snapshot:
>>> snapshot = prm.dataset.load_snapshot(10)
or just
>>> snapshot = prm.dataset[10]
-
load_time_series
(array_prefix: str) → Type[xarray.core.dataarray.DataArray]¶ Load the entire time series for a given variable.
Note
Make sure to have enough memory to load all files at the same time.
Parameters: array_prefix (str) – Name of the variable, for instance ux
,uy
,uz
,pp
,phi1
.Returns: DataArray containing the time series loaded from the disc, with the appropriate dimensions, coordinates and attributes. Return type: xarray.DataArray
Raises: IOError
– Raises IO error if it does not find any snapshot for this variable.Examples
Initial setup:
>>> prm = xcompact3d_toolbox.Parameters(loadfile="input.i3d") >>> prm.dataset.set( ... filename_properties=dict( ... separator="-", ... file_extension=".bin", ... number_of_digits=3 ... ), ... stack_scalar=True, ... stack_velocity=True, ... )
Load the entire time series for a given variable:
>>> ux = prm.dataset.load_time_series("ux") >>> uy = prm.dataset.load_time_series("uy") >>> uz = prm.dataset.load_time_series("uz")
or just:
>>> ux = prm.dataset["ux"] >>> uy = prm.dataset["uy"] >>> uz = prm.dataset["uz"]
You can organize them using a dataset:
>>> dataset = xarray.Dataset() >>> for var in "ux uy uz".split(): ... dataset[var] = prm.dataset[var]
-
load_wind_turbine_data
(file_pattern: Optional[str] = None) → Type[xarray.core.dataset.Dataset]¶ Load the data produced by wind turbine simulations.
Note
This feature is experimental
Parameters: file_pattern (str, optional) – A filename pattern used to locate the files with glob.iglob
. If None, it is obtained fromdatapath
, i.g., ifdatapath = ./examples/Wind-Turbine/data
thenfile_pattern = ./examples/Wind-Turbine/data/../*.perf
. By default None.Returns: A dataset with all variables as a function of the time Return type: xarray.Dataset
Examples
>>> prm = xcompact3d_toolbox.Parameters(loadfile="NREL-5MW.i3d") >>> ds = prm.dataset.load_wind_turbine_data() >>> ds <xarray.Dataset> Dimensions: (t: 21) Coordinates: * t (t) float64 0.0 2.0 4.0 6.0 8.0 ... 34.0 36.0 38.0 40.0 Data variables: (12/14) Number of Revs (t) float64 0.0 0.4635 0.9281 1.347 ... 7.374 7.778 8.181 GeneratorSpeed (t) float64 0.0 149.3 133.6 123.2 ... 122.9 122.9 123.0 GeneratorTorque (t) float64 0.0 2.972e+04 3.83e+04 ... 4.31e+04 4.309e+04 BladePitch1 (t) float64 0.0 12.0 14.21 13.21 ... 11.44 11.44 11.44 BladePitch2 (t) float64 0.0 12.0 14.21 13.21 ... 11.44 11.44 11.44 BladePitch3 (t) float64 0.0 12.0 14.21 13.21 ... 11.44 11.44 11.44 ... ... Ux (t) float64 0.0 15.0 15.0 15.0 15.0 ... 15.0 15.0 15.0 15.0 Uy (t) float64 0.0 -1.562e-05 2.541e-05 ... 7.28e-07 7.683e-07 Uz (t) float64 0.0 1.55e-06 ... -1.828e-06 2.721e-06 Thrust (t) float64 9.39e+05 1.826e+05 ... 4.084e+05 4.066e+05 Torque (t) float64 8.78e+06 1.268e+06 ... 4.231e+06 4.203e+06 Power (t) float64 1.112e+07 1.952e+06 ... 5.362e+06 5.328e+06
-
set
(**kwargs)¶ Set new values for any of the properties after the initialization.
Parameters: - filename_properties (dict, optional) – Keyword arguments for
FilenameProperties
, likeseparator
,file_extension
and so on. - **kwargs – Keyword arguments for the parameters, like
data_path
,drop_coords
and so on.
Raises: KeyError
– Exception is raised when an Keyword arguments is not a valid parameter.Examples
>>> prm = xcompact3d_toolbox.Parameters(loadfile="input.i3d") >>> prm.dataset.set( ... filename_properties=dict( ... separator="-", ... file_extension=".bin", ... number_of_digits=3 ... ), ... stack_scalar=True, ... stack_velocity=True, ... )
- filename_properties (dict, optional) – Keyword arguments for
-
write
(data: Union[xarray.core.dataarray.DataArray, xarray.core.dataset.Dataset], file_prefix: Optional[str] = None)¶ Write an array or dataset to raw binary files on the disc, in the same order that Xcompact3d would do, so they can be easily read with 2DECOMP.
In order to avoid overwriting any relevant field, only the variables in a dataset with an attribute called
file_name
will be written.Coordinates are properly aligned before writing.
If
n
is a valid coordinate (for scalar fractions) in the array, one numerated binary file will be written for each scalar field.If
i
is a valid coordinate (for velocity components) in the array, one binary file will be written for each of them (x, y or z).If
t
is a valid coordinate (for time) in the array, one numerated binary file will be written for each available time.Parameters: - data (
xarray.DataArray
orxarray.Dataset
) – Data to be written - file_prefix (str, optional) – filename prefix for the array, if data is
xarray.DataArray
, by default None
Raises: IOError
– Raises IO error data is not anxarray.DataArray
orxarray.Dataset
.Examples
Initial setup:
>>> prm = xcompact3d_toolbox.Parameters(loadfile="input.i3d") >>> prm.dataset.set( ... filename_properties=dict( ... separator="-", ... file_extension=".bin", ... number_of_digits=3 ... ), ... stack_scalar=True, ... stack_velocity=True, ... )
- From a dataset, write only the variables with the atribute
file_name
,
notice that
ux
anduy
will not be overwritten because them do not have the atributefile_name
:>>> for ds in prm.dataset: ... ds["vort"] = ds.uy.x3d.first_derivative("x") - ds.ux.x3d. first_derivative("y") ... ds["vort"].attrs["file_name"] = "vorticity" ... prm.dataset.write(ds)
Write an array:
>>> for ds in prm.dataset: ... vort = ds.uy.x3d.first_derivative("x") - ds.ux.x3d.first_derivative("y") ... vort.attrs["file_name"] = "vorticity" ... prm.dataset.write(vort)
or
>>> for ds in prm.dataset: ... vort = ds.uy.x3d.first_derivative("x") - ds.ux.x3d.first_derivative("y") ... prm.dataset.write(data = vort, file_prefix = "vorticity")
Note
It is not recomended to load the arrays with
add_time = False
when planning to write the results in a time series (e.g., vort-000.bin, vort-001.bin, vort-002.bin, …)- data (
-
write_xdmf
(xdmf_name: str = 'snapshots.xdmf') → None¶ Write the xdmf file, so the results from the simulation and its postprocessing can be opened in an external visualization tool, like Paraview.
Make sure to set all the parameters in this object properly.
If
set_of_objects
is empty, the files are obtained automatically withglob.glob
.Parameters: xdmf_name (str, optional) – Filename for the xdmf file, by default “snapshots.xdmf” Raises: IOError
– Raises IO error if it does not find any file for this simulation.Examples
Initial setup:
>>> prm = xcompact3d_toolbox.Parameters(loadfile="input.i3d") >>> prm.dataset.set( ... filename_properties=dict( ... separator="-", ... file_extension=".bin", ... number_of_digits=3 ... ), ... stack_scalar=True, ... stack_velocity=True, ... )
It is possible to produce a new xdmf file, so all data can be visualized on any external tool:
>>> prm.dataset.write_xdmf()
- data_path (str) –
-
class
xcompact3d_toolbox.io.
FilenameProperties
(**kwargs)¶ Bases:
traitlets.traitlets.HasTraits
Filename properties are important to guarantee consistency for input/output operations. This class makes xcompact3d-toolbox work with different types of file names for the binary fields produced from the numerical simulations and their pre/postprocessing.
Parameters: - separator (str) – The string used as separator between the name of the variable and its numeration, it
can be an empty string (default is
"-"
). - file_extension (str) – The file extension that identify the raw binary files from XCompact3d, it
can be an empty string (default is
".bin"
). - number_of_digits (int) – The number of numerical digits used to identify the time series (default is
3
). - scalar_num_of_digits (int) – The number of numerical digits used to identify each scalar field (default is
1
).
Notes
FilenameProperties
is in fact an atribute ofxcompact3d_toolbox.io.Dataset
, so there is no need to initialize it manually for most of the common use cases.-
__init__
(**kwargs)¶ Initializes the object.
Parameters: **kwargs – Keyword arguments for the parameters, like separator
,file_extension
and so on.Raises: KeyError
– Raises an error if the user tries to set an invalid parameter.Returns: Filename properties Return type: xcompact3d_toolbox.io.FilenameProperties
-
__repr__
()¶ Return repr(self).
-
get_filename_for_binary
(prefix: str, counter: int, data_path='') → str¶ Get the filename for an array.
Parameters: Returns: The filename
Return type: Examples
>>> prm = xcompact3d_toolbox.Parameters() >>> prm.dataset.filename_properties.set( ... separator = "-", ... file_extension = ".bin", ... number_of_digits = 3 ... ) >>> prm.dataset.filename_properties.get_filename_for_binary("ux", 10) 'ux-010.bin' >>> prm.dataset.filename_properties.get_filename_for_binary("ux", "*") 'ux-???.bin'
>>> prm.dataset.filename_properties.set( ... separator = "", ... file_extension = "", ... number_of_digits = 4 ... ) >>> prm.dataset.filename_properties.get_filename_for_binary("ux", 10) 'ux0010' >>> prm.dataset.filename_properties.get_filename_for_binary("ux", "*") 'ux????'
-
get_info_from_filename
(filename: str) → tuple[int, str]¶ Get information from the name of a binary file.
Parameters: filename (str) – The name of the array. Returns: A tuple with the name of the array and the number that identifies it. Return type: tuple[int, str] Examples
>>> prm = xcompact3d_toolbox.Parameters() >>> prm.dataset.filename_properties.set( ... separator = "-", ... file_extension = ".bin", ... number_of_digits = 3 ... ) >>> prm.dataset.filename_properties.get_info_from_filename('ux-010.bin') (10, 'ux')
>>> prm.dataset.filename_properties.set( ... separator = "", ... file_extension = "", ... number_of_digits = 4 ... ) >>> prm.dataset.filename_properties.get_info_from_filename("ux0010") (10, 'ux')
-
get_name_from_filename
(filename: str) → str¶ Same as
get_info_from_filename
, but just returns the name.
-
get_num_from_filename
(filename: str) → int¶ Same as
get_info_from_filename
, but just returns the number.
-
set
(**kwargs) → None¶ Set new values for any of the properties after the initialization.
Parameters: **kwargs – Keyword arguments for parameters, like separator
,file_extension
and so on.Raises: KeyError
– Raises an error if the user tries to set an invalid parameter.Examples
If the simulated fields are named like
ux-000.bin
, they are in the default configuration, there is no need to specify filename properties. But just in case, it would be like:>>> prm = xcompact3d_toolbox.Parameters() >>> prm.dataset.filename_properties.set( ... separator = "-", ... file_extension = ".bin", ... number_of_digits = 3 ... )
If the simulated fields are named like
ux0000
, the parameters are:>>> prm = xcompact3d_toolbox.Parameters() >>> prm.dataset.filename_properties.set( ... separator = "", ... file_extension = "", ... number_of_digits = 4 ... )
- separator (str) – The string used as separator between the name of the variable and its numeration, it
can be an empty string (default is
Computation and Plotting¶
The data structure is provided by xarray, that introduces labels in the form of dimensions, coordinates and attributes on top of raw NumPy-like arrays, which allows for a more intuitive, more concise, and less error-prone developer experience.
See xarray’s User Guide for a complete overview about its data structures and built-in functions for indexing, selecting, computing, plotting and much more. It integrates tightly with dask for parallel computing.
Consider using hvPlot to explore your data interactively, see how to plot Gridded Data.
Xcompact3d-toolbox adds extra functions on top of xarray.DataArray
and xarray.Dataset
, all the details are described bellow.
-
class
xcompact3d_toolbox.array.
X3dDataArray
(data_array)¶ An accessor with extra utilities for
xarray.DataArray
.-
cumtrapz
(dim)¶ Cumulatively integrate
xarray.DataArray
in directiondim
using the composite trapezoidal rule. It is a wrapper forscipy.integrate.cumtrapz
. Initial value is defined to zero.Parameters: dim (str) – Coordinate used for the integration. Returns: Integrated Return type: xarray.DataArray
Examples
>>> da.x3d.cumtrapz('t')
-
first_derivative
(dim)¶ Compute first derivative with the 4th order accurate centered scheme.
It is fully functional with all boundary conditions available on XCompact3d and stretched mesh in the vertical direction (y). The atribute
BC
is used to store Boundary Condition information in a dictionary (see examples), default isncl1 = ncln = 2
andnpaire = 1
.Parameters: dim (str) – Coordinate used for the derivative. Returns: differentiated Return type: xarray.DataArray
Examples
>>> da.attrs['BC'] = { ... 'x': { ... 'ncl1': 1, ... 'ncln': 1, ... 'npaire': 0 ... }, ... 'y': { ... 'ncl1': 2, ... 'ncln': 1, ... 'npaire': 1, ... 'istret': 0, ... 'beta': 1.0 ... }, ... 'z': { ... 'ncl1': 0, ... 'ncln': 0, ... 'npaire': 1 ... } >>> da.x3d.first_derivative('x')
or just:
>>> prm = xcompact3d_toolbox.Parameters() >>> da.attrs['BC'] = prm.get_boundary_condition('ux') >>> da.x3d.first_derivative('x')
-
pencil_decomp
(*args)¶ Coerce the data array into dask array.
It applies
chunk=-1
for all coordinates listed inargs
, which means no decomposition, and'auto'
to the others, resulting in a pencil decomposition for parallel evaluation.For customized
chunks
adjust, seexarray.DataArray.chunk
.Parameters: arg (str or sequence of str) – Dimension(s) to apply no decomposition. Returns: chunked Return type: xarray.DataArray
Raises: ValueError
– args must be valid dimensions in the data arrayExamples
>>> da.x3d.pencil_decomp('x') # Pencil decomposition >>> da.x3d.pencil_decomp('t') >>> da.x3d.pencil_decomp('y', 'z') # Slab decomposition
-
second_derivative
(dim)¶ Compute second derivative with the 4th order accurate centered scheme.
It is fully functional with all boundary conditions available on Xcompact3d and stretched mesh in y direction. The atribute
BC
is used to store Boundary Condition information in a dictionary (see examples), default isncl1 = ncln = 2
andnpaire = 1
.Parameters: dim (str) – Coordinate used for the derivative. Returns: differentiated Return type: xarray.DataArray
Examples
>>> da.attrs['BC'] = { ... 'x': { ... 'ncl1': 1, ... 'ncln': 1, ... 'npaire': 0 ... }, ... 'y': { ... 'ncl1': 2, ... 'ncln': 1, ... 'npaire': 1 ... 'istret': 0, ... 'beta': 1.0 ... }, ... 'z': { ... 'ncl1': 0, ... 'ncln': 0, ... 'npaire': 1 ... } >>> da.x3d.second_derivative('x')
or just:
>>> prm = xcompact3d_toolbox.Parameters() >>> da.attrs['BC'] = prm.get_boundary_condition('ux') >>> da.x3d.second_derivative('x')
-
simps
(*args)¶ Integrate
xarray.DataArray
in direction(s)args
using the composite Simpson’s rule. It is a wrapper forscipy.integrate.simps
.Parameters: arg (str or sequence of str) – Dimension(s) to compute integration. Returns: Integrated Return type: xarray.DataArray
Raises: ValueError
– args must be valid dimensions in the data arrayExamples
>>> da.x3d.simps('x') >>> da.x3d.simps('t') >>> da.x3d.simps('x', 'y', 'z')
-
-
class
xcompact3d_toolbox.array.
X3dDataset
(data_set)¶ An accessor with extra utilities for
xarray.Dataset
.-
cumtrapz
(dim)¶ Cumulatively integrate all arrays in this dataset in direction
dim
using the composite trapezoidal rule. It is a wrapper forscipy.integrate.cumtrapz
. Initial value is defined to zero.Parameters: dim (str) – Coordinate used for the integration. Returns: Integrated Return type: xarray.Dataset
Examples
>>> ds.x3d.cumtrapz('t')
-
pencil_decomp
(*args)¶ Coerce all arrays in this dataset into dask arrays.
It applies
chunk=-1
for all coordinates listed inargs
, which means no decomposition, and"auto"
to the others, resulting in a pencil decomposition for parallel evaluation.For customized
chunks
adjust, seexarray.Dataset.chunk
.Parameters: arg (str or sequence of str) – Dimension(s) to apply no decomposition. Returns: chunked Return type: xarray.Dataset
Raises: ValueError
– args must be valid dimensions in the datasetExamples
>>> ds.x3d.pencil_decomp('x') # Pencil decomposition >>> ds.x3d.pencil_decomp('t') >>> ds.x3d.pencil_decomp('y', 'z') # Slab decomposition
-
simps
(*args)¶ Integrate all arrays in this dataset in direction(s)
args
using the composite Simpson’s rule. It is a wrapper forscipy.integrate.simps
.Parameters: arg (str or sequence of str) – Dimension(s) to compute integration. Returns: Integrated Return type: xarray.Dataset
Raises: ValueError
– args must be valid dimensions in the datasetExamples
>>> ds.x3d.simps('x') >>> ds.x3d.simps('t') >>> ds.x3d.simps('x', 'y', 'z')
-
Sandbox¶
The new Sandbox Flow Configuration (itype = 12
) aims to break many of the
barriers to entry in a Navier-Stokes solver.
The idea is to easily provide everything that XCompact3d needs from a Python Jupyter
Notebook, like initial conditions, solid geometry, boundary conditions, and the
parameters. For students in computational fluid dynamics, it provides a
direct hands-on experience and a safe place for practicing and learning, while
for advanced users and code developers, it works as a rapid prototyping tool.
For more details, see:
-
class
xcompact3d_toolbox.sandbox.
Geometry
(data_array)¶ An accessor with some standard geometries for
xarray.DataArray
. Use them in combination with the arrays initialized atxcompact3d_toolbox.sandbox.init_epsi
and the newxcompact3d_toolbox.genepsi.gene_epsi_3D
.-
ahmed_body
(scale=1.0, angle=45.0, wheels=False, remp=True, **kwargs)¶ Draw an Ahmed body.
Parameters: - scale (float) – Ahmed body’s scale (the default is 1).
- angle (float) – Ahmed body’s angle at the back, in degrees (the default is 45).
- wheel (bool) – Draw “wheels” if True (the default is False).
- remp (bool) – Adds the geometry to the
xarray.DataArray
if True and removes it if False (the default is True). - **kwargs (float) – Ahmed body’s center.
Returns: Array with(out) the Ahmed body
Return type: Raises: KeyError
– Center coordinates must be valid dimensions.NotImplementedError
– Body must be centered inz
.
Examples
>>> prm = xcompact3d_toolbox.Parameters() >>> epsi = xcompact3d_toolbox.init_epsi(prm) >>> for key in epsi.keys(): >>> epsi[key] = epsi[key].geo.ahmed_body(x=2)
-
box
(remp=True, **kwargs)¶ Draw a box.
Parameters: - remp (bool) – Adds the geometry to the
xarray.DataArray
if True and removes it if False (the default is True). - **kwargs (tuple of float) – Box’s boundaries.
Returns: Array with(out) the box
Return type: Raises: KeyError
– Boundaries coordinates must be valid dimensionsExamples
>>> prm = xcompact3d_toolbox.Parameters() >>> epsi = xcompact3d_toolbox.init_epsi(prm) >>> for key in epsi.keys(): >>> epsi[key] = epsi[key].geo.box(x=(2,5), y=(0,1))
- remp (bool) – Adds the geometry to the
-
cylinder
(radius=0.5, axis='z', height=None, remp=True, **kwargs)¶ Draw a cylinder.
Parameters: - radius (float) – Cylinder’s radius (the default is 0.5).
- axis (str) – Cylinder’s axis (the default is
"z"
). - height (float or None) – Cylinder’s height (the default is None), if None, it will take the entire axis, otherwise \(\pm h/2\) is considered from the center.
- remp (bool) – Adds the geometry to the
xarray.DataArray
if True and removes it if False (the default is True). - **kwargs (float) – Cylinder’s center point.
Returns: Array with(out) the cylinder
Return type: Raises: KeyError
– Center coordinates must be valid dimensionsExamples
>>> prm = xcompact3d_toolbox.Parameters() >>> epsi = xcompact3d_toolbox.init_epsi(prm) >>> for key in epsi.keys(): >>> epsi[key] = epsi[key].geo.cylinder(x=4.0, y=5.0)
-
from_stl
(filename: str = None, stl_mesh: stl.mesh.Mesh = None, origin: dict = None, rotate: dict = None, scale: float = None, user_tol: float = 6.283185307179586, remp: bool = True)¶ Load a STL file and compute if the nodes of the computational mesh are inside or outside the object. In this way, the customized geometry can be used at the flow solver.
The methodology is based on the work of:
- Jacobson, A., Kavan, L., & Sorkine-Hornung, O. (2013). Robust inside-outside segmentation using generalized winding numbers. ACM Transactions on Graphics (TOG), 32(4), 1-12.
The Python implementation is an adaptation from inside-3d-mesh (licensed under the MIT License), by @marmakoide.
To maximize the performance here at the toolbox,
from_stl
is powered by Numba, that translates Python functions to optimized machine code at runtime. This method is compatible with Dask for parallel computation. In addition, just the subdomain near the object is tested, to save computational time.Note
The precision of the method is influenced by the complexity of the STL mesh, there is no guarantee it will work for all geometries. This feature is experimental, its interface may change in future releases.
Parameters: - filename (str, optional) – Filename of the STL file to be loaded and included in the cartesian domain, by default None
- scale (float, optional) – This parameters can be used to scale up the object when greater than one and scale it down when smaller than one, by default None
- rotate (dict, optional) – Rotate the object, including keyword arguments that are
expected by
stl.mesh.Mesh.rotate
, likeaxis
,theta
andpoint
. For more details, see numpy-stl’s documentation. By default None - origin (dict, optional) – Specify the location of the origin point for the geometry.
It is considered as the minimum value computed from all
points in the object for each coordinate, after scaling
and rotating them. The keys of the dictionary are the
coordinate names (
x
,y
andz
) and the values are the origin on that coordinate. For missing keys, the value is assumed as zero. By default None - stl_mesh (stl.mesh.Mesh, optional) – For very customizable control over the 3D object, you can provide it directly. Note that none of the arguments above are applied in this case. For more details about how to create and modify the geometry, see numpy-stl’s documentation. By default None
- user_tol (float, optional) – Control the tolerance used to compute if a mesh node is inside or outside the object. Values smaller than the default may reduce the number of false negatives. By default \(2\pi\)
- remp (bool, optional) – Add the geometry to the
xarray.DataArray
ifTrue
and removes it ifFalse
, by default True
Returns: Array with(out) the customized geometry
Return type: Raises: ValueError
– If neitherfilename
orstl_mesh
are specifiedValueError
– Ifstl_mesh
is not valid, the test is performed bystl.mesh.Mesh.check
ValueError
– Ifstl_mesh
is not closed, the test is performed bystl.mesh.Mesh.is_closed
Examples
>>> prm = xcompact3d_toolbox.Parameters() >>> epsi = xcompact3d_toolbox.init_epsi(prm, dask = True) >>> for key in epsi.keys(): >>> epsi[key] = epsi[key].geo.from_stl( ... "My_file.stl", ... scale=1.0, ... rotate=dict(axis=[0, 0.5, 0], theta=math.radians(90)), ... origin=dict(x=2, y=1, z=0), ... )
-
mirror
(dim='x')¶ Mirror the \(\epsilon\) array with respect to the central plane in the direction
dim
.Parameters: dim (str) – Reference for the mirror (the default is x
).Returns: Mirrored array Return type: xarray.DataArray
Examples
>>> prm = xcompact3d_toolbox.Parameters() >>> epsi = xcompact3d_toolbox.init_epsi(prm) >>> for key in epsi.keys(): >>> epsi[key] = epsi[key].geo.cylinder(x=4, y=5).geo.mirror("x")
-
sphere
(radius=0.5, remp=True, **kwargs)¶ Draw a sphere.
Parameters: - radius (float) – Sphere’s radius (the default is 0.5).
- remp (bool) – Adds the geometry to the
xarray.DataArray
if True and removes it if False (the default is True). - **kwargs (float) – Sphere’s center.
Returns: Array with(out) the sphere
Return type: Raises: KeyError
– Center coordinates must be valid dimensionsExamples
>>> prm = xcompact3d_toolbox.Parameters() >>> epsi = xcompact3d_toolbox.init_epsi(prm) >>> for key in epsi.keys(): >>> epsi[key] = epsi[key].geo.sphere(x=1, y=1, z=1)
-
square
(length=1.0, thickness=0.1, remp=True, **kwargs)¶ Draw a squared frame.
Parameters: - length (float) – Frame’s external length (the default is 1).
- thickness (float) – Frames’s tickness (the default is 0.1).
- remp (bool) – Adds the geometry to the
xarray.DataArray
if True and removes it if False (the default is True). - **kwargs (float) – Frames’s center.
Returns: Array with(out) the squared frame
Return type: Raises: KeyError
– Center coordinates must be valid dimensionsExamples
>>> prm = xcompact3d_toolbox.Parameters() >>> epsi = xcompact3d_toolbox.init_epsi(prm) >>> for key in epsi.keys(): >>> epsi[key] = epsi[key].geo.square(x=5, y=2, z=1)
-
-
xcompact3d_toolbox.sandbox.
init_dataset
(prm)¶ This function initializes a
xarray.Dataset
including all variables that should be provided to XCompact3d and the sandbox flow configuration, according to the computational and physical parameters.Parameters: prm ( xcompact3d_toolbox.parameters.Parameters
) – Contains the computational and physical parameters.Returns: Each variable is initialized with np.zeros(dtype=xcompact3d_toolbox.param["mytype"])
and wrapped into axarray.Dataset
with the proper size, dimensions, coordinates and attributes, check them for more details. The variables are:bxx1
,bxy1
,bxz1
- Inflow boundary condition for ux, uy and uz, respectively (if nclx1 = 2);noise_mod_x1
- for random noise modulation at inflow boundary condition (if nclx1 = 2);bxphi1
- Inflow boundary condition for scalar field(s) (if nclx1 = 2 and numscalar > 0);byphi1
- Bottom boundary condition for scalar field(s) (if nclyS1 = 2, numscalar > 0 and uset = 0);byphin
- Top boundary condition for scalar field(s) (if nclySn = 2, numscalar > 0 and uset = 0);ux
,uy
,uz
- Initial condition for velocity field;phi
- Initial condition for scalar field(s) (if numscalar > 0);vol_frc
- Integral operator employed for flow rate control in case of periodicity in x direction (nclx1 = 0 and nclxn = 0). Xcompact3d will compute the volumetric integration as I = sum(vol_frc * ux) and them will correct streamwise velocity as ux = ux / I, so, setvol_frc
properly.
Return type: xarray.Dataset
Examples
>>> prm = xcompact3d_toolbox.Parameters() >>> dataset = xcompact3d_toolbox.init_dataset(prm) >>> # >>> # Code here your customized flow configuration >>> # >>> prm.dataset.write(dataset) # write the files to the disc
-
xcompact3d_toolbox.sandbox.
init_epsi
(prm, dask=False)¶ Initializes the \(\epsilon\) arrays that define the solid geometry for the Immersed Boundary Method.
Parameters: - prm (
xcompact3d_toolbox.parameters.Parameters
) – Contains the computational and physical parameters. - dask (bool) – Defines the lazy parallel execution with dask arrays.
See
xcompact3d_toolbox.array.x3d.pencil_decomp()
.
Returns: A dictionary containing the epsi(s) array(s):
- epsi (nx, ny, nz) if
iibm
!= 0; - xepsi (nxraf, ny, nz) if
iibm
= 2; - yepsi (nx, nyraf, nz) if
iibm
= 2; - zepsi (nx, ny, nzraf) if
iibm
= 2.
Each one initialized with np.zeros(dtype=np.bool) and wrapped into a
xarray.DataArray
with the proper size, dimensions and coordinates. They are used to define the object(s) that is(are) going to be inserted into the cartesian domain by the Immersed Boundary Method (IBM). They should be set to one (True) at the solid points and stay zero (False) at the fluid points, some standard geometries are provided by the accessorxcompact3d_toolbox.sandbox.Geometry
.Return type: Examples
>>> prm = xcompact3d_toolbox.Parameters() >>> epsi = xcompact3d_toolbox.init_epsi(prm)
- prm (
Genepsi¶
This module generates all the files necessary for our customized Immersed Boundary Method, based on Lagrange reconstructions. It is an adaptation to Python from the original Fortran code and methods from:
- Gautier R., Laizet S. & Lamballais E., 2014, A DNS study of jet control with microjets using an alternating direction forcing strategy, Int. J. of Computational Fluid Dynamics, 28, 393–410.
gene_epsi_3D
is powered by Numba, it translates Python functions to
optimized machine code at runtime. Numba-compiled numerical algorithms in Python
can approach the speeds of C or FORTRAN.
-
xcompact3d_toolbox.genepsi.
gene_epsi_3D
(epsi_in_dict, prm)¶ This function generates all the auxiliar files necessary for our customize IBM, based on Lagrange reconstructions. The arrays can be initialized with
xcompact3d_toolbox.sandbox.init_epsi()
, then, some standard geometries are provided by the accessorxcompact3d_toolbox.sandbox.Geometry
. Notice that you can apply our own routines for your own objects. The main outputs of the function are written to disc at the filesepsilon.bin
,nobjx.dat
,nobjy.dat
,nobjz.dat
,nxifpif.dat
,nyifpif.dat
,nzifpif.dat
,xixf.dat
,yiyf.dat
andzizf.dat
. They will be used by Xcompact3d and the sandbox flow configuration.Parameters: - epsi_in_dict (
dict
ofxarray.DataArray
) – A dictionary containing the epsi(s) array(s). - prm (
xcompact3d_toolbox.parameters.Parameters
) – Contains the computational and physical parameters.
Returns: All computed variables are returned in a Dataset if
prm.iibm >= 2
, but just for reference, since all the relevant values are written to the disc.Return type: Examples
>>> prm = x3d.Parameters() >>> epsi = x3d.sandbox.init_epsi(prm) >>> for key in epsi.keys(): ... epsi[key] = epsi[key].geo.cylinder(x=4, y=5) >>> dataset = x3d.gene_epsi_3D(epsi, prm)
Remember to set the number of objects after that if
prm.iibm >= 2
:>>> if prm.iibm >= 2: ... prm.nobjmax = dataset.obj.size
- epsi_in_dict (
Sample Data¶
-
xcompact3d_toolbox.tutorial.
open_dataset
(name: str, **kws) → tuple[xr.Dataset, Parameters]¶ Open a dataset from the online repository (requires internet).
If a local copy is found then always use that to avoid network traffic.
Available datasets: *
"cylinder"
: Flow around a cylinderParameters: - name (str) – Name of the file containing the dataset. e.g. ‘cylinder’.
- **kws (dict, optional) – Passed to
xarray.tutorial.open_dataset
See also
Tutorials¶
Parameters¶
The computational and physical parameters are handled by class xcompact3d_toolbox.Parameters
. It is built on top of Traitlets, which aims to make the parameters compatible with what xcompact3d expects, and also brings some advantages:
- Attributes are type-checked;
- Default values, restrictions and connections between related parameters are applied where necessary;
- ‘On change’ callbacks for validation and observation;
- Two-way linking with ipywidgets.
[1]:
import numpy as np
import xcompact3d_toolbox as x3d
The first step is to establish numerical precision. Use np.float64
if Xcompact3d was compiled with the flag -DDOUBLE_PREC
(check the Makefile), use np.float32
otherwise:
[2]:
x3d.param["mytype"] = np.float32
Initialization¶
There are a few ways to initialize the class. First, calling it with no arguments initializes all variables with default value:
[3]:
prm = x3d.Parameters()
You can access a list with all the available variables at the Api reference.
Let’s see how it looks like:
[4]:
print(prm)
! -*- mode: f90 -*-
!===================
&BasicParam
!===================
C_filter = 0.49 !
beta = 1.0 ! Refinement parameter
dt = 0.001 ! Time step
gravx = 0.0 ! Gravity unitary vector in x-direction
gravy = 0.0 ! Gravity unitary vector in y-direction
gravz = 0.0 ! Gravity unitary vector in z-direction
ifilter = 0 !
ifirst = 0 ! The number for the first iteration
iibm = 0 ! Flag for immersed boundary method (0: No, 1: Yes)
iin = 0 ! Defines perturbation at initial condition
ilast = 0 ! The number for the last iteration
ilesmod = 0 ! Enables Large-Eddy methodologies (0: No, 1: Yes)
ilmn = .false. !
inflow_noise = 0.0 ! Turbulence intensity (1=100%) !! Inflow condition
init_noise = 0.0 ! Turbulence intensity (1=100%) !! Initial condition
ipost = 0 ! Enables online postprocessing at a frequency iprocessing (0: No, 1: Yes)
iscalar = 0 !
istret = 0 ! y mesh refinement (0:no, 1:center, 2:both sides, 3:bottom)
iturbine = 0 !
itype = 12 ! Flow configuration (1:Lock-exchange, 2:TGV, 3:Channel, and others)
ivisu = 1 ! Enable store snapshots at a frequency ioutput (0: No, 1: Yes)
nclx1 = 2 ! Velocity boundary condition where x=0
nclxn = 2 ! Velocity boundary condition where x=xlx
ncly1 = 2 ! Velocity boundary condition where y=0
nclyn = 2 ! Velocity boundary condition where y=yly
nclz1 = 2 ! Velocity boundary condition where z=0
nclzn = 2 ! Velocity boundary condition where z=zlz
numscalar = 0 ! Number of scalar fractions
nx = 17 ! X-direction nodes
ny = 17 ! Y-direction nodes
nz = 17 ! Z-direction nodes
p_col = 0 ! Column partition for domain decomposition and parallel computation
p_row = 0 ! Row partition for domain decomposition and parallel computation
re = 1000.0 ! Reynolds number
u1 = 2.0 !
u2 = 1.0 !
xlx = 1.0 ! Size of the box in x-direction
yly = 1.0 ! Size of the box in y-direction
zlz = 1.0 ! Size of the box in z-direction
/End
!===================
&NumOptions
!===================
cnu = 0.44 ! Ratio between hyperviscosity at km=2/3π and kc=π (dissipation factor range)
ifirstder = 4 !
iimplicit = 0 !
isecondder = 4 ! Scheme for second order derivative
itimescheme = 3 ! Time integration scheme (1: Euler, 2: AB2, 3: AB3, 5: RK3)
nu0nu = 4.0 ! Ratio between hyperviscosity/viscosity at nu (dissipation factor intensity)
/End
!===================
&InOutParam
!===================
icheckpoint = 1000 ! Frequency for writing backup file
ioutflow = 0 !
ioutput = 1000 ! Frequency for visualization file
iprocessing = 1000 ! Frequency for online postprocessing
irestart = 0 ! Read initial flow field (0: No, 1: Yes)
ninflows = 1 !
nprobes = 0 !
ntimesteps = 1 !
nvisu = 1 ! Size for visualization collection
output2D = 0 !
/End
!===================
&Statistics
!===================
/End
!===================
&CASE
!===================
/End
It is possible to access and/or set values afterwards:
[5]:
# Reynolds Number
print(prm.re)
# attribute new value
prm.re = 1e6
print(prm.re)
1000.0
1000000.0
Second, we can specify some values, and let the missing ones be initialized with default value:
[6]:
prm = x3d.Parameters(
filename="example.i3d",
itype=10,
nx=129,
ny=65,
nz=32,
xlx=15.0,
yly=10.0,
zlz=3.0,
nclx1=2,
nclxn=2,
ncly1=1,
nclyn=1,
nclz1=0,
nclzn=0,
iin=1,
istret=2,
re=300.0,
init_noise=0.0125,
inflow_noise=0.0125,
dt=0.0025,
ifirst=1,
ilast=45000,
irestart=0,
icheckpoint=45000,
ioutput=200,
iprocessing=50,
)
It is easy to write example.i3d
to disc, just type:
[7]:
prm.write()
And finally, it is possible to read the parameters from the disc:
[8]:
prm = x3d.Parameters(filename="example.i3d")
prm.load()
The same result is obtained in a more concise way:
[9]:
prm = x3d.Parameters(loadfile="example.i3d")
The class can also read the previous parameters format (se more information here):
prm = x3d.Parameters(loadfile="incompact3d.prm")
There are extra objects read and write the raw binary files from XCompact3d on-demand.
Read a binary field from the disc:
ux = prm.dataset.load_array("ux-0000.bin")
Read the entire time series for a given variable:
ux = prm.dataset.load_time_series("ux")
Read all variables for a given snapshot:
snapshot = prm.dataset.load_snapshot(10)
Write
xdmf
files, so the binary files can be open in any external visualization tool:prm.dataset.write_xdmf()
Compute the coordinates, including support for mesh refinement in y:
[10]:
prm.get_mesh()
[10]:
{'x': array([ 0. , 0.1171875, 0.234375 , 0.3515625, 0.46875 ,
0.5859375, 0.703125 , 0.8203125, 0.9375 , 1.0546875,
1.171875 , 1.2890625, 1.40625 , 1.5234375, 1.640625 ,
1.7578125, 1.875 , 1.9921875, 2.109375 , 2.2265625,
2.34375 , 2.4609375, 2.578125 , 2.6953125, 2.8125 ,
2.9296875, 3.046875 , 3.1640625, 3.28125 , 3.3984375,
3.515625 , 3.6328125, 3.75 , 3.8671875, 3.984375 ,
4.1015625, 4.21875 , 4.3359375, 4.453125 , 4.5703125,
4.6875 , 4.8046875, 4.921875 , 5.0390625, 5.15625 ,
5.2734375, 5.390625 , 5.5078125, 5.625 , 5.7421875,
5.859375 , 5.9765625, 6.09375 , 6.2109375, 6.328125 ,
6.4453125, 6.5625 , 6.6796875, 6.796875 , 6.9140625,
7.03125 , 7.1484375, 7.265625 , 7.3828125, 7.5 ,
7.6171875, 7.734375 , 7.8515625, 7.96875 , 8.0859375,
8.203125 , 8.3203125, 8.4375 , 8.5546875, 8.671875 ,
8.7890625, 8.90625 , 9.0234375, 9.140625 , 9.2578125,
9.375 , 9.4921875, 9.609375 , 9.7265625, 9.84375 ,
9.9609375, 10.078125 , 10.1953125, 10.3125 , 10.4296875,
10.546875 , 10.6640625, 10.78125 , 10.8984375, 11.015625 ,
11.1328125, 11.25 , 11.3671875, 11.484375 , 11.6015625,
11.71875 , 11.8359375, 11.953125 , 12.0703125, 12.1875 ,
12.3046875, 12.421875 , 12.5390625, 12.65625 , 12.7734375,
12.890625 , 13.0078125, 13.125 , 13.2421875, 13.359375 ,
13.4765625, 13.59375 , 13.7109375, 13.828125 , 13.9453125,
14.0625 , 14.1796875, 14.296875 , 14.4140625, 14.53125 ,
14.6484375, 14.765625 , 14.8828125, 15. ], dtype=float32),
'y': array([ 0. , 0.04504663, 0.09029302, 0.13594234, 0.18220465,
0.2293007 , 0.27746594, 0.3269554 , 0.37804887, 0.43105724,
0.4863303 , 0.5442656 , 0.60532016, 0.670024 , 0.7389978 ,
0.81297535, 0.8928308 , 0.9796148 , 1.0746001 , 1.1793398 ,
1.2957417 , 1.4261622 , 1.5735214 , 1.7414377 , 1.9343702 ,
2.1577313 , 2.4178853 , 2.72186 , 3.0764673 , 3.4864438 ,
3.9514096 , 4.462363 , 5. , 5.537637 , 6.0485907 ,
6.5135565 , 6.923533 , 7.27814 , 7.5821147 , 7.842269 ,
8.06563 , 8.258562 , 8.426478 , 8.573838 , 8.704258 ,
8.820661 , 8.9254 , 9.020385 , 9.107169 , 9.187025 ,
9.261003 , 9.329976 , 9.39468 , 9.455734 , 9.51367 ,
9.568943 , 9.621951 , 9.673044 , 9.722534 , 9.7706995 ,
9.817796 , 9.864058 , 9.909707 , 9.954953 , 10. ],
dtype=float32),
'z': array([0. , 0.09375, 0.1875 , 0.28125, 0.375 , 0.46875, 0.5625 ,
0.65625, 0.75 , 0.84375, 0.9375 , 1.03125, 1.125 , 1.21875,
1.3125 , 1.40625, 1.5 , 1.59375, 1.6875 , 1.78125, 1.875 ,
1.96875, 2.0625 , 2.15625, 2.25 , 2.34375, 2.4375 , 2.53125,
2.625 , 2.71875, 2.8125 , 2.90625], dtype=float32)}
More details about I/O and array manipulations with xarray will be included in a new tutorial.
Traitlets¶
Type-checking¶
All parameters are type-checked, to make sure that they are what Xcompact3d
expects. Use the cellcode below to see how a TraitError
pops out when we try:
prm.itype = 10.5
prm.itype = -5
prm.itype = 20
prm.itype = 'sandbox'
[ ]:
Validation¶
Some parameters, like mesh points (nx
, ny
and nz
), trigger a validation operation when a new value is attributed to them. Due to restrictions at the FFT library, they must be equal to:
where \(a\), \(b\) and \(c\) are non negative integers. In addition, the derivatives stencil imposes that:
Again, give it a try at the cellcode below:
prm.nx = 129
prm.nx = 4
prm.nx = 60
prm.nx = 61
[ ]:
Observation¶
Other parameters, like mesh resolution (dx
, dy
and dz
), are automatically updated when any new attribution occurs to mesh points and/or domain size. Let’s create a quick print functions to play with:
[11]:
def show_param():
for var in "nclx1 nclxn nx xlx dx".split():
print(f"{var:>5} = {getattr(prm, var)}")
We are starting with:
[12]:
show_param()
nclx1 = 2
nclxn = 2
nx = 129
xlx = 15.0
dx = 0.1171875
Let’s change just the domain’s length:
[13]:
prm.xlx = 50.0
show_param()
nclx1 = 2
nclxn = 2
nx = 129
xlx = 50.0
dx = 0.390625
The resolution was updated as well. Now the number of mesh points:
[14]:
prm.nx = 121
show_param()
nclx1 = 2
nclxn = 2
nx = 121
xlx = 50.0
dx = 0.4166666666666667
Again, the resolution was updated. Now we set a new mesh resolution, this time, xlx
will be updated in order to satisfy the new resolution:
[15]:
prm.dx = 1e-2
show_param()
nclx1 = 2
nclxn = 2
nx = 121
xlx = 1.2
dx = 0.01
Boundary conditions are observed as well. Xcompact3d allows three different BC for velocity:
- Periodic
0
; - Free-slip
1
; - Dirichlet
2
.
They can be assigned individually for each of the six boundaries:
nclx1
andnclxn
, where \(x=0\) and \(x=xlx\);ncly1
andnclyn
, where \(y=0\) and \(y=yly\);nclz1
andnclzn
, where \(z=0\) and \(z=zlz\).
It leads to 5 possibilities (00
, 11
, 12
, 21
and 22
), because both boundary must be periodic, or not, so 0
cannot be combined.
Let’s check it out, we are starting with:
[16]:
show_param()
nclx1 = 2
nclxn = 2
nx = 121
xlx = 1.2
dx = 0.01
We will change just one side to periodic (nclx1 = 0
), for consistence, the other side should be periodic too. Let’s see:
[17]:
prm.nclx1 = 0
show_param()
nclx1 = 0
nclxn = 0
nx = 120
xlx = 1.2
dx = 0.01
Now free-slip in one side (nclx1 = 1
), and the other should be non-periodic:
[18]:
prm.nclx1 = 1
show_param()
nclx1 = 1
nclxn = 1
nx = 121
xlx = 1.2
dx = 0.01
Setting the other boundary to periodic:
[19]:
prm.nclxn = 0
show_param()
nclx1 = 0
nclxn = 0
nx = 120
xlx = 1.2
dx = 0.01
and now back to Dirichlet:
[20]:
prm.nclxn = 2
show_param()
nclx1 = 2
nclxn = 2
nx = 121
xlx = 1.2
dx = 0.01
This time, free-slip:
[21]:
prm.nclxn = 1
show_param()
nclx1 = 2
nclxn = 1
nx = 121
xlx = 1.2
dx = 0.01
There was no need to update nclx1
, because 1
and 2
can be freely combined. Notice that nx
was modified properly from 121 to 120 and then back, according to the possible values, dx
and xlx
stayed untouched.
Metadata¶
Traitlets types constructors have a tag
method to store metadata in a dictionary. In the case of Xcompact3d-toolbox, two are especially useful:
group
defines to what namespace a given parameter belongs when the class is written to.i3d
file (.write()
method) or read from.i3d
or.prm
files (.load()
method), parameters without a group are ignored for both methods;desc
contains a brief description of each parameter that is shown on screen as we saw above, and also printed with the.write()
method.
Declaring new parameters¶
You probably would like to add more parameters for your own flow configuration, or because some of them were not implemented yet (it is a work in progress).
To do so, any auxiliar variable can be included after initialization, like:
[22]:
prm.my_variable = 0 # or any other datatype
It was called auxiliar variable because, in this way, it will be available only for the Python application.
In order to include it at the .i3d
file and make it available for XCompact3d, we can create a subclass that inherits all the functionality from xcompact3d_toolbox.Parameters
:
[23]:
import traitlets
# Create a class named my_Parameters, which inherits the properties all properties and methods
class my_Parameters(x3d.Parameters):
# .tag with group and description guarantees that the new variable will
# be compatible with all functionalities (like .write() and .load())
a_my_variable = traitlets.Int(default_value=0, min=0).tag(
group="BasicParam", desc="An example at the Tutorial <------"
)
# And a custom method, for instance
def my_method(self):
return self.a_my_variable * 2
prm = my_Parameters(nx=257, ny=129, nz=31, a_my_variable=10) # and here we go
# Testing the method
print(prm.my_method())
# Show all parameters on screen
print(prm)
20
! -*- mode: f90 -*-
!===================
&BasicParam
!===================
C_filter = 0.49 !
a_my_variable = 10 ! An example at the Tutorial <------
beta = 1.0 ! Refinement parameter
dt = 0.001 ! Time step
gravx = 0.0 ! Gravity unitary vector in x-direction
gravy = 0.0 ! Gravity unitary vector in y-direction
gravz = 0.0 ! Gravity unitary vector in z-direction
ifilter = 0 !
ifirst = 0 ! The number for the first iteration
iibm = 0 ! Flag for immersed boundary method (0: No, 1: Yes)
iin = 0 ! Defines perturbation at initial condition
ilast = 0 ! The number for the last iteration
ilesmod = 0 ! Enables Large-Eddy methodologies (0: No, 1: Yes)
ilmn = .false. !
inflow_noise = 0.0 ! Turbulence intensity (1=100%) !! Inflow condition
init_noise = 0.0 ! Turbulence intensity (1=100%) !! Initial condition
ipost = 0 ! Enables online postprocessing at a frequency iprocessing (0: No, 1: Yes)
iscalar = 0 !
istret = 0 ! y mesh refinement (0:no, 1:center, 2:both sides, 3:bottom)
iturbine = 0 !
itype = 12 ! Flow configuration (1:Lock-exchange, 2:TGV, 3:Channel, and others)
ivisu = 1 ! Enable store snapshots at a frequency ioutput (0: No, 1: Yes)
nclx1 = 2 ! Velocity boundary condition where x=0
nclxn = 2 ! Velocity boundary condition where x=xlx
ncly1 = 2 ! Velocity boundary condition where y=0
nclyn = 2 ! Velocity boundary condition where y=yly
nclz1 = 2 ! Velocity boundary condition where z=0
nclzn = 2 ! Velocity boundary condition where z=zlz
numscalar = 0 ! Number of scalar fractions
nx = 257 ! X-direction nodes
ny = 129 ! Y-direction nodes
nz = 31 ! Z-direction nodes
p_col = 0 ! Column partition for domain decomposition and parallel computation
p_row = 0 ! Row partition for domain decomposition and parallel computation
re = 1000.0 ! Reynolds number
u1 = 2.0 !
u2 = 1.0 !
xlx = 1.0 ! Size of the box in x-direction
yly = 1.0 ! Size of the box in y-direction
zlz = 1.0 ! Size of the box in z-direction
/End
!===================
&NumOptions
!===================
cnu = 0.44 ! Ratio between hyperviscosity at km=2/3π and kc=π (dissipation factor range)
ifirstder = 4 !
iimplicit = 0 !
isecondder = 4 ! Scheme for second order derivative
itimescheme = 3 ! Time integration scheme (1: Euler, 2: AB2, 3: AB3, 5: RK3)
nu0nu = 4.0 ! Ratio between hyperviscosity/viscosity at nu (dissipation factor intensity)
/End
!===================
&InOutParam
!===================
icheckpoint = 1000 ! Frequency for writing backup file
ioutflow = 0 !
ioutput = 1000 ! Frequency for visualization file
iprocessing = 1000 ! Frequency for online postprocessing
irestart = 0 ! Read initial flow field (0: No, 1: Yes)
ninflows = 1 !
nprobes = 0 !
ntimesteps = 1 !
nvisu = 1 ! Size for visualization collection
output2D = 0 !
/End
!===================
&Statistics
!===================
/End
!===================
&CASE
!===================
/End
Take a look at the source code of parameters.py if you need more examples for different datatypes.
Graphical User Interface¶
To conclude this part of the tutorial, let’s see another option to handle the parameters. The class ParametersGui
is a subclass of Parameters
, and includes all the features described above. In addition, ParametersGui
offers an user interface with IPywidgets.
It is still under development, more parameters and features are going to be included soon, as well as more widgets.
Just like before, we start with:
[24]:
prm = x3d.ParametersGui()
Widgets are returned on demand when any instance of class ParametersGui
is called, let’s see:
[25]:
prm("nx", "xlx", "dx", "nclx1", "nclxn")
You can play around with the widgets above and see the effect of the observations made previously.
Notice that the Traitlets parameters are related to the value at their widgets in a two-way link, in this way, a print will show the actual value on the widgets:
[26]:
show_param()
nclx1 = 2
nclxn = 2
nx = 17
xlx = 1.0
dx = 0.0625
Give it a try, modify the values at the widgets and print them again.
It also works on the other way, set a new value to a parameters will change its widget, try it:
[27]:
#prm.nclx1 = 0
And of course, different widgets for the same parameter are always synchronized, change the widget below and see what happens with the widget above:
[28]:
prm('nx')
A last example is about the domain decomposition for parallel computation, Xcompact3d uses 2DECOMP&FFT. The available options for p_row
and p_col
are presented as functions of the number of computational cores ncores
, notice that p_row * p_col = ncores
should be respected and p_row * p_col = 0
activates the auto-tunning mode. The widgets are prepared to respect these restrictions:
[29]:
prm('ncores', 'p_row', 'p_col')
To conclude this part of the tutorial, let’s see what happens when class ParametersGui
is presented on screen, hover the mouse over some variable to see its description:
[30]:
prm
Reading and writing files¶
This tutorial includes an overview of the different ways available to load the binary arrays from the disc after running a numerical simulation with XCompact3d. Besides that, some options are presented to save the results from our analysis, together with some tips and tricks.
Preparation¶
Here we prepare the dataset for this notebook, so it can be reproduced on local machines or on the cloud, you are invited to test and interact with many of the concepts. It also provides nice support for courses and tutorials, let us know if you produce any of them.
The very first step is to import the toolbox and other packages:
[1]:
import warnings
import numpy as np
import xarray as xr
import xcompact3d_toolbox as x3d
Then we can download an example from the online database, the flow around a cylinder in this case. We set cache=True
and a local destination where it can be saved in our computer cache_dir="./example/"
, so there is no need to download it everytime the kernel is restarted.
[2]:
cylinder_ds, prm = x3d.tutorial.open_dataset(
"cylinder", cache=True, cache_dir="./example/"
)
let’s take a look at the dataset:
[3]:
cylinder_ds.info()
xarray.Dataset {
dimensions:
i = 2 ;
x = 257 ;
y = 128 ;
t = 201 ;
variables:
float32 u(i, x, y, t) ;
float32 pp(x, y, t) ;
float32 epsi(x, y) ;
float64 x(x) ;
float64 y(y) ;
float64 t(t) ;
object i(i) ;
// global attributes:
:xcompact3d_version = v3.0-397-gff531df ;
:xcompact3d_toolbox_version = 1.0.1 ;
:url = https://github.com/fschuch/xcompact3d_toolbox_data ;
:dataset_license = MIT License ;
}
We got a xarray.Dataset with the variables u
(velocity vector), pp
(pressure) and epsi
(describes the geometry), their coordinates (x
, y
, t
and i
) and some atributes like the xcompact3d_version
used to run this simulation, the url
where you can find the dataset, and others.
In the next block, we configure the toolbox and some atributes at the dataset, so we can write all the binary fields to the disc. Do not worry about the details right now, this is just the preparation step, we are going to discuss them later.
[4]:
x3d.param["mytype"] = np.float32
prm.dataset.set(data_path="./data/", drop_coords="z")
cylinder_ds.u.attrs["file_name"] = "u"
cylinder_ds.pp.attrs["file_name"] = "pp"
cylinder_ds.epsi.attrs["file_name"] = "epsilon"
prm.write("input.i3d")
prm.dataset.write(cylinder_ds)
prm.dataset.write_xdmf("xy-planes.xdmf")
del cylinder_ds, prm
After that, the files are organized as follow:
tutorial
│ computing_and_plotting.ipynb
│ io.ipynb
│ input.i3d
│ parameters.ipynb
│ xy-planes.xdmf
│
└─── data
│ │ epsilon.bin
│ │ pp-000.bin
│ │ pp-001.bin
│ │ ...
│ │ pp-199.bin
│ │ pp-200.bin
│ │ ux-000.bin
│ │ ux-001.bin
│ │ ...
│ │ ux-199.bin
│ │ ux-200.bin
│ │ uy-000.bin
│ │ uy-001.bin
│ │ ...
│ │ uy-199.bin
│ │ uy-200.bin
│ │ uz-000.bin
│ │ uz-001.bin
│ │ ...
│ │ uz-199.bin
│ │ uz-200.bin
│
└─── example
│ │ cylinder.nc
It is very similar to what we get after successfully running a simulation, so now we can move on to the tutorial.
Why xarray?¶
The data structures are provided by xarray, that introduces labels in the form of dimensions, coordinates and attributes on top of raw NumPy-like arrays, which allows for a more intuitive, more concise, and less error-prone developer experience. It integrates tightly with dask for parallel computing.
The goal here is to speed up the development of customized post-processing applications with the concise interface provided by xarray. Ultimately, we can compute solutions with fewer lines of code and better readability, so we expend less time testing and debugging and more time exploring our datasets and getting insights.
Additionally, xcompact3d-toolbox includes extra functionalities for DataArray and Dataset.
Before going forward, please, take a look at Overview: Why xarray? and Quick overview to understand the motivation to use xarray’s data structures instead of just numpy-like arrays.
Xarray objects on demand¶
To start our post-processing, let’s load the parameters file:
[5]:
prm = x3d.Parameters(loadfile="input.i3d")
Notice there is an entire tutorial dedicated to it.
To save space on the disc, our dataset was converted from double precision to single, so we have to configure the toolbox to:
[6]:
x3d.param["mytype"] = np.float32
The methods in the toolbox support different filename properties, like the classic ux000
or the new ux-0000.bin
, besides some combinations between them. For our case, we set the parameters as:
[7]:
prm.dataset.filename_properties.set(
separator = "-",
file_extension = ".bin",
number_of_digits = 3,
)
Now we specify the parameters for our dataset, like where it is found (data_path
), if it needs to drop some coordinate (drop_coords
, again, to save space, we are working with a span-wise averaged dataset, so we drop z
to work with xy
planes), we inform the parameter that controls the number of timesteps snapshot_counting
and their step snapshot_step
. Consult the dataset
documentation to see different ways to customize your experience, and choose the ones that best suits your post-processing application. In this example, they are defined as:
[8]:
prm.dataset.set(
data_path="./data/",
drop_coords="z",
snapshot_counting="ilast",
snapshot_step="ioutput"
)
Now we are good to go.
We can check the length of the dataset we are dealing with:
[9]:
len(prm.dataset)
[9]:
201
Meaning that our binary files range from 0 (i.g., ux-000.bin
) to 200 (i.g., ux-200.bin
), exactly as expected.
It is possible to load any given array:
[10]:
epsilon = prm.dataset.load_array("./data/epsilon.bin", add_time=False)
Notice that load_array requires the entire path to the file, and we use add_time=False
because this array does not evolve in time like the others, i.e., it is not numerated for several snapshots.
We can see it on the screen:
[11]:
epsilon
[11]:
<xarray.DataArray (x: 257, y: 128)> array([[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], dtype=float32) Coordinates: * x (x) float32 0.0 0.07812 0.1562 0.2344 ... 19.77 19.84 19.92 20.0 * y (y) float32 0.0 0.09375 0.1875 0.2812 ... 11.62 11.72 11.81 11.91
- x: 257
- y: 128
- 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
array([[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], dtype=float32)
- x(x)float320.0 0.07812 0.1562 ... 19.92 20.0
array([ 0. , 0.078125, 0.15625 , ..., 19.84375 , 19.921875, 20. ], dtype=float32)
- y(y)float320.0 0.09375 0.1875 ... 11.81 11.91
array([ 0. , 0.09375, 0.1875 , 0.28125, 0.375 , 0.46875, 0.5625 , 0.65625, 0.75 , 0.84375, 0.9375 , 1.03125, 1.125 , 1.21875, 1.3125 , 1.40625, 1.5 , 1.59375, 1.6875 , 1.78125, 1.875 , 1.96875, 2.0625 , 2.15625, 2.25 , 2.34375, 2.4375 , 2.53125, 2.625 , 2.71875, 2.8125 , 2.90625, 3. , 3.09375, 3.1875 , 3.28125, 3.375 , 3.46875, 3.5625 , 3.65625, 3.75 , 3.84375, 3.9375 , 4.03125, 4.125 , 4.21875, 4.3125 , 4.40625, 4.5 , 4.59375, 4.6875 , 4.78125, 4.875 , 4.96875, 5.0625 , 5.15625, 5.25 , 5.34375, 5.4375 , 5.53125, 5.625 , 5.71875, 5.8125 , 5.90625, 6. , 6.09375, 6.1875 , 6.28125, 6.375 , 6.46875, 6.5625 , 6.65625, 6.75 , 6.84375, 6.9375 , 7.03125, 7.125 , 7.21875, 7.3125 , 7.40625, 7.5 , 7.59375, 7.6875 , 7.78125, 7.875 , 7.96875, 8.0625 , 8.15625, 8.25 , 8.34375, 8.4375 , 8.53125, 8.625 , 8.71875, 8.8125 , 8.90625, 9. , 9.09375, 9.1875 , 9.28125, 9.375 , 9.46875, 9.5625 , 9.65625, 9.75 , 9.84375, 9.9375 , 10.03125, 10.125 , 10.21875, 10.3125 , 10.40625, 10.5 , 10.59375, 10.6875 , 10.78125, 10.875 , 10.96875, 11.0625 , 11.15625, 11.25 , 11.34375, 11.4375 , 11.53125, 11.625 , 11.71875, 11.8125 , 11.90625], dtype=float32)
Let’s do it again, this time for ux
and using add_time=True
:
[12]:
ux = prm.dataset.load_array("./data/ux-100.bin", add_time=True)
See that t
is now a coordinate, and for this snapshot it was computed automatically as dimensionless time 75.0
:
[13]:
ux
[13]:
<xarray.DataArray 'ux' (x: 257, y: 128, t: 1)> array([[[1. ], [1. ], [1. ], ..., [1. ], [1. ], [1. ]], [[1.0000466 ], [0.99996716], [1.0000466 ], ..., [0.9999681 ], [1.0000459 ], [0.9999675 ]], [[1.0000602 ], [1.0000144 ], [1.0000602 ], ..., ... ..., [1.0140737 ], [1.0142432 ], [1.0144366 ]], [[1.0146521 ], [1.0148891 ], [1.0151588 ], ..., [1.0141058 ], [1.0142633 ], [1.0144445 ]], [[1.0146475 ], [1.0148702 ], [1.0151254 ], ..., [1.014144 ], [1.0142874 ], [1.014454 ]]], dtype=float32) Coordinates: * x (x) float32 0.0 0.07812 0.1562 0.2344 ... 19.77 19.84 19.92 20.0 * y (y) float32 0.0 0.09375 0.1875 0.2812 ... 11.62 11.72 11.81 11.91 * t (t) float32 75.0
- x: 257
- y: 128
- t: 1
- 1.0 1.0 1.0 1.0 1.0 1.0 1.0 ... 1.014 1.014 1.014 1.014 1.014 1.014
array([[[1. ], [1. ], [1. ], ..., [1. ], [1. ], [1. ]], [[1.0000466 ], [0.99996716], [1.0000466 ], ..., [0.9999681 ], [1.0000459 ], [0.9999675 ]], [[1.0000602 ], [1.0000144 ], [1.0000602 ], ..., ... ..., [1.0140737 ], [1.0142432 ], [1.0144366 ]], [[1.0146521 ], [1.0148891 ], [1.0151588 ], ..., [1.0141058 ], [1.0142633 ], [1.0144445 ]], [[1.0146475 ], [1.0148702 ], [1.0151254 ], ..., [1.014144 ], [1.0142874 ], [1.014454 ]]], dtype=float32)
- x(x)float320.0 0.07812 0.1562 ... 19.92 20.0
array([ 0. , 0.078125, 0.15625 , ..., 19.84375 , 19.921875, 20. ], dtype=float32)
- y(y)float320.0 0.09375 0.1875 ... 11.81 11.91
array([ 0. , 0.09375, 0.1875 , 0.28125, 0.375 , 0.46875, 0.5625 , 0.65625, 0.75 , 0.84375, 0.9375 , 1.03125, 1.125 , 1.21875, 1.3125 , 1.40625, 1.5 , 1.59375, 1.6875 , 1.78125, 1.875 , 1.96875, 2.0625 , 2.15625, 2.25 , 2.34375, 2.4375 , 2.53125, 2.625 , 2.71875, 2.8125 , 2.90625, 3. , 3.09375, 3.1875 , 3.28125, 3.375 , 3.46875, 3.5625 , 3.65625, 3.75 , 3.84375, 3.9375 , 4.03125, 4.125 , 4.21875, 4.3125 , 4.40625, 4.5 , 4.59375, 4.6875 , 4.78125, 4.875 , 4.96875, 5.0625 , 5.15625, 5.25 , 5.34375, 5.4375 , 5.53125, 5.625 , 5.71875, 5.8125 , 5.90625, 6. , 6.09375, 6.1875 , 6.28125, 6.375 , 6.46875, 6.5625 , 6.65625, 6.75 , 6.84375, 6.9375 , 7.03125, 7.125 , 7.21875, 7.3125 , 7.40625, 7.5 , 7.59375, 7.6875 , 7.78125, 7.875 , 7.96875, 8.0625 , 8.15625, 8.25 , 8.34375, 8.4375 , 8.53125, 8.625 , 8.71875, 8.8125 , 8.90625, 9. , 9.09375, 9.1875 , 9.28125, 9.375 , 9.46875, 9.5625 , 9.65625, 9.75 , 9.84375, 9.9375 , 10.03125, 10.125 , 10.21875, 10.3125 , 10.40625, 10.5 , 10.59375, 10.6875 , 10.78125, 10.875 , 10.96875, 11.0625 , 11.15625, 11.25 , 11.34375, 11.4375 , 11.53125, 11.625 , 11.71875, 11.8125 , 11.90625], dtype=float32)
- t(t)float3275.0
array([75.], dtype=float32)
That is not all. If you have enough memory, you can load the entire time series for a given variable with load_time_series, or simply by:
[14]:
ux = prm.dataset["ux"]
Let’s see it (note 201 files are loaded and wrapped with the appropriate coordinates):
[15]:
ux
[15]:
<xarray.DataArray 'ux' (x: 257, y: 128, t: 201)> array([[[0.9999885 , 1. , 1. , ..., 1. , 1. , 1. ], [0.9999782 , 1. , 1. , ..., 1. , 1. , 1. ], [0.9999907 , 1. , 1. , ..., 1. , 1. , 1. ], ..., [1.0000122 , 1. , 1. , ..., 1. , 1. , 1. ], [0.99999744, 1. , 1. , ..., 1. , 1. , 1. ], [0.9999945 , 1. , 1. , ..., 1. , 1. , 1. ]], [[0.99999535, 1.0000458 , 1.0000486 , ..., 1.0000464 , 1.0000468 , 1.0000476 ], [1.0000107 , 0.99997103, 0.99996907, ..., 0.9999675 , 0.99996674, 0.9999665 ], [1.0000069 , 1.0000455 , 1.0000486 , ..., 1.0000459 , 1.0000468 , 1.0000478 ], ... [0.9999908 , 1.0001078 , 1.000192 , ..., 1.0155317 , 1.0153327 , 1.0146557 ], [0.9999987 , 1.0001054 , 1.0001911 , ..., 1.0152053 , 1.0150691 , 1.0146141 ], [0.9999874 , 1.0000997 , 1.0001901 , ..., 1.0149139 , 1.0148364 , 1.0145978 ]], [[1.0000043 , 1.0000877 , 1.0001792 , ..., 1.0146514 , 1.0146394 , 1.0146087 ], [1.0000119 , 1.0000889 , 1.0001761 , ..., 1.014433 , 1.0144511 , 1.0146273 ], [1.0000004 , 1.0000932 , 1.000174 , ..., 1.0142416 , 1.0142918 , 1.0146769 ], ..., [1.0000123 , 1.0000978 , 1.0001832 , ..., 1.0154953 , 1.0153852 , 1.0147215 ], [0.99998474, 1.000096 , 1.0001816 , ..., 1.0151795 , 1.0151051 , 1.0146575 ], [0.99999154, 1.0000918 , 1.0001806 , ..., 1.0148991 , 1.0148568 , 1.0146192 ]]], dtype=float32) Coordinates: * x (x) float32 0.0 0.07812 0.1562 0.2344 ... 19.77 19.84 19.92 20.0 * y (y) float32 0.0 0.09375 0.1875 0.2812 ... 11.62 11.72 11.81 11.91 * t (t) float64 0.0 0.75 1.5 2.25 3.0 ... 147.0 147.8 148.5 149.2 150.0
- x: 257
- y: 128
- t: 201
- 1.0 1.0 1.0 1.0 1.0 1.0 1.0 ... 1.014 1.014 1.015 1.015 1.015 1.015
array([[[0.9999885 , 1. , 1. , ..., 1. , 1. , 1. ], [0.9999782 , 1. , 1. , ..., 1. , 1. , 1. ], [0.9999907 , 1. , 1. , ..., 1. , 1. , 1. ], ..., [1.0000122 , 1. , 1. , ..., 1. , 1. , 1. ], [0.99999744, 1. , 1. , ..., 1. , 1. , 1. ], [0.9999945 , 1. , 1. , ..., 1. , 1. , 1. ]], [[0.99999535, 1.0000458 , 1.0000486 , ..., 1.0000464 , 1.0000468 , 1.0000476 ], [1.0000107 , 0.99997103, 0.99996907, ..., 0.9999675 , 0.99996674, 0.9999665 ], [1.0000069 , 1.0000455 , 1.0000486 , ..., 1.0000459 , 1.0000468 , 1.0000478 ], ... [0.9999908 , 1.0001078 , 1.000192 , ..., 1.0155317 , 1.0153327 , 1.0146557 ], [0.9999987 , 1.0001054 , 1.0001911 , ..., 1.0152053 , 1.0150691 , 1.0146141 ], [0.9999874 , 1.0000997 , 1.0001901 , ..., 1.0149139 , 1.0148364 , 1.0145978 ]], [[1.0000043 , 1.0000877 , 1.0001792 , ..., 1.0146514 , 1.0146394 , 1.0146087 ], [1.0000119 , 1.0000889 , 1.0001761 , ..., 1.014433 , 1.0144511 , 1.0146273 ], [1.0000004 , 1.0000932 , 1.000174 , ..., 1.0142416 , 1.0142918 , 1.0146769 ], ..., [1.0000123 , 1.0000978 , 1.0001832 , ..., 1.0154953 , 1.0153852 , 1.0147215 ], [0.99998474, 1.000096 , 1.0001816 , ..., 1.0151795 , 1.0151051 , 1.0146575 ], [0.99999154, 1.0000918 , 1.0001806 , ..., 1.0148991 , 1.0148568 , 1.0146192 ]]], dtype=float32)
- x(x)float320.0 0.07812 0.1562 ... 19.92 20.0
array([ 0. , 0.078125, 0.15625 , ..., 19.84375 , 19.921875, 20. ], dtype=float32)
- y(y)float320.0 0.09375 0.1875 ... 11.81 11.91
array([ 0. , 0.09375, 0.1875 , 0.28125, 0.375 , 0.46875, 0.5625 , 0.65625, 0.75 , 0.84375, 0.9375 , 1.03125, 1.125 , 1.21875, 1.3125 , 1.40625, 1.5 , 1.59375, 1.6875 , 1.78125, 1.875 , 1.96875, 2.0625 , 2.15625, 2.25 , 2.34375, 2.4375 , 2.53125, 2.625 , 2.71875, 2.8125 , 2.90625, 3. , 3.09375, 3.1875 , 3.28125, 3.375 , 3.46875, 3.5625 , 3.65625, 3.75 , 3.84375, 3.9375 , 4.03125, 4.125 , 4.21875, 4.3125 , 4.40625, 4.5 , 4.59375, 4.6875 , 4.78125, 4.875 , 4.96875, 5.0625 , 5.15625, 5.25 , 5.34375, 5.4375 , 5.53125, 5.625 , 5.71875, 5.8125 , 5.90625, 6. , 6.09375, 6.1875 , 6.28125, 6.375 , 6.46875, 6.5625 , 6.65625, 6.75 , 6.84375, 6.9375 , 7.03125, 7.125 , 7.21875, 7.3125 , 7.40625, 7.5 , 7.59375, 7.6875 , 7.78125, 7.875 , 7.96875, 8.0625 , 8.15625, 8.25 , 8.34375, 8.4375 , 8.53125, 8.625 , 8.71875, 8.8125 , 8.90625, 9. , 9.09375, 9.1875 , 9.28125, 9.375 , 9.46875, 9.5625 , 9.65625, 9.75 , 9.84375, 9.9375 , 10.03125, 10.125 , 10.21875, 10.3125 , 10.40625, 10.5 , 10.59375, 10.6875 , 10.78125, 10.875 , 10.96875, 11.0625 , 11.15625, 11.25 , 11.34375, 11.4375 , 11.53125, 11.625 , 11.71875, 11.8125 , 11.90625], dtype=float32)
- t(t)float640.0 0.75 1.5 ... 148.5 149.2 150.0
array([ 0. , 0.75, 1.5 , ..., 148.5 , 149.25, 150. ])
You can store each array in a different variable, like:
[16]:
ux = prm.dataset["ux"]
uy = prm.dataset["uy"]
pp = prm.dataset["pp"]
Or organize many arrays in a dataset:
[17]:
# create an empty dataset
ds = xr.Dataset()
# populate it
for var in ["ux", "uy", "pp"]:
ds[var] = prm.dataset[var]
# show on the screen
ds
[17]:
<xarray.Dataset> Dimensions: (x: 257, y: 128, t: 201) Coordinates: * x (x) float32 0.0 0.07812 0.1562 0.2344 ... 19.77 19.84 19.92 20.0 * y (y) float32 0.0 0.09375 0.1875 0.2812 ... 11.62 11.72 11.81 11.91 * t (t) float64 0.0 0.75 1.5 2.25 3.0 ... 147.0 147.8 148.5 149.2 150.0 Data variables: ux (x, y, t) float32 1.0 1.0 1.0 1.0 1.0 ... 1.015 1.015 1.015 1.015 uy (x, y, t) float32 9.98e-06 8.496e-08 ... -0.0005357 0.003209 pp (x, y, t) float32 0.0 0.03264 0.03613 ... 0.04078 0.03922 0.03859
- x: 257
- y: 128
- t: 201
- x(x)float320.0 0.07812 0.1562 ... 19.92 20.0
array([ 0. , 0.078125, 0.15625 , ..., 19.84375 , 19.921875, 20. ], dtype=float32)
- y(y)float320.0 0.09375 0.1875 ... 11.81 11.91
array([ 0. , 0.09375, 0.1875 , 0.28125, 0.375 , 0.46875, 0.5625 , 0.65625, 0.75 , 0.84375, 0.9375 , 1.03125, 1.125 , 1.21875, 1.3125 , 1.40625, 1.5 , 1.59375, 1.6875 , 1.78125, 1.875 , 1.96875, 2.0625 , 2.15625, 2.25 , 2.34375, 2.4375 , 2.53125, 2.625 , 2.71875, 2.8125 , 2.90625, 3. , 3.09375, 3.1875 , 3.28125, 3.375 , 3.46875, 3.5625 , 3.65625, 3.75 , 3.84375, 3.9375 , 4.03125, 4.125 , 4.21875, 4.3125 , 4.40625, 4.5 , 4.59375, 4.6875 , 4.78125, 4.875 , 4.96875, 5.0625 , 5.15625, 5.25 , 5.34375, 5.4375 , 5.53125, 5.625 , 5.71875, 5.8125 , 5.90625, 6. , 6.09375, 6.1875 , 6.28125, 6.375 , 6.46875, 6.5625 , 6.65625, 6.75 , 6.84375, 6.9375 , 7.03125, 7.125 , 7.21875, 7.3125 , 7.40625, 7.5 , 7.59375, 7.6875 , 7.78125, 7.875 , 7.96875, 8.0625 , 8.15625, 8.25 , 8.34375, 8.4375 , 8.53125, 8.625 , 8.71875, 8.8125 , 8.90625, 9. , 9.09375, 9.1875 , 9.28125, 9.375 , 9.46875, 9.5625 , 9.65625, 9.75 , 9.84375, 9.9375 , 10.03125, 10.125 , 10.21875, 10.3125 , 10.40625, 10.5 , 10.59375, 10.6875 , 10.78125, 10.875 , 10.96875, 11.0625 , 11.15625, 11.25 , 11.34375, 11.4375 , 11.53125, 11.625 , 11.71875, 11.8125 , 11.90625], dtype=float32)
- t(t)float640.0 0.75 1.5 ... 148.5 149.2 150.0
array([ 0. , 0.75, 1.5 , ..., 148.5 , 149.25, 150. ])
- ux(x, y, t)float321.0 1.0 1.0 ... 1.015 1.015 1.015
array([[[0.9999885 , 1. , 1. , ..., 1. , 1. , 1. ], [0.9999782 , 1. , 1. , ..., 1. , 1. , 1. ], [0.9999907 , 1. , 1. , ..., 1. , 1. , 1. ], ..., [1.0000122 , 1. , 1. , ..., 1. , 1. , 1. ], [0.99999744, 1. , 1. , ..., 1. , 1. , 1. ], [0.9999945 , 1. , 1. , ..., 1. , 1. , 1. ]], [[0.99999535, 1.0000458 , 1.0000486 , ..., 1.0000464 , 1.0000468 , 1.0000476 ], [1.0000107 , 0.99997103, 0.99996907, ..., 0.9999675 , 0.99996674, 0.9999665 ], [1.0000069 , 1.0000455 , 1.0000486 , ..., 1.0000459 , 1.0000468 , 1.0000478 ], ... [0.9999908 , 1.0001078 , 1.000192 , ..., 1.0155317 , 1.0153327 , 1.0146557 ], [0.9999987 , 1.0001054 , 1.0001911 , ..., 1.0152053 , 1.0150691 , 1.0146141 ], [0.9999874 , 1.0000997 , 1.0001901 , ..., 1.0149139 , 1.0148364 , 1.0145978 ]], [[1.0000043 , 1.0000877 , 1.0001792 , ..., 1.0146514 , 1.0146394 , 1.0146087 ], [1.0000119 , 1.0000889 , 1.0001761 , ..., 1.014433 , 1.0144511 , 1.0146273 ], [1.0000004 , 1.0000932 , 1.000174 , ..., 1.0142416 , 1.0142918 , 1.0146769 ], ..., [1.0000123 , 1.0000978 , 1.0001832 , ..., 1.0154953 , 1.0153852 , 1.0147215 ], [0.99998474, 1.000096 , 1.0001816 , ..., 1.0151795 , 1.0151051 , 1.0146575 ], [0.99999154, 1.0000918 , 1.0001806 , ..., 1.0148991 , 1.0148568 , 1.0146192 ]]], dtype=float32)
- uy(x, y, t)float329.98e-06 8.496e-08 ... 0.003209
array([[[ 9.97988354e-06, 8.49550474e-08, 7.13089747e-08, ..., -8.24902656e-07, -2.60075126e-06, -2.86581985e-06], [ 1.95531647e-05, -7.69747430e-08, -6.73220626e-08, ..., 3.28200031e-07, 2.38231701e-06, 3.15269222e-06], [ 3.23466520e-06, 7.58641789e-08, 6.87333710e-08, ..., -8.22868401e-07, -2.60304864e-06, -2.86488989e-06], ..., [-6.78599736e-06, -6.34202166e-08, -6.34171471e-08, ..., 3.27393138e-07, 2.38772441e-06, 3.14991462e-06], [ 5.60609988e-06, 9.24364798e-08, 7.38993293e-08, ..., -8.25677262e-07, -2.59799208e-06, -2.86752447e-06], [ 4.75289698e-06, -6.79251002e-08, -6.53620873e-08, ..., 3.26972867e-07, 2.38457028e-06, 3.15169700e-06]], [[ 8.17127875e-06, -5.76831951e-07, 2.31006970e-06, ..., 1.04692674e-06, -2.17211462e-04, -2.06557655e-04], [-9.58256805e-06, -2.44471339e-05, -2.38329212e-05, ..., -2.73195601e-05, -2.43618590e-04, -2.29676007e-04], [-1.56297228e-05, -4.50514381e-05, -4.61988166e-05, ..., -4.24469617e-05, -2.60806963e-04, -2.51242163e-04], ... -7.39102345e-03, 5.73747639e-05, 3.82003514e-03], [-3.16069963e-06, -2.01298026e-04, -1.89392798e-04, ..., -7.35661760e-03, 6.12066970e-06, 3.76115902e-03], [ 1.06863872e-05, -1.87718950e-04, -1.75856665e-04, ..., -7.33621093e-03, -3.47090245e-05, 3.71675403e-03]], [[ 1.14502300e-05, -1.77631853e-04, -1.64712968e-04, ..., -7.52553809e-03, -5.55378327e-04, 3.18954163e-03], [-4.91587525e-06, -1.66795871e-04, -1.52920198e-04, ..., -7.52645032e-03, -5.47196891e-04, 3.20842443e-03], [ 2.38375487e-05, -1.55161368e-04, -1.41728029e-04, ..., -7.54353357e-03, -5.31221100e-04, 3.24137555e-03], ..., [-5.17192575e-06, -2.13182488e-04, -2.02694311e-04, ..., -7.60111213e-03, -4.52007138e-04, 3.31370509e-03], [-2.28461449e-05, -1.99920411e-04, -1.90276100e-04, ..., -7.56283524e-03, -5.08141296e-04, 3.24189453e-03], [ 1.96180008e-05, -1.87553553e-04, -1.77575974e-04, ..., -7.53604714e-03, -5.35702275e-04, 3.20866751e-03]]], dtype=float32)
- pp(x, y, t)float320.0 0.03264 ... 0.03922 0.03859
array([[[ 0. , 0.03264126, 0.03612559, ..., 0.05173054, 0.05321342, 0.0555568 ], [ 0. , 0.03249451, 0.03596627, ..., 0.0515916 , 0.05332436, 0.05563498], [ 0. , 0.03269685, 0.03618003, ..., 0.05181858, 0.05380777, 0.05609087], ..., [ 0. , 0.03260394, 0.03610066, ..., 0.05163186, 0.05236094, 0.05479917], [ 0. , 0.03269532, 0.03619223, ..., 0.05175101, 0.05272993, 0.05513581], [ 0. , 0.03249378, 0.03597238, ..., 0.05155691, 0.05278588, 0.05515926]], [[ 0. , 0.03256193, 0.03604122, ..., 0.05164916, 0.05313087, 0.05547334], [ 0. , 0.03255073, 0.03602634, ..., 0.05165312, 0.05338719, 0.05569855], [ 0. , 0.03261778, 0.03609589, ..., 0.05173779, 0.05372536, 0.05600698], ... [ 0. , -0.00597118, -0.00516765, ..., 0.04166358, 0.04048561, 0.04038416], [ 0. , -0.00597305, -0.00516866, ..., 0.04122475, 0.03985312, 0.03948712], [ 0. , -0.00597509, -0.00516978, ..., 0.04078778, 0.03922178, 0.03859093]], [[ 0. , -0.00597691, -0.00517167, ..., 0.04035036, 0.03859136, 0.03769449], [ 0. , -0.00597803, -0.00517183, ..., 0.03991735, 0.03795951, 0.03679422], [ 0. , -0.00598033, -0.00517296, ..., 0.03948206, 0.03732474, 0.03588924], ..., [ 0. , -0.00597219, -0.00516751, ..., 0.04165559, 0.04048872, 0.04039202], [ 0. , -0.00597349, -0.00516917, ..., 0.04121848, 0.03985493, 0.03949196], [ 0. , -0.00597574, -0.00516981, ..., 0.04078456, 0.03922356, 0.03859415]]], dtype=float32)
It is possible to load all the variables from a given snapshot with load_snapshot, or simply:
[18]:
snapshot = prm.dataset[100]
And we got a xarray.Dataset with all the variables and their coordinates. You can access each of them with the dot notation (i.g., snapshot.pp
, snapshot.ux
, snapshot.uy
) or the dict-like notation (i.g., snapshot["pp"]
, snapshot["ux"]
, snapshot["uy"]
). See the dataset:
[19]:
snapshot
[19]:
<xarray.Dataset> Dimensions: (x: 257, y: 128, t: 1) Coordinates: * x (x) float32 0.0 0.07812 0.1562 0.2344 ... 19.77 19.84 19.92 20.0 * y (y) float32 0.0 0.09375 0.1875 0.2812 ... 11.62 11.72 11.81 11.91 * t (t) float32 75.0 Data variables: pp (x, y, t) float32 0.05232 0.05219 0.05243 ... 0.03986 0.03989 ux (x, y, t) float32 1.0 1.0 1.0 1.0 1.0 ... 1.014 1.014 1.014 1.014 uy (x, y, t) float32 3.407e-07 1.503e-07 ... 0.007724 0.007703
- x: 257
- y: 128
- t: 1
- x(x)float320.0 0.07812 0.1562 ... 19.92 20.0
array([ 0. , 0.078125, 0.15625 , ..., 19.84375 , 19.921875, 20. ], dtype=float32)
- y(y)float320.0 0.09375 0.1875 ... 11.81 11.91
array([ 0. , 0.09375, 0.1875 , 0.28125, 0.375 , 0.46875, 0.5625 , 0.65625, 0.75 , 0.84375, 0.9375 , 1.03125, 1.125 , 1.21875, 1.3125 , 1.40625, 1.5 , 1.59375, 1.6875 , 1.78125, 1.875 , 1.96875, 2.0625 , 2.15625, 2.25 , 2.34375, 2.4375 , 2.53125, 2.625 , 2.71875, 2.8125 , 2.90625, 3. , 3.09375, 3.1875 , 3.28125, 3.375 , 3.46875, 3.5625 , 3.65625, 3.75 , 3.84375, 3.9375 , 4.03125, 4.125 , 4.21875, 4.3125 , 4.40625, 4.5 , 4.59375, 4.6875 , 4.78125, 4.875 , 4.96875, 5.0625 , 5.15625, 5.25 , 5.34375, 5.4375 , 5.53125, 5.625 , 5.71875, 5.8125 , 5.90625, 6. , 6.09375, 6.1875 , 6.28125, 6.375 , 6.46875, 6.5625 , 6.65625, 6.75 , 6.84375, 6.9375 , 7.03125, 7.125 , 7.21875, 7.3125 , 7.40625, 7.5 , 7.59375, 7.6875 , 7.78125, 7.875 , 7.96875, 8.0625 , 8.15625, 8.25 , 8.34375, 8.4375 , 8.53125, 8.625 , 8.71875, 8.8125 , 8.90625, 9. , 9.09375, 9.1875 , 9.28125, 9.375 , 9.46875, 9.5625 , 9.65625, 9.75 , 9.84375, 9.9375 , 10.03125, 10.125 , 10.21875, 10.3125 , 10.40625, 10.5 , 10.59375, 10.6875 , 10.78125, 10.875 , 10.96875, 11.0625 , 11.15625, 11.25 , 11.34375, 11.4375 , 11.53125, 11.625 , 11.71875, 11.8125 , 11.90625], dtype=float32)
- t(t)float3275.0
array([75.], dtype=float32)
- pp(x, y, t)float320.05232 0.05219 ... 0.03986 0.03989
array([[[0.05232061], [0.05219164], [0.05243129], ..., [0.05219198], [0.05231902], [0.0521366 ]], [[0.05223907], [0.05225366], [0.05234953], ..., [0.05225244], [0.05223813], [0.05219809]], [[0.05220748], [0.05222414], [0.05231803], ..., ... ..., [0.03980655], [0.03984426], [0.03988079]], [[0.03991373], [0.0399437 ], [0.0399735 ], ..., [0.03981845], [0.03985148], [0.03988307]], [[0.03991202], [0.03993938], [0.03996518], ..., [0.03982718], [0.0398563 ], [0.03988532]]], dtype=float32)
- ux(x, y, t)float321.0 1.0 1.0 ... 1.014 1.014 1.014
array([[[1. ], [1. ], [1. ], ..., [1. ], [1. ], [1. ]], [[1.0000466 ], [0.99996716], [1.0000466 ], ..., [0.9999681 ], [1.0000459 ], [0.9999675 ]], [[1.0000602 ], [1.0000144 ], [1.0000602 ], ..., ... ..., [1.0140737 ], [1.0142432 ], [1.0144366 ]], [[1.0146521 ], [1.0148891 ], [1.0151588 ], ..., [1.0141058 ], [1.0142633 ], [1.0144445 ]], [[1.0146475 ], [1.0148702 ], [1.0151254 ], ..., [1.014144 ], [1.0142874 ], [1.014454 ]]], dtype=float32)
- uy(x, y, t)float323.407e-07 1.503e-07 ... 0.007703
array([[[ 3.4073531e-07], [ 1.5034894e-07], [ 3.4228231e-07], ..., [ 1.4578703e-07], [ 3.3796812e-07], [ 1.4887451e-07]], [[-3.8211783e-05], [-5.7585352e-05], [-8.1790080e-05], ..., [ 3.8404520e-05], [ 5.6476906e-06], [-9.7466746e-06]], [[-9.5541123e-05], [-1.4544252e-04], [-1.8961391e-04], ..., ... ..., [ 7.6859673e-03], [ 7.6573351e-03], [ 7.6414165e-03]], [[ 7.7379229e-03], [ 7.7515850e-03], [ 7.7808392e-03], ..., [ 7.7937511e-03], [ 7.7590533e-03], [ 7.7407509e-03]], [[ 7.7001532e-03], [ 7.7144550e-03], [ 7.7471440e-03], ..., [ 7.7630985e-03], [ 7.7244956e-03], [ 7.7031888e-03]]], dtype=float32)
Do you need the snapshots in a range? No problem. Let’s do a slice to load the last 100, and just to exemplify, compute a time average:
[20]:
time_averaged = prm.dataset[-100:].mean("t")
time_averaged
[20]:
<xarray.Dataset> Dimensions: (x: 257, y: 128) Coordinates: * x (x) float32 0.0 0.07812 0.1562 0.2344 ... 19.77 19.84 19.92 20.0 * y (y) float32 0.0 0.09375 0.1875 0.2812 ... 11.62 11.72 11.81 11.91 Data variables: pp (x, y) float32 0.05351 0.05335 0.05356 ... 0.03887 0.03886 0.03886 ux (x, y) float32 1.0 1.0 1.0 1.0 1.0 ... 1.015 1.015 1.015 1.015 uy (x, y) float32 -6.206e-09 2.081e-09 ... -6.504e-05 -6.531e-05
- x: 257
- y: 128
- x(x)float320.0 0.07812 0.1562 ... 19.92 20.0
array([ 0. , 0.078125, 0.15625 , ..., 19.84375 , 19.921875, 20. ], dtype=float32)
- y(y)float320.0 0.09375 0.1875 ... 11.81 11.91
array([ 0. , 0.09375, 0.1875 , 0.28125, 0.375 , 0.46875, 0.5625 , 0.65625, 0.75 , 0.84375, 0.9375 , 1.03125, 1.125 , 1.21875, 1.3125 , 1.40625, 1.5 , 1.59375, 1.6875 , 1.78125, 1.875 , 1.96875, 2.0625 , 2.15625, 2.25 , 2.34375, 2.4375 , 2.53125, 2.625 , 2.71875, 2.8125 , 2.90625, 3. , 3.09375, 3.1875 , 3.28125, 3.375 , 3.46875, 3.5625 , 3.65625, 3.75 , 3.84375, 3.9375 , 4.03125, 4.125 , 4.21875, 4.3125 , 4.40625, 4.5 , 4.59375, 4.6875 , 4.78125, 4.875 , 4.96875, 5.0625 , 5.15625, 5.25 , 5.34375, 5.4375 , 5.53125, 5.625 , 5.71875, 5.8125 , 5.90625, 6. , 6.09375, 6.1875 , 6.28125, 6.375 , 6.46875, 6.5625 , 6.65625, 6.75 , 6.84375, 6.9375 , 7.03125, 7.125 , 7.21875, 7.3125 , 7.40625, 7.5 , 7.59375, 7.6875 , 7.78125, 7.875 , 7.96875, 8.0625 , 8.15625, 8.25 , 8.34375, 8.4375 , 8.53125, 8.625 , 8.71875, 8.8125 , 8.90625, 9. , 9.09375, 9.1875 , 9.28125, 9.375 , 9.46875, 9.5625 , 9.65625, 9.75 , 9.84375, 9.9375 , 10.03125, 10.125 , 10.21875, 10.3125 , 10.40625, 10.5 , 10.59375, 10.6875 , 10.78125, 10.875 , 10.96875, 11.0625 , 11.15625, 11.25 , 11.34375, 11.4375 , 11.53125, 11.625 , 11.71875, 11.8125 , 11.90625], dtype=float32)
- pp(x, y)float320.05351 0.05335 ... 0.03886 0.03886
array([[0.05350577, 0.05334765, 0.05356117, ..., 0.05345961, 0.0535612 , 0.05334766], [0.0534233 , 0.05341006, 0.05347893, ..., 0.05352153, 0.05347894, 0.05341007], [0.05339126, 0.05337996, 0.05344687, ..., 0.05349133, 0.05344689, 0.05337997], ..., [0.03886158, 0.03885861, 0.03885458, ..., 0.03886537, 0.03886495, 0.03886379], [0.03886124, 0.03885819, 0.03885429, ..., 0.03886476, 0.03886453, 0.0388633 ], [0.03886105, 0.03885868, 0.03885414, ..., 0.03886512, 0.03886428, 0.03886374]], dtype=float32)
- ux(x, y)float321.0 1.0 1.0 ... 1.015 1.015 1.015
array([[1. , 1. , 1. , ..., 1. , 1. , 1. ], [1.000047 , 0.9999672, 1.0000467, ..., 0.9999675, 1.0000467, 0.9999672], [1.0000609, 1.0000151, 1.0000609, ..., 1.0000153, 1.0000609, 1.0000149], ..., [1.014633 , 1.0146457, 1.0146878, ..., 1.0147717, 1.014696 , 1.0146499], [1.0146337, 1.0146464, 1.0146886, ..., 1.014772 , 1.0146965, 1.0146502], [1.0146341, 1.0146468, 1.0146891, ..., 1.0147722, 1.0146966, 1.0146506]], dtype=float32)
- uy(x, y)float32-6.206e-09 2.081e-09 ... -6.531e-05
array([[-6.2061507e-09, 2.0807329e-09, -6.2151546e-09, ..., 2.1238338e-09, -6.1867742e-09, 2.0955053e-09], [ 1.2998876e-07, -2.4157436e-05, -4.4205062e-05, ..., 7.2888673e-05, 4.4463806e-05, 2.4339783e-05], [ 4.2155676e-07, -4.4589146e-05, -9.5065327e-05, ..., 1.3574678e-04, 9.5904950e-05, 4.5521323e-05], ..., [-6.4251049e-05, -6.5562090e-05, -6.6985704e-05, ..., -6.0804643e-05, -6.1885214e-05, -6.3014835e-05], [-6.4824388e-05, -6.5339118e-05, -6.5953936e-05, ..., -6.3980537e-05, -6.4151391e-05, -6.4441243e-05], [-6.5726759e-05, -6.6256522e-05, -6.6938665e-05, ..., -6.4873107e-05, -6.5041131e-05, -6.5311178e-05]], dtype=float32)
You can even use the slice notation to load all the snapshots at once:
[21]:
prm.dataset[:]
[21]:
<xarray.Dataset> Dimensions: (x: 257, y: 128, t: 201) Coordinates: * x (x) float32 0.0 0.07812 0.1562 0.2344 ... 19.77 19.84 19.92 20.0 * y (y) float32 0.0 0.09375 0.1875 0.2812 ... 11.62 11.72 11.81 11.91 * t (t) float64 0.0 0.75 1.5 2.25 3.0 ... 147.0 147.8 148.5 149.2 150.0 Data variables: pp (x, y, t) float32 0.0 0.03264 0.03613 ... 0.04078 0.03922 0.03859 ux (x, y, t) float32 1.0 1.0 1.0 1.0 1.0 ... 1.015 1.015 1.015 1.015 uy (x, y, t) float32 9.98e-06 8.496e-08 ... -0.0005357 0.003209
- x: 257
- y: 128
- t: 201
- x(x)float320.0 0.07812 0.1562 ... 19.92 20.0
array([ 0. , 0.078125, 0.15625 , ..., 19.84375 , 19.921875, 20. ], dtype=float32)
- y(y)float320.0 0.09375 0.1875 ... 11.81 11.91
array([ 0. , 0.09375, 0.1875 , 0.28125, 0.375 , 0.46875, 0.5625 , 0.65625, 0.75 , 0.84375, 0.9375 , 1.03125, 1.125 , 1.21875, 1.3125 , 1.40625, 1.5 , 1.59375, 1.6875 , 1.78125, 1.875 , 1.96875, 2.0625 , 2.15625, 2.25 , 2.34375, 2.4375 , 2.53125, 2.625 , 2.71875, 2.8125 , 2.90625, 3. , 3.09375, 3.1875 , 3.28125, 3.375 , 3.46875, 3.5625 , 3.65625, 3.75 , 3.84375, 3.9375 , 4.03125, 4.125 , 4.21875, 4.3125 , 4.40625, 4.5 , 4.59375, 4.6875 , 4.78125, 4.875 , 4.96875, 5.0625 , 5.15625, 5.25 , 5.34375, 5.4375 , 5.53125, 5.625 , 5.71875, 5.8125 , 5.90625, 6. , 6.09375, 6.1875 , 6.28125, 6.375 , 6.46875, 6.5625 , 6.65625, 6.75 , 6.84375, 6.9375 , 7.03125, 7.125 , 7.21875, 7.3125 , 7.40625, 7.5 , 7.59375, 7.6875 , 7.78125, 7.875 , 7.96875, 8.0625 , 8.15625, 8.25 , 8.34375, 8.4375 , 8.53125, 8.625 , 8.71875, 8.8125 , 8.90625, 9. , 9.09375, 9.1875 , 9.28125, 9.375 , 9.46875, 9.5625 , 9.65625, 9.75 , 9.84375, 9.9375 , 10.03125, 10.125 , 10.21875, 10.3125 , 10.40625, 10.5 , 10.59375, 10.6875 , 10.78125, 10.875 , 10.96875, 11.0625 , 11.15625, 11.25 , 11.34375, 11.4375 , 11.53125, 11.625 , 11.71875, 11.8125 , 11.90625], dtype=float32)
- t(t)float640.0 0.75 1.5 ... 148.5 149.2 150.0
array([ 0. , 0.75, 1.5 , ..., 148.5 , 149.25, 150. ])
- pp(x, y, t)float320.0 0.03264 ... 0.03922 0.03859
array([[[ 0. , 0.03264126, 0.03612559, ..., 0.05173054, 0.05321342, 0.0555568 ], [ 0. , 0.03249451, 0.03596627, ..., 0.0515916 , 0.05332436, 0.05563498], [ 0. , 0.03269685, 0.03618003, ..., 0.05181858, 0.05380777, 0.05609087], ..., [ 0. , 0.03260394, 0.03610066, ..., 0.05163186, 0.05236094, 0.05479917], [ 0. , 0.03269532, 0.03619223, ..., 0.05175101, 0.05272993, 0.05513581], [ 0. , 0.03249378, 0.03597238, ..., 0.05155691, 0.05278588, 0.05515926]], [[ 0. , 0.03256193, 0.03604122, ..., 0.05164916, 0.05313087, 0.05547334], [ 0. , 0.03255073, 0.03602634, ..., 0.05165312, 0.05338719, 0.05569855], [ 0. , 0.03261778, 0.03609589, ..., 0.05173779, 0.05372536, 0.05600698], ... [ 0. , -0.00597118, -0.00516765, ..., 0.04166358, 0.04048561, 0.04038416], [ 0. , -0.00597305, -0.00516866, ..., 0.04122475, 0.03985312, 0.03948712], [ 0. , -0.00597509, -0.00516978, ..., 0.04078778, 0.03922178, 0.03859093]], [[ 0. , -0.00597691, -0.00517167, ..., 0.04035036, 0.03859136, 0.03769449], [ 0. , -0.00597803, -0.00517183, ..., 0.03991735, 0.03795951, 0.03679422], [ 0. , -0.00598033, -0.00517296, ..., 0.03948206, 0.03732474, 0.03588924], ..., [ 0. , -0.00597219, -0.00516751, ..., 0.04165559, 0.04048872, 0.04039202], [ 0. , -0.00597349, -0.00516917, ..., 0.04121848, 0.03985493, 0.03949196], [ 0. , -0.00597574, -0.00516981, ..., 0.04078456, 0.03922356, 0.03859415]]], dtype=float32)
- ux(x, y, t)float321.0 1.0 1.0 ... 1.015 1.015 1.015
array([[[0.9999885 , 1. , 1. , ..., 1. , 1. , 1. ], [0.9999782 , 1. , 1. , ..., 1. , 1. , 1. ], [0.9999907 , 1. , 1. , ..., 1. , 1. , 1. ], ..., [1.0000122 , 1. , 1. , ..., 1. , 1. , 1. ], [0.99999744, 1. , 1. , ..., 1. , 1. , 1. ], [0.9999945 , 1. , 1. , ..., 1. , 1. , 1. ]], [[0.99999535, 1.0000458 , 1.0000486 , ..., 1.0000464 , 1.0000468 , 1.0000476 ], [1.0000107 , 0.99997103, 0.99996907, ..., 0.9999675 , 0.99996674, 0.9999665 ], [1.0000069 , 1.0000455 , 1.0000486 , ..., 1.0000459 , 1.0000468 , 1.0000478 ], ... [0.9999908 , 1.0001078 , 1.000192 , ..., 1.0155317 , 1.0153327 , 1.0146557 ], [0.9999987 , 1.0001054 , 1.0001911 , ..., 1.0152053 , 1.0150691 , 1.0146141 ], [0.9999874 , 1.0000997 , 1.0001901 , ..., 1.0149139 , 1.0148364 , 1.0145978 ]], [[1.0000043 , 1.0000877 , 1.0001792 , ..., 1.0146514 , 1.0146394 , 1.0146087 ], [1.0000119 , 1.0000889 , 1.0001761 , ..., 1.014433 , 1.0144511 , 1.0146273 ], [1.0000004 , 1.0000932 , 1.000174 , ..., 1.0142416 , 1.0142918 , 1.0146769 ], ..., [1.0000123 , 1.0000978 , 1.0001832 , ..., 1.0154953 , 1.0153852 , 1.0147215 ], [0.99998474, 1.000096 , 1.0001816 , ..., 1.0151795 , 1.0151051 , 1.0146575 ], [0.99999154, 1.0000918 , 1.0001806 , ..., 1.0148991 , 1.0148568 , 1.0146192 ]]], dtype=float32)
- uy(x, y, t)float329.98e-06 8.496e-08 ... 0.003209
array([[[ 9.97988354e-06, 8.49550474e-08, 7.13089747e-08, ..., -8.24902656e-07, -2.60075126e-06, -2.86581985e-06], [ 1.95531647e-05, -7.69747430e-08, -6.73220626e-08, ..., 3.28200031e-07, 2.38231701e-06, 3.15269222e-06], [ 3.23466520e-06, 7.58641789e-08, 6.87333710e-08, ..., -8.22868401e-07, -2.60304864e-06, -2.86488989e-06], ..., [-6.78599736e-06, -6.34202166e-08, -6.34171471e-08, ..., 3.27393138e-07, 2.38772441e-06, 3.14991462e-06], [ 5.60609988e-06, 9.24364798e-08, 7.38993293e-08, ..., -8.25677262e-07, -2.59799208e-06, -2.86752447e-06], [ 4.75289698e-06, -6.79251002e-08, -6.53620873e-08, ..., 3.26972867e-07, 2.38457028e-06, 3.15169700e-06]], [[ 8.17127875e-06, -5.76831951e-07, 2.31006970e-06, ..., 1.04692674e-06, -2.17211462e-04, -2.06557655e-04], [-9.58256805e-06, -2.44471339e-05, -2.38329212e-05, ..., -2.73195601e-05, -2.43618590e-04, -2.29676007e-04], [-1.56297228e-05, -4.50514381e-05, -4.61988166e-05, ..., -4.24469617e-05, -2.60806963e-04, -2.51242163e-04], ... -7.39102345e-03, 5.73747639e-05, 3.82003514e-03], [-3.16069963e-06, -2.01298026e-04, -1.89392798e-04, ..., -7.35661760e-03, 6.12066970e-06, 3.76115902e-03], [ 1.06863872e-05, -1.87718950e-04, -1.75856665e-04, ..., -7.33621093e-03, -3.47090245e-05, 3.71675403e-03]], [[ 1.14502300e-05, -1.77631853e-04, -1.64712968e-04, ..., -7.52553809e-03, -5.55378327e-04, 3.18954163e-03], [-4.91587525e-06, -1.66795871e-04, -1.52920198e-04, ..., -7.52645032e-03, -5.47196891e-04, 3.20842443e-03], [ 2.38375487e-05, -1.55161368e-04, -1.41728029e-04, ..., -7.54353357e-03, -5.31221100e-04, 3.24137555e-03], ..., [-5.17192575e-06, -2.13182488e-04, -2.02694311e-04, ..., -7.60111213e-03, -4.52007138e-04, 3.31370509e-03], [-2.28461449e-05, -1.99920411e-04, -1.90276100e-04, ..., -7.56283524e-03, -5.08141296e-04, 3.24189453e-03], [ 1.96180008e-05, -1.87553553e-04, -1.77575974e-04, ..., -7.53604714e-03, -5.35702275e-04, 3.20866751e-03]]], dtype=float32)
Of course, some simulations may not fit in the memory like in this tutorial. For these cases we can iterate over all snapshots, loading them one by one:
[22]:
for ds in prm.dataset:
# Computing the vorticity, just to exemplify
vort = ds.uy.x3d.first_derivative("x") - ds.ux.x3d.first_derivative("y")
Note that reversed(prm.dataset)
also works.
Or for better control, we can iterate over a selected range of snapshots loading them one by one. The arguments are the same of a classic range in Python:
[23]:
for ds in prm.dataset(100, 200, 1):
# Computing the vorticity, just to exemplify
vort = ds.uy.x3d.first_derivative("x") - ds.ux.x3d.first_derivative("y")
[24]:
# Result from the last iteration
vort
[24]:
<xarray.DataArray (y: 128, t: 1, x: 257)> array([[[-0.00268999, 0.00181677, 0.0001196 , ..., 0.00324146, 0.00302246, -0.01646465]], [[-0.0034743 , -0.00406752, -0.00344934, ..., 0.0029434 , 0.00254392, -0.01612649]], [[-0.00303078, -0.00340789, -0.0030852 , ..., 0.0026302 , 0.0024012 , -0.01718407]], ..., [[-0.00178402, -0.00190772, -0.00161242, ..., 0.00415556, 0.00375753, -0.01497194]], [[-0.00232817, -0.00317189, -0.00255065, ..., 0.00385816, 0.00362989, -0.01590095]], [[-0.00263563, 0.00207518, 0.00038911, ..., 0.00355052, 0.00316822, -0.01547501]]], dtype=float32) Coordinates: * x (x) float32 0.0 0.07812 0.1562 0.2344 ... 19.77 19.84 19.92 20.0 * y (y) float32 0.0 0.09375 0.1875 0.2812 ... 11.62 11.72 11.81 11.91 * t (t) float32 149.2
- y: 128
- t: 1
- x: 257
- -0.00269 0.001817 0.0001196 -0.0013 ... 0.003551 0.003168 -0.01548
array([[[-0.00268999, 0.00181677, 0.0001196 , ..., 0.00324146, 0.00302246, -0.01646465]], [[-0.0034743 , -0.00406752, -0.00344934, ..., 0.0029434 , 0.00254392, -0.01612649]], [[-0.00303078, -0.00340789, -0.0030852 , ..., 0.0026302 , 0.0024012 , -0.01718407]], ..., [[-0.00178402, -0.00190772, -0.00161242, ..., 0.00415556, 0.00375753, -0.01497194]], [[-0.00232817, -0.00317189, -0.00255065, ..., 0.00385816, 0.00362989, -0.01590095]], [[-0.00263563, 0.00207518, 0.00038911, ..., 0.00355052, 0.00316822, -0.01547501]]], dtype=float32)
- x(x)float320.0 0.07812 0.1562 ... 19.92 20.0
array([ 0. , 0.078125, 0.15625 , ..., 19.84375 , 19.921875, 20. ], dtype=float32)
- y(y)float320.0 0.09375 0.1875 ... 11.81 11.91
array([ 0. , 0.09375, 0.1875 , 0.28125, 0.375 , 0.46875, 0.5625 , 0.65625, 0.75 , 0.84375, 0.9375 , 1.03125, 1.125 , 1.21875, 1.3125 , 1.40625, 1.5 , 1.59375, 1.6875 , 1.78125, 1.875 , 1.96875, 2.0625 , 2.15625, 2.25 , 2.34375, 2.4375 , 2.53125, 2.625 , 2.71875, 2.8125 , 2.90625, 3. , 3.09375, 3.1875 , 3.28125, 3.375 , 3.46875, 3.5625 , 3.65625, 3.75 , 3.84375, 3.9375 , 4.03125, 4.125 , 4.21875, 4.3125 , 4.40625, 4.5 , 4.59375, 4.6875 , 4.78125, 4.875 , 4.96875, 5.0625 , 5.15625, 5.25 , 5.34375, 5.4375 , 5.53125, 5.625 , 5.71875, 5.8125 , 5.90625, 6. , 6.09375, 6.1875 , 6.28125, 6.375 , 6.46875, 6.5625 , 6.65625, 6.75 , 6.84375, 6.9375 , 7.03125, 7.125 , 7.21875, 7.3125 , 7.40625, 7.5 , 7.59375, 7.6875 , 7.78125, 7.875 , 7.96875, 8.0625 , 8.15625, 8.25 , 8.34375, 8.4375 , 8.53125, 8.625 , 8.71875, 8.8125 , 8.90625, 9. , 9.09375, 9.1875 , 9.28125, 9.375 , 9.46875, 9.5625 , 9.65625, 9.75 , 9.84375, 9.9375 , 10.03125, 10.125 , 10.21875, 10.3125 , 10.40625, 10.5 , 10.59375, 10.6875 , 10.78125, 10.875 , 10.96875, 11.0625 , 11.15625, 11.25 , 11.34375, 11.4375 , 11.53125, 11.625 , 11.71875, 11.8125 , 11.90625], dtype=float32)
- t(t)float32149.2
array([149.25], dtype=float32)
Writting the results to binary files¶
In the last example we computed the vorticity but did nothing with it. This time, let’s write it to the disc using write:
[25]:
for ds in prm.dataset:
vort = ds.uy.x3d.first_derivative("x") - ds.ux.x3d.first_derivative("y")
prm.dataset.write(data = vort, file_prefix = "w3")
The example above works for a xarray.DataArray. We can do it for a xarray.Dataset as well, but with one key difference. Only the arrays with an attribute called file_name
will be written. It is done to avoid overwriting the base fields (ux
, uy
, uz
, …) by accident.
Let’s rewrite the previous example to store vort
in the dataset ds
. We set an atribute file_name
to w3
, so the arrays will be written as w3-000.bin
, w3-001.bin
, w3-002.bin
, etc.
We are also suppressing warnings, because the application will tell us it can not save pp
, ux
and uy
, since they do not have a file_name
. But in fact, we do not want to rewrite them anyway.
See the code:
[26]:
with warnings.catch_warnings():
warnings.filterwarnings('ignore', category=UserWarning)
for ds in prm.dataset:
ds["vort"] = ds.uy.x3d.first_derivative("x") - ds.ux.x3d.first_derivative("y")
ds["vort"].attrs["file_name"] = "w3"
prm.dataset.write(ds)
The method prm.dataset.write() writes the files as raw binaries in the same way that XCompact3d would do. It means you can read them at the flow solver and also process them on any other tool that you are already familiar with, including the toolbox.
For instance, we get w3
if we load snapshot 0 again:
[27]:
prm.dataset[0]
[27]:
<xarray.Dataset> Dimensions: (x: 257, y: 128, t: 1) Coordinates: * x (x) float32 0.0 0.07812 0.1562 0.2344 ... 19.77 19.84 19.92 20.0 * y (y) float32 0.0 0.09375 0.1875 0.2812 ... 11.62 11.72 11.81 11.91 * t (t) float32 0.0 Data variables: pp (x, y, t) float32 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 ux (x, y, t) float32 1.0 1.0 1.0 1.0 1.0 1.0 ... 1.0 1.0 1.0 1.0 1.0 uy (x, y, t) float32 9.98e-06 1.955e-05 ... -2.285e-05 1.962e-05 w3 (x, y, t) float32 0.00038 -0.000863 ... -0.001097 4.864e-05
- x: 257
- y: 128
- t: 1
- x(x)float320.0 0.07812 0.1562 ... 19.92 20.0
array([ 0. , 0.078125, 0.15625 , ..., 19.84375 , 19.921875, 20. ], dtype=float32)
- y(y)float320.0 0.09375 0.1875 ... 11.81 11.91
array([ 0. , 0.09375, 0.1875 , 0.28125, 0.375 , 0.46875, 0.5625 , 0.65625, 0.75 , 0.84375, 0.9375 , 1.03125, 1.125 , 1.21875, 1.3125 , 1.40625, 1.5 , 1.59375, 1.6875 , 1.78125, 1.875 , 1.96875, 2.0625 , 2.15625, 2.25 , 2.34375, 2.4375 , 2.53125, 2.625 , 2.71875, 2.8125 , 2.90625, 3. , 3.09375, 3.1875 , 3.28125, 3.375 , 3.46875, 3.5625 , 3.65625, 3.75 , 3.84375, 3.9375 , 4.03125, 4.125 , 4.21875, 4.3125 , 4.40625, 4.5 , 4.59375, 4.6875 , 4.78125, 4.875 , 4.96875, 5.0625 , 5.15625, 5.25 , 5.34375, 5.4375 , 5.53125, 5.625 , 5.71875, 5.8125 , 5.90625, 6. , 6.09375, 6.1875 , 6.28125, 6.375 , 6.46875, 6.5625 , 6.65625, 6.75 , 6.84375, 6.9375 , 7.03125, 7.125 , 7.21875, 7.3125 , 7.40625, 7.5 , 7.59375, 7.6875 , 7.78125, 7.875 , 7.96875, 8.0625 , 8.15625, 8.25 , 8.34375, 8.4375 , 8.53125, 8.625 , 8.71875, 8.8125 , 8.90625, 9. , 9.09375, 9.1875 , 9.28125, 9.375 , 9.46875, 9.5625 , 9.65625, 9.75 , 9.84375, 9.9375 , 10.03125, 10.125 , 10.21875, 10.3125 , 10.40625, 10.5 , 10.59375, 10.6875 , 10.78125, 10.875 , 10.96875, 11.0625 , 11.15625, 11.25 , 11.34375, 11.4375 , 11.53125, 11.625 , 11.71875, 11.8125 , 11.90625], dtype=float32)
- t(t)float320.0
array([0.], dtype=float32)
- pp(x, y, t)float320.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
array([[[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., ... ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]]], dtype=float32)
- ux(x, y, t)float321.0 1.0 1.0 1.0 ... 1.0 1.0 1.0 1.0
array([[[0.9999885 ], [0.9999782 ], [0.9999907 ], ..., [1.0000122 ], [0.99999744], [0.9999945 ]], [[0.99999535], [1.0000107 ], [1.0000069 ], ..., [0.9999595 ], [0.9999916 ], [1.0000165 ]], [[0.9999961 ], [0.9999833 ], [0.9999893 ], ..., ... ..., [0.9999767 ], [1.000011 ], [0.9999879 ]], [[1.0000291 ], [1.0000066 ], [1.0000228 ], ..., [0.9999908 ], [0.9999987 ], [0.9999874 ]], [[1.0000043 ], [1.0000119 ], [1.0000004 ], ..., [1.0000123 ], [0.99998474], [0.99999154]]], dtype=float32)
- uy(x, y, t)float329.98e-06 1.955e-05 ... 1.962e-05
array([[[ 9.97988354e-06], [ 1.95531647e-05], [ 3.23466520e-06], ..., [-6.78599736e-06], [ 5.60609988e-06], [ 4.75289698e-06]], [[ 8.17127875e-06], [-9.58256805e-06], [-1.56297228e-05], ..., [ 2.22768977e-05], [-1.19880242e-05], [ 1.55943108e-05]], [[-7.73779175e-06], [ 2.75870798e-06], [ 6.36937921e-06], ..., ... ..., [ 5.06950937e-06], [-2.75268358e-05], [ 1.18241824e-05]], [[-3.40437009e-06], [ 7.18877664e-06], [ 2.21101054e-05], ..., [ 8.57373834e-07], [-3.16069963e-06], [ 1.06863872e-05]], [[ 1.14502300e-05], [-4.91587525e-06], [ 2.38375487e-05], ..., [-5.17192575e-06], [-2.28461449e-05], [ 1.96180008e-05]]], dtype=float32)
- w3(x, y, t)float320.00038 -0.000863 ... 4.864e-05
array([[[ 3.7999949e-04], [-8.6302852e-04], [-1.2169171e-03], ..., [ 5.3181400e-04], [-3.4472678e-04], [-6.9962436e-04]], [[-4.3674174e-04], [-6.3654225e-05], [ 3.4481002e-04], ..., [ 1.6624911e-04], [-5.9153017e-04], [ 7.3439372e-04]], [[ 1.5946515e-04], [ 2.3157787e-04], [ 1.2911536e-04], ..., ... ..., [-1.5627242e-04], [-2.6290008e-04], [ 1.3722491e-03]], [[ 9.7848650e-04], [-1.4690481e-04], [ 2.7931578e-04], ..., [-2.5280163e-04], [ 3.5106039e-04], [ 1.5018106e-04]], [[-1.7982686e-04], [-2.3540645e-04], [-4.6544732e-04], ..., [ 3.3861716e-04], [-1.0970247e-03], [ 4.8644899e-05]]], dtype=float32)
Update the xdmf file¶
After computing and writing new results to the disc, you can open them on any external tools, like Paraview or Visit. You can update the xdmf file to include the recently computed w3
. See the code:
[28]:
prm.dataset.write_xdmf("xy-planes.xdmf")
Other formats¶
Xarray objects can be exported to many other formats, depending on your needs.
For instance, xarray.DataArray and xarray.Dataset can be written as netCDF. In this way, they will keep all dimensions, coordinates, and attributes. This format is easier to handle and share because the files are self-sufficient. It is the format used to download the dataset used in this tutorial, and it is a good alternative to use when sharing the results of your research.
Just to give you an estimation about the disk usage, the size of the dataset cylinder.nc
that we downloaded for this tutorial is 75.8 MB. The size of the folder ./data/
after producing the binary files in the same way that XCompact3d would do is 75.7 MB.
To exemplify the use of netCDF, let’s take one snapshot:
[29]:
snapshot = prm.dataset[0]
snapshot
[29]:
<xarray.Dataset> Dimensions: (x: 257, y: 128, t: 1) Coordinates: * x (x) float32 0.0 0.07812 0.1562 0.2344 ... 19.77 19.84 19.92 20.0 * y (y) float32 0.0 0.09375 0.1875 0.2812 ... 11.62 11.72 11.81 11.91 * t (t) float32 0.0 Data variables: pp (x, y, t) float32 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 ux (x, y, t) float32 1.0 1.0 1.0 1.0 1.0 1.0 ... 1.0 1.0 1.0 1.0 1.0 uy (x, y, t) float32 9.98e-06 1.955e-05 ... -2.285e-05 1.962e-05 w3 (x, y, t) float32 0.00038 -0.000863 ... -0.001097 4.864e-05
- x: 257
- y: 128
- t: 1
- x(x)float320.0 0.07812 0.1562 ... 19.92 20.0
array([ 0. , 0.078125, 0.15625 , ..., 19.84375 , 19.921875, 20. ], dtype=float32)
- y(y)float320.0 0.09375 0.1875 ... 11.81 11.91
array([ 0. , 0.09375, 0.1875 , 0.28125, 0.375 , 0.46875, 0.5625 , 0.65625, 0.75 , 0.84375, 0.9375 , 1.03125, 1.125 , 1.21875, 1.3125 , 1.40625, 1.5 , 1.59375, 1.6875 , 1.78125, 1.875 , 1.96875, 2.0625 , 2.15625, 2.25 , 2.34375, 2.4375 , 2.53125, 2.625 , 2.71875, 2.8125 , 2.90625, 3. , 3.09375, 3.1875 , 3.28125, 3.375 , 3.46875, 3.5625 , 3.65625, 3.75 , 3.84375, 3.9375 , 4.03125, 4.125 , 4.21875, 4.3125 , 4.40625, 4.5 , 4.59375, 4.6875 , 4.78125, 4.875 , 4.96875, 5.0625 , 5.15625, 5.25 , 5.34375, 5.4375 , 5.53125, 5.625 , 5.71875, 5.8125 , 5.90625, 6. , 6.09375, 6.1875 , 6.28125, 6.375 , 6.46875, 6.5625 , 6.65625, 6.75 , 6.84375, 6.9375 , 7.03125, 7.125 , 7.21875, 7.3125 , 7.40625, 7.5 , 7.59375, 7.6875 , 7.78125, 7.875 , 7.96875, 8.0625 , 8.15625, 8.25 , 8.34375, 8.4375 , 8.53125, 8.625 , 8.71875, 8.8125 , 8.90625, 9. , 9.09375, 9.1875 , 9.28125, 9.375 , 9.46875, 9.5625 , 9.65625, 9.75 , 9.84375, 9.9375 , 10.03125, 10.125 , 10.21875, 10.3125 , 10.40625, 10.5 , 10.59375, 10.6875 , 10.78125, 10.875 , 10.96875, 11.0625 , 11.15625, 11.25 , 11.34375, 11.4375 , 11.53125, 11.625 , 11.71875, 11.8125 , 11.90625], dtype=float32)
- t(t)float320.0
array([0.], dtype=float32)
- pp(x, y, t)float320.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
array([[[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., ... ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]]], dtype=float32)
- ux(x, y, t)float321.0 1.0 1.0 1.0 ... 1.0 1.0 1.0 1.0
array([[[0.9999885 ], [0.9999782 ], [0.9999907 ], ..., [1.0000122 ], [0.99999744], [0.9999945 ]], [[0.99999535], [1.0000107 ], [1.0000069 ], ..., [0.9999595 ], [0.9999916 ], [1.0000165 ]], [[0.9999961 ], [0.9999833 ], [0.9999893 ], ..., ... ..., [0.9999767 ], [1.000011 ], [0.9999879 ]], [[1.0000291 ], [1.0000066 ], [1.0000228 ], ..., [0.9999908 ], [0.9999987 ], [0.9999874 ]], [[1.0000043 ], [1.0000119 ], [1.0000004 ], ..., [1.0000123 ], [0.99998474], [0.99999154]]], dtype=float32)
- uy(x, y, t)float329.98e-06 1.955e-05 ... 1.962e-05
array([[[ 9.97988354e-06], [ 1.95531647e-05], [ 3.23466520e-06], ..., [-6.78599736e-06], [ 5.60609988e-06], [ 4.75289698e-06]], [[ 8.17127875e-06], [-9.58256805e-06], [-1.56297228e-05], ..., [ 2.22768977e-05], [-1.19880242e-05], [ 1.55943108e-05]], [[-7.73779175e-06], [ 2.75870798e-06], [ 6.36937921e-06], ..., ... ..., [ 5.06950937e-06], [-2.75268358e-05], [ 1.18241824e-05]], [[-3.40437009e-06], [ 7.18877664e-06], [ 2.21101054e-05], ..., [ 8.57373834e-07], [-3.16069963e-06], [ 1.06863872e-05]], [[ 1.14502300e-05], [-4.91587525e-06], [ 2.38375487e-05], ..., [-5.17192575e-06], [-2.28461449e-05], [ 1.96180008e-05]]], dtype=float32)
- w3(x, y, t)float320.00038 -0.000863 ... 4.864e-05
array([[[ 3.7999949e-04], [-8.6302852e-04], [-1.2169171e-03], ..., [ 5.3181400e-04], [-3.4472678e-04], [-6.9962436e-04]], [[-4.3674174e-04], [-6.3654225e-05], [ 3.4481002e-04], ..., [ 1.6624911e-04], [-5.9153017e-04], [ 7.3439372e-04]], [[ 1.5946515e-04], [ 2.3157787e-04], [ 1.2911536e-04], ..., ... ..., [-1.5627242e-04], [-2.6290008e-04], [ 1.3722491e-03]], [[ 9.7848650e-04], [-1.4690481e-04], [ 2.7931578e-04], ..., [-2.5280163e-04], [ 3.5106039e-04], [ 1.5018106e-04]], [[-1.7982686e-04], [-2.3540645e-04], [-4.6544732e-04], ..., [ 3.3861716e-04], [-1.0970247e-03], [ 4.8644899e-05]]], dtype=float32)
Now, let’s include additional information for the ones that are going to use our data. You can set attributes for each array, coordinate, and also global attributes for the dataset. They are stored in a dictionary.
See the example:
[30]:
# Setting attributes for each coordinate
snapshot.x.attrs = dict(
name = "x",
long_name = "Stream-wise coordinate",
units = "-"
)
snapshot.y.attrs = dict(
name = "y",
long_name = "Vertical coordinate",
units = "-"
)
snapshot.t.attrs = dict(
name = "t",
long_name = "Time",
units = "-"
)
# Setting attributes for each array
snapshot.ux.attrs = dict(
name = "ux",
long_name = "Stream-wise velocity",
units = "-"
)
snapshot.uy.attrs = dict(
name = "y",
long_name = "Vertical velocity",
units = "-"
)
snapshot.pp.attrs = dict(
name = "p",
long_name = "Pressure",
units = "-"
)
snapshot.w3.attrs = dict(
name = "w3",
long_name = "Vorticity",
units = "-"
)
# Setting attributes for the dataset
snapshot.attrs = dict(
title = "An example from the tutorials",
url = "https://xcompact3d-toolbox.readthedocs.io/en/stable/tutorial/io.html",
authors = "List of names",
doi = "maybe a fancy doi from zenodo",
)
Exporting it as a netCDF file:
[31]:
snapshot.to_netcdf("snapshot-000.nc")
Importing the netCDF file:
[32]:
snapshot_in = xr.open_dataset("snapshot-000.nc")
See the result, it keeps all dimensions, coordinates, and attributes:
[33]:
snapshot_in
[33]:
<xarray.Dataset> Dimensions: (x: 257, y: 128, t: 1) Coordinates: * x (x) float32 0.0 0.07812 0.1562 0.2344 ... 19.77 19.84 19.92 20.0 * y (y) float32 0.0 0.09375 0.1875 0.2812 ... 11.62 11.72 11.81 11.91 * t (t) float32 0.0 Data variables: pp (x, y, t) float32 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 ux (x, y, t) float32 1.0 1.0 1.0 1.0 1.0 1.0 ... 1.0 1.0 1.0 1.0 1.0 uy (x, y, t) float32 9.98e-06 1.955e-05 ... -2.285e-05 1.962e-05 w3 (x, y, t) float32 0.00038 -0.000863 ... -0.001097 4.864e-05 Attributes: title: An example from the tutorials url: https://xcompact3d-toolbox.readthedocs.io/en/stable/tutorial/io... authors: List of names doi: maybe a fancy doi from zenodo
- x: 257
- y: 128
- t: 1
- x(x)float320.0 0.07812 0.1562 ... 19.92 20.0
- name :
- x
- long_name :
- Stream-wise coordinate
- units :
- -
array([ 0. , 0.078125, 0.15625 , ..., 19.84375 , 19.921875, 20. ], dtype=float32)
- y(y)float320.0 0.09375 0.1875 ... 11.81 11.91
- name :
- y
- long_name :
- Vertical coordinate
- units :
- -
array([ 0. , 0.09375, 0.1875 , 0.28125, 0.375 , 0.46875, 0.5625 , 0.65625, 0.75 , 0.84375, 0.9375 , 1.03125, 1.125 , 1.21875, 1.3125 , 1.40625, 1.5 , 1.59375, 1.6875 , 1.78125, 1.875 , 1.96875, 2.0625 , 2.15625, 2.25 , 2.34375, 2.4375 , 2.53125, 2.625 , 2.71875, 2.8125 , 2.90625, 3. , 3.09375, 3.1875 , 3.28125, 3.375 , 3.46875, 3.5625 , 3.65625, 3.75 , 3.84375, 3.9375 , 4.03125, 4.125 , 4.21875, 4.3125 , 4.40625, 4.5 , 4.59375, 4.6875 , 4.78125, 4.875 , 4.96875, 5.0625 , 5.15625, 5.25 , 5.34375, 5.4375 , 5.53125, 5.625 , 5.71875, 5.8125 , 5.90625, 6. , 6.09375, 6.1875 , 6.28125, 6.375 , 6.46875, 6.5625 , 6.65625, 6.75 , 6.84375, 6.9375 , 7.03125, 7.125 , 7.21875, 7.3125 , 7.40625, 7.5 , 7.59375, 7.6875 , 7.78125, 7.875 , 7.96875, 8.0625 , 8.15625, 8.25 , 8.34375, 8.4375 , 8.53125, 8.625 , 8.71875, 8.8125 , 8.90625, 9. , 9.09375, 9.1875 , 9.28125, 9.375 , 9.46875, 9.5625 , 9.65625, 9.75 , 9.84375, 9.9375 , 10.03125, 10.125 , 10.21875, 10.3125 , 10.40625, 10.5 , 10.59375, 10.6875 , 10.78125, 10.875 , 10.96875, 11.0625 , 11.15625, 11.25 , 11.34375, 11.4375 , 11.53125, 11.625 , 11.71875, 11.8125 , 11.90625], dtype=float32)
- t(t)float320.0
- name :
- t
- long_name :
- Time
- units :
- -
array([0.], dtype=float32)
- pp(x, y, t)float32...
- name :
- p
- long_name :
- Pressure
- units :
- -
array([[[0.], [0.], ..., [0.], [0.]], [[0.], [0.], ..., [0.], [0.]], ..., [[0.], [0.], ..., [0.], [0.]], [[0.], [0.], ..., [0.], [0.]]], dtype=float32)
- ux(x, y, t)float32...
- name :
- ux
- long_name :
- Stream-wise velocity
- units :
- -
array([[[0.999988], [0.999978], ..., [0.999997], [0.999995]], [[0.999995], [1.000011], ..., [0.999992], [1.000016]], ..., [[1.000029], [1.000007], ..., [0.999999], [0.999987]], [[1.000004], [1.000012], ..., [0.999985], [0.999992]]], dtype=float32)
- uy(x, y, t)float32...
- name :
- y
- long_name :
- Vertical velocity
- units :
- -
array([[[ 9.979884e-06], [ 1.955316e-05], ..., [ 5.606100e-06], [ 4.752897e-06]], [[ 8.171279e-06], [-9.582568e-06], ..., [-1.198802e-05], [ 1.559431e-05]], ..., [[-3.404370e-06], [ 7.188777e-06], ..., [-3.160700e-06], [ 1.068639e-05]], [[ 1.145023e-05], [-4.915875e-06], ..., [-2.284614e-05], [ 1.961800e-05]]], dtype=float32)
- w3(x, y, t)float32...
- name :
- w3
- long_name :
- Vorticity
- units :
- -
array([[[ 3.799995e-04], [-8.630285e-04], ..., [-3.447268e-04], [-6.996244e-04]], [[-4.367417e-04], [-6.365422e-05], ..., [-5.915302e-04], [ 7.343937e-04]], ..., [[ 9.784865e-04], [-1.469048e-04], ..., [ 3.510604e-04], [ 1.501811e-04]], [[-1.798269e-04], [-2.354064e-04], ..., [-1.097025e-03], [ 4.864490e-05]]], dtype=float32)
- title :
- An example from the tutorials
- url :
- https://xcompact3d-toolbox.readthedocs.io/en/stable/tutorial/io.html
- authors :
- List of names
- doi :
- maybe a fancy doi from zenodo
We can compare them and see that their data, dimensions and coordinates are exactly the same:
[34]:
xr.testing.assert_equal(snapshot, snapshot_in)
Xarray is built on top of Numpy, so you can access a numpy.ndarray
object with the property data
. It is compatible with numpy.save
and many other methods, see the example:
[35]:
np.save("epsi.npy", epsilon.data)
epsi_in = np.load("epsi.npy")
print(type(epsi_in))
epsi_in
<class 'numpy.ndarray'>
[35]:
array([[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
...,
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.]], dtype=float32)
You can use it for backwards compatibility with your previous post-processing tools. It is just not so effective, because we lost track of metadata like the coordinates and attributes.
If you manage to reduce the dataset’s dimensions with some integral, average, or selecting subsets of data, you can convert it to a pandas.Dataframe
and then export it to CSV, Excel, and many other options.
For instance, let’s select a vertical profile for all variables where x = 20
and convert it to a dataframe:
[36]:
snapshot_in.sel(x=20.0).to_dataframe()
[36]:
x | pp | ux | uy | w3 | ||
---|---|---|---|---|---|---|
y | t | |||||
0.00000 | 0.0 | 20.0 | 0.0 | 1.000004 | 0.000011 | -0.000180 |
0.09375 | 0.0 | 20.0 | 0.0 | 1.000012 | -0.000005 | -0.000235 |
0.18750 | 0.0 | 20.0 | 0.0 | 1.000000 | 0.000024 | -0.000465 |
0.28125 | 0.0 | 20.0 | 0.0 | 1.000002 | -0.000019 | -0.000969 |
0.37500 | 0.0 | 20.0 | 0.0 | 0.999997 | -0.000018 | 0.002280 |
... | ... | ... | ... | ... | ... | ... |
11.53125 | 0.0 | 20.0 | 0.0 | 1.000013 | 0.000023 | 0.000101 |
11.62500 | 0.0 | 20.0 | 0.0 | 1.000009 | -0.000010 | -0.002189 |
11.71875 | 0.0 | 20.0 | 0.0 | 1.000012 | -0.000005 | 0.000339 |
11.81250 | 0.0 | 20.0 | 0.0 | 0.999985 | -0.000023 | -0.001097 |
11.90625 | 0.0 | 20.0 | 0.0 | 0.999992 | 0.000020 | 0.000049 |
128 rows × 5 columns
Now, you can refer to pandas documentation for more details.
Computing and Plotting¶
This tutorial includes an overview of the different ways available to compute, select data and plot using the xarray objects that are provided by xcompact3d-toolbox.
The very first step is to import the toolbox and other packages:
[1]:
import hvplot.xarray
import matplotlib.pyplot as plt
import numpy as np
import xcompact3d_toolbox as x3d
Why xarray?¶
The data structures are provided by xarray, that introduces labels in the form of dimensions, coordinates and attributes on top of raw NumPy-like arrays, which allows for a more intuitive, more concise, and less error-prone developer experience. It integrates tightly with dask for parallel computing.
The goal here is to speed up the development of customized post-processing applications with the concise interface provided by xarray. Ultimately, we can compute solutions with fewer lines of code and better readability, so we expend less time testing and debugging and more time exploring our datasets and getting insights.
Additionally, xcompact3d-toolbox includes extra functionalities for DataArray and Dataset.
Before going forward, please, take a look at Overview: Why xarray? and Quick overview to understand the motivation to use xarray’s data structures instead of just numpy-like arrays.
Example - Flow around a cylinder¶
We can download the example from the online database, the flow around a cylinder in this case. We set cache=True
and a local destination where it can be saved in our computer cache_dir="./example/"
, so there is no need to download it every time the kernel is restarted.
[2]:
dataset, prm = x3d.tutorial.open_dataset("cylinder", cache=True, cache_dir="./example/")
Notice there is an entire tutorial dedicated to the parameters file. Now, let’s take a look at the dataset:
[3]:
dataset
[3]:
<xarray.Dataset> Dimensions: (i: 2, x: 257, y: 128, t: 201) Coordinates: * x (x) float64 0.0 0.07812 0.1562 0.2344 ... 19.77 19.84 19.92 20.0 * y (y) float64 0.0 0.09375 0.1875 0.2812 ... 11.62 11.72 11.81 11.91 * t (t) float64 0.0 0.75 1.5 2.25 3.0 ... 147.0 147.8 148.5 149.2 150.0 * i (i) object 'x' 'y' Data variables: u (i, x, y, t) float32 ... pp (x, y, t) float32 ... epsi (x, y) float32 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0 Attributes: xcompact3d_version: v3.0-397-gff531df xcompact3d_toolbox_version: 1.0.1 url: https://github.com/fschuch/xcompact3d_toolbo... dataset_license: MIT License
- i: 2
- x: 257
- y: 128
- t: 201
- x(x)float640.0 0.07812 0.1562 ... 19.92 20.0
array([ 0. , 0.078125, 0.15625 , ..., 19.84375 , 19.921875, 20. ])
- y(y)float640.0 0.09375 0.1875 ... 11.81 11.91
array([ 0. , 0.09375, 0.1875 , 0.28125, 0.375 , 0.46875, 0.5625 , 0.65625, 0.75 , 0.84375, 0.9375 , 1.03125, 1.125 , 1.21875, 1.3125 , 1.40625, 1.5 , 1.59375, 1.6875 , 1.78125, 1.875 , 1.96875, 2.0625 , 2.15625, 2.25 , 2.34375, 2.4375 , 2.53125, 2.625 , 2.71875, 2.8125 , 2.90625, 3. , 3.09375, 3.1875 , 3.28125, 3.375 , 3.46875, 3.5625 , 3.65625, 3.75 , 3.84375, 3.9375 , 4.03125, 4.125 , 4.21875, 4.3125 , 4.40625, 4.5 , 4.59375, 4.6875 , 4.78125, 4.875 , 4.96875, 5.0625 , 5.15625, 5.25 , 5.34375, 5.4375 , 5.53125, 5.625 , 5.71875, 5.8125 , 5.90625, 6. , 6.09375, 6.1875 , 6.28125, 6.375 , 6.46875, 6.5625 , 6.65625, 6.75 , 6.84375, 6.9375 , 7.03125, 7.125 , 7.21875, 7.3125 , 7.40625, 7.5 , 7.59375, 7.6875 , 7.78125, 7.875 , 7.96875, 8.0625 , 8.15625, 8.25 , 8.34375, 8.4375 , 8.53125, 8.625 , 8.71875, 8.8125 , 8.90625, 9. , 9.09375, 9.1875 , 9.28125, 9.375 , 9.46875, 9.5625 , 9.65625, 9.75 , 9.84375, 9.9375 , 10.03125, 10.125 , 10.21875, 10.3125 , 10.40625, 10.5 , 10.59375, 10.6875 , 10.78125, 10.875 , 10.96875, 11.0625 , 11.15625, 11.25 , 11.34375, 11.4375 , 11.53125, 11.625 , 11.71875, 11.8125 , 11.90625])
- t(t)float640.0 0.75 1.5 ... 148.5 149.2 150.0
array([ 0. , 0.75, 1.5 , ..., 148.5 , 149.25, 150. ])
- i(i)object'x' 'y'
array(['x', 'y'], dtype=object)
- u(i, x, y, t)float32...
[13224192 values with dtype=float32]
- pp(x, y, t)float32...
[6612096 values with dtype=float32]
- epsi(x, y)float32...
array([[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], dtype=float32)
- xcompact3d_version :
- v3.0-397-gff531df
- xcompact3d_toolbox_version :
- 1.0.1
- url :
- https://github.com/fschuch/xcompact3d_toolbox_data
- dataset_license :
- MIT License
We got a xarray.Dataset with the variables u
(velocity vector), pp
(pressure) and epsi
(that describes the geometry), their coordinates (x
, y
, t
and i
) and some atributes like the xcompact3d_version
used to run this simulation, the url
where you can find the dataset and others.
We can access each of variables or coordinates with the dot notation (i.g., snapshot.pp
, snapshot.u
, snapshot.x
) or the dict-like notation (i.g., snapshot["pp"]
, snapshot["u"]
, snapshot["x"]
).
Once the arrays are wrapped with their coordinates, we can use xarray’s plotting functionality to explore our data with just a few lines of code.
Starting with epsi
, that represents the geometry (it is 1 inside the cylinder and 0 outside), we select it from the dataset and then use the method plot:
[4]:
dataset.epsi.plot()
[4]:
<matplotlib.collections.QuadMesh at 0x7f50b8e7f610>

The array in the example was two-dimensional, in this case .plot()
automatically calls xarray.plot.pcolormesh().
There are many options to customize the plots, besides that, xarray plotting functionality is a thin wrapper around the popular matplotlib library.
To improve the figure, let’s set the x-axis of the plot as the coordinate x
of our array, same for y
. Then let’s use matplotlib to set the axis aspect to equal
. Take a look:
[5]:
ax = dataset.epsi.plot(x="x", y="y")
ax.axes.set_aspect("equal")

It might be important in the cylinder case to ignore the values that are inside the solid cylinder when plotting or computing any quantity. We can do it by preserving the values of u
and pp
where where epsi
is equal to zero, and setting the values to np.NaN
otherwise.
xarray.Dataset.where is a handy method for that, take a look:
[6]:
for var in ["u", "pp"]:
dataset[var] = dataset[var].where(dataset.epsi == 0.0, np.NaN)
Have you noticed that we are doing this comparison between variables with different dimensions, and it just worked? I mean, epsi
is 2D (x, y), pp
is 3D (x, y, t) and u
is 4D (i, x, y, t). That is because xarray automatically broadcasted the values of epsi
to each point at the coordinates t
and i
.
Another cool feature of xarray is that we can select data based on the actual value of its coordinates, not only on the integer indexes used for selection on numpy-like arrays.
To exemplify, let’s select one position at the same heigh of the cylinder, but a bit downstream. Note we can get the time evolution for all variables at this specified point:
[7]:
dataset.sel(x=10.0, y=6.0, method="nearest")
[7]:
<xarray.Dataset> Dimensions: (i: 2, t: 201) Coordinates: x float64 10.0 y float64 6.0 * t (t) float64 0.0 0.75 1.5 2.25 3.0 ... 147.0 147.8 148.5 149.2 150.0 * i (i) object 'x' 'y' Data variables: u (i, t) float32 1.005 0.9915 0.987 0.9834 ... 0.838 -0.5676 -0.749 pp (t) float32 0.0 -0.003727 -0.001281 ... -0.4308 -0.5678 -0.2354 epsi float32 0.0 Attributes: xcompact3d_version: v3.0-397-gff531df xcompact3d_toolbox_version: 1.0.1 url: https://github.com/fschuch/xcompact3d_toolbo... dataset_license: MIT License
- i: 2
- t: 201
- x()float6410.0
array(10.)
- y()float646.0
array(6.)
- t(t)float640.0 0.75 1.5 ... 148.5 149.2 150.0
array([ 0. , 0.75, 1.5 , ..., 148.5 , 149.25, 150. ])
- i(i)object'x' 'y'
array(['x', 'y'], dtype=object)
- u(i, t)float321.005 0.9915 ... -0.5676 -0.749
array([[ 1.0050466e+00, 9.9151999e-01, 9.8698294e-01, 9.8339641e-01, 9.7692180e-01, 9.7582245e-01, 9.6976292e-01, 9.6941078e-01, 9.7474968e-01, 9.4925112e-01, 9.1301501e-01, 8.7358981e-01, 8.4338820e-01, 8.2099408e-01, 7.8031898e-01, 7.1290475e-01, 7.0057237e-01, 7.5358826e-01, 7.6811922e-01, 6.9968998e-01, 4.7466475e-01, 5.4348302e-01, 6.3292307e-01, 6.6338509e-01, 5.4809201e-01, 3.4386140e-01, 4.5068860e-01, 6.6093957e-01, 7.0059520e-01, 7.8714991e-01, 9.7290230e-01, 1.1076094e+00, 1.2634958e+00, 1.0439249e+00, 8.9840025e-01, 6.2564510e-01, 7.8143853e-01, 8.0766308e-01, 5.8369124e-01, 6.6911119e-01, 7.9822206e-01, 6.7960417e-01, 8.5084581e-01, 8.7373948e-01, 7.6711136e-01, 9.1678655e-01, 8.8365871e-01, 7.0765084e-01, 8.5749114e-01, 8.6977410e-01, 7.4461067e-01, 8.9814866e-01, 8.7835783e-01, 7.5894672e-01, 8.9871693e-01, 8.7412632e-01, 7.5734192e-01, 8.9172286e-01, 8.6916983e-01, 7.6642394e-01, 8.9645296e-01, 8.6637628e-01, 7.7334237e-01, 8.9777631e-01, 8.6234158e-01, 7.7908409e-01, 8.9845222e-01, 8.5793936e-01, 7.8544170e-01, 8.9951271e-01, 8.5327154e-01, 7.9158741e-01, 9.0010005e-01, 8.4817249e-01, 7.9771376e-01, 9.0045536e-01, 8.4264100e-01, 8.0377024e-01, 9.0056646e-01, 8.3660847e-01, ... -7.2356749e-01, 6.9366443e-01, 7.4169677e-01, 6.8034559e-01, -7.2023743e-01, -7.4131531e-01, -6.3344514e-01, 7.4411678e-01, 7.4157214e-01, 5.8374679e-01, -7.6529485e-01, -7.4248213e-01, -5.3196394e-01, 7.8375047e-01, 7.4405903e-01, 4.7862995e-01, -7.9945004e-01, -7.4631143e-01, -4.2412418e-01, 8.1235480e-01, 7.4923980e-01, 3.6871812e-01, -8.2243466e-01, -7.5283694e-01, -3.1262314e-01, 8.2968652e-01, 7.5709367e-01, 2.5602695e-01, -8.3415437e-01, -7.6200670e-01, -1.9911350e-01, 8.3594650e-01, 7.6758963e-01, 1.4206900e-01, -8.3524758e-01, -7.7388310e-01, -8.5079387e-02, 8.3232158e-01, 7.8095436e-01, 2.8326184e-02, -8.2750398e-01, -7.8888518e-01, 2.8015513e-02, 8.2118559e-01, 7.9773831e-01, -8.3774805e-02, -8.1378800e-01, -8.0750322e-01, 1.3877988e-01, 8.0573475e-01, 8.1802833e-01, -1.9285190e-01, -7.9742360e-01, -8.2894987e-01, 2.4580052e-01, 7.8920174e-01, 8.3963960e-01, -2.9742256e-01, -7.8134966e-01, -8.4918964e-01, 3.4750438e-01, 7.7407306e-01, 8.5645241e-01, -3.9582849e-01, -7.6750332e-01, -8.6014026e-01, 4.4218248e-01, 7.6170725e-01, 8.5897452e-01, -4.8636919e-01, -7.5670010e-01, -8.5185820e-01, 5.2821708e-01, 7.5246328e-01, 8.3803260e-01, -5.6758696e-01, -7.4895942e-01]], dtype=float32)
- pp(t)float320.0 -0.003727 ... -0.5678 -0.2354
array([ 0. , -0.00372704, -0.0012806 , 0.00548125, 0.01192788, 0.01819267, 0.02454225, 0.03113307, 0.03837142, 0.04643057, 0.05466292, 0.06294026, 0.0717836 , 0.08086249, 0.08842299, 0.09354008, 0.09838215, 0.10428193, 0.10689771, 0.09085366, 0.05016406, 0.02201033, -0.00069486, -0.0518169 , -0.19853248, -0.30324376, -0.23762481, -0.26261356, -0.46279153, -0.55223125, -0.3219201 , -0.267523 , -0.27221647, -0.07494604, -0.09741227, -0.37916234, -0.17141525, -0.13610364, -0.35932806, -0.35918653, -0.19393663, -0.4185423 , -0.40083432, -0.2208759 , -0.4884497 , -0.39601892, -0.22077534, -0.53087354, -0.42512083, -0.22871658, -0.5606629 , -0.4214235 , -0.23194526, -0.5854999 , -0.40748584, -0.2351996 , -0.6050867 , -0.39830738, -0.24004272, -0.6208197 , -0.38567874, -0.24368042, -0.63364863, -0.3710815 , -0.2474935 , -0.6441184 , -0.35712177, -0.25195745, -0.6523374 , -0.34355032, -0.25699124, -0.6587043 , -0.33075446, -0.2627814 , -0.6632486 , -0.31879288, -0.26930684, -0.6659652 , -0.3076601 , -0.27659318, -0.66687846, -0.29740942, -0.28471693, -0.66600364, -0.2880378 , -0.29374886, -0.6633666 , -0.27952534, -0.30376852, -0.6590034 , -0.2718439 , -0.31486532, -0.6529617 , -0.26495743, -0.32712838, -0.6453031 , -0.25882673, -0.34063798, -0.6361038 , -0.2534113 , ... -0.24457243, -0.38899994, -0.600258 , -0.24108061, -0.40758544, -0.58596545, -0.23816897, -0.4271543 , -0.5707351 , -0.23581491, -0.4474498 , -0.55472076, -0.23400031, -0.46816424, -0.53808 , -0.23271132, -0.48896465, -0.5209713 , -0.23193763, -0.50952 , -0.5035509 , -0.2316723 , -0.5295236 , -0.48597008, -0.2319118 , -0.54870903, -0.46837348, -0.23265591, -0.5668565 , -0.45089746, -0.2339082 , -0.58379185, -0.4336689 , -0.23567596, -0.5993794 , -0.41680586, -0.23797037, -0.61351335, -0.40041682, -0.24080656, -0.6261087 , -0.3846002 , -0.24420378, -0.63709694, -0.3694437 , -0.24818537, -0.64642185, -0.35502335, -0.25277933, -0.65403813, -0.34140155, -0.25801876, -0.6599117 , -0.32862636, -0.2639426 , -0.66401887, -0.3167304 , -0.27059665, -0.66634697, -0.3057303 , -0.2780347 , -0.6668949 , -0.29562703, -0.28632 , -0.66567284, -0.28640774, -0.29552624, -0.66270304, -0.27804804, -0.30573657, -0.65801996, -0.27051517, -0.31704056, -0.6516718 , -0.26377115, -0.3295267 , -0.64372164, -0.25777557, -0.34327194, -0.6342477 , -0.25248793, -0.35832733, -0.62334424, -0.24786948, -0.37470084, -0.6111212 , -0.24388446, -0.39234072, -0.59770304, -0.24050163, -0.41112235, -0.58322734, -0.23769437, -0.430845 , -0.5678417 , -0.23544094], dtype=float32)
- epsi()float320.0
array(0., dtype=float32)
- xcompact3d_version :
- v3.0-397-gff531df
- xcompact3d_toolbox_version :
- 1.0.1
- url :
- https://github.com/fschuch/xcompact3d_toolbox_data
- dataset_license :
- MIT License
We can chain the methods, selecting a variable, selecting a point in the domain and doing a plot, all with just one line of code:
[8]:
dataset.u.sel(x=10.0, y=6.0, method="nearest").plot(x="t", hue="i")
[8]:
[<matplotlib.lines.Line2D at 0x7f50b8b9e410>,
<matplotlib.lines.Line2D at 0x7f50b8c0e790>]

Note this time the data was 1D, so the plot was handled internally by xarray.plot.line.
To give you another example, let’s plot the time-averaged (\(60 \le t \le 150\)) vertical velocity profile where \(x=10\):
[9]:
dataset.u.sel(x=10.0, t=slice(60.0, 150.0)).mean("t").plot(y="y", hue="i")
[9]:
[<matplotlib.lines.Line2D at 0x7f50b8b425d0>,
<matplotlib.lines.Line2D at 0x7f50b8b37710>]

As you saw, we can refer to the coordinates by their name when working with xarray, instead of keeping track of their axis number.
To extend this concept, let’s now compute the time evolution of the kinetic energy in our flow. It is given by the equation:
Now the code:
[10]:
dataset["kinetic_energy"] = ((dataset.u ** 2.0).sum("i").x3d.simps("x", "y")) * 0.5
dataset["kinetic_energy"].attrs = dict(name="k", long_name="kinetic Energy", units="-")
dataset["kinetic_energy"].plot()
[10]:
[<matplotlib.lines.Line2D at 0x7f50b8a621d0>]

In the code above we:
- Solved the equation with a very readable code. A good point is that it worked for the
xy
planes in the dataset in this example, and all we need to do to run it in a real 3D case is includez
at the integration; - Included attributes to describe what we just computed, making our application easier to share and collaborate. As a bonus, they were automatically included in the plot;
- Plotted the results.
We can use a quick list comprehension to get the dimensions for the volumetric integration:
[11]:
V_coords = [dim for dim in dataset.u.coords if dim in "xyz"]
V_coords
[11]:
['x', 'y']
and rewrite the previous example to make it more robust, now it works for 1D, 2D and 3D cases:
[12]:
dataset["kinetic_energy"] = ((dataset.u ** 2.0).sum("i").x3d.simps(*V_coords)) * 0.5
dataset["kinetic_energy"].attrs = dict(name="k", long_name="kinetic Energy", units="-")
Going back to 2D plots, let’s take the velocity vector u
, select it for \(60 \le t \le 150\) (sel), compute a time average (mean) and plot:
[13]:
g = dataset.u.sel(t=slice(60.0, 150.0)).mean("t").plot(
x="x", y="y", row="i", cmap="turbo", rasterized=True
)
for ax in g.axes.flat:
ax.axes.set_aspect("equal")

Do you want to see the time evolution? No problem. Let’s take the velocity vector u
, use isel with a slice selecting every 40 points in time (otherwise we would get too many figures), and plot:
[14]:
g = dataset.u.isel(t=slice(None, None, 40)).plot(
x="x", y="y", col="t", row="i", cmap="turbo", rasterized=True
)
for ax in g.axes.flat:
ax.axes.set_aspect("equal")

To exemplify differentiation and parallel computing capabilities, let’s compute the vorticity for our dataset. We just have one component for this 2D example, it is given by the equation:
We can use xarray.DataArray.differentiate just out of the box with its second order accurate central differences. However, we can use the 4th order accurate centered scheme available at X3dDataArray.first_derivative.
We start setting the attribute boundary conditions (BC
) for the velocity field:
[15]:
dataset["u"].attrs["BC"] = prm.get_boundary_condition("u")
and then we compute the vorticity:
[16]:
%%time
dataset["vort"] = (
dataset.u.sel(i="y").x3d.first_derivative("x")
- dataset.u.sel(i="x").x3d.first_derivative("y")
)
CPU times: user 948 ms, sys: 59.8 ms, total: 1.01 s
Wall time: 1.01 s
Notice the equation above computed the vorticity for the entire time series in our dataset.
We can use X3dDataArray.pencil_decomp to coarse the velocity array to a dask array, ready for parallel computing (see Using Dask with xarray). Notice that
X3dDataArray.pencil_decomp applies chunk=-1
for all coordinates listed in args
, which means no decomposition, and 'auto'
to the others, delagating to dask the job of finding the optimal distribition. One important point here is that dask considers the dataset in this example so small that the overhead for parallel computing is not worth it. As a result, it
returns with just one chunk:
[17]:
u_chunked = dataset.u.x3d.pencil_decomp("x", "y")
u_chunked
[17]:
<xarray.DataArray 'u' (i: 2, x: 257, y: 128, t: 201)> dask.array<xarray-<this-array>, shape=(2, 257, 128, 201), dtype=float32, chunksize=(2, 257, 128, 201), chunktype=numpy.ndarray> Coordinates: * x (x) float64 0.0 0.07812 0.1562 0.2344 ... 19.77 19.84 19.92 20.0 * y (y) float64 0.0 0.09375 0.1875 0.2812 ... 11.62 11.72 11.81 11.91 * t (t) float64 0.0 0.75 1.5 2.25 3.0 ... 147.0 147.8 148.5 149.2 150.0 * i (i) object 'x' 'y' Attributes: BC: {'x': {'ncl1': 2, 'ncln': 2, 'npaire': 1}, 'y': {'ncl1': 0, 'nc...
- i: 2
- x: 257
- y: 128
- t: 201
- dask.array<chunksize=(2, 257, 128, 201), meta=np.ndarray>
Array Chunk Bytes 50.45 MiB 50.45 MiB Shape (2, 257, 128, 201) (2, 257, 128, 201) Count 1 Tasks 1 Chunks Type float32 numpy.ndarray - x(x)float640.0 0.07812 0.1562 ... 19.92 20.0
array([ 0. , 0.078125, 0.15625 , ..., 19.84375 , 19.921875, 20. ])
- y(y)float640.0 0.09375 0.1875 ... 11.81 11.91
array([ 0. , 0.09375, 0.1875 , 0.28125, 0.375 , 0.46875, 0.5625 , 0.65625, 0.75 , 0.84375, 0.9375 , 1.03125, 1.125 , 1.21875, 1.3125 , 1.40625, 1.5 , 1.59375, 1.6875 , 1.78125, 1.875 , 1.96875, 2.0625 , 2.15625, 2.25 , 2.34375, 2.4375 , 2.53125, 2.625 , 2.71875, 2.8125 , 2.90625, 3. , 3.09375, 3.1875 , 3.28125, 3.375 , 3.46875, 3.5625 , 3.65625, 3.75 , 3.84375, 3.9375 , 4.03125, 4.125 , 4.21875, 4.3125 , 4.40625, 4.5 , 4.59375, 4.6875 , 4.78125, 4.875 , 4.96875, 5.0625 , 5.15625, 5.25 , 5.34375, 5.4375 , 5.53125, 5.625 , 5.71875, 5.8125 , 5.90625, 6. , 6.09375, 6.1875 , 6.28125, 6.375 , 6.46875, 6.5625 , 6.65625, 6.75 , 6.84375, 6.9375 , 7.03125, 7.125 , 7.21875, 7.3125 , 7.40625, 7.5 , 7.59375, 7.6875 , 7.78125, 7.875 , 7.96875, 8.0625 , 8.15625, 8.25 , 8.34375, 8.4375 , 8.53125, 8.625 , 8.71875, 8.8125 , 8.90625, 9. , 9.09375, 9.1875 , 9.28125, 9.375 , 9.46875, 9.5625 , 9.65625, 9.75 , 9.84375, 9.9375 , 10.03125, 10.125 , 10.21875, 10.3125 , 10.40625, 10.5 , 10.59375, 10.6875 , 10.78125, 10.875 , 10.96875, 11.0625 , 11.15625, 11.25 , 11.34375, 11.4375 , 11.53125, 11.625 , 11.71875, 11.8125 , 11.90625])
- t(t)float640.0 0.75 1.5 ... 148.5 149.2 150.0
array([ 0. , 0.75, 1.5 , ..., 148.5 , 149.25, 150. ])
- i(i)object'x' 'y'
array(['x', 'y'], dtype=object)
- BC :
- {'x': {'ncl1': 2, 'ncln': 2, 'npaire': 1}, 'y': {'ncl1': 0, 'ncln': 0, 'npaire': 1, 'istret': 0, 'beta': 1.0}, 'z': {'ncl1': 0, 'ncln': 0, 'npaire': 1}}
Parallel computing is presented in this tutorial anyway, because X3dDataArray.pencil_decomp returns the arrays with several chunks for datasets in real scale. Each of these chunks will be computed in parallel in multi-core systems.
Just to exemplify, let’s create blocks with 51 points in time, so we can use 4 cores to compute it in parallel:
[18]:
u_chunked = dataset.u.chunk(chunks=dict(t = 51))
u_chunked
[18]:
<xarray.DataArray 'u' (i: 2, x: 257, y: 128, t: 201)> dask.array<xarray-<this-array>, shape=(2, 257, 128, 201), dtype=float32, chunksize=(2, 257, 128, 51), chunktype=numpy.ndarray> Coordinates: * x (x) float64 0.0 0.07812 0.1562 0.2344 ... 19.77 19.84 19.92 20.0 * y (y) float64 0.0 0.09375 0.1875 0.2812 ... 11.62 11.72 11.81 11.91 * t (t) float64 0.0 0.75 1.5 2.25 3.0 ... 147.0 147.8 148.5 149.2 150.0 * i (i) object 'x' 'y' Attributes: BC: {'x': {'ncl1': 2, 'ncln': 2, 'npaire': 1}, 'y': {'ncl1': 0, 'nc...
- i: 2
- x: 257
- y: 128
- t: 201
- dask.array<chunksize=(2, 257, 128, 51), meta=np.ndarray>
Array Chunk Bytes 50.45 MiB 12.80 MiB Shape (2, 257, 128, 201) (2, 257, 128, 51) Count 4 Tasks 4 Chunks Type float32 numpy.ndarray - x(x)float640.0 0.07812 0.1562 ... 19.92 20.0
array([ 0. , 0.078125, 0.15625 , ..., 19.84375 , 19.921875, 20. ])
- y(y)float640.0 0.09375 0.1875 ... 11.81 11.91
array([ 0. , 0.09375, 0.1875 , 0.28125, 0.375 , 0.46875, 0.5625 , 0.65625, 0.75 , 0.84375, 0.9375 , 1.03125, 1.125 , 1.21875, 1.3125 , 1.40625, 1.5 , 1.59375, 1.6875 , 1.78125, 1.875 , 1.96875, 2.0625 , 2.15625, 2.25 , 2.34375, 2.4375 , 2.53125, 2.625 , 2.71875, 2.8125 , 2.90625, 3. , 3.09375, 3.1875 , 3.28125, 3.375 , 3.46875, 3.5625 , 3.65625, 3.75 , 3.84375, 3.9375 , 4.03125, 4.125 , 4.21875, 4.3125 , 4.40625, 4.5 , 4.59375, 4.6875 , 4.78125, 4.875 , 4.96875, 5.0625 , 5.15625, 5.25 , 5.34375, 5.4375 , 5.53125, 5.625 , 5.71875, 5.8125 , 5.90625, 6. , 6.09375, 6.1875 , 6.28125, 6.375 , 6.46875, 6.5625 , 6.65625, 6.75 , 6.84375, 6.9375 , 7.03125, 7.125 , 7.21875, 7.3125 , 7.40625, 7.5 , 7.59375, 7.6875 , 7.78125, 7.875 , 7.96875, 8.0625 , 8.15625, 8.25 , 8.34375, 8.4375 , 8.53125, 8.625 , 8.71875, 8.8125 , 8.90625, 9. , 9.09375, 9.1875 , 9.28125, 9.375 , 9.46875, 9.5625 , 9.65625, 9.75 , 9.84375, 9.9375 , 10.03125, 10.125 , 10.21875, 10.3125 , 10.40625, 10.5 , 10.59375, 10.6875 , 10.78125, 10.875 , 10.96875, 11.0625 , 11.15625, 11.25 , 11.34375, 11.4375 , 11.53125, 11.625 , 11.71875, 11.8125 , 11.90625])
- t(t)float640.0 0.75 1.5 ... 148.5 149.2 150.0
array([ 0. , 0.75, 1.5 , ..., 148.5 , 149.25, 150. ])
- i(i)object'x' 'y'
array(['x', 'y'], dtype=object)
- BC :
- {'x': {'ncl1': 2, 'ncln': 2, 'npaire': 1}, 'y': {'ncl1': 0, 'ncln': 0, 'npaire': 1, 'istret': 0, 'beta': 1.0}, 'z': {'ncl1': 0, 'ncln': 0, 'npaire': 1}}
Now computing the vorticity in parallel:
[19]:
%%time
dataset["vort"] = (
u_chunked.sel(i="y").x3d.first_derivative("x")
- u_chunked.sel(i="x").x3d.first_derivative("y")
).compute()
CPU times: user 3.03 s, sys: 1.34 s, total: 4.37 s
Wall time: 2.76 s
Again, remember that the dataset in this tutorial is to small that the overhead for parallel computing is not worth it. The wall time was 3 times bigger, but the code is here if you plan to try it on large scale simulations.
As usual, we can set attributes to the array we just computed:
[20]:
dataset["vort"].attrs = dict(name = "wz", long_name="Vorticity", units="-")
And plot it:
[21]:
g = dataset.vort.isel(t=slice(None, None, 10)).plot(
x="x", y="y", col="t", col_wrap=7, cmap="turbo", rasterized=True, robust=True
)
for ax in g.axes.flat:
ax.axes.set_aspect("equal")

Notice that xarray is built on top of Numpy, so its arrays and datasets are compatibles with many tools of the Numpy/SciPy universe. You can even access a numpy.ndarray
object with the property data
:
[22]:
dataset.epsi.data
[22]:
array([[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
...,
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.]], dtype=float32)
You can use it for backwards compatibility with your previous post-processing tools, in this way, the transition to xcompact3d-toolbox should be easier. It is just not so effective, because we lost track of metadata like the coordinates and attributes, they are key points for data analysis with xarray.
Interactive Visualization¶
All the previous examples where based on matplotlib, but xarray is compatible with more options. One of them is hvPlot (see Gridded Data).
hvPlot is recommended when you are exploring your data and need a bit more interactivity.
To exemplify, let’s reproduce one of the figure we did before, choosing one specific location in our mesh and looking at the time evolution of the velocity there:
[23]:
dataset.u.sel(x=10.0, y=6.0, method="nearest").hvplot(x="t", by="i")
[23]:
One key aspect about hvPlot is that when it gets more coordinates than it can handle in a plot, it presents the extra coordinates in widgets. So if we do not select any specific point in the domain and reproduce the same figure above, we will get widgets to select the point where we are looking:
[24]:
dataset.u.hvplot(x="t", by="i", widget_location="bottom")
[24]:
Here we reproduce the time evolution of the kinect energy, this time with hvPlot:
[25]:
dataset["kinetic_energy"].hvplot()
[25]:
And one last example, we can see a really nice animation of the vorticity field, here in a Jupyter Notebook, with a very few lines of code:
[26]:
dataset.sel(t = slice(40, None)).vort.hvplot(
x="x",
y="y",
aspect="equal",
clim=(-5, 5),
rasterize=True,
cmap="turbo",
widget_type="scrubber",
widget_location="bottom",
title="Flow around a Cylinder",
clabel=r"Vorticity [-]",
)
[26]:
Note: The sel(t = slice(40, None))
in the block above is not necessary, of course, we can see the animation since the beginning. It was just used to look better at readthedocs.
Sandbox Examples¶
Turbidity Current in Axisymmetric Configuration¶
[1]:
import matplotlib.pyplot as plt
import numpy as np
import xarray as xr
import xcompact3d_toolbox as x3d
Parameters¶
- Numerical precision
Use np.float64
if Xcompact3d was compiled with the flag -DDOUBLE_PREC
, use np.float32
otherwise.
[2]:
x3d.param["mytype"] = np.float32
- Xcompact3d’s parameters
For more information about them, checkout the API reference.
[3]:
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):
[4]:
ds = x3d.init_dataset(prm)
Let’s see it, data and attributes are attached, try to interact with the icons:
[5]:
ds
[5]:
<xarray.Dataset> Dimensions: (x: 501, y: 73, z: 501, n: 1) Coordinates: * x (x) float32 0.0 0.04 0.08 0.12 0.16 ... 19.88 19.92 19.96 20.0 * y (y) float32 0.0 0.02778 0.05556 0.08333 ... 1.917 1.944 1.972 2.0 * z (z) float32 0.0 0.04 0.08 0.12 0.16 ... 19.88 19.92 19.96 20.0 * n (n) int32 1 Data variables: ux (x, y, z) float32 0.0 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 0.0 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 0.0 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 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0
- x: 501
- y: 73
- z: 501
- n: 1
- x(x)float320.0 0.04 0.08 ... 19.92 19.96 20.0
- name :
- Streamwise coordinate
- long_name :
- $x_1$
array([ 0. , 0.04, 0.08, ..., 19.92, 19.96, 20. ], dtype=float32)
- y(y)float320.0 0.02778 0.05556 ... 1.972 2.0
- name :
- Vertical coordinate
- long_name :
- $x_2$
array([0. , 0.027778, 0.055556, 0.083333, 0.111111, 0.138889, 0.166667, 0.194444, 0.222222, 0.25 , 0.277778, 0.305556, 0.333333, 0.361111, 0.388889, 0.416667, 0.444444, 0.472222, 0.5 , 0.527778, 0.555556, 0.583333, 0.611111, 0.638889, 0.666667, 0.694444, 0.722222, 0.75 , 0.777778, 0.805556, 0.833333, 0.861111, 0.888889, 0.916667, 0.944444, 0.972222, 1. , 1.027778, 1.055556, 1.083333, 1.111111, 1.138889, 1.166667, 1.194444, 1.222222, 1.25 , 1.277778, 1.305556, 1.333333, 1.361111, 1.388889, 1.416667, 1.444444, 1.472222, 1.5 , 1.527778, 1.555556, 1.583333, 1.611111, 1.638889, 1.666667, 1.694444, 1.722222, 1.75 , 1.777778, 1.805556, 1.833333, 1.861111, 1.888889, 1.916667, 1.944444, 1.972222, 2. ], dtype=float32)
- z(z)float320.0 0.04 0.08 ... 19.92 19.96 20.0
- name :
- Spanwise coordinate
- long_name :
- $x_3$
array([ 0. , 0.04, 0.08, ..., 19.92, 19.96, 20. ], dtype=float32)
- n(n)int321
- name :
- Scalar fraction
- long_name :
- $\ell$
array([1])
- ux(x, y, z)float320.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- ux
- name :
- Initial Condition for Streamwise Velocity
- long_name :
- $u_1 (x_1,x_2,x_3,t=0)$
- BC :
- {'x': {'ncl1': 1, 'ncln': 1, 'npaire': 0}, 'y': {'ncl1': 2, 'ncln': 1, 'npaire': 1, 'istret': 0, 'beta': 1.0}, 'z': {'ncl1': 1, 'ncln': 1, 'npaire': 1}}
array([[[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., ... ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]]], dtype=float32)
- uy(x, y, z)float320.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- uy
- name :
- Initial Condition for Vertical Velocity
- long_name :
- $u_2 (x_1,x_2,x_3,t=0)$
- BC :
- {'x': {'ncl1': 1, 'ncln': 1, 'npaire': 1}, 'y': {'ncl1': 2, 'ncln': 1, 'npaire': 0, 'istret': 0, 'beta': 1.0}, 'z': {'ncl1': 1, 'ncln': 1, 'npaire': 1}}
array([[[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., ... ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]]], dtype=float32)
- uz(x, y, z)float320.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- uz
- name :
- Initial Condition for Spanwise Velocity
- long_name :
- $u_3 (x_1,x_2,x_3,t=0)$
- BC :
- {'x': {'ncl1': 1, 'ncln': 1, 'npaire': 1}, 'y': {'ncl1': 2, 'ncln': 1, 'npaire': 1, 'istret': 0, 'beta': 1.0}, 'z': {'ncl1': 1, 'ncln': 1, 'npaire': 0}}
array([[[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., ... ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]]], dtype=float32)
- phi(n, x, y, z)float320.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- phi
- name :
- Initial Condition for Scalar field(s)
- long_name :
- $\varphi (x_1,x_2,x_3,n,t=0)$
- BC :
- {'x': {'ncl1': 1, 'ncln': 1, 'npaire': 1}, 'y': {'ncl1': 1, 'ncln': 1, 'npaire': 1, 'istret': 0, 'beta': 1.0}, 'z': {'ncl1': 1, 'ncln': 1, 'npaire': 1}}
array([[[[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., ... ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]]]], dtype=float32)
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:
[6]:
# 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();

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:
[7]:
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

Initial Condition for Vertical Velocity

Initial Condition for Spanwise Velocity

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:
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:
[8]:
# 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"][dict(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)

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
Flow Around a Complex Body¶
[1]:
import matplotlib.pyplot as plt
import numpy as np
import xarray as xr
import xcompact3d_toolbox as x3d
Parameters¶
- Numerical precision
Use np.float64
if Xcompact3d was compiled with the flag -DDOUBLE_PREC
, use np.float32
otherwise.
[2]:
x3d.param["mytype"] = np.float64
- Xcompact3d’s parameters
For more information about them, checkout the API reference.
[3]:
prm = x3d.Parameters(
filename="input.i3d",
itype=12,
p_row=0,
p_col=0,
nx=257,
ny=129,
nz=32,
xlx=15.0,
yly=10.0,
zlz=3.0,
nclx1=2,
nclxn=2,
ncly1=1,
nclyn=1,
nclz1=0,
nclzn=0,
iin=1,
re=300.0,
init_noise=0.0125,
inflow_noise=0.0125,
dt=0.0025,
ifirst=1,
ilast=45000,
ilesmod=1,
iibm=2,
nu0nu=4.0,
cnu=0.44,
irestart=0,
icheckpoint=45000,
ioutput=200,
iprocessing=50,
jles=4,
)
Setup¶
Geometry¶
Everything needed is in one dictionary of Arrays (see API reference):
[4]:
epsi = x3d.init_epsi(prm)
The four \(\epsilon\) matrices are stored in a dictionary:
[5]:
epsi.keys()
[5]:
dict_keys(['epsi', 'xepsi', 'yepsi', 'zepsi'])
Just to exemplify, we can draw and plot a cylinder. Make sure to apply the same operation over all arrays in the dictionary. 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 select one value in \(z\) and make a 2D plot:
[6]:
for key in epsi.keys():
epsi[key] = epsi[key].geo.cylinder(x=1, y=prm.yly / 4.0)
epsi["epsi"].sel(z=0, method="nearest").plot(x="x");

Notice that the geometries are added by default, however, we can revert it by setting remp=False
. We can execute several methods in a chain, resulting in more complex geometries.
[7]:
for key in epsi.keys():
epsi[key] = (
epsi[key]
.geo.cylinder(x=2, y=prm.yly / 8.0)
.geo.cylinder(x=2, y=prm.yly / 8.0, radius=0.25, remp=False)
.geo.sphere(x=6, y=prm.yly / 4, z=prm.zlz / 2.0)
.geo.box(x=[3, 4], y=[3, 4])
)
epsi["epsi"].sel(z=prm.zlz / 2, method="nearest").plot(x="x");

Other example, Ahmed body:
[8]:
for key in epsi.keys():
epsi[key] = epsi[key].geo.ahmed_body(x=10, wheels=False)
epsi["epsi"].sel(z=prm.zlz / 2, method="nearest").plot(x="x");

Zooming in:
[9]:
epsi["epsi"].sel(x=slice(8, None), y=slice(None, 4)).sel(
z=prm.zlz / 2, method="nearest"
).plot(x="x");

And just as an example, we can mirror it:
[10]:
for key in epsi.keys():
epsi[key] = epsi[key].geo.mirror("y")
epsi["epsi"].sel(z=prm.zlz / 2, method="nearest").plot(x="x");

It was just to show the capabilities of xcompact3d_toolbox.sandbox
, you can use it to build many different geometries and arrange them in many ways. However, 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.
For a complete description about the available geometries see Api reference. Notice that you combine them for the creation of unique geometries, or even create your own routines for your own objects.
So, let’s start over with a simpler geometry:
[11]:
epsi = x3d.sandbox.init_epsi(prm)
for key in epsi.keys():
epsi[key] = epsi[key].geo.cylinder(x=prm.xlx / 3, y=prm.yly / 2)
epsi["epsi"].sel(z=0, method="nearest").plot(x="x")
plt.show();

The next step is to produce all the auxiliary files describing the geometry, so then Xcompact3d can read them:
[12]:
%%time
dataset = x3d.gene_epsi_3D(epsi, prm)
prm.nobjmax = dataset.obj.size
dataset
x
nobjraf : 1
nobjmaxraf : 1
bug : 0
y
nobjraf : 1
nobjmaxraf : 1
bug : 0
z
nobjraf : 1
nobjmaxraf : 1
bug : 0
number of points with potential problem in x : 0
number of points with potential problem in y : 0
number of points with potential problem in z : 0
Writing...
Wall time: 6.01 s
[12]:
<xarray.Dataset> Dimensions: (obj_aux: 2, obj: 1, x: 257, y: 129, z: 32) Coordinates: * obj_aux (obj_aux) int32 -1 0 * obj (obj) int32 0 * x (x) float64 0.0 0.05859 0.1172 0.1758 ... 14.88 14.94 15.0 * y (y) float64 0.0 0.07812 0.1562 0.2344 ... 9.844 9.922 10.0 * z (z) float64 0.0 0.09375 0.1875 0.2812 ... 2.719 2.812 2.906 Data variables: (12/28) epsi (x, y, z) bool False False False False ... False False False nobj_x (y, z) int64 0 0 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 0 0 nobjmax_x int64 1 nobjraf_x (y, z) int64 0 0 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 0 0 nobjmaxraf_x int64 1 ibug_x int64 0 ... ... nxipif_y (x, z, obj_aux) int64 2 2 2 2 2 2 2 2 2 ... 2 2 2 2 2 2 2 2 2 nxfpif_y (x, z, obj_aux) int64 128 2 128 2 128 2 ... 128 2 128 2 128 2 xi_z (x, y, obj) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 xf_z (x, y, obj) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 nxipif_z (x, y, obj_aux) int64 2 2 2 2 2 2 2 2 2 ... 2 2 2 2 2 2 2 2 2 nxfpif_z (x, y, obj_aux) int64 31 2 31 2 31 2 31 2 ... 2 31 2 31 2 31 2
- obj_aux: 2
- obj: 1
- x: 257
- y: 129
- z: 32
- obj_aux(obj_aux)int32-1 0
array([-1, 0])
- obj(obj)int320
array([0])
- x(x)float640.0 0.05859 0.1172 ... 14.94 15.0
array([ 0. , 0.058594, 0.117188, ..., 14.882812, 14.941406, 15. ])
- y(y)float640.0 0.07812 0.1562 ... 9.922 10.0
array([ 0. , 0.078125, 0.15625 , 0.234375, 0.3125 , 0.390625, 0.46875 , 0.546875, 0.625 , 0.703125, 0.78125 , 0.859375, 0.9375 , 1.015625, 1.09375 , 1.171875, 1.25 , 1.328125, 1.40625 , 1.484375, 1.5625 , 1.640625, 1.71875 , 1.796875, 1.875 , 1.953125, 2.03125 , 2.109375, 2.1875 , 2.265625, 2.34375 , 2.421875, 2.5 , 2.578125, 2.65625 , 2.734375, 2.8125 , 2.890625, 2.96875 , 3.046875, 3.125 , 3.203125, 3.28125 , 3.359375, 3.4375 , 3.515625, 3.59375 , 3.671875, 3.75 , 3.828125, 3.90625 , 3.984375, 4.0625 , 4.140625, 4.21875 , 4.296875, 4.375 , 4.453125, 4.53125 , 4.609375, 4.6875 , 4.765625, 4.84375 , 4.921875, 5. , 5.078125, 5.15625 , 5.234375, 5.3125 , 5.390625, 5.46875 , 5.546875, 5.625 , 5.703125, 5.78125 , 5.859375, 5.9375 , 6.015625, 6.09375 , 6.171875, 6.25 , 6.328125, 6.40625 , 6.484375, 6.5625 , 6.640625, 6.71875 , 6.796875, 6.875 , 6.953125, 7.03125 , 7.109375, 7.1875 , 7.265625, 7.34375 , 7.421875, 7.5 , 7.578125, 7.65625 , 7.734375, 7.8125 , 7.890625, 7.96875 , 8.046875, 8.125 , 8.203125, 8.28125 , 8.359375, 8.4375 , 8.515625, 8.59375 , 8.671875, 8.75 , 8.828125, 8.90625 , 8.984375, 9.0625 , 9.140625, 9.21875 , 9.296875, 9.375 , 9.453125, 9.53125 , 9.609375, 9.6875 , 9.765625, 9.84375 , 9.921875, 10. ])
- z(z)float640.0 0.09375 0.1875 ... 2.812 2.906
array([0. , 0.09375, 0.1875 , 0.28125, 0.375 , 0.46875, 0.5625 , 0.65625, 0.75 , 0.84375, 0.9375 , 1.03125, 1.125 , 1.21875, 1.3125 , 1.40625, 1.5 , 1.59375, 1.6875 , 1.78125, 1.875 , 1.96875, 2.0625 , 2.15625, 2.25 , 2.34375, 2.4375 , 2.53125, 2.625 , 2.71875, 2.8125 , 2.90625])
- epsi(x, y, z)boolFalse False False ... False False
- file_name :
- geometry\epsilon
array([[[False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], ..., [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False]], [[False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], ..., [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False]], [[False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], ..., ... ..., [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False]], [[False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], ..., [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False]], [[False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], ..., [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False]]])
- nobj_x(y, z)int640 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=int64)
- nobjmax_x()int641
array(1, dtype=int64)
- nobjraf_x(y, z)int640 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=int64)
- nobjmaxraf_x()int641
array(1, dtype=int64)
- ibug_x()int640
array(0, dtype=int64)
- nobj_y(x, z)int640 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=int64)
- nobjmax_y()int641
array(1, dtype=int64)
- nobjraf_y(x, z)int640 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=int64)
- nobjmaxraf_y()int641
array(1, dtype=int64)
- ibug_y()int640
array(0, dtype=int64)
- nobj_z(x, y)int640 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=int64)
- nobjmax_z()int641
array(1, dtype=int64)
- nobjraf_z(x, y)int640 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=int64)
- nobjmaxraf_z()int641
array(1, dtype=int64)
- ibug_z()int640
array(0, dtype=int64)
- xi_x(y, z, obj)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
array([[[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., ... ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]]])
- xf_x(y, z, obj)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
array([[[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., ... ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]]])
- nxipif_x(y, z, obj_aux)int642 2 2 2 2 2 2 2 ... 2 2 2 2 2 2 2 2
array([[[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., ... ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]]], dtype=int64)
- nxfpif_x(y, z, obj_aux)int64256 2 256 2 256 2 ... 2 256 2 256 2
array([[[256, 2], [256, 2], [256, 2], ..., [256, 2], [256, 2], [256, 2]], [[256, 2], [256, 2], [256, 2], ..., [256, 2], [256, 2], [256, 2]], [[256, 2], [256, 2], [256, 2], ..., ... ..., [256, 2], [256, 2], [256, 2]], [[256, 2], [256, 2], [256, 2], ..., [256, 2], [256, 2], [256, 2]], [[256, 2], [256, 2], [256, 2], ..., [256, 2], [256, 2], [256, 2]]], dtype=int64)
- xi_y(x, z, obj)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
array([[[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., ... ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]]])
- xf_y(x, z, obj)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
array([[[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., ... ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]]])
- nxipif_y(x, z, obj_aux)int642 2 2 2 2 2 2 2 ... 2 2 2 2 2 2 2 2
array([[[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., ... ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]]], dtype=int64)
- nxfpif_y(x, z, obj_aux)int64128 2 128 2 128 2 ... 2 128 2 128 2
array([[[128, 2], [128, 2], [128, 2], ..., [128, 2], [128, 2], [128, 2]], [[128, 2], [128, 2], [128, 2], ..., [128, 2], [128, 2], [128, 2]], [[128, 2], [128, 2], [128, 2], ..., ... ..., [128, 2], [128, 2], [128, 2]], [[128, 2], [128, 2], [128, 2], ..., [128, 2], [128, 2], [128, 2]], [[128, 2], [128, 2], [128, 2], ..., [128, 2], [128, 2], [128, 2]]], dtype=int64)
- xi_z(x, y, obj)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
array([[[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., ... ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]]])
- xf_z(x, y, obj)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
array([[[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., ... ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]]])
- nxipif_z(x, y, obj_aux)int642 2 2 2 2 2 2 2 ... 2 2 2 2 2 2 2 2
array([[[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., ... ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]]], dtype=int64)
- nxfpif_z(x, y, obj_aux)int6431 2 31 2 31 2 ... 31 2 31 2 31 2
array([[[31, 2], [31, 2], [31, 2], ..., [31, 2], [31, 2], [31, 2]], [[31, 2], [31, 2], [31, 2], ..., [31, 2], [31, 2], [31, 2]], [[31, 2], [31, 2], [31, 2], ..., ... ..., [31, 2], [31, 2], [31, 2]], [[31, 2], [31, 2], [31, 2], ..., [31, 2], [31, 2], [31, 2]], [[31, 2], [31, 2], [31, 2], ..., [31, 2], [31, 2], [31, 2]]], dtype=int64)
Boundary Condition¶
Everything needed is in one Dataset (see API reference):
[13]:
ds = x3d.init_dataset(prm)
Let’s see it, data and attributes are attached, try to interact with the icons:
[14]:
ds
[14]:
<xarray.Dataset> Dimensions: (x: 257, y: 129, z: 32, n: 0) Coordinates: * x (x) float64 0.0 0.05859 0.1172 0.1758 ... 14.88 14.94 15.0 * y (y) float64 0.0 0.07812 0.1562 0.2344 ... 9.844 9.922 10.0 * z (z) float64 0.0 0.09375 0.1875 0.2812 ... 2.719 2.812 2.906 * n (n) float64 Data variables: bxx1 (y, z) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 bxy1 (y, z) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 bxz1 (y, z) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 noise_mod_x1 (y, z) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 ux (x, y, z) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 uy (x, y, z) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 uz (x, y, z) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0
- x: 257
- y: 129
- z: 32
- n: 0
- x(x)float640.0 0.05859 0.1172 ... 14.94 15.0
- name :
- Streamwise coordinate
- long_name :
- $x_1$
array([ 0. , 0.058594, 0.117188, ..., 14.882812, 14.941406, 15. ])
- y(y)float640.0 0.07812 0.1562 ... 9.922 10.0
- name :
- Vertical coordinate
- long_name :
- $x_2$
array([ 0. , 0.078125, 0.15625 , 0.234375, 0.3125 , 0.390625, 0.46875 , 0.546875, 0.625 , 0.703125, 0.78125 , 0.859375, 0.9375 , 1.015625, 1.09375 , 1.171875, 1.25 , 1.328125, 1.40625 , 1.484375, 1.5625 , 1.640625, 1.71875 , 1.796875, 1.875 , 1.953125, 2.03125 , 2.109375, 2.1875 , 2.265625, 2.34375 , 2.421875, 2.5 , 2.578125, 2.65625 , 2.734375, 2.8125 , 2.890625, 2.96875 , 3.046875, 3.125 , 3.203125, 3.28125 , 3.359375, 3.4375 , 3.515625, 3.59375 , 3.671875, 3.75 , 3.828125, 3.90625 , 3.984375, 4.0625 , 4.140625, 4.21875 , 4.296875, 4.375 , 4.453125, 4.53125 , 4.609375, 4.6875 , 4.765625, 4.84375 , 4.921875, 5. , 5.078125, 5.15625 , 5.234375, 5.3125 , 5.390625, 5.46875 , 5.546875, 5.625 , 5.703125, 5.78125 , 5.859375, 5.9375 , 6.015625, 6.09375 , 6.171875, 6.25 , 6.328125, 6.40625 , 6.484375, 6.5625 , 6.640625, 6.71875 , 6.796875, 6.875 , 6.953125, 7.03125 , 7.109375, 7.1875 , 7.265625, 7.34375 , 7.421875, 7.5 , 7.578125, 7.65625 , 7.734375, 7.8125 , 7.890625, 7.96875 , 8.046875, 8.125 , 8.203125, 8.28125 , 8.359375, 8.4375 , 8.515625, 8.59375 , 8.671875, 8.75 , 8.828125, 8.90625 , 8.984375, 9.0625 , 9.140625, 9.21875 , 9.296875, 9.375 , 9.453125, 9.53125 , 9.609375, 9.6875 , 9.765625, 9.84375 , 9.921875, 10. ])
- z(z)float640.0 0.09375 0.1875 ... 2.812 2.906
- name :
- Spanwise coordinate
- long_name :
- $x_3$
array([0. , 0.09375, 0.1875 , 0.28125, 0.375 , 0.46875, 0.5625 , 0.65625, 0.75 , 0.84375, 0.9375 , 1.03125, 1.125 , 1.21875, 1.3125 , 1.40625, 1.5 , 1.59375, 1.6875 , 1.78125, 1.875 , 1.96875, 2.0625 , 2.15625, 2.25 , 2.34375, 2.4375 , 2.53125, 2.625 , 2.71875, 2.8125 , 2.90625])
- n(n)float64
- name :
- Scalar fraction
- long_name :
- $\ell$
array([], dtype=float64)
- bxx1(y, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- bxx1
- name :
- Inflow Plane for Streamwise Velocity
- long_name :
- $u_1 (x_1=0,x_2,x_3)$
array([[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]])
- bxy1(y, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- bxy1
- name :
- Inflow Plane for Vertical Velocity
- long_name :
- $u_2 (x_1=0,x_2,x_3)$
array([[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]])
- bxz1(y, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- bxz1
- name :
- Inflow Plane for Spanwise Velocity
- long_name :
- $u_3 (x_1=0,x_2,x_3)$
array([[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]])
- noise_mod_x1(y, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- noise_mod_x1
- name :
- Modulation function for Random Numbers at Inflow Plane
- long_name :
- mod $ (x_1=0,x_2,x_3)$
array([[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]])
- ux(x, y, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- ux
- name :
- Initial Condition for Streamwise Velocity
- long_name :
- $u_1 (x_1,x_2,x_3,t=0)$
- BC :
- {'x': {'ncl1': 2, 'ncln': 2, 'npaire': 0}, 'y': {'ncl1': 1, 'ncln': 1, 'npaire': 1, 'istret': 0, 'beta': 1.0}, 'z': {'ncl1': 0, 'ncln': 0, 'npaire': 1}}
array([[[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., ... ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]]])
- uy(x, y, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- uy
- name :
- Initial Condition for Vertical Velocity
- long_name :
- $u_2 (x_1,x_2,x_3,t=0)$
- BC :
- {'x': {'ncl1': 2, 'ncln': 2, 'npaire': 1}, 'y': {'ncl1': 1, 'ncln': 1, 'npaire': 0, 'istret': 0, 'beta': 1.0}, 'z': {'ncl1': 0, 'ncln': 0, 'npaire': 1}}
array([[[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., ... ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]]])
- uz(x, y, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- uz
- name :
- Initial Condition for Spanwise Velocity
- long_name :
- $u_3 (x_1,x_2,x_3,t=0)$
- BC :
- {'x': {'ncl1': 2, 'ncln': 2, 'npaire': 1}, 'y': {'ncl1': 1, 'ncln': 1, 'npaire': 1, 'istret': 0, 'beta': 1.0}, 'z': {'ncl1': 0, 'ncln': 0, 'npaire': 0}}
array([[[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., ... ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]]])
Inflow profile: Since the boundary conditions for velocity at the top and at the bottom are free-slip in this case (ncly1=nclyn=1
), the inflow profile for streamwise velocity is just 1 everywhere:
[15]:
fun = xr.ones_like(ds.y)
# This attribute will be shown in the figure
fun.attrs["long_name"] = r"Inflow Profile - f($x_2$)"
fun.plot();

Now, we reset the inflow planes ds[key] *= 0.0
, just to guarantee consistency in 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. Then, we add the inflow profile to the streamwise componente and plot them for reference:
[16]:
for key in "bxx1 bxy1 bxz1".split():
#
print(ds[key].attrs["name"])
#
ds[key] *= 0.0
#
if key == "bxx1":
ds[key] += fun
#
ds[key].plot()
plt.show()
plt.close("all")
Inflow Plane for Streamwise Velocity

Inflow Plane for Vertical Velocity

Inflow Plane for Spanwise Velocity

A random noise will be applied at the inflow boundary, we can create a modulation function mod
to control were it will be applied. In this case, we will concentrate the noise near the center region and make it zero were \(y=0\) and \(y=L_y\). The domain is periodic in \(z\) nclz1=nclzn=0
, so there is no need to make mod
functions of \(z\). The functions looks like:
See the code:
[17]:
# Random noise with fixed seed,
# important for reproducibility, development and debugging
if prm.iin == 2:
np.random.seed(seed=67)
mod = np.exp(-0.2 * (ds.y - ds.y[-1] * 0.5) ** 2.0)
# This attribute will be shown in the figure
mod.attrs["long_name"] = "Noise modulation"
mod.plot();

Again, we reset the array ds['noise_mod_x1'] *= 0.0
, just to guarantee consistency in case of multiple executions of this cell. Notice that ds['noise_mod_x1'] *= 0.0
may overwrite all the metadata contained in the array, so it should be avoided. Then, we add the modulation profile to the proper array and plot it for reference:
[18]:
ds["noise_mod_x1"] *= 0.0
ds["noise_mod_x1"] += mod
ds.noise_mod_x1.plot();

Notice one of the many advantages of using xarray, mod
, with shape (ny
), was automatically broadcasted for every point in z
into ds.noise_mod_x1
, with shape (ny
, nz
).
Initial Condition¶
Now we reset velocity fields ds[key] *= 0.0
, just to guarantee consistency in the case of multiple executions of this cell.
We then add a random number array with the right shape, multiply by the noise amplitude at the initial condition init_noise
and multiply again by our modulation function mod
, defined previously. Finally, we add the streamwise profile fun
to ux
and make the plots for reference, I’m adding extra options just to exemplify how easily we can slice the spanwise coordinate and produce multiple plots:
[19]:
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
#
if key == "ux":
ds[key] += fun
#
ds[key].sel(z=slice(None, None, ds.z.size // 3)).plot(
x="x", y="y", col="z", col_wrap=2
)
plt.show()
#
plt.close("all")
Initial Condition for Streamwise Velocity

Initial Condition for Vertical Velocity

Initial Condition for Spanwise Velocity

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
Flow Around a Square and Flow Visualization with Passive Scalar¶
[1]:
import matplotlib.pyplot as plt
import numpy as np
import xarray as xr
import xcompact3d_toolbox as x3d
Parameters¶
- Numerical precision
Use np.float64
if Xcompact3d was compiled with the flag -DDOUBLE_PREC
, use np.float32
otherwise.
[2]:
x3d.param["mytype"] = np.float64
- Xcompact3d’s parameters
For more information about them, checkout the API reference.
[3]:
prm = x3d.Parameters(
filename="input.i3d",
# BasicParam
itype=12,
p_row=0,
p_col=0,
nx=257,
ny=129,
nz=32,
xlx=15.0,
yly=10.0,
zlz=3.0,
nclx1=2,
nclxn=2,
ncly1=1,
nclyn=1,
nclz1=0,
nclzn=0,
iin=1,
re=300.0,
init_noise=0.0125,
inflow_noise=0.0125,
dt=0.0025,
ifirst=1,
ilast=90000,
ilesmod=1,
iibm=2, # This is experimental, not available at the main repo
# NumOptions
nu0nu=4.0,
cnu=0.44,
# InOutParam
irestart=0,
icheckpoint=45000,
ioutput=500,
iprocessing=100,
# LESModel
jles=4,
# ScalarParam
numscalar=1,
nclxS1=2,
nclxSn=2,
nclyS1=1,
nclySn=1,
nclzS1=0,
nclzSn=0,
sc=[1.0],
ri=[0.0], # Zero for numerical dye
uset=[0.0], # Zero for numerical dye
cp=[1.0],
#iibmS=3, # This is experimental, not available at the main repo
)
Setup¶
Geometry¶
Everything needed is in one dictionary of Arrays (see API reference):
[4]:
epsi = x3d.init_epsi(prm)
The four \(\epsilon\) matrices are stored in a dictionary:
[5]:
epsi.keys()
[5]:
dict_keys(['epsi', 'xepsi', 'yepsi', 'zepsi'])
Now we draw a square:
[6]:
# Here we set the center
center = dict(x=prm.xlx / 3.0, y=prm.yly / 2.0)
# And apply geo.box over the four arrays
for key in epsi.keys():
epsi[key] = epsi[key].geo.box(
x=[center["x"] - 0.5, center["x"] + 0.5],
y=[center["y"] - 0.5, center["y"] + 0.5],
)
# A quickie plot for reference
epsi["epsi"].sel(z=0, method="nearest").plot(x="x");

The next step is to produce all the auxiliary files describing the geometry, so then Xcompact3d can read them:
[7]:
%%time
dataset = x3d.gene_epsi_3D(epsi, prm)
prm.nobjmax = dataset.obj.size
dataset
x
nobjraf : 1
nobjmaxraf : 1
bug : 0
y
nobjraf : 1
nobjmaxraf : 1
bug : 0
z
nobjraf : 1
nobjmaxraf : 1
bug : 0
number of points with potential problem in x : 0
number of points with potential problem in y : 0
number of points with potential problem in z : 0
Writing...
Wall time: 5.32 s
[7]:
<xarray.Dataset> Dimensions: (obj_aux: 2, obj: 1, x: 257, y: 129, z: 32) Coordinates: * obj_aux (obj_aux) int32 -1 0 * obj (obj) int32 0 * x (x) float64 0.0 0.05859 0.1172 0.1758 ... 14.88 14.94 15.0 * y (y) float64 0.0 0.07812 0.1562 0.2344 ... 9.844 9.922 10.0 * z (z) float64 0.0 0.09375 0.1875 0.2812 ... 2.719 2.812 2.906 Data variables: (12/28) epsi (x, y, z) bool False False False False ... False False False nobj_x (y, z) int64 0 0 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 0 0 nobjmax_x int64 1 nobjraf_x (y, z) int64 0 0 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 0 0 nobjmaxraf_x int64 1 ibug_x int64 0 ... ... nxipif_y (x, z, obj_aux) int64 2 2 2 2 2 2 2 2 2 ... 2 2 2 2 2 2 2 2 2 nxfpif_y (x, z, obj_aux) int64 128 2 128 2 128 2 ... 128 2 128 2 128 2 xi_z (x, y, obj) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 xf_z (x, y, obj) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 nxipif_z (x, y, obj_aux) int64 2 2 2 2 2 2 2 2 2 ... 2 2 2 2 2 2 2 2 2 nxfpif_z (x, y, obj_aux) int64 31 2 31 2 31 2 31 2 ... 2 31 2 31 2 31 2
- obj_aux: 2
- obj: 1
- x: 257
- y: 129
- z: 32
- obj_aux(obj_aux)int32-1 0
array([-1, 0])
- obj(obj)int320
array([0])
- x(x)float640.0 0.05859 0.1172 ... 14.94 15.0
array([ 0. , 0.058594, 0.117188, ..., 14.882812, 14.941406, 15. ])
- y(y)float640.0 0.07812 0.1562 ... 9.922 10.0
array([ 0. , 0.078125, 0.15625 , 0.234375, 0.3125 , 0.390625, 0.46875 , 0.546875, 0.625 , 0.703125, 0.78125 , 0.859375, 0.9375 , 1.015625, 1.09375 , 1.171875, 1.25 , 1.328125, 1.40625 , 1.484375, 1.5625 , 1.640625, 1.71875 , 1.796875, 1.875 , 1.953125, 2.03125 , 2.109375, 2.1875 , 2.265625, 2.34375 , 2.421875, 2.5 , 2.578125, 2.65625 , 2.734375, 2.8125 , 2.890625, 2.96875 , 3.046875, 3.125 , 3.203125, 3.28125 , 3.359375, 3.4375 , 3.515625, 3.59375 , 3.671875, 3.75 , 3.828125, 3.90625 , 3.984375, 4.0625 , 4.140625, 4.21875 , 4.296875, 4.375 , 4.453125, 4.53125 , 4.609375, 4.6875 , 4.765625, 4.84375 , 4.921875, 5. , 5.078125, 5.15625 , 5.234375, 5.3125 , 5.390625, 5.46875 , 5.546875, 5.625 , 5.703125, 5.78125 , 5.859375, 5.9375 , 6.015625, 6.09375 , 6.171875, 6.25 , 6.328125, 6.40625 , 6.484375, 6.5625 , 6.640625, 6.71875 , 6.796875, 6.875 , 6.953125, 7.03125 , 7.109375, 7.1875 , 7.265625, 7.34375 , 7.421875, 7.5 , 7.578125, 7.65625 , 7.734375, 7.8125 , 7.890625, 7.96875 , 8.046875, 8.125 , 8.203125, 8.28125 , 8.359375, 8.4375 , 8.515625, 8.59375 , 8.671875, 8.75 , 8.828125, 8.90625 , 8.984375, 9.0625 , 9.140625, 9.21875 , 9.296875, 9.375 , 9.453125, 9.53125 , 9.609375, 9.6875 , 9.765625, 9.84375 , 9.921875, 10. ])
- z(z)float640.0 0.09375 0.1875 ... 2.812 2.906
array([0. , 0.09375, 0.1875 , 0.28125, 0.375 , 0.46875, 0.5625 , 0.65625, 0.75 , 0.84375, 0.9375 , 1.03125, 1.125 , 1.21875, 1.3125 , 1.40625, 1.5 , 1.59375, 1.6875 , 1.78125, 1.875 , 1.96875, 2.0625 , 2.15625, 2.25 , 2.34375, 2.4375 , 2.53125, 2.625 , 2.71875, 2.8125 , 2.90625])
- epsi(x, y, z)boolFalse False False ... False False
- file_name :
- geometry\epsilon
array([[[False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], ..., [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False]], [[False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], ..., [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False]], [[False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], ..., ... ..., [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False]], [[False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], ..., [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False]], [[False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], ..., [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False]]])
- nobj_x(y, z)int640 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=int64)
- nobjmax_x()int641
array(1, dtype=int64)
- nobjraf_x(y, z)int640 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=int64)
- nobjmaxraf_x()int641
array(1, dtype=int64)
- ibug_x()int640
array(0, dtype=int64)
- nobj_y(x, z)int640 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=int64)
- nobjmax_y()int641
array(1, dtype=int64)
- nobjraf_y(x, z)int640 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=int64)
- nobjmaxraf_y()int641
array(1, dtype=int64)
- ibug_y()int640
array(0, dtype=int64)
- nobj_z(x, y)int640 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=int64)
- nobjmax_z()int641
array(1, dtype=int64)
- nobjraf_z(x, y)int640 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=int64)
- nobjmaxraf_z()int641
array(1, dtype=int64)
- ibug_z()int640
array(0, dtype=int64)
- xi_x(y, z, obj)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
array([[[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., ... ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]]])
- xf_x(y, z, obj)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
array([[[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., ... ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]]])
- nxipif_x(y, z, obj_aux)int642 2 2 2 2 2 2 2 ... 2 2 2 2 2 2 2 2
array([[[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., ... ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]]], dtype=int64)
- nxfpif_x(y, z, obj_aux)int64256 2 256 2 256 2 ... 2 256 2 256 2
array([[[256, 2], [256, 2], [256, 2], ..., [256, 2], [256, 2], [256, 2]], [[256, 2], [256, 2], [256, 2], ..., [256, 2], [256, 2], [256, 2]], [[256, 2], [256, 2], [256, 2], ..., ... ..., [256, 2], [256, 2], [256, 2]], [[256, 2], [256, 2], [256, 2], ..., [256, 2], [256, 2], [256, 2]], [[256, 2], [256, 2], [256, 2], ..., [256, 2], [256, 2], [256, 2]]], dtype=int64)
- xi_y(x, z, obj)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
array([[[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., ... ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]]])
- xf_y(x, z, obj)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
array([[[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., ... ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]]])
- nxipif_y(x, z, obj_aux)int642 2 2 2 2 2 2 2 ... 2 2 2 2 2 2 2 2
array([[[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., ... ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]]], dtype=int64)
- nxfpif_y(x, z, obj_aux)int64128 2 128 2 128 2 ... 2 128 2 128 2
array([[[128, 2], [128, 2], [128, 2], ..., [128, 2], [128, 2], [128, 2]], [[128, 2], [128, 2], [128, 2], ..., [128, 2], [128, 2], [128, 2]], [[128, 2], [128, 2], [128, 2], ..., ... ..., [128, 2], [128, 2], [128, 2]], [[128, 2], [128, 2], [128, 2], ..., [128, 2], [128, 2], [128, 2]], [[128, 2], [128, 2], [128, 2], ..., [128, 2], [128, 2], [128, 2]]], dtype=int64)
- xi_z(x, y, obj)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
array([[[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., ... ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]]])
- xf_z(x, y, obj)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
array([[[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., ... ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]]])
- nxipif_z(x, y, obj_aux)int642 2 2 2 2 2 2 2 ... 2 2 2 2 2 2 2 2
array([[[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., ... ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]]], dtype=int64)
- nxfpif_z(x, y, obj_aux)int6431 2 31 2 31 2 ... 31 2 31 2 31 2
array([[[31, 2], [31, 2], [31, 2], ..., [31, 2], [31, 2], [31, 2]], [[31, 2], [31, 2], [31, 2], ..., [31, 2], [31, 2], [31, 2]], [[31, 2], [31, 2], [31, 2], ..., ... ..., [31, 2], [31, 2], [31, 2]], [[31, 2], [31, 2], [31, 2], ..., [31, 2], [31, 2], [31, 2]], [[31, 2], [31, 2], [31, 2], ..., [31, 2], [31, 2], [31, 2]]], dtype=int64)
Boundary Condition¶
Everything needed is in one Dataset (see API reference):
[8]:
ds = x3d.init_dataset(prm)
Let’s see it, data and attributes are attached, try to interact with the icons:
[9]:
ds
[9]:
<xarray.Dataset> Dimensions: (x: 257, y: 129, z: 32, n: 1) Coordinates: * x (x) float64 0.0 0.05859 0.1172 0.1758 ... 14.88 14.94 15.0 * y (y) float64 0.0 0.07812 0.1562 0.2344 ... 9.844 9.922 10.0 * z (z) float64 0.0 0.09375 0.1875 0.2812 ... 2.719 2.812 2.906 * n (n) int32 1 Data variables: bxx1 (y, z) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 bxy1 (y, z) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 bxz1 (y, z) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 noise_mod_x1 (y, z) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 bxphi1 (n, y, z) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 ux (x, y, z) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 uy (x, y, z) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 uz (x, y, z) float64 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) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- x: 257
- y: 129
- z: 32
- n: 1
- x(x)float640.0 0.05859 0.1172 ... 14.94 15.0
- name :
- Streamwise coordinate
- long_name :
- $x_1$
array([ 0. , 0.058594, 0.117188, ..., 14.882812, 14.941406, 15. ])
- y(y)float640.0 0.07812 0.1562 ... 9.922 10.0
- name :
- Vertical coordinate
- long_name :
- $x_2$
array([ 0. , 0.078125, 0.15625 , 0.234375, 0.3125 , 0.390625, 0.46875 , 0.546875, 0.625 , 0.703125, 0.78125 , 0.859375, 0.9375 , 1.015625, 1.09375 , 1.171875, 1.25 , 1.328125, 1.40625 , 1.484375, 1.5625 , 1.640625, 1.71875 , 1.796875, 1.875 , 1.953125, 2.03125 , 2.109375, 2.1875 , 2.265625, 2.34375 , 2.421875, 2.5 , 2.578125, 2.65625 , 2.734375, 2.8125 , 2.890625, 2.96875 , 3.046875, 3.125 , 3.203125, 3.28125 , 3.359375, 3.4375 , 3.515625, 3.59375 , 3.671875, 3.75 , 3.828125, 3.90625 , 3.984375, 4.0625 , 4.140625, 4.21875 , 4.296875, 4.375 , 4.453125, 4.53125 , 4.609375, 4.6875 , 4.765625, 4.84375 , 4.921875, 5. , 5.078125, 5.15625 , 5.234375, 5.3125 , 5.390625, 5.46875 , 5.546875, 5.625 , 5.703125, 5.78125 , 5.859375, 5.9375 , 6.015625, 6.09375 , 6.171875, 6.25 , 6.328125, 6.40625 , 6.484375, 6.5625 , 6.640625, 6.71875 , 6.796875, 6.875 , 6.953125, 7.03125 , 7.109375, 7.1875 , 7.265625, 7.34375 , 7.421875, 7.5 , 7.578125, 7.65625 , 7.734375, 7.8125 , 7.890625, 7.96875 , 8.046875, 8.125 , 8.203125, 8.28125 , 8.359375, 8.4375 , 8.515625, 8.59375 , 8.671875, 8.75 , 8.828125, 8.90625 , 8.984375, 9.0625 , 9.140625, 9.21875 , 9.296875, 9.375 , 9.453125, 9.53125 , 9.609375, 9.6875 , 9.765625, 9.84375 , 9.921875, 10. ])
- z(z)float640.0 0.09375 0.1875 ... 2.812 2.906
- name :
- Spanwise coordinate
- long_name :
- $x_3$
array([0. , 0.09375, 0.1875 , 0.28125, 0.375 , 0.46875, 0.5625 , 0.65625, 0.75 , 0.84375, 0.9375 , 1.03125, 1.125 , 1.21875, 1.3125 , 1.40625, 1.5 , 1.59375, 1.6875 , 1.78125, 1.875 , 1.96875, 2.0625 , 2.15625, 2.25 , 2.34375, 2.4375 , 2.53125, 2.625 , 2.71875, 2.8125 , 2.90625])
- n(n)int321
- name :
- Scalar fraction
- long_name :
- $\ell$
array([1])
- bxx1(y, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- bxx1
- name :
- Inflow Plane for Streamwise Velocity
- long_name :
- $u_1 (x_1=0,x_2,x_3)$
array([[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]])
- bxy1(y, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- bxy1
- name :
- Inflow Plane for Vertical Velocity
- long_name :
- $u_2 (x_1=0,x_2,x_3)$
array([[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]])
- bxz1(y, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- bxz1
- name :
- Inflow Plane for Spanwise Velocity
- long_name :
- $u_3 (x_1=0,x_2,x_3)$
array([[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]])
- noise_mod_x1(y, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- noise_mod_x1
- name :
- Modulation function for Random Numbers at Inflow Plane
- long_name :
- mod $ (x_1=0,x_2,x_3)$
array([[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]])
- bxphi1(n, y, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- bxphi1
- name :
- Inflow Plane for Scalar field(s)
- long_name :
- $\varphi (x_1=0,x_2,x_3,n)$
array([[[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]]])
- ux(x, y, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- ux
- name :
- Initial Condition for Streamwise Velocity
- long_name :
- $u_1 (x_1,x_2,x_3,t=0)$
- BC :
- {'x': {'ncl1': 2, 'ncln': 2, 'npaire': 0}, 'y': {'ncl1': 1, 'ncln': 1, 'npaire': 1, 'istret': 0, 'beta': 1.0}, 'z': {'ncl1': 0, 'ncln': 0, 'npaire': 1}}
array([[[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., ... ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]]])
- uy(x, y, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- uy
- name :
- Initial Condition for Vertical Velocity
- long_name :
- $u_2 (x_1,x_2,x_3,t=0)$
- BC :
- {'x': {'ncl1': 2, 'ncln': 2, 'npaire': 1}, 'y': {'ncl1': 1, 'ncln': 1, 'npaire': 0, 'istret': 0, 'beta': 1.0}, 'z': {'ncl1': 0, 'ncln': 0, 'npaire': 1}}
array([[[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., ... ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]]])
- uz(x, y, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- uz
- name :
- Initial Condition for Spanwise Velocity
- long_name :
- $u_3 (x_1,x_2,x_3,t=0)$
- BC :
- {'x': {'ncl1': 2, 'ncln': 2, 'npaire': 1}, 'y': {'ncl1': 1, 'ncln': 1, 'npaire': 1, 'istret': 0, 'beta': 1.0}, 'z': {'ncl1': 0, 'ncln': 0, 'npaire': 0}}
array([[[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., ... ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 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)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- phi
- name :
- Initial Condition for Scalar field(s)
- long_name :
- $\varphi (x_1,x_2,x_3,n,t=0)$
- BC :
- {'x': {'ncl1': 2, 'ncln': 2, 'npaire': 1}, 'y': {'ncl1': 1, 'ncln': 1, 'npaire': 1, 'istret': 0, 'beta': 1.0}, 'z': {'ncl1': 0, 'ncln': 0, 'npaire': 1}}
array([[[[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., ... ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]]]])
Inflow profile: Since the boundary conditions for velocity at the top and at the bottom are free-slip in this case (ncly1=nclyn=1
), the inflow profile for streamwise velocity is just 1 everywhere:
[10]:
fun = xr.ones_like(ds.y)
# This attribute will be shown in the figure
fun.attrs["long_name"] = r"Inflow Profile - f($x_2$)"
fun.plot();

Now, we reset the inflow planes ds[key] *= 0.0
, just to guarantee consistency in 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. Then, we add the inflow profile to the streamwise componente and plot them for reference:
[11]:
for key in "bxx1 bxy1 bxz1".split():
#
print(ds[key].attrs["name"])
#
ds[key] *= 0.0
#
if key == "bxx1":
ds[key] += fun
#
ds[key].plot()
plt.show()
plt.close("all")
Inflow Plane for Streamwise Velocity

Inflow Plane for Vertical Velocity

Inflow Plane for Spanwise Velocity

A random noise will be applied at the inflow boundary, we can create a modulation function mod
to control were it will be applied. In this case, we will concentrate the noise near the center region and make it zero were \(y=0\) and \(y=L_y\). The domain is periodic in \(z\) nclz1=nclzn=0
, so there is no need to make mod
functions of \(z\). The functions looks like:
See the code:
[12]:
# Random noise with fixed seed,
# important for reproducibility, development and debugging
if prm.iin == 2:
np.random.seed(seed=67)
mod = np.exp(-0.2 * (ds.y - ds.y[-1] * 0.5) ** 2.0)
# This attribute will be shown in the figure
mod.attrs["long_name"] = "Noise modulation"
mod.plot();

Again, we reset the array ds['noise_mod_x1'] *= 0.0
, just to guarantee consistency in case of multiple executions of this cell. Notice that ds['noise_mod_x1'] *= 0.0
may overwrite all the metadata contained in the array, so it should be avoided. Then, we add the modulation profile to the proper array and plot it for reference:
[13]:
ds["noise_mod_x1"] *= 0.0
ds["noise_mod_x1"] += mod
ds.noise_mod_x1.plot();

Notice one of the many advantages of using xarray, mod
, with shape (ny
), was automatically broadcasted for every point in z
into ds.noise_mod_x1
, with shape (ny
, nz
).
Inflow BC for the passive scalar: For this case, the choise was a “smooth” square wave, because it is differentiable.
Notice that Xcompact3d supports multiple scalar fields (controlled by numscalar
, this example just includes one), so different visualization patterns can be set for each one of them.
[14]:
# Concentration
print(ds["bxphi1"].attrs["name"])
ds["bxphi1"] *= 0.0
for n in range(prm.numscalar):
ds["bxphi1"][dict(n=n)] += (
0.5
+ np.arctan(
np.sin(2.0 * np.pi * ds.y / prm.yly * 11.5) * (prm.sc[n] * prm.re) ** 0.5
)
/ np.pi
)
ds.bxphi1.isel(n=n).plot()
plt.show()
plt.close("all")
Inflow Plane for Scalar field(s)

Initial Condition¶
Now we reset velocity fields ds[key] *= 0.0
, just to guarantee consistency in the case of multiple executions of this cell.
We then add a random number array with the right shape, multiply by the noise amplitude at the initial condition init_noise
and multiply again by our modulation function mod
, defined previously. Finally, we add the streamwise profile fun
to ux
and make the plots for reference, I’m adding extra options just to exemplify how easily we can slice the spanwise coordinate and produce multiple plots:
[15]:
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
#
if key == "ux":
ds[key] += fun
#
ds[key].sel(z=slice(None, None, ds.z.size // 3)).plot(
x="x", y="y", col="z", col_wrap=2
)
plt.show()
#
plt.close("all")
Initial Condition for Streamwise Velocity

Initial Condition for Vertical Velocity

Initial Condition for Spanwise Velocity

For concentration, let’s start with a clean domain:
[16]:
ds["phi"] *= 0
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
Periodic Heat Exchanger¶
[1]:
import matplotlib.pyplot as plt
import numpy as np
import xarray as xr
import xcompact3d_toolbox as x3d
Parameters¶
- Numerical precision
Use np.float64
if Xcompact3d was compiled with the flag -DDOUBLE_PREC
, use np.float32
otherwise.
[2]:
x3d.param["mytype"] = np.float64
- Xcompact3d’s parameters
For more information about them, checkout the API reference.
[3]:
prm = x3d.Parameters(
filename="input.i3d",
# BasicParam
itype=12,
p_row=0,
p_col=0,
nx=128,
ny=129,
nz=8,
xlx=6.0,
yly=6.0,
zlz=0.375,
nclx1=0,
nclxn=0,
ncly1=2,
nclyn=2,
nclz1=0,
nclzn=0,
iin=1,
re=300.0,
init_noise=0.0125,
inflow_noise=0.0,
dt=0.0025,
ifirst=1,
ilast=90000,
ilesmod=1,
iibm=2,
gravx=0.0,
gravy=-1.0,
gravz=0.0,
# NumOptions
nu0nu=4.0,
cnu=0.44,
# InOutParam
irestart=0,
icheckpoint=45000,
ioutput=500,
iprocessing=100,
# LESModel
jles=4,
# ScalarParam
numscalar=1,
nclxS1=0,
nclxSn=0,
nclyS1=2,
nclySn=2,
nclzS1=0,
nclzSn=0,
sc=[1.0],
ri=[-0.25],
uset=[0.0],
cp=[1.0],
)
Setup¶
Geometry¶
Everything needed is in one dictionary of Arrays (see API reference):
[4]:
epsi = x3d.init_epsi(prm)
The four \(\epsilon\) matrices are stored in a dictionary:
[5]:
epsi.keys()
[5]:
dict_keys(['epsi', 'xepsi', 'yepsi', 'zepsi'])
Now we draw a cylinder:
[6]:
# And apply geo.cylinder over the four arrays
for key in epsi.keys():
epsi[key] = epsi[key].geo.cylinder(x=prm.xlx / 2.0, y=prm.yly / 2.0,)
# A quickie plot for reference
epsi["epsi"].sel(z=0, method="nearest").plot(x="x", aspect=1, size=5);

The next step is to produce all the auxiliary files describing the geometry, so then Xcompact3d can read them:
[7]:
%%time
dataset = x3d.gene_epsi_3D(epsi, prm)
prm.nobjmax = dataset.obj.size
dataset
x
nobjraf : 1
nobjmaxraf : 1
bug : 0
y
nobjraf : 1
nobjmaxraf : 1
bug : 0
z
nobjraf : 1
nobjmaxraf : 1
bug : 0
number of points with potential problem in x : 0
number of points with potential problem in y : 0
number of points with potential problem in z : 0
Writing...
Wall time: 4.52 s
[7]:
<xarray.Dataset> Dimensions: (obj_aux: 2, obj: 1, x: 128, y: 129, z: 8) Coordinates: * obj_aux (obj_aux) int32 -1 0 * obj (obj) int32 0 * x (x) float64 0.0 0.04688 0.09375 0.1406 ... 5.859 5.906 5.953 * y (y) float64 0.0 0.04688 0.09375 0.1406 ... 5.906 5.953 6.0 * z (z) float64 0.0 0.04688 0.09375 ... 0.2344 0.2812 0.3281 Data variables: (12/28) epsi (x, y, z) bool False False False False ... False False False nobj_x (y, z) int64 0 0 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 0 0 nobjmax_x int64 1 nobjraf_x (y, z) int64 0 0 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 0 0 nobjmaxraf_x int64 1 ibug_x int64 0 ... ... nxipif_y (x, z, obj_aux) int64 2 2 2 2 2 2 2 2 2 ... 2 2 2 2 2 2 2 2 2 nxfpif_y (x, z, obj_aux) int64 128 2 128 2 128 2 ... 128 2 128 2 128 2 xi_z (x, y, obj) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 xf_z (x, y, obj) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 nxipif_z (x, y, obj_aux) int64 2 2 2 2 2 2 2 2 2 ... 2 2 2 2 2 2 2 2 2 nxfpif_z (x, y, obj_aux) int64 7 2 7 2 7 2 7 2 7 ... 2 7 2 7 2 7 2 7 2
- obj_aux: 2
- obj: 1
- x: 128
- y: 129
- z: 8
- obj_aux(obj_aux)int32-1 0
array([-1, 0])
- obj(obj)int320
array([0])
- x(x)float640.0 0.04688 0.09375 ... 5.906 5.953
array([0. , 0.046875, 0.09375 , 0.140625, 0.1875 , 0.234375, 0.28125 , 0.328125, 0.375 , 0.421875, 0.46875 , 0.515625, 0.5625 , 0.609375, 0.65625 , 0.703125, 0.75 , 0.796875, 0.84375 , 0.890625, 0.9375 , 0.984375, 1.03125 , 1.078125, 1.125 , 1.171875, 1.21875 , 1.265625, 1.3125 , 1.359375, 1.40625 , 1.453125, 1.5 , 1.546875, 1.59375 , 1.640625, 1.6875 , 1.734375, 1.78125 , 1.828125, 1.875 , 1.921875, 1.96875 , 2.015625, 2.0625 , 2.109375, 2.15625 , 2.203125, 2.25 , 2.296875, 2.34375 , 2.390625, 2.4375 , 2.484375, 2.53125 , 2.578125, 2.625 , 2.671875, 2.71875 , 2.765625, 2.8125 , 2.859375, 2.90625 , 2.953125, 3. , 3.046875, 3.09375 , 3.140625, 3.1875 , 3.234375, 3.28125 , 3.328125, 3.375 , 3.421875, 3.46875 , 3.515625, 3.5625 , 3.609375, 3.65625 , 3.703125, 3.75 , 3.796875, 3.84375 , 3.890625, 3.9375 , 3.984375, 4.03125 , 4.078125, 4.125 , 4.171875, 4.21875 , 4.265625, 4.3125 , 4.359375, 4.40625 , 4.453125, 4.5 , 4.546875, 4.59375 , 4.640625, 4.6875 , 4.734375, 4.78125 , 4.828125, 4.875 , 4.921875, 4.96875 , 5.015625, 5.0625 , 5.109375, 5.15625 , 5.203125, 5.25 , 5.296875, 5.34375 , 5.390625, 5.4375 , 5.484375, 5.53125 , 5.578125, 5.625 , 5.671875, 5.71875 , 5.765625, 5.8125 , 5.859375, 5.90625 , 5.953125])
- y(y)float640.0 0.04688 0.09375 ... 5.953 6.0
array([0. , 0.046875, 0.09375 , 0.140625, 0.1875 , 0.234375, 0.28125 , 0.328125, 0.375 , 0.421875, 0.46875 , 0.515625, 0.5625 , 0.609375, 0.65625 , 0.703125, 0.75 , 0.796875, 0.84375 , 0.890625, 0.9375 , 0.984375, 1.03125 , 1.078125, 1.125 , 1.171875, 1.21875 , 1.265625, 1.3125 , 1.359375, 1.40625 , 1.453125, 1.5 , 1.546875, 1.59375 , 1.640625, 1.6875 , 1.734375, 1.78125 , 1.828125, 1.875 , 1.921875, 1.96875 , 2.015625, 2.0625 , 2.109375, 2.15625 , 2.203125, 2.25 , 2.296875, 2.34375 , 2.390625, 2.4375 , 2.484375, 2.53125 , 2.578125, 2.625 , 2.671875, 2.71875 , 2.765625, 2.8125 , 2.859375, 2.90625 , 2.953125, 3. , 3.046875, 3.09375 , 3.140625, 3.1875 , 3.234375, 3.28125 , 3.328125, 3.375 , 3.421875, 3.46875 , 3.515625, 3.5625 , 3.609375, 3.65625 , 3.703125, 3.75 , 3.796875, 3.84375 , 3.890625, 3.9375 , 3.984375, 4.03125 , 4.078125, 4.125 , 4.171875, 4.21875 , 4.265625, 4.3125 , 4.359375, 4.40625 , 4.453125, 4.5 , 4.546875, 4.59375 , 4.640625, 4.6875 , 4.734375, 4.78125 , 4.828125, 4.875 , 4.921875, 4.96875 , 5.015625, 5.0625 , 5.109375, 5.15625 , 5.203125, 5.25 , 5.296875, 5.34375 , 5.390625, 5.4375 , 5.484375, 5.53125 , 5.578125, 5.625 , 5.671875, 5.71875 , 5.765625, 5.8125 , 5.859375, 5.90625 , 5.953125, 6. ])
- z(z)float640.0 0.04688 ... 0.2812 0.3281
array([0. , 0.046875, 0.09375 , 0.140625, 0.1875 , 0.234375, 0.28125 , 0.328125])
- epsi(x, y, z)boolFalse False False ... False False
- file_name :
- geometry\epsilon
array([[[False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], ..., [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False]], [[False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], ..., [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False]], [[False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], ..., ... ..., [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False]], [[False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], ..., [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False]], [[False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], ..., [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False], [False, False, False, ..., False, False, False]]])
- nobj_x(y, z)int640 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=int64)
- nobjmax_x()int641
array(1, dtype=int64)
- nobjraf_x(y, z)int640 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=int64)
- nobjmaxraf_x()int641
array(1, dtype=int64)
- ibug_x()int640
array(0, dtype=int64)
- nobj_y(x, z)int640 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=int64)
- nobjmax_y()int641
array(1, dtype=int64)
- nobjraf_y(x, z)int640 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=int64)
- nobjmaxraf_y()int641
array(1, dtype=int64)
- ibug_y()int640
array(0, dtype=int64)
- nobj_z(x, y)int640 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=int64)
- nobjmax_z()int641
array(1, dtype=int64)
- nobjraf_z(x, y)int640 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=int64)
- nobjmaxraf_z()int641
array(1, dtype=int64)
- ibug_z()int640
array(0, dtype=int64)
- xi_x(y, z, obj)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
array([[[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., ... ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]]])
- xf_x(y, z, obj)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
array([[[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., ... ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]]])
- nxipif_x(y, z, obj_aux)int642 2 2 2 2 2 2 2 ... 2 2 2 2 2 2 2 2
array([[[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., ... ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]]], dtype=int64)
- nxfpif_x(y, z, obj_aux)int64127 2 127 2 127 2 ... 2 127 2 127 2
array([[[127, 2], [127, 2], [127, 2], ..., [127, 2], [127, 2], [127, 2]], [[127, 2], [127, 2], [127, 2], ..., [127, 2], [127, 2], [127, 2]], [[127, 2], [127, 2], [127, 2], ..., ... ..., [127, 2], [127, 2], [127, 2]], [[127, 2], [127, 2], [127, 2], ..., [127, 2], [127, 2], [127, 2]], [[127, 2], [127, 2], [127, 2], ..., [127, 2], [127, 2], [127, 2]]], dtype=int64)
- xi_y(x, z, obj)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
array([[[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., ... ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]]])
- xf_y(x, z, obj)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
array([[[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., ... ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]]])
- nxipif_y(x, z, obj_aux)int642 2 2 2 2 2 2 2 ... 2 2 2 2 2 2 2 2
array([[[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., ... ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]]], dtype=int64)
- nxfpif_y(x, z, obj_aux)int64128 2 128 2 128 2 ... 2 128 2 128 2
array([[[128, 2], [128, 2], [128, 2], ..., [128, 2], [128, 2], [128, 2]], [[128, 2], [128, 2], [128, 2], ..., [128, 2], [128, 2], [128, 2]], [[128, 2], [128, 2], [128, 2], ..., ... ..., [128, 2], [128, 2], [128, 2]], [[128, 2], [128, 2], [128, 2], ..., [128, 2], [128, 2], [128, 2]], [[128, 2], [128, 2], [128, 2], ..., [128, 2], [128, 2], [128, 2]]], dtype=int64)
- xi_z(x, y, obj)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
array([[[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., ... ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]]])
- xf_z(x, y, obj)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
array([[[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., ... ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]], [[0.], [0.], [0.], ..., [0.], [0.], [0.]]])
- nxipif_z(x, y, obj_aux)int642 2 2 2 2 2 2 2 ... 2 2 2 2 2 2 2 2
array([[[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., ... ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]], [[2, 2], [2, 2], [2, 2], ..., [2, 2], [2, 2], [2, 2]]], dtype=int64)
- nxfpif_z(x, y, obj_aux)int647 2 7 2 7 2 7 2 ... 7 2 7 2 7 2 7 2
array([[[7, 2], [7, 2], [7, 2], ..., [7, 2], [7, 2], [7, 2]], [[7, 2], [7, 2], [7, 2], ..., [7, 2], [7, 2], [7, 2]], [[7, 2], [7, 2], [7, 2], ..., ... ..., [7, 2], [7, 2], [7, 2]], [[7, 2], [7, 2], [7, 2], ..., [7, 2], [7, 2], [7, 2]], [[7, 2], [7, 2], [7, 2], ..., [7, 2], [7, 2], [7, 2]]], dtype=int64)
Boundary Condition¶
Everything needed is in one Dataset (see API reference):
[8]:
ds = x3d.init_dataset(prm)
Let’s see it, data and attributes are attached, try to interact with the icons:
[9]:
ds
[9]:
<xarray.Dataset> Dimensions: (x: 128, y: 129, z: 8, n: 1) Coordinates: * x (x) float64 0.0 0.04688 0.09375 0.1406 ... 5.812 5.859 5.906 5.953 * y (y) float64 0.0 0.04688 0.09375 0.1406 ... 5.859 5.906 5.953 6.0 * z (z) float64 0.0 0.04688 0.09375 0.1406 0.1875 0.2344 0.2812 0.3281 * n (n) int32 1 Data variables: byphi1 (n, x, z) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 byphin (n, x, z) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 ux (x, y, z) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 uy (x, y, z) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 uz (x, y, z) float64 0.0 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) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 vol_frc (x, y, z) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0
- x: 128
- y: 129
- z: 8
- n: 1
- x(x)float640.0 0.04688 0.09375 ... 5.906 5.953
- name :
- Streamwise coordinate
- long_name :
- $x_1$
array([0. , 0.046875, 0.09375 , 0.140625, 0.1875 , 0.234375, 0.28125 , 0.328125, 0.375 , 0.421875, 0.46875 , 0.515625, 0.5625 , 0.609375, 0.65625 , 0.703125, 0.75 , 0.796875, 0.84375 , 0.890625, 0.9375 , 0.984375, 1.03125 , 1.078125, 1.125 , 1.171875, 1.21875 , 1.265625, 1.3125 , 1.359375, 1.40625 , 1.453125, 1.5 , 1.546875, 1.59375 , 1.640625, 1.6875 , 1.734375, 1.78125 , 1.828125, 1.875 , 1.921875, 1.96875 , 2.015625, 2.0625 , 2.109375, 2.15625 , 2.203125, 2.25 , 2.296875, 2.34375 , 2.390625, 2.4375 , 2.484375, 2.53125 , 2.578125, 2.625 , 2.671875, 2.71875 , 2.765625, 2.8125 , 2.859375, 2.90625 , 2.953125, 3. , 3.046875, 3.09375 , 3.140625, 3.1875 , 3.234375, 3.28125 , 3.328125, 3.375 , 3.421875, 3.46875 , 3.515625, 3.5625 , 3.609375, 3.65625 , 3.703125, 3.75 , 3.796875, 3.84375 , 3.890625, 3.9375 , 3.984375, 4.03125 , 4.078125, 4.125 , 4.171875, 4.21875 , 4.265625, 4.3125 , 4.359375, 4.40625 , 4.453125, 4.5 , 4.546875, 4.59375 , 4.640625, 4.6875 , 4.734375, 4.78125 , 4.828125, 4.875 , 4.921875, 4.96875 , 5.015625, 5.0625 , 5.109375, 5.15625 , 5.203125, 5.25 , 5.296875, 5.34375 , 5.390625, 5.4375 , 5.484375, 5.53125 , 5.578125, 5.625 , 5.671875, 5.71875 , 5.765625, 5.8125 , 5.859375, 5.90625 , 5.953125])
- y(y)float640.0 0.04688 0.09375 ... 5.953 6.0
- name :
- Vertical coordinate
- long_name :
- $x_2$
array([0. , 0.046875, 0.09375 , 0.140625, 0.1875 , 0.234375, 0.28125 , 0.328125, 0.375 , 0.421875, 0.46875 , 0.515625, 0.5625 , 0.609375, 0.65625 , 0.703125, 0.75 , 0.796875, 0.84375 , 0.890625, 0.9375 , 0.984375, 1.03125 , 1.078125, 1.125 , 1.171875, 1.21875 , 1.265625, 1.3125 , 1.359375, 1.40625 , 1.453125, 1.5 , 1.546875, 1.59375 , 1.640625, 1.6875 , 1.734375, 1.78125 , 1.828125, 1.875 , 1.921875, 1.96875 , 2.015625, 2.0625 , 2.109375, 2.15625 , 2.203125, 2.25 , 2.296875, 2.34375 , 2.390625, 2.4375 , 2.484375, 2.53125 , 2.578125, 2.625 , 2.671875, 2.71875 , 2.765625, 2.8125 , 2.859375, 2.90625 , 2.953125, 3. , 3.046875, 3.09375 , 3.140625, 3.1875 , 3.234375, 3.28125 , 3.328125, 3.375 , 3.421875, 3.46875 , 3.515625, 3.5625 , 3.609375, 3.65625 , 3.703125, 3.75 , 3.796875, 3.84375 , 3.890625, 3.9375 , 3.984375, 4.03125 , 4.078125, 4.125 , 4.171875, 4.21875 , 4.265625, 4.3125 , 4.359375, 4.40625 , 4.453125, 4.5 , 4.546875, 4.59375 , 4.640625, 4.6875 , 4.734375, 4.78125 , 4.828125, 4.875 , 4.921875, 4.96875 , 5.015625, 5.0625 , 5.109375, 5.15625 , 5.203125, 5.25 , 5.296875, 5.34375 , 5.390625, 5.4375 , 5.484375, 5.53125 , 5.578125, 5.625 , 5.671875, 5.71875 , 5.765625, 5.8125 , 5.859375, 5.90625 , 5.953125, 6. ])
- z(z)float640.0 0.04688 ... 0.2812 0.3281
- name :
- Spanwise coordinate
- long_name :
- $x_3$
array([0. , 0.046875, 0.09375 , 0.140625, 0.1875 , 0.234375, 0.28125 , 0.328125])
- n(n)int321
- name :
- Scalar fraction
- long_name :
- $\ell$
array([1])
- byphi1(n, x, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- byphi1
- name :
- Bottom Boundary Condition for Scalar field(s)
- long_name :
- $\varphi (x_1,x_2=0,x_3,n)$
array([[[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]]])
- byphin(n, x, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- byphin
- name :
- Top Boundary Condition for Scalar field(s)
- long_name :
- $\varphi (x_1,x_2=L_2,x_3,n)$
array([[[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]]])
- ux(x, y, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- ux
- name :
- Initial Condition for Streamwise Velocity
- long_name :
- $u_1 (x_1,x_2,x_3,t=0)$
- BC :
- {'x': {'ncl1': 0, 'ncln': 0, 'npaire': 0}, 'y': {'ncl1': 2, 'ncln': 2, 'npaire': 1, 'istret': 0, 'beta': 1.0}, 'z': {'ncl1': 0, 'ncln': 0, 'npaire': 1}}
array([[[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., ... ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]]])
- uy(x, y, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- uy
- name :
- Initial Condition for Vertical Velocity
- long_name :
- $u_2 (x_1,x_2,x_3,t=0)$
- BC :
- {'x': {'ncl1': 0, 'ncln': 0, 'npaire': 1}, 'y': {'ncl1': 2, 'ncln': 2, 'npaire': 0, 'istret': 0, 'beta': 1.0}, 'z': {'ncl1': 0, 'ncln': 0, 'npaire': 1}}
array([[[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., ... ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]]])
- uz(x, y, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- uz
- name :
- Initial Condition for Spanwise Velocity
- long_name :
- $u_3 (x_1,x_2,x_3,t=0)$
- BC :
- {'x': {'ncl1': 0, 'ncln': 0, 'npaire': 1}, 'y': {'ncl1': 2, 'ncln': 2, 'npaire': 1, 'istret': 0, 'beta': 1.0}, 'z': {'ncl1': 0, 'ncln': 0, 'npaire': 0}}
array([[[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., ... ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 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)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- phi
- name :
- Initial Condition for Scalar field(s)
- long_name :
- $\varphi (x_1,x_2,x_3,n,t=0)$
- BC :
- {'x': {'ncl1': 0, 'ncln': 0, 'npaire': 1}, 'y': {'ncl1': 2, 'ncln': 2, 'npaire': 1, 'istret': 0, 'beta': 1.0}, 'z': {'ncl1': 0, 'ncln': 0, 'npaire': 1}}
array([[[[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., ... ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]]]])
- vol_frc(x, y, z)float640.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
- file_name :
- vol_frc
- name :
- Integral Operator for Flow Rate Control
array([[[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., ... ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]], [[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]]])
The dimensionless temperature at the objects’s surface will always be set to zero by the Immersed Boundary Method, so in opposition to that, let’s set the dimensionless temperature at the top and bottom boundaries to one:
[10]:
for var in "byphi1 byphin".split():
ds[var] *= 0.0
ds[var] += 1.0
Initial Condition¶
Velocity profile: Since the boundary conditions for velocity at the top and at the bottom are no-slip in this case (ncly2=nclyn=2
), the inflow profile for streamwise velocity must be zero near walls:
[11]:
# This function gives the shape
fun = -((ds.y - prm.yly / 2.0) ** 2.0)
# This attribute will be shown in the figure
fun.attrs["long_name"] = r"Inflow Profile - f($x_2$)"
# Now, let's adjust its magnitude
fun -= fun.isel(y=0)
fun /= fun.x3d.simps("y") / prm.yly
fun.plot();

Now, let’s make sure that the dimensionless averaged velocity is unitary:
[12]:
fun.x3d.simps("y") / prm.yly
[12]:
<xarray.DataArray 'y' ()> array(1.)
- 1.0
array(1.)
A random noise will be applied at the three velocity components, we can create a modulation function mod
to control were it will be applied. In this case, we will concentrate the noise near the center region and make it zero were \(y=0\) and \(y=L_y\). The domain is periodic in \(z\) nclz1=nclzn=0
, so there is no need to make mod
functions of \(z\). The functions looks like:
See the code:
[13]:
# Random noise with fixed seed,
# important for reproducibility, development and debugging
if prm.iin == 2:
np.random.seed(seed=67)
mod = np.exp(-0.5 * (ds.y - prm.yly * 0.5) ** 2.0)
# This attribute will be shown in the figure
mod.attrs["long_name"] = r"Noise Modulation - f($x_2$)"
mod.plot();

Now we reset velocity fields ds[key] *= 0.0
, just to guarantee consistency in the case of multiple executions of this cell.
We then add a random number array with the right shape, multiply by the noise amplitude at the initial condition init_noise
and multiply again by our modulation function mod
, defined previously. Finally, we add the streamwise profile fun
to ux
and make the plots for reference, I’m adding extra options just to exemplify how easily we can slice the spanwise coordinate and produce multiple plots:
[14]:
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
#
if key == "ux":
ds[key] += fun
#
ds[key].sel(z=slice(None, None, ds.z.size // 3)).plot(
x="x", y="y", col="z", col_wrap=2, aspect=1, size=3
)
plt.show()
#
plt.close("all")
Initial Condition for Streamwise Velocity

Initial Condition for Vertical Velocity

Initial Condition for Spanwise Velocity

For temperature, let’s start with one everywhere:
[15]:
ds["phi"] *= 0.0
ds["phi"] += 1.0
Flow rate control¶
The Sandbox flow configuration is prepared with a forcing term when the flow is periodic in the streamwise direction \(x_1\), in order to compensate viscous dissipation and keep the flow rate constant.
It is done with the help of a personalized volumetric integral operator (vol_frc
), then, the streamwise velocity will be corrected at each simulated time-step as:
I = sum(vol_frc * ux)
ux = ux / I
For the composed trapezoidal rule in a uniform grid, the integral operator in the vertical direction can be computed as:
For a unitary averaged velocity, vol_frc
must be divided by the domain’s heigh. Besides that, for streamwise and spanwise averaged values, vol_frc
must be divided by nx
and nz
.
Finally, vol_frc
can be coded as:
[16]:
ds["vol_frc"] *= 0.0
ds["vol_frc"] += prm.dy / prm.yly / prm.nx / prm.nz
ds["vol_frc"][dict(y=0)] *= 0.5
ds["vol_frc"][dict(y=-1)] *= 0.5
ds.vol_frc.isel(z=0).plot(x="x", y="y", aspect=1, size=5);

Now, let’s make sure that sum(vol_frc * ux)
is near to one:
[17]:
(ds.vol_frc * ds.ux).sum(["x", "y", "z"])
[17]:
<xarray.DataArray ()> array(0.99994064)
- 0.9999
array(0.99994064)
And the last step, we can remove the solid geometry from our integral operator using the code:
[18]:
ds["vol_frc"] = ds.vol_frc.where(epsi["epsi"] == False, 0.0)
ds.vol_frc.isel(z=0).plot(x="x", y="y", aspect=1, size=5);

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.
The Sandbox Flow Configuration is still in prerelease, it can be found at fschuch/Xcompact3d.
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