From 4c0a89c92f6fded7af5a5251fb0494b7176c8723 Mon Sep 17 00:00:00 2001 From: "Documenter.jl" Date: Mon, 14 Oct 2024 13:13:23 +0000 Subject: [PATCH] build based on 158151a --- dev/.documenter-siteinfo.json | 2 +- dev/contributor_guide/index.html | 14 +- .../index.html | 2 +- .../index.html | 2 +- .../index.html | 2 +- .../04_2d-inflow-using-Flux/index.html | 6 +- .../index.html | 14 +- dev/examples/flux_comparison.svg | 310 +++++------ dev/examples/flux_comparison_untrained.svg | 510 +++++++++--------- .../optimisation_iterations_vs_experiment.svg | 164 +++--- dev/examples/optimisation_vs_iteration.svg | 274 +++++----- dev/index.html | 2 +- dev/objects.inv | Bin 4534 -> 4534 bytes dev/quick_start/index.html | 2 +- dev/reference/index.html | 80 +-- dev/release_notes/index.html | 2 +- dev/search_index.js | 2 +- dev/theory_guide/introduction/index.html | 2 +- .../0_introduction_and_workflow/index.html | 2 +- dev/user_guide/1_preprocessing/index.html | 6 +- .../2_physics_and_models/index.html | 2 +- dev/user_guide/3_numerical_setup/index.html | 6 +- .../4_runtime_and_solvers/index.html | 8 +- dev/user_guide/5_postprocessing/index.html | 2 +- 24 files changed, 702 insertions(+), 714 deletions(-) diff --git a/dev/.documenter-siteinfo.json b/dev/.documenter-siteinfo.json index 1a0c67f8..2b1dc89e 100644 --- a/dev/.documenter-siteinfo.json +++ b/dev/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.10.5","generation_timestamp":"2024-10-14T12:23:10","documenter_version":"1.7.0"}} \ No newline at end of file +{"documenter":{"julia_version":"1.10.5","generation_timestamp":"2024-10-14T13:13:03","documenter_version":"1.7.0"}} \ No newline at end of file diff --git a/dev/contributor_guide/index.html b/dev/contributor_guide/index.html index 02b8b440..865d05d7 100644 --- a/dev/contributor_guide/index.html +++ b/dev/contributor_guide/index.html @@ -13,10 +13,10 @@ get_float::SV3 # store mesh float type get_int::UR # store mesh integer type boundary_cellsID::VI # vector of indices of boundary cell IDs -endsource
XCALibre.Mesh.NodeType
struct Node{SV3<:SVector{3,<:AbstractFloat}, UR<:UnitRange{<:Integer}}
+end
source
XCALibre.Mesh.NodeType
struct Node{SV3<:SVector{3,<:AbstractFloat}, UR<:UnitRange{<:Integer}}
     coords::SV3     # node coordinates
     cells_range::UR # range to access neighbour cells in Mesh3.node_cells
-end
source
XCALibre.Mesh.Face3DType
struct Face3D{
+end
source
XCALibre.Mesh.Face3DType
struct Face3D{
     F<:AbstractFloat, 
     SV2<:SVector{2,<:Integer},
     SV3<:SVector{3,F}, 
@@ -31,22 +31,22 @@
     area::F         # face area
     delta::F        # distance between owner cells centres
     weight::F       # linear interpolation weight
-end
source
XCALibre.Mesh.CellType
struct Cell{F<:AbstractFloat, SV3<:SVector{3,F},UR<:UnitRange{<:Integer}}
+end
source
XCALibre.Mesh.CellType
struct Cell{F<:AbstractFloat, SV3<:SVector{3,F},UR<:UnitRange{<:Integer}}
     centre::SV3     # coordinate of cell centroid
     volume::F       # cell volume
     nodes_range::UR # range to access cell nodes in Mesh3.cell_nodes
     faces_range::UR # range to access cell faces info (faces, neighbours cells, etc.)
-end
source
XCALibre.Mesh.BoundaryType

struct Boundary{S<:Symbol, UR<:UnitRange{<:Integer}} name::S # Boundary patch name IDsrange::UR # range to access boundary info (faces and boundarycellsID) end

source

To fully characterise how mesh information is represented in XCALibre.jl, it is important to highlight the following "contracts" that are exploited throughout:

Field types

After the Mesh2 and Mesh3 objects, the most fundamental data structure in XCALibre.jl are fields used to represent the flow variables. In the current implementation, the prime field is the ScalarField for storing information at cell centres, and the corresponding FaceScalarField to store information at cell faces (normally fluxes). Internally, both are identical, therefore, the internal structure of the "Face" variants will not be discussed. ScalarFields have the following definition:

XCALibre.Fields.ScalarFieldType
struct ScalarField{VF,M<:AbstractMesh,BC} <: AbstractScalarField
+end
source
XCALibre.Mesh.BoundaryType

struct Boundary{S<:Symbol, UR<:UnitRange{<:Integer}} name::S # Boundary patch name IDsrange::UR # range to access boundary info (faces and boundarycellsID) end

source

To fully characterise how mesh information is represented in XCALibre.jl, it is important to highlight the following "contracts" that are exploited throughout:

Field types

After the Mesh2 and Mesh3 objects, the most fundamental data structure in XCALibre.jl are fields used to represent the flow variables. In the current implementation, the prime field is the ScalarField for storing information at cell centres, and the corresponding FaceScalarField to store information at cell faces (normally fluxes). Internally, both are identical, therefore, the internal structure of the "Face" variants will not be discussed. ScalarFields have the following definition:

XCALibre.Fields.ScalarFieldType
struct ScalarField{VF,M<:AbstractMesh,BC} <: AbstractScalarField
     values::VF  # scalar values at cell centre
     mesh::M     # reference to mesh
     BCs::BC     # store user-provided boundary conditions
-end
source

Vector and tensors are represented internally by their individual components, as an illustration the VectorField type is shown below. Notice that each component of both vector and tensor fields are themselves represented by the same ScalarField type shown above. This has some implementation benefits, i.e. reducing duplication and allowing for rapid development. However, the performance of other means of storing these fields is being investigated. Thus, these internals may change if we identify performance gains.

XCALibre.Fields.VectorFieldType
struct VectorField{S1<:ScalarField,S2,S3,M<:AbstractMesh,BC} <: AbstractVectorField
+end
source

Vector and tensors are represented internally by their individual components, as an illustration the VectorField type is shown below. Notice that each component of both vector and tensor fields are themselves represented by the same ScalarField type shown above. This has some implementation benefits, i.e. reducing duplication and allowing for rapid development. However, the performance of other means of storing these fields is being investigated. Thus, these internals may change if we identify performance gains.

XCALibre.Fields.VectorFieldType
struct VectorField{S1<:ScalarField,S2,S3,M<:AbstractMesh,BC} <: AbstractVectorField
     x::S1   # x-component is itself a `ScalarField`
     y::S2   # y-component is itself a `ScalarField`
     z::S3   # z-component is itself a `ScalarField`
     mesh::M
     BCs::BC
-end
source

All fields behave (mostly) like regular arrays and can be indexed using the standard Julia syntax e.g. say U is a VectorField, then U[3] would return the vector stored in cell with ID = 3 (as a SVector{3} for improved performance).

Note

The implementation of broadcasting operations has been put on hold until a more thorough investigation of alternative data structures for vector and tensor fields has been completed. This is ongoing work.

Boundary conditions


To implement a new boundary condition the following elements are required (see source code for Dirichlet, for example):

Developers and contributors are encouraged to explore the source code for examples on existing implementations of boundary conditions. To ease their implementation the XCALibre.Discretise.@define_boundary is provided.

XCALibre.Discretise.@define_boundaryMacro
macro define_boundary(boundary, operator, definition)
+end
source

All fields behave (mostly) like regular arrays and can be indexed using the standard Julia syntax e.g. say U is a VectorField, then U[3] would return the vector stored in cell with ID = 3 (as a SVector{3} for improved performance).

Note

The implementation of broadcasting operations has been put on hold until a more thorough investigation of alternative data structures for vector and tensor fields has been completed. This is ongoing work.

Boundary conditions


To implement a new boundary condition the following elements are required (see source code for Dirichlet, for example):

Developers and contributors are encouraged to explore the source code for examples on existing implementations of boundary conditions. To ease their implementation the XCALibre.Discretise.@define_boundary is provided.

XCALibre.Discretise.@define_boundaryMacro
macro define_boundary(boundary, operator, definition)
     quote
         @inline (bc::$boundary)(
             term::Operator{F,P,I,$operator}, cellID, zcellID, cell, face, fID, i, component, time
@@ -58,4 +58,4 @@
     flux = J*area/delta     # calculate the face flux
     ap = term.sign*(-flux)  # diagonal (cell) matrix coefficient
     ap, ap*bc.value         # return `ap` and `an`
-end

When called, this functor will return two values ap and an, where ap is the cell contribution for approximating the boundary face value, and an is the explicit part of the face value approximation i.e. ap contributes to the diagonal of the sparse matrix (left-hand side) and an is the explicit contribution assigned to the solution vector b on the right-hand of the linear system of equations $Ax = b$

source

Implementing new models


The internal API for models is still somewhat experimental, thus, it is more instructive to explore the source code. Although not fully finalised, the implementation is reasonably straight forward to follow thanks to the abstractions that have been adopted, some of which are described above, as well as the use of descriptive names for internal functions. If you need help on any aspect of the internals, for now, it is recommended to contact us by opening an issue.

+end

When called, this functor will return two values ap and an, where ap is the cell contribution for approximating the boundary face value, and an is the explicit part of the face value approximation i.e. ap contributes to the diagonal of the sparse matrix (left-hand side) and an is the explicit contribution assigned to the solution vector b on the right-hand of the linear system of equations $Ax = b$

source

Implementing new models


The internal API for models is still somewhat experimental, thus, it is more instructive to explore the source code. Although not fully finalised, the implementation is reasonably straight forward to follow thanks to the abstractions that have been adopted, some of which are described above, as well as the use of descriptive names for internal functions. If you need help on any aspect of the internals, for now, it is recommended to contact us by opening an issue.

diff --git a/dev/examples/01_2d-isothermal-backward-facing-step/index.html b/dev/examples/01_2d-isothermal-backward-facing-step/index.html index d73b137d..eab78c79 100644 --- a/dev/examples/01_2d-isothermal-backward-facing-step/index.html +++ b/dev/examples/01_2d-isothermal-backward-facing-step/index.html @@ -82,4 +82,4 @@ initialise!(model.momentum.U, velocity) initialise!(model.momentum.p, 0.0) -residuals = run!(model, config);

Results


Domain and mesh

Simulation domain

OpenFoam solution

Simulation domain

XCALibre solution

Simulation domain

Quantitative comparision

The figure below compares the results obtained with OpenFOAM and XCALibre.jl. The profiles are extracted along the y-direction at x = 0.5 m. Comparison with OpenFOAM

+residuals = run!(model, config);

Results


Domain and mesh

Simulation domain

OpenFoam solution

Simulation domain

XCALibre solution

Simulation domain

Quantitative comparision

The figure below compares the results obtained with OpenFOAM and XCALibre.jl. The profiles are extracted along the y-direction at x = 0.5 m. Comparison with OpenFOAM

diff --git a/dev/examples/02_2d-incompressible-transient-cylinder/index.html b/dev/examples/02_2d-incompressible-transient-cylinder/index.html index b15dc00d..cfd7fa7c 100644 --- a/dev/examples/02_2d-incompressible-transient-cylinder/index.html +++ b/dev/examples/02_2d-incompressible-transient-cylinder/index.html @@ -84,4 +84,4 @@ initialise!(model.momentum.U, velocity) initialise!(model.momentum.p, 0.0) -residuals = run!(model, config) +residuals = run!(model, config) diff --git a/dev/examples/03_2d-constant-temperature-flat-plate/index.html b/dev/examples/03_2d-constant-temperature-flat-plate/index.html index eec1c12f..de819ab0 100644 --- a/dev/examples/03_2d-constant-temperature-flat-plate/index.html +++ b/dev/examples/03_2d-constant-temperature-flat-plate/index.html @@ -94,4 +94,4 @@ initialise!(model.momentum.p, 100000.0) initialise!(model.energy.T, 300.0) -residuals = run!(model, config)

Results


The results of the model are compared to the theoretical correlation in the figure below:

Nusselt number distribution results.

+residuals = run!(model, config)

Results


The results of the model are compared to the theoretical correlation in the figure below:

Nusselt number distribution results.

diff --git a/dev/examples/04_2d-inflow-using-Flux/index.html b/dev/examples/04_2d-inflow-using-Flux/index.html index 91b79006..7556a70d 100644 --- a/dev/examples/04_2d-inflow-using-Flux/index.html +++ b/dev/examples/04_2d-inflow-using-Flux/index.html @@ -1,5 +1,5 @@ -Advanced: 2D inflow using Flux.jl · XCALibre.jl

Advanced: 2D inflow using Flux.jl

Introduction


In this example a simple neural network is constructed and used to define an inlet boundary condition for the x-component of the velocity vector. This example serves to illustrate how other packages from the Julia ecosystem can be integrated into XCALibre.jl to extend its functionality. In particular, this example will show how to build a basic neural network using Flux.jl to represent a parabolic velocity profile and how this neural network can be used to define an inlet condition in XCALibre.jl.

The boundary condition is injected into the solution using the builtin DirichletFunction boundary condition, which is designed to pass arbitrary Julia functions to a given boundary.

XCALibre.Discretise.DirichletFunctionType
DirichletFunction(ID, value) <: AbstractDirichlet

Dirichlet boundary condition defined with user-provided function.

Input

  • ID Boundary name provided as symbol e.g. :inlet
  • value Custom function for Dirichlet boundary condition.

Function requirements

The function passed to this boundary condition must have the following signature:

f(coords, time, index) = SVector{3}(ux, uy, uz)

Where, coords is a vector containing the coordinates of a face, time is the current time in transient simulations (and the iteration number in steady simulations), and index is the local face index (from 1 to N, where N is the number of faces in a given boundary). The function must return an SVector (from StaticArrays.jl) representing the velocity vector.

source

In this example, instead of passing a Julia function, the boundary velocity profile will be given via a simple neural network.

Note

This interface is experimental and subject to change. Currently it can only be used for vectors.

Set up steps


Install and load modules

To be able to run this example the following modules need to be installed. This can be done by entering into package mode (using "]" in the REPL) and typing the following:

add Plots, XCALibre, Flux, StaticArrays, LinearAlgebra, KernelAbstractions, Adapt

This will download and install the required packages. Once installed, the packages can be loaded as follows:

using Plots
+Advanced: 2D inflow using Flux.jl · XCALibre.jl

Advanced: 2D inflow using Flux.jl

Introduction


In this example a simple neural network is constructed and used to define an inlet boundary condition for the x-component of the velocity vector. This example serves to illustrate how other packages from the Julia ecosystem can be integrated into XCALibre.jl to extend its functionality. In particular, this example will show how to build a basic neural network using Flux.jl to represent a parabolic velocity profile and how this neural network can be used to define an inlet condition in XCALibre.jl.

The boundary condition is injected into the solution using the builtin DirichletFunction boundary condition, which is designed to pass arbitrary Julia functions to a given boundary.

XCALibre.Discretise.DirichletFunctionType
DirichletFunction(ID, value) <: AbstractDirichlet

Dirichlet boundary condition defined with user-provided function.

Input

  • ID Boundary name provided as symbol e.g. :inlet
  • value Custom function for Dirichlet boundary condition.

Function requirements

The function passed to this boundary condition must have the following signature:

f(coords, time, index) = SVector{3}(ux, uy, uz)

Where, coords is a vector containing the coordinates of a face, time is the current time in transient simulations (and the iteration number in steady simulations), and index is the local face index (from 1 to N, where N is the number of faces in a given boundary). The function must return an SVector (from StaticArrays.jl) representing the velocity vector.

source

In this example, instead of passing a Julia function, the boundary velocity profile will be given via a simple neural network.

Note

This interface is experimental and subject to change. Currently it can only be used for vectors.

Set up steps


Install and load modules

To be able to run this example the following modules need to be installed. This can be done by entering into package mode (using "]" in the REPL) and typing the following:

add Plots, XCALibre, Flux, StaticArrays, LinearAlgebra, KernelAbstractions, Adapt

This will download and install the required packages. Once installed, the packages can be loaded as follows:

using Plots
 using XCALibre
 using Flux
 using StaticArrays
@@ -103,7 +103,7 @@
     inflowNetwork,
     [1,0,0],
     true
-)
Main.Inflow{Float64, Matrix{Float64}, Matrix{Float64}, Flux.Chain{Tuple{Flux.Dense{typeof(NNlib.σ), Matrix{Float64}, Vector{Float64}}, Flux.Dense{typeof(identity), Matrix{Float64}, Vector{Float64}}}}, Vector{Int64}, Bool}(0.5, 0.1, [0.5 0.5 … 0.5 0.5], [0.4981767709985014 0.4981767709985014 … 0.4981767709985014 0.4981767709985014; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0], Chain(Dense(1 => 6, σ), Dense(6 => 1)), [1, 0, 0], true)

Run simulation

The final step is simply to set up and run a simulation in XCALibre.jl. Notice that this does not require any special considerations, only to remember to use the DirichletFunction boundary condition when setting the inlet velocity. The inlet_profile functor object is then passed to the boundary.

velocity = [0.5, 0.0, 0.0]
+)
Main.Inflow{Float64, Matrix{Float64}, Matrix{Float64}, Flux.Chain{Tuple{Flux.Dense{typeof(NNlib.σ), Matrix{Float64}, Vector{Float64}}, Flux.Dense{typeof(identity), Matrix{Float64}, Vector{Float64}}}}, Vector{Int64}, Bool}(0.5, 0.1, [0.5 0.5 … 0.5 0.5], [0.49968404006320616 0.49968404006320616 … 0.49968404006320616 0.49968404006320616; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0], Chain(Dense(1 => 6, σ), Dense(6 => 1)), [1, 0, 0], true)

Run simulation

The final step is simply to set up and run a simulation in XCALibre.jl. Notice that this does not require any special considerations, only to remember to use the DirichletFunction boundary condition when setting the inlet velocity. The inlet_profile functor object is then passed to the boundary.

velocity = [0.5, 0.0, 0.0]
 nu = 1e-3
 Re = velocity[1]*0.1/nu
 
@@ -170,4 +170,4 @@
 
 residuals = run!(model, config)
 
-"done"
"done"

Simulation result


Comparison with OpenFOAM

+"done"
"done"

Simulation result


Comparison with OpenFOAM

diff --git a/dev/examples/05_2d-aerofoil-inflow-optimisation/index.html b/dev/examples/05_2d-aerofoil-inflow-optimisation/index.html index 9dc3114c..0aa9d7f3 100644 --- a/dev/examples/05_2d-aerofoil-inflow-optimisation/index.html +++ b/dev/examples/05_2d-aerofoil-inflow-optimisation/index.html @@ -30,18 +30,10 @@ mesh = UNV2D_mesh(mesh_file, scale=0.001) mesh_dev = mesh # running on CPU -# mesh_dev = adapt(CUDABackend(), mesh) # uncomment to run on GPU
2D Mesh
+# mesh_dev = adapt(CUDABackend(), mesh) # uncomment to run on GPU
2D Mesh with:
 -> 79591 cells
 -> 128509 faces
--> 48918 nodes
-
-Boundaries 
--> inlet (faces: 1:56)
--> outlet (faces: 57:112)
--> top (faces: 113:201)
--> bottom (faces: 202:290)
--> foil (faces: 291:1145)
-

Setup the CFD simulation as a function to be optimised

The BayesianOptimization.jl package can optimise a Julia function that is passed to it. To interface with XCALibre.jl, the entire CFD simulation setup must simply be wrapped within a function, which can then be passed to the optimiser. The function must take the variable to be changed (angle of attack, in this case) as its input, and must return the desired output (lift-to-drag ratio). Therefore, the post-processing step to calculate lift-to-drag ratio is also wrapped in the same function.

function foil_optim(α::Vector{Float64})
+-> 48918 nodes

Setup the CFD simulation as a function to be optimised

The BayesianOptimization.jl package can optimise a Julia function that is passed to it. To interface with XCALibre.jl, the entire CFD simulation setup must simply be wrapped within a function, which can then be passed to the optimiser. The function must take the variable to be changed (angle of attack, in this case) as its input, and must return the desired output (lift-to-drag ratio). Therefore, the post-processing step to calculate lift-to-drag ratio is also wrapped in the same function.

function foil_optim(α::Vector{Float64})
     println("\nSelected α value: $(α[1])")
 
     # Parameters
@@ -216,4 +208,4 @@
 result = boptimize!(opt) # Runs the optimisation procedure
 
 
-"done"
"done"

Example Optimisation Results


+"done"
"done"

Example Optimisation Results


diff --git a/dev/examples/flux_comparison.svg b/dev/examples/flux_comparison.svg index c6550aca..d0217a7b 100644 --- a/dev/examples/flux_comparison.svg +++ b/dev/examples/flux_comparison.svg @@ -1,169 +1,169 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/examples/flux_comparison_untrained.svg b/dev/examples/flux_comparison_untrained.svg index 703046e3..d99953d9 100644 --- a/dev/examples/flux_comparison_untrained.svg +++ b/dev/examples/flux_comparison_untrained.svg @@ -1,270 +1,266 @@ - + - + - + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/examples/optimisation_iterations_vs_experiment.svg b/dev/examples/optimisation_iterations_vs_experiment.svg index 3f47fc06..a3fe3314 100644 --- a/dev/examples/optimisation_iterations_vs_experiment.svg +++ b/dev/examples/optimisation_iterations_vs_experiment.svg @@ -1,95 +1,95 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - - - - - - - + + + + + + + + diff --git a/dev/examples/optimisation_vs_iteration.svg b/dev/examples/optimisation_vs_iteration.svg index 272ed49e..19f18146 100644 --- a/dev/examples/optimisation_vs_iteration.svg +++ b/dev/examples/optimisation_vs_iteration.svg @@ -1,156 +1,156 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/index.html b/dev/index.html index cd7fc1d4..9bf2fb21 100644 --- a/dev/index.html +++ b/dev/index.html @@ -6,4 +6,4 @@ == -Source(∇p.result) - ) → VectorEquation(mesh)

Planned development


Capabilities, solvers, algorithms, models, etc.

  • Solver for highly compressible flows (including shockwaves)
  • Conjugate heat transfer
  • $k-\epsilon$ turbulence model
  • Implement parallel versions of more efficient preconditioners

API

  • Pass boundary conditions as a separate object. The current approach results in some internal methods/objects not being fully compatible with GPU kernels, and results is some performance degradation (due to unnecessary data transfer between GPU and host device when boundary condition information is needed/applied). A separation of boundary conditions from field data (scalar and vector fields primarily) would address both of these issues.
  • There are no immediate plans for changing the user API
  • Fine-tuning of the public API expected based on of user feedback

Internals

  • Overhaul of field data. Currently, both vectors and tensors are built on the primitive scalar field object. Whilst this was convenient during the early development stage, the package has reached a level of maturity that makes this approach hard to maintain, adding unneeded complexity when working with tensors. We plan to define separate internals (how tensors are defined and stored in memory). It is anticipated that this will ease the implementation of models working with tensors, give some performance gains and allow all fields to participate in Julia's broadcasting framework.

Main dependencies


XCALibre.jl is possible (and relies) on the functionality provided by other packages in the Julia ecosystem. For a full list of direct dependencies please refer to the Project.toml file included with this repository. We are thankful to the teams that have helped develop and maintain every single of our dependencies. Major functionally is provided by the following:

  • KernelAbstractions.jl - provides a unified parallel programming framework for CPUs and GPUs
  • Krylov.jl - provide solvers for linear systems at the heart of XCALibre.jl
  • LinearOperators.jl - wrappers for matrices and linear operators
  • Atomix.jl - enable atomix operations to ensure race conditions are avoided in parallel kernels
  • CUDA.jl, AMD.jl, Metal.jl and OneAPI.jl - not direct dependencies but packages enable GPU usage in Julia

There are other wonderful fluid simulation packages available in the Julia ecosystem (please let us know if we missed any):

+ ) → VectorEquation(mesh)

Planned development


Capabilities, solvers, algorithms, models, etc.

  • Solver for highly compressible flows (including shockwaves)
  • Conjugate heat transfer
  • $k-\epsilon$ turbulence model
  • Implement parallel versions of more efficient preconditioners

API

  • Pass boundary conditions as a separate object. The current approach results in some internal methods/objects not being fully compatible with GPU kernels, and results is some performance degradation (due to unnecessary data transfer between GPU and host device when boundary condition information is needed/applied). A separation of boundary conditions from field data (scalar and vector fields primarily) would address both of these issues.
  • There are no immediate plans for changing the user API
  • Fine-tuning of the public API expected based on of user feedback

Internals

  • Overhaul of field data. Currently, both vectors and tensors are built on the primitive scalar field object. Whilst this was convenient during the early development stage, the package has reached a level of maturity that makes this approach hard to maintain, adding unneeded complexity when working with tensors. We plan to define separate internals (how tensors are defined and stored in memory). It is anticipated that this will ease the implementation of models working with tensors, give some performance gains and allow all fields to participate in Julia's broadcasting framework.

Main dependencies


XCALibre.jl is possible (and relies) on the functionality provided by other packages in the Julia ecosystem. For a full list of direct dependencies please refer to the Project.toml file included with this repository. We are thankful to the teams that have helped develop and maintain every single of our dependencies. Major functionally is provided by the following:

  • KernelAbstractions.jl - provides a unified parallel programming framework for CPUs and GPUs
  • Krylov.jl - provide solvers for linear systems at the heart of XCALibre.jl
  • LinearOperators.jl - wrappers for matrices and linear operators
  • Atomix.jl - enable atomix operations to ensure race conditions are avoided in parallel kernels
  • CUDA.jl, AMD.jl, Metal.jl and OneAPI.jl - not direct dependencies but packages enable GPU usage in Julia

There are other wonderful fluid simulation packages available in the Julia ecosystem (please let us know if we missed any):

diff --git a/dev/objects.inv b/dev/objects.inv index daefcbe03ea9c319e376d3b9c742c48b06678fd8..e053362b02d8bd0c23cfd1491702be29131ced3b 100644 GIT binary patch delta 12 Tcmdm{yiIw6Go#@~mm)y`9zg^! delta 12 Tcmdm{yiIw6Go!&qmm)y`9y|mu diff --git a/dev/quick_start/index.html b/dev/quick_start/index.html index b10ac7a4..521633b5 100644 --- a/dev/quick_start/index.html +++ b/dev/quick_start/index.html @@ -97,4 +97,4 @@ residuals = run!(model, config); # Step 12. Post-process -pwd() # find active directory where the file "iteration_002000.vtk" was saved

Output

If you chose to run the example above, XCALibre.jl would have written a simulation result file to your computer. The name of the file is iteration_002000.vtk. The file will be located in your current active directory (you can check this by running pwd()). This file can be open directly in ParaView for further post-processing. You can find out more about ParaView on their website. The image below is the output solution generated by XCALibre.jl to the example simulation above.

Simulation result visualisation in ParaView

+pwd() # find active directory where the file "iteration_002000.vtk" was saved

Output

If you chose to run the example above, XCALibre.jl would have written a simulation result file to your computer. The name of the file is iteration_002000.vtk. The file will be located in your current active directory (you can check this by running pwd()). This file can be open directly in ParaView for further post-processing. You can find out more about ParaView on their website. The image below is the output solution generated by XCALibre.jl to the example simulation above.

Simulation result visualisation in ParaView

diff --git a/dev/reference/index.html b/dev/reference/index.html index 382cc9c4..2382d8b7 100644 --- a/dev/reference/index.html +++ b/dev/reference/index.html @@ -1,10 +1,10 @@ -Reference · XCALibre.jl

Reference

XCALibre.Mesh.BoundaryType

struct Boundary{S<:Symbol, UR<:UnitRange{<:Integer}} name::S # Boundary patch name IDsrange::UR # range to access boundary info (faces and boundarycellsID) end

source
XCALibre.Mesh.CellType
struct Cell{F<:AbstractFloat, SV3<:SVector{3,F},UR<:UnitRange{<:Integer}}
+Reference · XCALibre.jl

Reference

XCALibre.Mesh.BoundaryType

struct Boundary{S<:Symbol, UR<:UnitRange{<:Integer}} name::S # Boundary patch name IDsrange::UR # range to access boundary info (faces and boundarycellsID) end

source
XCALibre.Mesh.CellType
struct Cell{F<:AbstractFloat, SV3<:SVector{3,F},UR<:UnitRange{<:Integer}}
     centre::SV3     # coordinate of cell centroid
     volume::F       # cell volume
     nodes_range::UR # range to access cell nodes in Mesh3.cell_nodes
     faces_range::UR # range to access cell faces info (faces, neighbours cells, etc.)
-end
source
XCALibre.Mesh.Face3DType
struct Face3D{
     F<:AbstractFloat, 
     SV2<:SVector{2,<:Integer},
     SV3<:SVector{3,F}, 
@@ -19,7 +19,7 @@
     area::F         # face area
     delta::F        # distance between owner cells centres
     weight::F       # linear interpolation weight
-end
source
XCALibre.Mesh.Mesh3Type
struct Mesh3{VC, VI, VF<:AbstractArray{<:Face3D}, VB, VN, SV3, UR} <: AbstractMesh
     cells::VC           # vector of cells
     cell_nodes::VI      # vector of indices to access cell nodes
     cell_faces::VI      # vector of indices to access cell faces
@@ -33,28 +33,28 @@
     get_float::SV3      # store mesh float type
     get_int::UR         # store mesh integer type
     boundary_cellsID::VI # vector of indices of boundary cell IDs
-end
source
XCALibre.Mesh.NodeType
struct Node{SV3<:SVector{3,<:AbstractFloat}, UR<:UnitRange{<:Integer}}
     coords::SV3     # node coordinates
     cells_range::UR # range to access neighbour cells in Mesh3.node_cells
-end
source
XCALibre.UNV2.UNV2D_meshMethod
UNV2D_mesh(meshFile; scale=1, integer_type=Int64, float_type=Float64)

Read and convert 2D UNV mesh file into XCALibre.jl

Input

  • meshFile – path to mesh file.

Optional arguments

  • scale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling

  • integer_type - select interger type to use in the mesh (Int32 may be useful on GPU runs)

  • float_type - select interger type to use in the mesh (Float32 may be useful on GPU runs)

source
XCALibre.UNV3.UNV3D_meshMethod
UNV3D_mesh(unv_mesh; scale=1, integer_type=Int64, float_type=Float64)

Read and convert 3D UNV mesh file into XCALibre.jl. Note that a limitation of the .unv mesh format is that it only supports the following 3D cells:

  • Tetahedrals
  • Prisms
  • Hexahedrals

Input

  • unv_mesh – path to mesh file.

Optional arguments

  • scale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling

  • integer_type - select interger type to use in the mesh (Int32 may be useful on GPU runs)

  • float_type - select interger type to use in the mesh (Float32 may be useful on GPU runs)

source
XCALibre.FoamMesh.FOAM3D_meshMethod
FOAM3D_mesh(mesh_file; scale=1, integer_type=Int64, float_type=Float64)

Read and convert 3D OpenFOAM mesh file into XCALibre.jl. Note that, at present, it is not recommended to run 2D cases using meshes imported using this function.

Input

  • mesh_file – path to mesh file.

Optional arguments

  • scale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling

  • integer_type - select interger type to use in the mesh (Int32 may be useful on GPU runs)

  • float_type - select interger type to use in the mesh (Float32 may be useful on GPU runs)

source
XCALibre.UNV2.UNV2D_meshMethod
UNV2D_mesh(meshFile; scale=1, integer_type=Int64, float_type=Float64)

Read and convert 2D UNV mesh file into XCALibre.jl

Input

  • meshFile – path to mesh file.

Optional arguments

  • scale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling

  • integer_type - select interger type to use in the mesh (Int32 may be useful on GPU runs)

  • float_type - select interger type to use in the mesh (Float32 may be useful on GPU runs)

source
XCALibre.UNV3.UNV3D_meshMethod
UNV3D_mesh(unv_mesh; scale=1, integer_type=Int64, float_type=Float64)

Read and convert 3D UNV mesh file into XCALibre.jl. Note that a limitation of the .unv mesh format is that it only supports the following 3D cells:

  • Tetahedrals
  • Prisms
  • Hexahedrals

Input

  • unv_mesh – path to mesh file.

Optional arguments

  • scale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling

  • integer_type - select interger type to use in the mesh (Int32 may be useful on GPU runs)

  • float_type - select interger type to use in the mesh (Float32 may be useful on GPU runs)

source
XCALibre.FoamMesh.FOAM3D_meshMethod
FOAM3D_mesh(mesh_file; scale=1, integer_type=Int64, float_type=Float64)

Read and convert 3D OpenFOAM mesh file into XCALibre.jl. Note that, at present, it is not recommended to run 2D cases using meshes imported using this function.

Input

  • mesh_file – path to mesh file.

Optional arguments

  • scale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling

  • integer_type - select interger type to use in the mesh (Int32 may be useful on GPU runs)

  • float_type - select interger type to use in the mesh (Float32 may be useful on GPU runs)

source
XCALibre.Fields.ScalarFieldType
struct ScalarField{VF,M<:AbstractMesh,BC} <: AbstractScalarField
     values::VF  # scalar values at cell centre
     mesh::M     # reference to mesh
     BCs::BC     # store user-provided boundary conditions
-end
source
XCALibre.Fields.VectorFieldType
struct VectorField{S1<:ScalarField,S2,S3,M<:AbstractMesh,BC} <: AbstractVectorField
     x::S1   # x-component is itself a `ScalarField`
     y::S2   # y-component is itself a `ScalarField`
     z::S3   # z-component is itself a `ScalarField`
     mesh::M
     BCs::BC
-end
source
XCALibre.Fields.initialise!Method
function initialise!(field, value) # dummy function for documentation
     # Assign `value` to field in-place
     nothing
 end

This function will set the given field to the value provided in-place. Useful for initialising fields prior to running a simulation.

Input arguments

  • field specifies the field to be initialised. The field must be either a AbractScalarField or AbstractVectorField
  • value defines the value to be set. This should be a scalar or vector (3 components) depending on the field to be modified e.g. for an AbstractVectorField we can specify as value=[10,0,0]

Note: in most cases the fields to be modified are stored within a physics model i.e. a Physics object. Thus, the argument value must fully qualify the model. For example, if we have created a Physics model named mymodel to set the velocity field, U, we would set the argument field to mymodel.momentum.U. See the example below.

Example

initialise!(mymodel.momentum.U, [2.5, 0, 0])
-initialise!(mymodel.momentum.p, 1.25)
source
XCALibre.Discretise.DirichletType
Dirichlet <: AbstractDirichlet

Dirichlet boundary condition model.

Fields

  • 'ID' – Boundary ID
  • value – Scalar or Vector value for Dirichlet boundary condition.
source
XCALibre.Discretise.DirichletFunctionType
DirichletFunction(ID, value) <: AbstractDirichlet

Dirichlet boundary condition defined with user-provided function.

Input

  • ID Boundary name provided as symbol e.g. :inlet
  • value Custom function for Dirichlet boundary condition.

Function requirements

The function passed to this boundary condition must have the following signature:

f(coords, time, index) = SVector{3}(ux, uy, uz)

Where, coords is a vector containing the coordinates of a face, time is the current time in transient simulations (and the iteration number in steady simulations), and index is the local face index (from 1 to N, where N is the number of faces in a given boundary). The function must return an SVector (from StaticArrays.jl) representing the velocity vector.

source
XCALibre.Discretise.FixedTemperatureType
FixedTemperature <: AbstractDirichlet

Fixed temperature boundary condition model, which allows the user to specify wall temperature that can be translated to the energy specific model, such as sensivle enthalpy.

Fields

  • 'ID' – Boundary ID
  • value – Scalar or Vector value for Dirichlet boundary condition.
  • T - Temperature value in Kelvin.
  • model - Energy physics model for case.

Examples

FixedTemperature(:inlet, T=300.0, model=model.energy),
source
XCALibre.Discretise.NeumannType
Neumann <: AbstractNeumann

Neumann boundary condition model (currently only configured for zero gradient)

Fields

  • 'ID' – Boundary ID
  • value – Scalar or Vector value for Neumann boundary condition.
source
XCALibre.Discretise.DirichletType
Dirichlet <: AbstractDirichlet

Dirichlet boundary condition model.

Fields

  • 'ID' – Boundary ID
  • value – Scalar or Vector value for Dirichlet boundary condition.
source
XCALibre.Discretise.DirichletFunctionType
DirichletFunction(ID, value) <: AbstractDirichlet

Dirichlet boundary condition defined with user-provided function.

Input

  • ID Boundary name provided as symbol e.g. :inlet
  • value Custom function for Dirichlet boundary condition.

Function requirements

The function passed to this boundary condition must have the following signature:

f(coords, time, index) = SVector{3}(ux, uy, uz)

Where, coords is a vector containing the coordinates of a face, time is the current time in transient simulations (and the iteration number in steady simulations), and index is the local face index (from 1 to N, where N is the number of faces in a given boundary). The function must return an SVector (from StaticArrays.jl) representing the velocity vector.

source
XCALibre.Discretise.FixedTemperatureType
FixedTemperature <: AbstractDirichlet

Fixed temperature boundary condition model, which allows the user to specify wall temperature that can be translated to the energy specific model, such as sensivle enthalpy.

Fields

  • 'ID' – Boundary ID
  • value – Scalar or Vector value for Dirichlet boundary condition.
  • T - Temperature value in Kelvin.
  • model - Energy physics model for case.

Examples

FixedTemperature(:inlet, T=300.0, model=model.energy),
source
XCALibre.Discretise.NeumannType
Neumann <: AbstractNeumann

Neumann boundary condition model (currently only configured for zero gradient)

Fields

  • 'ID' – Boundary ID
  • value – Scalar or Vector value for Neumann boundary condition.
source
XCALibre.Discretise.PeriodicType
struct Periodic{I,V} <: AbstractPhysicalConstraint
     ID::I
     value::V
-end

Periodic boundary condition model.

Fields

  • 'ID' – Boundary ID
  • value – tuple containing information needed to apply this boundary
source
XCALibre.Discretise.construct_periodicMethod
construct_periodic(mesh, backend, patch1::Symbol, patch2::Symbol)

Function for construction of periodic boundary conditions.

Input

  • mesh – Mesh.
  • backend – Backend configuraton.
  • patch1 – Primary periodic patch ID.
  • patch2 – Neighbour periodic patch ID.

Output

  • periodic::Tuple - tuple containing boundary defintions for patch1 and patch2 i.e. (periodic1, periodic2). The fields of periodic1 and periodic2 are

    • ID – Index to access boundary information in mesh object
    • value – represents a NamedTuple with the following keyword arguments:
      • index – ID used to find boundary geometry information in the mesh object
      • distance – perpendicular distance between the patches
      • face_map – vector providing indeces to faces of match patch
      • ismaster – flat to identify one of the patch pairs as the main patch

Example

- `periodic = construct_periodic(mesh, CPU(), :top, :bottom)` - Example using CPU 
-backend with periodic boundaries named `top` and `bottom`.
source
XCALibre.Discretise.set_schemesMethod
set_schemes(;
+end

Periodic boundary condition model.

Fields

  • 'ID' – Boundary ID
  • value – tuple containing information needed to apply this boundary
source
XCALibre.Discretise.construct_periodicMethod
construct_periodic(mesh, backend, patch1::Symbol, patch2::Symbol)

Function for construction of periodic boundary conditions.

Input

  • mesh – Mesh.
  • backend – Backend configuraton.
  • patch1 – Primary periodic patch ID.
  • patch2 – Neighbour periodic patch ID.

Output

  • periodic::Tuple - tuple containing boundary defintions for patch1 and patch2 i.e. (periodic1, periodic2). The fields of periodic1 and periodic2 are

    • ID – Index to access boundary information in mesh object
    • value – represents a NamedTuple with the following keyword arguments:
      • index – ID used to find boundary geometry information in the mesh object
      • distance – perpendicular distance between the patches
      • face_map – vector providing indeces to faces of match patch
      • ismaster – flat to identify one of the patch pairs as the main patch

Example

- `periodic = construct_periodic(mesh, CPU(), :top, :bottom)` - Example using CPU 
+backend with periodic boundaries named `top` and `bottom`.
source
XCALibre.Discretise.set_schemesMethod
set_schemes(;
     # keyword arguments and their default values
     time=SteadyState,
     divergence=Linear, 
@@ -68,7 +68,7 @@
         laplacian=laplacian,
         gradient=gradient
     )
-end

The set_schemes function is used at the top-level API to help users define discretisation schemes for every field solved. It offers default values, thus users can pick and choose which entry they wish to modify.

inputs

  • time is used to set the time schemes (default is SteadyState)
  • divergence is used to set the divergence scheme (default is Linear)
  • laplacian is used to set the laplacian scheme (default is Linear)
  • gradient is used to set the gradient scheme (default is Orthogonal)
source
XCALibre.Discretise.@define_boundaryMacro
macro define_boundary(boundary, operator, definition)
+end

The set_schemes function is used at the top-level API to help users define discretisation schemes for every field solved. It offers default values, thus users can pick and choose which entry they wish to modify.

inputs

  • time is used to set the time schemes (default is SteadyState)
  • divergence is used to set the divergence scheme (default is Linear)
  • laplacian is used to set the laplacian scheme (default is Linear)
  • gradient is used to set the gradient scheme (default is Orthogonal)
source
XCALibre.Discretise.@define_boundaryMacro
macro define_boundary(boundary, operator, definition)
     quote
         @inline (bc::$boundary)(
             term::Operator{F,P,I,$operator}, cellID, zcellID, cell, face, fID, i, component, time
@@ -80,7 +80,7 @@
     flux = J*area/delta     # calculate the face flux
     ap = term.sign*(-flux)  # diagonal (cell) matrix coefficient
     ap, ap*bc.value         # return `ap` and `an`
-end

When called, this functor will return two values ap and an, where ap is the cell contribution for approximating the boundary face value, and an is the explicit part of the face value approximation i.e. ap contributes to the diagonal of the sparse matrix (left-hand side) and an is the explicit contribution assigned to the solution vector b on the right-hand of the linear system of equations $Ax = b$

source
XCALibre.Solve.set_runtimeMethod
set_runtime(; 
+end

When called, this functor will return two values ap and an, where ap is the cell contribution for approximating the boundary face value, and an is the explicit part of the face value approximation i.e. ap contributes to the diagonal of the sparse matrix (left-hand side) and an is the explicit contribution assigned to the solution vector b on the right-hand of the linear system of equations $Ax = b$

source
XCALibre.Solve.set_runtimeMethod
set_runtime(; 
     # keyword arguments
     iterations::I, 
     write_interval::I, 
@@ -93,7 +93,7 @@
         dt=time_step, 
         write_interval=write_interval)
 end

This is a convenience function to set the top-level runtime information. The inputs are all keyword arguments and provide basic information to flow solvers just before running a simulation.

Input arguments

  • iterations::Integer specifies the number of iterations in a simulation run.
  • write_interval::Integer defines how often simulation results are written to file (on the current working directory). The interval is currently based on number of iterations. Set to -1 to run without writing results to file.
  • time_step::Number the time step to use in the simulation. Notice that for steady solvers this is simply a counter and it is recommended to simply use 1.

Example

runtime = set_runtime(
-    iterations=2000, time_step=1, write_interval=2000)
source
XCALibre.Solve.set_solverMethod
set_solver( 
     field::AbstractField;
     # keyword arguments and defaults
     solver::S, 
@@ -118,11 +118,11 @@
         atol=atol |> TF, 
         rtol=rtol |> TF
     )
-end

This function is used to provide solver settings that will be used internally in XCALibre.jl. It returns a NamedTuple with solver settings that are used internally by the flow solvers.

Input arguments

  • field reference to the field to which the solver settings will apply (used to provide integer and float types required)
  • solver solver object from Krylov.jl and it could be one of BicgstabSolver, CgSolver, GmresSolver which are re-exported in XCALibre.jl
  • preconditioner instance of preconditioner to be used e.g. Jacobi()
  • convergence sets the stopping criteria of this field
  • relax specifies the relaxation factor to be used e.g. set to 1 for no relaxation
  • limit used in some solvers to bound the solution within this limits e.g. (min, max). It defaults to ()
  • itmax maximum number of iterations in a single solver pass (defaults to 100)
  • atol absolute tolerance for the solver (default to eps(FloatType)^0.9)
  • rtol set relative tolerance for the solver (defaults to 1e-3)
source
XCALibre.ModelPhysics.CompressibleType
Compressible <: AbstractCompressible

Compressible fluid model containing fluid field parameters for compressible flows with constant parameters - ideal gas with constant viscosity.

Fields

  • 'nu' – Fluid kinematic viscosity.
  • 'cp' – Fluid specific heat capacity.
  • gamma – Ratio of specific heats.
  • Pr – Fluid Prantl number.

Examples

  • Fluid{Compressible}(; nu=1E-5, cp=1005.0, gamma=1.4, Pr=0.7) - Constructur with default values.
source
XCALibre.ModelPhysics.IncompressibleType
Incompressible <: AbstractIncompressible

Incompressible fluid model containing fluid field parameters for incompressible flows.

Fields

  • 'nu' – Fluid kinematic viscosity.
  • 'rho' – Fluid density.

Examples

  • Fluid{Incompressible}(nu=0.001, rho=1.0) - Constructor with default values.
source
XCALibre.ModelPhysics.KOmegaType
KOmega <: AbstractTurbulenceModel

kOmega model containing all kOmega field parameters.

Fields

  • 'k' – Turbulent kinetic energy ScalarField.
  • 'omega' – Specific dissipation rate ScalarField.
  • 'nut' – Eddy viscosity ScalarField.
  • 'kf' – Turbulent kinetic energy FaceScalarField.
  • 'omegaf' – Specific dissipation rate FaceScalarField.
  • 'nutf' – Eddy viscosity FaceScalarField.
  • 'coeffs' – Model coefficients.
source
XCALibre.ModelPhysics.KOmegaLKEType
KOmegaLKE <: AbstractTurbulenceModel

kOmega model containing all kOmega field parameters.

Fields

  • 'k' – Turbulent kinetic energy ScalarField.
  • 'omega' – Specific dissipation rate ScalarField.
  • 'kl' – ScalarField.
  • 'nut' – Eddy viscosity ScalarField.
  • 'kf' – Turbulent kinetic energy FaceScalarField.
  • 'omegaf' – Specific dissipation rate FaceScalarField.
  • 'klf' – FaceScalarField.
  • 'nutf' – Eddy viscosity FaceScalarField.
  • 'coeffs' – Model coefficients.
  • 'Tu' – Freestream turbulence intensity for model.
  • 'y' – Near-wall distance for model.
source
XCALibre.ModelPhysics.MomentumType
struct Momentum{V,S,SS} <: AbstractMomentumModel
+end

This function is used to provide solver settings that will be used internally in XCALibre.jl. It returns a NamedTuple with solver settings that are used internally by the flow solvers.

Input arguments

  • field reference to the field to which the solver settings will apply (used to provide integer and float types required)
  • solver solver object from Krylov.jl and it could be one of BicgstabSolver, CgSolver, GmresSolver which are re-exported in XCALibre.jl
  • preconditioner instance of preconditioner to be used e.g. Jacobi()
  • convergence sets the stopping criteria of this field
  • relax specifies the relaxation factor to be used e.g. set to 1 for no relaxation
  • limit used in some solvers to bound the solution within this limits e.g. (min, max). It defaults to ()
  • itmax maximum number of iterations in a single solver pass (defaults to 100)
  • atol absolute tolerance for the solver (default to eps(FloatType)^0.9)
  • rtol set relative tolerance for the solver (defaults to 1e-3)
source
XCALibre.ModelPhysics.CompressibleType
Compressible <: AbstractCompressible

Compressible fluid model containing fluid field parameters for compressible flows with constant parameters - ideal gas with constant viscosity.

Fields

  • 'nu' – Fluid kinematic viscosity.
  • 'cp' – Fluid specific heat capacity.
  • gamma – Ratio of specific heats.
  • Pr – Fluid Prantl number.

Examples

  • Fluid{Compressible}(; nu=1E-5, cp=1005.0, gamma=1.4, Pr=0.7) - Constructur with default values.
source
XCALibre.ModelPhysics.IncompressibleType
Incompressible <: AbstractIncompressible

Incompressible fluid model containing fluid field parameters for incompressible flows.

Fields

  • 'nu' – Fluid kinematic viscosity.
  • 'rho' – Fluid density.

Examples

  • Fluid{Incompressible}(nu=0.001, rho=1.0) - Constructor with default values.
source
XCALibre.ModelPhysics.KOmegaType
KOmega <: AbstractTurbulenceModel

kOmega model containing all kOmega field parameters.

Fields

  • 'k' – Turbulent kinetic energy ScalarField.
  • 'omega' – Specific dissipation rate ScalarField.
  • 'nut' – Eddy viscosity ScalarField.
  • 'kf' – Turbulent kinetic energy FaceScalarField.
  • 'omegaf' – Specific dissipation rate FaceScalarField.
  • 'nutf' – Eddy viscosity FaceScalarField.
  • 'coeffs' – Model coefficients.
source
XCALibre.ModelPhysics.KOmegaLKEType
KOmegaLKE <: AbstractTurbulenceModel

kOmega model containing all kOmega field parameters.

Fields

  • 'k' – Turbulent kinetic energy ScalarField.
  • 'omega' – Specific dissipation rate ScalarField.
  • 'kl' – ScalarField.
  • 'nut' – Eddy viscosity ScalarField.
  • 'kf' – Turbulent kinetic energy FaceScalarField.
  • 'omegaf' – Specific dissipation rate FaceScalarField.
  • 'klf' – FaceScalarField.
  • 'nutf' – Eddy viscosity FaceScalarField.
  • 'coeffs' – Model coefficients.
  • 'Tu' – Freestream turbulence intensity for model.
  • 'y' – Near-wall distance for model.
source
XCALibre.ModelPhysics.MomentumType
struct Momentum{V,S,SS} <: AbstractMomentumModel
     U::V 
     p::S 
     sources::SS
-end

Momentum model containing key momentum fields.

Fields

  • 'U' – Velocity VectorField.
  • 'p' – Pressure ScalarField.
  • 'sources' – Momentum model sources.

Examples

  • `Momentum(mesh::AbstractMesh)
source
XCALibre.ModelPhysics.PhysicsType
struct Physics{T,F,M,Tu,E,D,BI}
+end

Momentum model containing key momentum fields.

Fields

  • 'U' – Velocity VectorField.
  • 'p' – Pressure ScalarField.
  • 'sources' – Momentum model sources.

Examples

  • `Momentum(mesh::AbstractMesh)
source
XCALibre.ModelPhysics.PhysicsType
struct Physics{T,F,M,Tu,E,D,BI}
     time::T
     fluid::F
     momentum::M 
@@ -130,33 +130,33 @@
     energy::E
     domain::D
     boundary_info::BI
-end

XCALibre's parametric Physics type for user-level API. Also used to dispatch flow solvers.

Fields

  • 'time::Union{Steady, Transient}' – User-provided time model.
  • 'fluid::AbstractFluid' – User-provided Fluid` model.
  • 'momentum' – Momentum model. Currently this is auto-generated by the Physics constructor
  • 'turbulence::AbstractTurbulenceModel' – User-provided Turbulence` model.
  • 'energy:AbstractEnergyModel' – User-provided Energy model.
  • 'domain::AbstractMesh ' – User-provided Mesh. Must be adapted to target device before constructing a Physics object.
  • 'boundaryinfo::boundaryinfo' – Mesh boundary information. Auto-generated by the Physics constructor
source
XCALibre.ModelPhysics.PhysicsMethod
Physics(; time, fluid, turbulence, energy, domain)::Physics{T,F,M,Tu,E,D,BI}

Physics constructor part of the top-level API. It can be used to define the Physics and models relevant to a simulation. This constructor uses keyword arguments to allow users to fine-tune their simulations, whilst some fields are auto-generated behind the scenes for convenience (Momentum and boundary_info). Where:

  • time - specified the time model (Steady or Transient)
  • fluid - specifies the type of fluid (Incompressible, etc.)
  • turbulence - specified the Turbulence model
  • energy - specifies the Energy treatment
  • domain - provides the mesh to used (must be adapted to the target backend device)
source
XCALibre.ModelPhysics.SensibleEnthalpyType
SensibleEnthalpy <: AbstractEnergyModel

Type that represents energy model, coefficients and respective fields.

Fields

  • 'h' – Sensible enthalpy ScalarField.
  • 'T' – Temperature ScalarField.
  • 'hf' – Sensible enthalpy FaceScalarField.
  • 'Tf' – Temperature FaceScalarField.
  • 'K' – Specific kinetic energy ScalarField.
  • 'dpdt' – Pressure time derivative ScalarField.
  • 'updated_BC' – Boundary condition function to convert temperature to sensible enthalp on on a fixed value boudary.
  • 'coeffs' – A tuple of model coefficients.
source
XCALibre.ModelPhysics.SmagorinskyType
Smagorinsky <: AbstractTurbulenceModel

Smagorinsky LES model containing all Smagorinksy field parameters.

Fields

  • 'nut' – Eddy viscosity ScalarField.
  • 'nutf' – Eddy viscosity FaceScalarField.
  • 'coeffs' – Model coefficients.
source
XCALibre.ModelPhysics.WeaklyCompressibleType
WeaklyCompressible <: AbstractCompressible

Weakly compressible fluid model containing fluid field parameters for weakly compressible flows with constant parameters - ideal gas with constant viscosity.

Fields

  • 'nu' – Fluid kinematic viscosity.
  • 'cp' – Fluid specific heat capacity.
  • gamma – Ratio of specific heats.
  • Pr – Fluid Prandtl number.

Examples

  • Fluid{WeaklyCompressible}(; nu=1E-5, cp=1005.0, gamma=1.4, Pr=0.7) - Constructor with

default values.

source
XCALibre.ModelPhysics.Ttoh!Method
Ttoh!(model::Physics{T1,F,M,Tu,E,D,BI}, T::ScalarField, h::ScalarField
-) where {T1,F<:AbstractCompressible,M,Tu,E,D,BI}

Function coverts temperature ScalarField to sensible enthalpy ScalarField.

Input

  • model – Physics model defined by user.
  • T – Temperature ScalarField.
  • h – Sensible enthalpy ScalarField.
source
XCALibre.ModelPhysics.changeMethod
change(model::Physics, property, value) => updatedModel::Physics

A convenience function to change properties of an exisitng Physics model.

Input arguments

  • model::Physics a Physics model to modify
  • property is a symbol specifying the property to change
  • value is the new setting for the specified property

Output

This function return a new Physics object

Example

To change a model to run a transient simulation e.g. after converging in steady state

modelTransient = change(model, :time, Transient())
source
XCALibre.ModelPhysics.energy!Method
energy::Sensible_Enthalpy_Model{E1}, model::Physics{T1,F,M,Tu,E,D,BI}, prev, mdotf, rho, mueff, time, config
-) where {T1,F,M,Tu,E,D,BI,E1}

Run energy transport equations.

Input

  • energy – Energy model.
  • model – Physics model defined by user.
  • prev – Previous energy cell values.
  • mdtof – Face mass flow.
  • rho – Density ScalarField.
  • mueff – Effective viscosity FaceScalarField.
  • time
  • config – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.
source
XCALibre.ModelPhysics.htoT!Method
htoT!(model::Physics{T1,F,M,Tu,E,D,BI}, h::ScalarField, T::ScalarField
-) where {T1,F<:AbstractCompressible,M,Tu,E,D,BI}

Function coverts sensible enthalpy ScalarField to temperature ScalarField.

Input

  • model – Physics model defined by user.
  • h – Sensible enthalpy ScalarField.
  • T – Temperature ScalarField.
source
XCALibre.ModelPhysics.initialiseMethod
initialise(energy::SensibleEnthalpy, model::Physics{T1,F,M,Tu,E,D,BI}, mdotf, rho, peqn, config
-) where {T1,F,M,Tu,E,D,BI})

Initialisation of energy transport equations.

Input

  • energy – Energy model.
  • model – Physics model defined by user.
  • mdtof – Face mass flow.
  • rho – Density ScalarField.
  • peqn – Pressure equation.
  • config – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.

Output

  • Sensible_Enthalpy_Model – Energy model struct containing energy equation.
source
XCALibre.ModelPhysics.initialiseMethod
initialise(turbulence::KOmega, model::Physics{T,F,M,Tu,E,D,BI}, mdotf, peqn, config
-) where {T,F,M,Tu,E,D,BI}

Initialisation of turbulent transport equations.

Input

  • turbulence – turbulence model.
  • model – Physics model defined by user.
  • mdtof – Face mass flow.
  • peqn – Pressure equation.
  • config – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.

Output

  • KOmegaModel(k_eqn, ω_eqn) – Turbulence model structure.
source
XCALibre.ModelPhysics.initialiseMethod
initialise(turbulence::KOmegaLKE, model::Physics{T,F,M,Tu,E,D,BI}, mdotf, peqn, config
-) where {T,F,M,Tu,E,D,BI}

Initialisation of turbulent transport equations.

Input

  • turbulence – turbulence model.
  • model – Physics model defined by user.
  • mdtof – Face mass flow.
  • peqn – Pressure equation.
  • config – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.

Output

  • KOmegaLKEModel( k_eqn, ω_eqn, kl_eqn, nueffkLS, nueffkS, nueffωS, nuL, nuts, Ω, γ, fv, normU, Reυ, ∇k, ∇ω ) – Turbulence model structure.
source
XCALibre.ModelPhysics.initialiseMethod
function initialise(
+end

XCALibre's parametric Physics type for user-level API. Also used to dispatch flow solvers.

Fields

  • 'time::Union{Steady, Transient}' – User-provided time model.
  • 'fluid::AbstractFluid' – User-provided Fluid` model.
  • 'momentum' – Momentum model. Currently this is auto-generated by the Physics constructor
  • 'turbulence::AbstractTurbulenceModel' – User-provided Turbulence` model.
  • 'energy:AbstractEnergyModel' – User-provided Energy model.
  • 'domain::AbstractMesh ' – User-provided Mesh. Must be adapted to target device before constructing a Physics object.
  • 'boundaryinfo::boundaryinfo' – Mesh boundary information. Auto-generated by the Physics constructor
source
XCALibre.ModelPhysics.PhysicsMethod
Physics(; time, fluid, turbulence, energy, domain)::Physics{T,F,M,Tu,E,D,BI}

Physics constructor part of the top-level API. It can be used to define the Physics and models relevant to a simulation. This constructor uses keyword arguments to allow users to fine-tune their simulations, whilst some fields are auto-generated behind the scenes for convenience (Momentum and boundary_info). Where:

  • time - specified the time model (Steady or Transient)
  • fluid - specifies the type of fluid (Incompressible, etc.)
  • turbulence - specified the Turbulence model
  • energy - specifies the Energy treatment
  • domain - provides the mesh to used (must be adapted to the target backend device)
source
XCALibre.ModelPhysics.SensibleEnthalpyType
SensibleEnthalpy <: AbstractEnergyModel

Type that represents energy model, coefficients and respective fields.

Fields

  • 'h' – Sensible enthalpy ScalarField.
  • 'T' – Temperature ScalarField.
  • 'hf' – Sensible enthalpy FaceScalarField.
  • 'Tf' – Temperature FaceScalarField.
  • 'K' – Specific kinetic energy ScalarField.
  • 'dpdt' – Pressure time derivative ScalarField.
  • 'updated_BC' – Boundary condition function to convert temperature to sensible enthalp on on a fixed value boudary.
  • 'coeffs' – A tuple of model coefficients.
source
XCALibre.ModelPhysics.SmagorinskyType
Smagorinsky <: AbstractTurbulenceModel

Smagorinsky LES model containing all Smagorinksy field parameters.

Fields

  • 'nut' – Eddy viscosity ScalarField.
  • 'nutf' – Eddy viscosity FaceScalarField.
  • 'coeffs' – Model coefficients.
source
XCALibre.ModelPhysics.WeaklyCompressibleType
WeaklyCompressible <: AbstractCompressible

Weakly compressible fluid model containing fluid field parameters for weakly compressible flows with constant parameters - ideal gas with constant viscosity.

Fields

  • 'nu' – Fluid kinematic viscosity.
  • 'cp' – Fluid specific heat capacity.
  • gamma – Ratio of specific heats.
  • Pr – Fluid Prandtl number.

Examples

  • Fluid{WeaklyCompressible}(; nu=1E-5, cp=1005.0, gamma=1.4, Pr=0.7) - Constructor with

default values.

source
XCALibre.ModelPhysics.Ttoh!Method
Ttoh!(model::Physics{T1,F,M,Tu,E,D,BI}, T::ScalarField, h::ScalarField
+) where {T1,F<:AbstractCompressible,M,Tu,E,D,BI}

Function coverts temperature ScalarField to sensible enthalpy ScalarField.

Input

  • model – Physics model defined by user.
  • T – Temperature ScalarField.
  • h – Sensible enthalpy ScalarField.
source
XCALibre.ModelPhysics.changeMethod
change(model::Physics, property, value) => updatedModel::Physics

A convenience function to change properties of an exisitng Physics model.

Input arguments

  • model::Physics a Physics model to modify
  • property is a symbol specifying the property to change
  • value is the new setting for the specified property

Output

This function return a new Physics object

Example

To change a model to run a transient simulation e.g. after converging in steady state

modelTransient = change(model, :time, Transient())
source
XCALibre.ModelPhysics.energy!Method
energy::Sensible_Enthalpy_Model{E1}, model::Physics{T1,F,M,Tu,E,D,BI}, prev, mdotf, rho, mueff, time, config
+) where {T1,F,M,Tu,E,D,BI,E1}

Run energy transport equations.

Input

  • energy – Energy model.
  • model – Physics model defined by user.
  • prev – Previous energy cell values.
  • mdtof – Face mass flow.
  • rho – Density ScalarField.
  • mueff – Effective viscosity FaceScalarField.
  • time
  • config – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.
source
XCALibre.ModelPhysics.htoT!Method
htoT!(model::Physics{T1,F,M,Tu,E,D,BI}, h::ScalarField, T::ScalarField
+) where {T1,F<:AbstractCompressible,M,Tu,E,D,BI}

Function coverts sensible enthalpy ScalarField to temperature ScalarField.

Input

  • model – Physics model defined by user.
  • h – Sensible enthalpy ScalarField.
  • T – Temperature ScalarField.
source
XCALibre.ModelPhysics.initialiseMethod
initialise(energy::SensibleEnthalpy, model::Physics{T1,F,M,Tu,E,D,BI}, mdotf, rho, peqn, config
+) where {T1,F,M,Tu,E,D,BI})

Initialisation of energy transport equations.

Input

  • energy – Energy model.
  • model – Physics model defined by user.
  • mdtof – Face mass flow.
  • rho – Density ScalarField.
  • peqn – Pressure equation.
  • config – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.

Output

  • Sensible_Enthalpy_Model – Energy model struct containing energy equation.
source
XCALibre.ModelPhysics.initialiseMethod
initialise(turbulence::KOmega, model::Physics{T,F,M,Tu,E,D,BI}, mdotf, peqn, config
+) where {T,F,M,Tu,E,D,BI}

Initialisation of turbulent transport equations.

Input

  • turbulence – turbulence model.
  • model – Physics model defined by user.
  • mdtof – Face mass flow.
  • peqn – Pressure equation.
  • config – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.

Output

  • KOmegaModel(k_eqn, ω_eqn) – Turbulence model structure.
source
XCALibre.ModelPhysics.initialiseMethod
initialise(turbulence::KOmegaLKE, model::Physics{T,F,M,Tu,E,D,BI}, mdotf, peqn, config
+) where {T,F,M,Tu,E,D,BI}

Initialisation of turbulent transport equations.

Input

  • turbulence – turbulence model.
  • model – Physics model defined by user.
  • mdtof – Face mass flow.
  • peqn – Pressure equation.
  • config – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.

Output

  • KOmegaLKEModel( k_eqn, ω_eqn, kl_eqn, nueffkLS, nueffkS, nueffωS, nuL, nuts, Ω, γ, fv, normU, Reυ, ∇k, ∇ω ) – Turbulence model structure.
source
XCALibre.ModelPhysics.initialiseMethod
function initialise(
     turbulence::Laminar, model::Physics{T,F,M,Tu,E,D,BI}, mdotf, peqn, config
     ) where {T,F,M,Tu,E,D,BI}
-return LaminarModel()

end

Initialisation of turbulent transport equations.

Input

  • turbulence – turbulence model.
  • model – Physics model defined by user.
  • mdtof – Face mass flow.
  • peqn – Pressure equation.
  • config – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.

Output

  • LaminarModel() – Turbulence model structure.
source
XCALibre.ModelPhysics.initialiseMethod
initialise(turbulence::Smagorinsky, model::Physics{T,F,M,Tu,E,D,BI}, mdotf, peqn, config
-) where {T,F,M,Tu,E,D,BI}

Initialisation of turbulent transport equations.

Input

  • turbulence – turbulence model.
  • model – Physics model defined by user.
  • mdtof – Face mass flow.
  • peqn – Pressure equation.
  • config – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.

Output

  • SmagorinskyModel(Δ, magS) – Turbulence model structure.
source
XCALibre.ModelPhysics.thermo_Psi!Method
thermo_Psi!(model::Physics{T,F,M,Tu,E,D,BI}, Psif::FaceScalarField) 
-where {T,F<:AbstractCompressible,M,Tu,E,D,BI}

Function updates the value of Psi.

Input

  • model – Physics model defined by user.
  • Psif – Compressibility factor FaceScalarField.

Algorithm

Weakly compressible currently uses the ideal gas equation for establishing the compressibility factor where $\rho = p * \Psi$. $\Psi$ is calculated from the sensible enthalpy, reference temperature and fluid model specified $C_p$ and $R$ value where $R$ is calculated from $C_p$ and $\gamma$ specified in the fluid model.

source
XCALibre.ModelPhysics.thermo_Psi!Method
thermo_Psi!(model::Physics{T,F,M,Tu,E,D,BI}, Psi::ScalarField) 
-where {T,F<:AbstractCompressible,M,Tu,E,D,BI}

Model updates the value of Psi.

Input

  • model – Physics model defined by user.
  • Psi – Compressibility factor ScalarField.

Algorithm

Weakly compressible currently uses the ideal gas equation for establishing the compressibility factor where $\rho = p * \Psi$. $\Psi$ is calculated from the sensible enthalpy, reference temperature and fluid model specified $C_p$ and $R$ value where $R$ is calculated from $C_p$ and $\gamma$ specified in the fluid model.

source
XCALibre.ModelPhysics.turbulence!Method

turbulence!(rans::KOmegaLKEModel, model::Physics{T,F,M,Turb,E,D,BI}, S, S2, prev, time, config ) where {T,F,M,Turb<:KOmegaLKE,E,D,BI}

Run turbulence model transport equations.

Input

  • rans::KOmegaLKEModel – KOmega turbulence model.
  • model – Physics model defined by user.
  • S – Strain rate tensor.
  • S2 – Square of the strain rate magnitude.
  • prev – Previous field.
  • time
  • config – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.
source
XCALibre.ModelPhysics.turbulence!Method
turbulence!(rans::LaminarModel, model::Physics{T,F,M,Tu,E,D,BI}, S, S2, prev, time, config
-) where {T,F,M,Tu<:Laminar,E,D,BI}

Run turbulence model transport equations.

Input

  • rans::LaminarModel – Laminar turbulence model.
  • model – Physics model defined by user.
  • S – Strain rate tensor.
  • S2 – Square of the strain rate magnitude.
  • prev – Previous field.
  • time
  • config – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.
source
XCALibre.ModelPhysics.turbulence!Method
turbulence!(rans::KOmegaModel{E1,E2}, model::Physics{T,F,M,Tu,E,D,BI}, S, S2, prev, time, config
-) where {T,F,M,Tu<:KOmega,E,D,BI,E1,E2}

Run turbulence model transport equations.

Input

  • rans::KOmegaModel{E1,E2} – KOmega turbulence model.
  • model – Physics model defined by user.
  • S – Strain rate tensor.
  • S2 – Square of the strain rate magnitude.
  • prev – Previous field.
  • time
  • config – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.
source
XCALibre.ModelPhysics.turbulence!Method
turbulence!(les::SmagorinskyModel{E1,E2}, model::Physics{T,F,M,Tu,E,D,BI}, S, S2, prev, time, config
-) where {T,F,M,Tu<:Smagorinsky,E,D,BI,E1,E2}

Run turbulence model transport equations.

Input

  • les::SmagorinskyModel{E1,E2} – Smagorinsky LES turbulence model.
  • model – Physics model defined by user.
  • S – Strain rate tensor.
  • S2 – Square of the strain rate magnitude.
  • prev – Previous field.
  • time
  • config – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.
source
XCALibre.Simulate.ConfigurationType
@kwdef struct Configuration{SC,SL,RT,HW}
+return LaminarModel()

end

Initialisation of turbulent transport equations.

Input

  • turbulence – turbulence model.
  • model – Physics model defined by user.
  • mdtof – Face mass flow.
  • peqn – Pressure equation.
  • config – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.

Output

  • LaminarModel() – Turbulence model structure.
source
XCALibre.ModelPhysics.initialiseMethod
initialise(turbulence::Smagorinsky, model::Physics{T,F,M,Tu,E,D,BI}, mdotf, peqn, config
+) where {T,F,M,Tu,E,D,BI}

Initialisation of turbulent transport equations.

Input

  • turbulence – turbulence model.
  • model – Physics model defined by user.
  • mdtof – Face mass flow.
  • peqn – Pressure equation.
  • config – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.

Output

  • SmagorinskyModel(Δ, magS) – Turbulence model structure.
source
XCALibre.ModelPhysics.thermo_Psi!Method
thermo_Psi!(model::Physics{T,F,M,Tu,E,D,BI}, Psif::FaceScalarField) 
+where {T,F<:AbstractCompressible,M,Tu,E,D,BI}

Function updates the value of Psi.

Input

  • model – Physics model defined by user.
  • Psif – Compressibility factor FaceScalarField.

Algorithm

Weakly compressible currently uses the ideal gas equation for establishing the compressibility factor where $\rho = p * \Psi$. $\Psi$ is calculated from the sensible enthalpy, reference temperature and fluid model specified $C_p$ and $R$ value where $R$ is calculated from $C_p$ and $\gamma$ specified in the fluid model.

source
XCALibre.ModelPhysics.thermo_Psi!Method
thermo_Psi!(model::Physics{T,F,M,Tu,E,D,BI}, Psi::ScalarField) 
+where {T,F<:AbstractCompressible,M,Tu,E,D,BI}

Model updates the value of Psi.

Input

  • model – Physics model defined by user.
  • Psi – Compressibility factor ScalarField.

Algorithm

Weakly compressible currently uses the ideal gas equation for establishing the compressibility factor where $\rho = p * \Psi$. $\Psi$ is calculated from the sensible enthalpy, reference temperature and fluid model specified $C_p$ and $R$ value where $R$ is calculated from $C_p$ and $\gamma$ specified in the fluid model.

source
XCALibre.ModelPhysics.turbulence!Method

turbulence!(rans::KOmegaLKEModel, model::Physics{T,F,M,Turb,E,D,BI}, S, S2, prev, time, config ) where {T,F,M,Turb<:KOmegaLKE,E,D,BI}

Run turbulence model transport equations.

Input

  • rans::KOmegaLKEModel – KOmega turbulence model.
  • model – Physics model defined by user.
  • S – Strain rate tensor.
  • S2 – Square of the strain rate magnitude.
  • prev – Previous field.
  • time
  • config – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.
source
XCALibre.ModelPhysics.turbulence!Method
turbulence!(rans::LaminarModel, model::Physics{T,F,M,Tu,E,D,BI}, S, S2, prev, time, config
+) where {T,F,M,Tu<:Laminar,E,D,BI}

Run turbulence model transport equations.

Input

  • rans::LaminarModel – Laminar turbulence model.
  • model – Physics model defined by user.
  • S – Strain rate tensor.
  • S2 – Square of the strain rate magnitude.
  • prev – Previous field.
  • time
  • config – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.
source
XCALibre.ModelPhysics.turbulence!Method
turbulence!(rans::KOmegaModel{E1,E2}, model::Physics{T,F,M,Tu,E,D,BI}, S, S2, prev, time, config
+) where {T,F,M,Tu<:KOmega,E,D,BI,E1,E2}

Run turbulence model transport equations.

Input

  • rans::KOmegaModel{E1,E2} – KOmega turbulence model.
  • model – Physics model defined by user.
  • S – Strain rate tensor.
  • S2 – Square of the strain rate magnitude.
  • prev – Previous field.
  • time
  • config – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.
source
XCALibre.ModelPhysics.turbulence!Method
turbulence!(les::SmagorinskyModel{E1,E2}, model::Physics{T,F,M,Tu,E,D,BI}, S, S2, prev, time, config
+) where {T,F,M,Tu<:Smagorinsky,E,D,BI,E1,E2}

Run turbulence model transport equations.

Input

  • les::SmagorinskyModel{E1,E2} – Smagorinsky LES turbulence model.
  • model – Physics model defined by user.
  • S – Strain rate tensor.
  • S2 – Square of the strain rate magnitude.
  • prev – Previous field.
  • time
  • config – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.
source
XCALibre.Simulate.ConfigurationType
@kwdef struct Configuration{SC,SL,RT,HW}
     schemes::SC
     solvers::SL
     runtime::RT
     hardware::HW
 end

The Configuration type is passed to all flow solvers and provides all the relevant information to run a simulation.

Inputs

  • schemes::NamedTuple this keyword argument is used to pass distretisation scheme information to flow solvers. See Numerical setup for details.
  • solvers::NamedTuple this keyword argument is used to pass the configurations for the linear solvers for each field information to flow solvers. See Runtime and solvers for details.
  • runtime::NamedTuple this keyword argument is used to pass runtime information to the flow solvers. See Runtime and solvers for details.
  • hardware::NamedTuple this keyword argument is used to pass the hardware configuration and backend settings to the flow solvers. See Pre-processing for details.

Example

config = Configuration(
-    solvers=solvers, schemes=schemes, runtime=runtime, hardware=hardware)
source
XCALibre.Simulate.set_hardwareMethod
hardware = set_hardware(backend, workgroup)

Function used to configure the backend.

Inputs

  • backend named tuple used to specify the backend e.g. CPU(), CUDABackend() or other backends supported by KernelAbstraction.jl
  • workgroup::Int this is an integer specifying the number of workers that cooperate in a parallel run. For GPUs this could be set to the size of the device's warp e.g. workgroup = 32. On CPUs, the default value in KernelAbstractions.jl is currently workgroup = 1024.

Output

This function returns a NamedTuple with the fields backend and workgroup which are accessed by internally in XCALibre.jl to execute a given kernel.

source
XCALibre.Solvers.cpiso!Method
cpiso!(model, config; 
-    limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0)

Compressible and transient variant of the PISO algorithm with a sensible enthalpy transport equation for the energy.

Input arguments

  • model reference to a Physics` model defined by the user.
  • config Configuration structure defined by the user with solvers, schemes, runtime and hardware structures configuration details.
  • limit_gradient flag use to activate gradient limiters in the solver (default = false)
  • pref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only (default = nothing)
  • ncorrectors number of non-orthogonality correction loops (default = 0)
  • inner_loops number to inner loops used in transient solver based on PISO algorithm (default = 0)

Output

  • Ux Vector of x-velocity residuals for each iteration.
  • Uy Vector of y-velocity residuals for each iteration.
  • Uz Vector of y-velocity residuals for each iteration.
  • p Vector of pressure residuals for each iteration.
source
XCALibre.Simulate.set_hardwareMethod
hardware = set_hardware(backend, workgroup)

Function used to configure the backend.

Inputs

  • backend named tuple used to specify the backend e.g. CPU(), CUDABackend() or other backends supported by KernelAbstraction.jl
  • workgroup::Int this is an integer specifying the number of workers that cooperate in a parallel run. For GPUs this could be set to the size of the device's warp e.g. workgroup = 32. On CPUs, the default value in KernelAbstractions.jl is currently workgroup = 1024.

Output

This function returns a NamedTuple with the fields backend and workgroup which are accessed by internally in XCALibre.jl to execute a given kernel.

source
XCALibre.Solvers.cpiso!Method
cpiso!(model, config; 
+    limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0)

Compressible and transient variant of the PISO algorithm with a sensible enthalpy transport equation for the energy.

Input arguments

  • model reference to a Physics` model defined by the user.
  • config Configuration structure defined by the user with solvers, schemes, runtime and hardware structures configuration details.
  • limit_gradient flag use to activate gradient limiters in the solver (default = false)
  • pref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only (default = nothing)
  • ncorrectors number of non-orthogonality correction loops (default = 0)
  • inner_loops number to inner loops used in transient solver based on PISO algorithm (default = 0)

Output

  • Ux Vector of x-velocity residuals for each iteration.
  • Uy Vector of y-velocity residuals for each iteration.
  • Uz Vector of y-velocity residuals for each iteration.
  • p Vector of pressure residuals for each iteration.
source
XCALibre.Solvers.csimple!Method
csimple!(
     model_in, config; 
     limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0
-)

Compressible variant of the SIMPLE algorithm with a sensible enthalpy transport equation for the energy.

Input arguments

  • model reference to a Physics` model defined by the user.
  • config Configuration structure defined by the user with solvers, schemes, runtime and hardware structures configuration details.
  • limit_gradient flag use to activate gradient limiters in the solver (default = false)
  • pref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only (default = nothing)
  • ncorrectors number of non-orthogonality correction loops (default = 0)
  • inner_loops number to inner loops used in transient solver based on PISO algorithm (default = 0)

Output

  • Ux Vector of x-velocity residuals for each iteration.
  • Uy Vector of y-velocity residuals for each iteration.
  • Uz Vector of y-velocity residuals for each iteration.
  • p Vector of pressure residuals for each iteration.
  • e Vector of energy residuals for each iteration.
source
XCALibre.Solvers.piso!Method
cpiso!(model, config; 
-    limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0)

Incompressible and transient variant of the SIMPLE algorithm to solving coupled momentum and mass conservation equations.

Input arguments

  • model reference to a Physics` model defined by the user.
  • config Configuration structure defined by the user with solvers, schemes, runtime and hardware structures configuration details.
  • limit_gradient flag use to activate gradient limiters in the solver (default = false)
  • pref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only (default = nothing)
  • ncorrectors number of non-orthogonality correction loops (default = 0)
  • inner_loops number to inner loops used in transient solver based on PISO algorithm (default = 0)

Output

  • Ux Vector of x-velocity residuals for each iteration.
  • Uy Vector of y-velocity residuals for each iteration.
  • Uz Vector of y-velocity residuals for each iteration.
  • p Vector of pressure residuals for each iteration.
source
XCALibre.Solvers.run!Method
function run!(
+)

Compressible variant of the SIMPLE algorithm with a sensible enthalpy transport equation for the energy.

Input arguments

  • model reference to a Physics` model defined by the user.
  • config Configuration structure defined by the user with solvers, schemes, runtime and hardware structures configuration details.
  • limit_gradient flag use to activate gradient limiters in the solver (default = false)
  • pref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only (default = nothing)
  • ncorrectors number of non-orthogonality correction loops (default = 0)
  • inner_loops number to inner loops used in transient solver based on PISO algorithm (default = 0)

Output

  • Ux Vector of x-velocity residuals for each iteration.
  • Uy Vector of y-velocity residuals for each iteration.
  • Uz Vector of y-velocity residuals for each iteration.
  • p Vector of pressure residuals for each iteration.
  • e Vector of energy residuals for each iteration.
source
XCALibre.Solvers.piso!Method
cpiso!(model, config; 
+    limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0)

Incompressible and transient variant of the SIMPLE algorithm to solving coupled momentum and mass conservation equations.

Input arguments

  • model reference to a Physics` model defined by the user.
  • config Configuration structure defined by the user with solvers, schemes, runtime and hardware structures configuration details.
  • limit_gradient flag use to activate gradient limiters in the solver (default = false)
  • pref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only (default = nothing)
  • ncorrectors number of non-orthogonality correction loops (default = 0)
  • inner_loops number to inner loops used in transient solver based on PISO algorithm (default = 0)

Output

  • Ux Vector of x-velocity residuals for each iteration.
  • Uy Vector of y-velocity residuals for each iteration.
  • Uz Vector of y-velocity residuals for each iteration.
  • p Vector of pressure residuals for each iteration.
source
XCALibre.Solvers.run!Method
function run!(
     model::Physics, config; 
     limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0
     )
@@ -167,36 +167,36 @@
 
 # to access the pressure residual
 
-residuals.p 
source
XCALibre.Solvers.run!Method
run!(
     model::Physics{T,F,M,Tu,E,D,BI}, config;
     limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0
     ) where{T<:Steady,F<:Incompressible,M,Tu,E,D,BI} = 
 begin
     residuals = simple!(model, config, pref=pref)
     return residuals
-end

Calls the incompressible steady solver using the SIMPLE algorithm.

Input

  • model represents the Physics` model defined by user.
  • config Configuration structure defined by user with solvers, schemes, runtime and hardware structures configuration details.
  • pref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only.

Output

This function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux) with the following entries:

  • Ux - Vector of x-velocity residuals for each iteration.
  • Uy - Vector of y-velocity residuals for each iteration.
  • Uz - Vector of y-velocity residuals for each iteration.
  • p - Vector of pressure residuals for each iteration.
source
XCALibre.Solvers.run!Method
run!(
+end

Calls the incompressible steady solver using the SIMPLE algorithm.

Input

  • model represents the Physics` model defined by user.
  • config Configuration structure defined by user with solvers, schemes, runtime and hardware structures configuration details.
  • pref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only.

Output

This function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux) with the following entries:

  • Ux - Vector of x-velocity residuals for each iteration.
  • Uy - Vector of y-velocity residuals for each iteration.
  • Uz - Vector of y-velocity residuals for each iteration.
  • p - Vector of pressure residuals for each iteration.
source
XCALibre.Solvers.run!Method
run!(
     model::Physics{T,F,M,Tu,E,D,BI}, config; 
     limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0
     ) where{T<:Steady,F<:WeaklyCompressible,M,Tu,E,D,BI} = 
 begin
     residuals = csimple!(model, config, pref=pref); #, pref=0.0)
     return residuals
-end

Calls the compressible steady solver using the SIMPLE algorithm for weakly compressible fluids.

Input

  • model represents the Physics` model defined by user.
  • config Configuration structure defined by user with solvers, schemes, runtime and hardware structures configuration details.
  • pref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only.

Output

This function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux) with the following entries:

  • Ux - Vector of x-velocity residuals for each iteration.
  • Uy - Vector of y-velocity residuals for each iteration.
  • Uz - Vector of y-velocity residuals for each iteration.
  • p - Vector of pressure residuals for each iteration.
  • e - Vector of energy residuals for each iteration.
source
XCALibre.Solvers.run!Method
run!(
+end

Calls the compressible steady solver using the SIMPLE algorithm for weakly compressible fluids.

Input

  • model represents the Physics` model defined by user.
  • config Configuration structure defined by user with solvers, schemes, runtime and hardware structures configuration details.
  • pref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only.

Output

This function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux) with the following entries:

  • Ux - Vector of x-velocity residuals for each iteration.
  • Uy - Vector of y-velocity residuals for each iteration.
  • Uz - Vector of y-velocity residuals for each iteration.
  • p - Vector of pressure residuals for each iteration.
  • e - Vector of energy residuals for each iteration.
source
XCALibre.Solvers.run!Method
run!(
     model::Physics{T,F,M,Tu,E,D,BI}, config; 
     limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0
     ) where{T<:Transient,F<:Incompressible,M,Tu,E,D,BI} = 
 begin
     residuals = piso!(model, config, pref=pref); #, pref=0.0)
     return residuals
-end

Calls the incompressible transient solver using the PISO algorithm.

Input

  • model represents the Physics` model defined by user.
  • config Configuration structure defined by user with solvers, schemes, runtime and hardware structures configuration details.
  • pref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only.

Output

This function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux) with the following entries:

  • Ux - Vector of x-velocity residuals for each iteration.
  • Uy - Vector of y-velocity residuals for each iteration.
  • Uz - Vector of y-velocity residuals for each iteration.
  • p - Vector of pressure residuals for each iteration.
source
XCALibre.Solvers.run!Method
run!(
+end

Calls the incompressible transient solver using the PISO algorithm.

Input

  • model represents the Physics` model defined by user.
  • config Configuration structure defined by user with solvers, schemes, runtime and hardware structures configuration details.
  • pref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only.

Output

This function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux) with the following entries:

  • Ux - Vector of x-velocity residuals for each iteration.
  • Uy - Vector of y-velocity residuals for each iteration.
  • Uz - Vector of y-velocity residuals for each iteration.
  • p - Vector of pressure residuals for each iteration.
source
XCALibre.Solvers.run!Method
run!(
     model::Physics{T,F,M,Tu,E,D,BI}; 
     limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0
     ) where{T<:Transient,F<:WeaklyCompressible,M,Tu,E,D,BI} = 
 begin
     residuals = cpiso!(model, config)
     return residuals
-end

Calls the compressible transient solver using the PISO algorithm for weakly compressible fluids.

Input

  • model represents the Physics` model defined by user.
  • config Configuration structure defined by user with solvers, schemes, runtime and hardware structures configuration details.
  • pref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only.

Output

This function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux) with the following entries:

  • Ux - Vector of x-velocity residuals for each iteration.
  • Uy - Vector of y-velocity residuals for each iteration.
  • Uz - Vector of y-velocity residuals for each iteration.
  • p - Vector of pressure residuals for each iteration.
  • e - Vector of energy residuals for each iteration.
source
XCALibre.Solvers.simple!Method
simple!(model_in, config; 
-    limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0)

Incompressible variant of the SIMPLE algorithm to solving coupled momentum and mass conservation equations.

Input arguments

  • model reference to a Physics` model defined by the user.
  • config Configuration structure defined by the user with solvers, schemes, runtime and hardware structures configuration details.
  • limit_gradient flag use to activate gradient limiters in the solver (default = false)
  • pref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only (default = nothing)
  • ncorrectors number of non-orthogonality correction loops (default = 0)
  • inner_loops number to inner loops used in transient solver based on PISO algorithm (default = 0)

Output

This function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux) with the following entries:

  • Ux Vector of x-velocity residuals for each iteration.
  • Uy Vector of y-velocity residuals for each iteration.
  • Uz Vector of y-velocity residuals for each iteration.
  • p Vector of pressure residuals for each iteration.
source
XCALibre.Postprocess.boundary_averageMethod
function boundary_average(patch::Symbol, field, config; time=0)
+end

Calls the compressible transient solver using the PISO algorithm for weakly compressible fluids.

Input

  • model represents the Physics` model defined by user.
  • config Configuration structure defined by user with solvers, schemes, runtime and hardware structures configuration details.
  • pref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only.

Output

This function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux) with the following entries:

  • Ux - Vector of x-velocity residuals for each iteration.
  • Uy - Vector of y-velocity residuals for each iteration.
  • Uz - Vector of y-velocity residuals for each iteration.
  • p - Vector of pressure residuals for each iteration.
  • e - Vector of energy residuals for each iteration.
source
XCALibre.Solvers.simple!Method
simple!(model_in, config; 
+    limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0)

Incompressible variant of the SIMPLE algorithm to solving coupled momentum and mass conservation equations.

Input arguments

  • model reference to a Physics` model defined by the user.
  • config Configuration structure defined by the user with solvers, schemes, runtime and hardware structures configuration details.
  • limit_gradient flag use to activate gradient limiters in the solver (default = false)
  • pref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only (default = nothing)
  • ncorrectors number of non-orthogonality correction loops (default = 0)
  • inner_loops number to inner loops used in transient solver based on PISO algorithm (default = 0)

Output

This function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux) with the following entries:

  • Ux Vector of x-velocity residuals for each iteration.
  • Uy Vector of y-velocity residuals for each iteration.
  • Uz Vector of y-velocity residuals for each iteration.
  • p Vector of pressure residuals for each iteration.
source
XCALibre.Postprocess.pressure_forceMethod
pressure_force(patch::Symbol, p::ScalarField, rho)

Function to calculate the pressure force acting on a given patch/boundary.

Input arguments

  • patch::Symbol name of the boundary of interest (as a Symbol)
  • p::ScalarField pressure field
  • rho density. Set to 1 for incompressible solvers
source
XCALibre.Postprocess.viscous_forceMethod
viscous_force(patch::Symbol, U::VectorField, rho, ν, νt)

Function to calculate the pressure force acting on a given patch/boundary.

Input arguments

  • patch::Symbol name of the boundary of interest (as a Symbol)
  • U::VectorField pressure field
  • rho density. Set to 1 for incompressible solvers
  • ν laminar viscosity of the fluid
  • νt eddy viscosity from turbulence models. Pass ConstantScalar(0) for laminar flows
source
+end
source
XCALibre.Postprocess.pressure_forceMethod
pressure_force(patch::Symbol, p::ScalarField, rho)

Function to calculate the pressure force acting on a given patch/boundary.

Input arguments

  • patch::Symbol name of the boundary of interest (as a Symbol)
  • p::ScalarField pressure field
  • rho density. Set to 1 for incompressible solvers
source
XCALibre.Postprocess.viscous_forceMethod
viscous_force(patch::Symbol, U::VectorField, rho, ν, νt)

Function to calculate the pressure force acting on a given patch/boundary.

Input arguments

  • patch::Symbol name of the boundary of interest (as a Symbol)
  • U::VectorField pressure field
  • rho density. Set to 1 for incompressible solvers
  • ν laminar viscosity of the fluid
  • νt eddy viscosity from turbulence models. Pass ConstantScalar(0) for laminar flows
source
diff --git a/dev/release_notes/index.html b/dev/release_notes/index.html index f34f2b77..e744a5b7 100644 --- a/dev/release_notes/index.html +++ b/dev/release_notes/index.html @@ -1,2 +1,2 @@ -Release notes · XCALibre.jl

Release notes

The format used for this changelog is based on Keep a Changelog, and this project adheres to Semantic Versioning. Notice that until the package reaches version v1.0.0 minor releases are likely to be breaking. Starting from version v3.0.1 breaking changes will be recorded here.

Version v0.3.1 - 2024-10-18

Added

  • Vastly improved documentation with new examples provided
  • Changelog added to record changes more clearly. Record kept in Release notes

Fixed

  • The calculation of gradients can be limited for stability. This functionality can be activated by passing the key work argument limit_gradient to the run! function. The implementation has been improved for robustness.

Changed

  • Master branch protected and requires PRs to push changes

Breaking

  • No breaking changes

Deprecated

  • No functions deprecated

Removed

  • No functionality has been removed

Version v0.3.0 - 2024-09-21

  • New name - XCALibre.jl - which is now registered in the General Julia registry
  • Can do 3D and GPU accelerated simulations
  • Can read .unv and OpenFOAM mesh files (3D)
  • Can do incompressible and compressible simulations
  • RANS and LES models available
  • User-provided functions or neural networks for boundary conditions
  • Reasonably complete "user" documentation now provided
  • Made repository public (in v0.2 the work was kept in a private repository and could only do 2D simulations)
  • Tidy up mesh type definitions by @mberto79 in #5
  • Adapt code base to work with new mesh format by @mberto79 in #6
  • Mesh boundary struct changes PR by @TomMazin in #7
  • Mesh boundary struct changes PR fix by @TomMazin in #8

Version v0.2.0 - 2023-01-23

  • New mesh format and type implemented that are GPU friendly.
  • No functionality changes

Version v0.1.0 - 2023-01-23

Initial release

2D implementation of classic incompressible solvers for laminar and turbulent flows:

  • Framework for equation definition
  • SIMPLE nad PISO algorithms
  • Read UNV meshes in 2D
  • Capability for RANS models
  • Various discretisation schemes available
  • Planned extension to 3D and GPU acceleration!
+Release notes · XCALibre.jl

Release notes

The format used for this changelog is based on Keep a Changelog, and this project adheres to Semantic Versioning. Notice that until the package reaches version v1.0.0 minor releases are likely to be breaking. Starting from version v3.0.1 breaking changes will be recorded here.

Version v0.3.1 - 2024-10-18

Added

  • Vastly improved documentation with new examples provided #12
  • Changelog added to record changes more clearly. Record kept in Release notes

Fixed

  • The calculation of gradients can be limited for stability. This functionality can be activated by passing the key work argument limit_gradient to the run! function. The implementation has been improved for robustness #12
  • Removed face information being printed when Mesh objects are created to stop printing a ERROR: Scalar indexing is disallowed message #13

Changed

  • Master branch protected and requires PRs to push changes

Breaking

  • No breaking changes

Deprecated

  • No functions deprecated

Removed

  • No functionality has been removed

Version v0.3.0 - 2024-09-21

  • New name - XCALibre.jl - which is now registered in the General Julia registry
  • Can do 3D and GPU accelerated simulations
  • Can read .unv and OpenFOAM mesh files (3D)
  • Can do incompressible and compressible simulations
  • RANS and LES models available
  • User-provided functions or neural networks for boundary conditions
  • Reasonably complete "user" documentation now provided
  • Made repository public (in v0.2 the work was kept in a private repository and could only do 2D simulations)
  • Tidy up mesh type definitions by @mberto79 in #5
  • Adapt code base to work with new mesh format by @mberto79 in #6
  • Mesh boundary struct changes PR by @TomMazin in #7
  • Mesh boundary struct changes PR fix by @TomMazin in #8

Version v0.2.0 - 2023-01-23

  • New mesh format and type implemented that are GPU friendly.
  • No functionality changes

Version v0.1.0 - 2023-01-23

Initial release

2D implementation of classic incompressible solvers for laminar and turbulent flows:

  • Framework for equation definition
  • SIMPLE nad PISO algorithms
  • Read UNV meshes in 2D
  • Capability for RANS models
  • Various discretisation schemes available
  • Planned extension to 3D and GPU acceleration!
diff --git a/dev/search_index.js b/dev/search_index.js index dda9c9eb..9afb2387 100644 --- a/dev/search_index.js +++ b/dev/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"user_guide/4_runtime_and_solvers/#Runtime-and-solvers","page":"Runtime and solvers","title":"Runtime and solvers","text":"","category":"section"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"Final steps before launching a simulation","category":"page"},{"location":"user_guide/4_runtime_and_solvers/#Runtime-setup","page":"Runtime and solvers","title":"Runtime setup","text":"","category":"section"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"At this stage in the setup workflow, the user defines the runtime information to configure the runtime behaviour of the flow solver, including the time step to use (only meaningful for transient solutions), as well as information about how often to write results to disk. XCALibre.jl provides a the set_runtime to perform this operation. ","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"set_runtime","category":"page"},{"location":"user_guide/4_runtime_and_solvers/#XCALibre.Solve.set_runtime-user_guide-4_runtime_and_solvers","page":"Runtime and solvers","title":"XCALibre.Solve.set_runtime","text":"set_runtime(; \n # keyword arguments\n iterations::I, \n write_interval::I, \n time_step::N\n ) where {I<:Integer,N<:Number} = begin\n \n # returned `NamedTuple``\n (\n iterations=iterations, \n dt=time_step, \n write_interval=write_interval)\nend\n\nThis is a convenience function to set the top-level runtime information. The inputs are all keyword arguments and provide basic information to flow solvers just before running a simulation.\n\nInput arguments\n\niterations::Integer specifies the number of iterations in a simulation run.\nwrite_interval::Integer defines how often simulation results are written to file (on the current working directory). The interval is currently based on number of iterations. Set to -1 to run without writing results to file.\ntime_step::Number the time step to use in the simulation. Notice that for steady solvers this is simply a counter and it is recommended to simply use 1.\n\nExample\n\nruntime = set_runtime(\n iterations=2000, time_step=1, write_interval=2000)\n\n\n\n\n\n","category":"function"},{"location":"user_guide/4_runtime_and_solvers/#Configuration-object","page":"Runtime and solvers","title":"Configuration object","text":"","category":"section"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"Once all the simulation configuration information has been defined, from discretisation scheme to runtime information, all settings must be wrapped in a Configuration object. The definition, including expected input arguments, for the Configuration object are detailed below.","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"Configuration","category":"page"},{"location":"user_guide/4_runtime_and_solvers/#XCALibre.Simulate.Configuration-user_guide-4_runtime_and_solvers","page":"Runtime and solvers","title":"XCALibre.Simulate.Configuration","text":"@kwdef struct Configuration{SC,SL,RT,HW}\n schemes::SC\n solvers::SL\n runtime::RT\n hardware::HW\nend\n\nThe Configuration type is passed to all flow solvers and provides all the relevant information to run a simulation. \n\nInputs\n\nschemes::NamedTuple this keyword argument is used to pass distretisation scheme information to flow solvers. See Numerical setup for details.\nsolvers::NamedTuple this keyword argument is used to pass the configurations for the linear solvers for each field information to flow solvers. See Runtime and solvers for details.\nruntime::NamedTuple this keyword argument is used to pass runtime information to the flow solvers. See Runtime and solvers for details.\nhardware::NamedTuple this keyword argument is used to pass the hardware configuration and backend settings to the flow solvers. See Pre-processing for details.\n\nExample\n\nconfig = Configuration(\n solvers=solvers, schemes=schemes, runtime=runtime, hardware=hardware)\n\n\n\n\n\n","category":"type"},{"location":"user_guide/4_runtime_and_solvers/#Initialising-fields","page":"Runtime and solvers","title":"Initialising fields","text":"","category":"section"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"The last (optional) step before running the simulation is to provide an initial guess for all the fields being solved. Although this step is optional, in most cases the flow solvers will perform better when initialised. To set an initial value for a field, the initialise! function is provided, which assigns a starting value to a given field.","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"initialise!","category":"page"},{"location":"user_guide/4_runtime_and_solvers/#XCALibre.Fields.initialise!-user_guide-4_runtime_and_solvers","page":"Runtime and solvers","title":"XCALibre.Fields.initialise!","text":"function initialise!(field, value) # dummy function for documentation\n # Assign `value` to field in-place\n nothing\nend\n\nThis function will set the given field to the value provided in-place. Useful for initialising fields prior to running a simulation.\n\nInput arguments\n\nfield specifies the field to be initialised. The field must be either a AbractScalarField or AbstractVectorField\nvalue defines the value to be set. This should be a scalar or vector (3 components) depending on the field to be modified e.g. for an AbstractVectorField we can specify as value=[10,0,0]\n\nNote: in most cases the fields to be modified are stored within a physics model i.e. a Physics object. Thus, the argument value must fully qualify the model. For example, if we have created a Physics model named mymodel to set the velocity field, U, we would set the argument field to mymodel.momentum.U. See the example below.\n\nExample\n\ninitialise!(mymodel.momentum.U, [2.5, 0, 0])\ninitialise!(mymodel.momentum.p, 1.25)\n\n\n\n\n\n","category":"function"},{"location":"user_guide/4_runtime_and_solvers/#Launching-flow-solvers","page":"Runtime and solvers","title":"Launching flow solvers","text":"","category":"section"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"In XCALibre.jl the run! function is used to start a simulation, which will dispatch to the appropriate flow solver for execution. Once the simulation is complete a NamedTuple containing residual information is returned for users to explore the convergence history of the simulation. ","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"run!()","category":"page"},{"location":"user_guide/4_runtime_and_solvers/#XCALibre.Solvers.run!-Tuple{}-user_guide-4_runtime_and_solvers","page":"Runtime and solvers","title":"XCALibre.Solvers.run!","text":"function run!(\n model::Physics, config; \n limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0\n )\n\n # here an internal function is used for solver dispatch\n return residuals\nend\n\nThis is the top level API function to initiate a simulation. It uses the user-provided model defined as a Physics object to dispatch to the appropriate solver.\n\nDispatched flow solvers\n\nSteady incompressible (SIMPLE algorithm for coupling)\nTransient incompressible (PISO algorithm for coupling)\nSteady weakly compressible (SIMPLE algorithm for coupling)\nTransient weakly compressible (PISO algorithm for coupling)\n\nInput arguments\n\nmodel reference to a Physics model defined by the user.\nconfig Configuration structure defined by the user with solvers, schemes, runtime and hardware structures configuration details.\nlimit_gradient flag used to activate gradient limiters in the solver (default = false)\npref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only (default = nothing)\nncorrectors number of non-orthogonality correction loops (default = 0)\ninner_loops number to inner loops used in transient solver based on PISO algorithm (default = 0)\n\nOutput\n\nThis function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux). The fields available within the returned residuals tuple depend on the solver used. For example, for an incompressible solver, a x-momentum equation residual can be retrieved accessing the Ux field i.e. residuals.Ux. Look at reference guide for each dispatch method to find out which fields are available.\n\nExample\n\nresiduals = run!(model, config) \n\n# to access the pressure residual\n\nresiduals.p \n\n\n\n\n\n","category":"method"},{"location":"user_guide/4_runtime_and_solvers/#Restarting-simulations","page":"Runtime and solvers","title":"Restarting simulations","text":"","category":"section"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"It should be noted that when running a simulation with run!, the solution fields in the Physics model are mutated. Thus, running the simulation from the previous solution is simply a matter of reissuing the run! function. At present, this has the side effect of overwriting any existing solution files (.vtk or .vtu). Users must be aware of this behaviour.","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"In some cases, it may be desirable to solve a problem with a steady solver and use the solution to run transient simulations. This is possible using the change function.","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"XCALibre.ModelPhysics.change","category":"page"},{"location":"user_guide/4_runtime_and_solvers/#XCALibre.ModelPhysics.change-user_guide-4_runtime_and_solvers","page":"Runtime and solvers","title":"XCALibre.ModelPhysics.change","text":"change(model::Physics, property, value) => updatedModel::Physics\n\nA convenience function to change properties of an exisitng Physics model.\n\nInput arguments\n\nmodel::Physics a Physics model to modify\nproperty is a symbol specifying the property to change \nvalue is the new setting for the specified property\n\nOutput\n\nThis function return a new Physics object\n\nExample\n\nTo change a model to run a transient simulation e.g. after converging in steady state\n\nmodelTransient = change(model, :time, Transient())\n\n\n\n\n\n","category":"function"},{"location":"examples/04_2d-inflow-using-Flux/#Advanced:-2D-inflow-using-Flux.jl","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"","category":"section"},{"location":"examples/04_2d-inflow-using-Flux/#Introduction","page":"Advanced: 2D inflow using Flux.jl","title":"Introduction","text":"","category":"section"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"In this example a simple neural network is constructed and used to define an inlet boundary condition for the x-component of the velocity vector. This example serves to illustrate how other packages from the Julia ecosystem can be integrated into XCALibre.jl to extend its functionality. In particular, this example will show how to build a basic neural network using Flux.jl to represent a parabolic velocity profile and how this neural network can be used to define an inlet condition in XCALibre.jl. ","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"The boundary condition is injected into the solution using the builtin DirichletFunction boundary condition, which is designed to pass arbitrary Julia functions to a given boundary.","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"XCALibre.Discretise.DirichletFunction","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/#XCALibre.Discretise.DirichletFunction-examples-04_2d-inflow-using-Flux","page":"Advanced: 2D inflow using Flux.jl","title":"XCALibre.Discretise.DirichletFunction","text":"DirichletFunction(ID, value) <: AbstractDirichlet\n\nDirichlet boundary condition defined with user-provided function.\n\nInput\n\nID Boundary name provided as symbol e.g. :inlet\nvalue Custom function for Dirichlet boundary condition.\n\nFunction requirements\n\nThe function passed to this boundary condition must have the following signature:\n\nf(coords, time, index) = SVector{3}(ux, uy, uz)\n\nWhere, coords is a vector containing the coordinates of a face, time is the current time in transient simulations (and the iteration number in steady simulations), and index is the local face index (from 1 to N, where N is the number of faces in a given boundary). The function must return an SVector (from StaticArrays.jl) representing the velocity vector. \n\n\n\n\n\n","category":"type"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"In this example, instead of passing a Julia function, the boundary velocity profile will be given via a simple neural network. ","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"note: Note\nThis interface is experimental and subject to change. Currently it can only be used for vectors.","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/#Set-up-steps","page":"Advanced: 2D inflow using Flux.jl","title":"Set up steps","text":"","category":"section"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/#Install-and-load-modules","page":"Advanced: 2D inflow using Flux.jl","title":"Install and load modules","text":"","category":"section"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"To be able to run this example the following modules need to be installed. This can be done by entering into package mode (using \"]\" in the REPL) and typing the following:","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"add Plots, XCALibre, Flux, StaticArrays, LinearAlgebra, KernelAbstractions, Adapt","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"This will download and install the required packages. Once installed, the packages can be loaded as follows:","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"# using Logging; Logging.disable_logging(Logging.Info) # hide\nusing Pkg; # hide\ninstalled = \"BayesianOptimization\" ∈ keys(Pkg.project().dependencies) # hide\ninstalled && Pkg.rm(\"BayesianOptimization\", io=devnull) #hide\nPkg.add(\"Flux\", io=devnull) # hide\n\nusing Plots\nusing XCALibre\nusing Flux\nusing StaticArrays\nusing Statistics\nusing LinearAlgebra\nusing KernelAbstractions\nnothing # hide","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/#Build-a-neural-network-model","page":"Advanced: 2D inflow using Flux.jl","title":"Build a neural network model","text":"","category":"section"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"Next, a neural network will be created to return a parabolic velocity profile. In this case, the training data will be generated using an analytical expression. ","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"\nactual(y) = begin\n H = 1 # channel height\n H2 = H/2\n h = y - H2\n vx = (1 - (h/H2)^2)\n return vx\nend\n","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"And define a simple 2-layer neural network to model the inlet function:","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"inflowNetwork = Chain(\n Dense(1 => 6, sigmoid),\n Dense(6 => 1)) |> f64","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"Now, we generate the training and testing datasets using the analytical function. The neural network is not yet trained but it can already be used (of course, the prediction is not yet very useful). The various datasets, and initial model predictions are shown in the figure below.","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"\ny_actual = [0:0.01:1;] # array of y-values for plotting\nvx_actual = actual.(y_actual)\n\n# Generate training dataset\ny_train = hcat(rand(0:(0.1/100):0.1, 100)...)./0.1\nvx_train = actual.(y_train)\n\n# Test locations selected randomly\ny_test = hcat(rand(0:(0.1/100):0.1, 100)...)./0.1\nvx_untrained = inflowNetwork(y_test)\n\nplot(\n y_actual, vx_actual, label=\"Actual\", \n frame_style=:box, foreground_color_legend = nothing,\n xlabel=\"Dimensionless distance\", ylabel=\"Normalised velocity\")\nscatter!(y_train', vx_train', label=\"Training data\")\nscatter!(y_test', vx_untrained', label=\"Untrained output\")\nsavefig(\"flux_comparison_untrained.svg\"); nothing # hide","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"(Image: )","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"The next step is to train the model as shown below. Finally, to make sure that the model has trained correctly, it is tested with at randomly generated points and the output compared with the analytical function as shown in the figure below.","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"\nloss(inflowNetwork, y, vx) = mean(abs2.(inflowNetwork(y) .- vx))\n\nopt = Flux.setup(Adam(), inflowNetwork)\ndata = [(y_train, vx_train)]\nfor epoch in 1:20000\n Flux.train!(loss, inflowNetwork, data, opt)\nend\nloss(inflowNetwork, data[1]...,)\n\nvx_trained = inflowNetwork(y_test)\n\n\nplot(\n y_actual, vx_actual, label=\"Actual\", \n frame_style=:box, foreground_color_legend = nothing,\n xlabel=\"Dimensionless distance\", ylabel=\"Normalised velocity\")\nscatter!(y_test', vx_trained', label=\"Trained output\")\nsavefig(\"flux_comparison.svg\"); nothing # hide","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"(Image: )","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/#Define-inlet-condition-and-interface","page":"Advanced: 2D inflow using Flux.jl","title":"Define inlet condition and interface","text":"","category":"section"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"The next step is to define some interfaces to allow passing the model as if it was a simple Julia function. This requires only 3 key ingredients. First, a struct is defined that will contain any user data needed as well as the model itself. In this case, the following structure has been used (but users are completely free to define their own structures). The only requirements are that the structure should be a subtype of XCALibreUserFunctor and it must contain the steady property.","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"struct Inflow{F,I,O,N,V,T} <: XCALibreUserFunctor\n U::F # maximum velocity\n H::F # inlet height\n input::I # vector to hold input coordinates\n output::O # vector to hold model inferred values\n network::N # model itself\n xdir::V # struct used to define x-direction unit vector\n steady::T # required field! (Bool)\nend","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"Second, the struct above is used as a functor, defined following the requirements set by the DirichletFunction boundary condition. Essentially, this allows for external data to be stored in the Inflow object, which is then made \"callable\" to behave as a simple Julia function that returns the velocity vector at a given coordinate (vec) and time (t).","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"(bc::Inflow)(vec, t, i) = begin\n velocity = @view bc.output[:,i]\n return @inbounds SVector{3}(velocity[1], velocity[2], velocity[3])\nend","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"The third step is to define a new method for the update_user_boundary! function from the Discretise module. This function offers a mechanism to update the internals of the previously defined structure by calling the user-provided neural network model. In this particular example, this is not required since the boundary values are not changing in time (it would have been sufficient to do a single inference round and to simply store the values inside the Inflow struct). However, this function is implemented here to illustrate the interface, and provide an example of a user-defined kernel. Notice that, in this particular example, the only purpose of this function is to scale the velocity field inferred by the neural network (since it was defined with values between 0 and 1).","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"\nXCALibre.Discretise.update_user_boundary!(\n BC::DirichletFunction{I,V}, faces, cells, facesID_range, time, config\n ) where{I,V<:Inflow} = \nbegin\n\n (; hardware) = config\n (; backend, workgroup) = hardware\n\n kernel_range = length(facesID_range)\n kernel! = _update_user_boundary!(backend, workgroup, kernel_range)\n kernel!(BC, faces, cells, facesID_range, time, ndrange=kernel_range)\n KernelAbstractions.synchronize(backend)\n\n (; output, input, U, network, xdir) = BC.value\n output .= U.*network(input).*xdir # convert to vector\nend\n\n@kernel function _update_user_boundary!(BC, faces, cells, facesID_range, time)\n i = @index(Global)\n startID = facesID_range[1]\n fID = i + startID - 1\n coords = faces[fID].centre\n BC.value.input[i] = coords[2]/BC.value.H # scale coordinates\nend\n","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/#Create-an-instance-of-Inflow","page":"Advanced: 2D inflow using Flux.jl","title":"Create an instance of Inflow","text":"","category":"section"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"An instance of the Inflow object is now created. Notice that the input and output fields contain vectors to hold the boundary face information, thus, they must be of the same size as the number of boundary faces. The mesh is, therefore, loaded first.","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"\ngrids_dir = pkgdir(XCALibre, \"examples/0_GRIDS\")\ngrid = \"backwardFacingStep_5mm.unv\"\nmesh_file = joinpath(grids_dir, grid)\n\nmesh = UNV2D_mesh(mesh_file, scale=0.001)\n\nnfaces = mesh.boundaries[1].IDs_range |> length","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"The Inflow functor is now constructed.","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"\nU = 0.5 # maximum velocity\nH = 0.1 # inlet height\ninput = zeros(1,nfaces)\ninput .= (H/2)/H\noutput = U.*inflowNetwork(input).*[1 0 0]'\n@view output[:,2]\n\ninlet_profile= Inflow(\n 0.5,\n 0.1,\n input,\n output,\n inflowNetwork,\n [1,0,0],\n true\n)\n","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/#Run-simulation","page":"Advanced: 2D inflow using Flux.jl","title":"Run simulation","text":"","category":"section"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"The final step is simply to set up and run a simulation in XCALibre.jl. Notice that this does not require any special considerations, only to remember to use the DirichletFunction boundary condition when setting the inlet velocity. The inlet_profile functor object is then passed to the boundary. ","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"\nvelocity = [0.5, 0.0, 0.0]\nnu = 1e-3\nRe = velocity[1]*0.1/nu\n\nmodel = Physics(\n time = Steady(),\n fluid = Fluid{Incompressible}(nu = nu),\n turbulence = RANS{Laminar}(),\n energy = Energy{Isothermal}(),\n domain = mesh\n )\n\n@assign! model momentum U (\n DirichletFunction(:inlet, inlet_profile), # Pass functor\n Neumann(:outlet, 0.0),\n Dirichlet(:wall, [0.0, 0.0, 0.0]),\n Dirichlet(:top, [0.0, 0.0, 0.0]),\n)\n\n@assign! model momentum p (\n Neumann(:inlet, 0.0),\n Dirichlet(:outlet, 0.0),\n Neumann(:wall, 0.0),\n Neumann(:top, 0.0)\n)\n\nschemes = (\n U = set_schemes(divergence = Linear),\n p = set_schemes()\n)\n\n\nsolvers = (\n U = set_solver(\n model.momentum.U;\n solver = BicgstabSolver,\n preconditioner = Jacobi(),\n convergence = 1e-7,\n relax = 0.7,\n rtol = 1e-4,\n atol = 1e-10\n ),\n p = set_solver(\n model.momentum.p;\n solver = CgSolver,\n preconditioner = Jacobi(),\n convergence = 1e-7,\n relax = 0.3,\n rtol = 1e-4,\n atol = 1e-10\n )\n)\n\nruntime = set_runtime(iterations=500, time_step=1, write_interval=500)\nruntime = set_runtime(iterations=1, time_step=1, write_interval=-1) # hide\n\nhardware = set_hardware(backend=CPU(), workgroup=1024)\n\nconfig = Configuration(\n solvers=solvers, schemes=schemes, runtime=runtime, hardware=hardware)\n\nGC.gc()\n\ninitialise!(model.momentum.U, velocity)\ninitialise!(model.momentum.p, 0.0)\n\nresiduals = run!(model, config)\n\nPkg.rm(\"Flux\", io=devnull) # hide\nnothing # hide\n\"done\"","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/#Simulation-result","page":"Advanced: 2D inflow using Flux.jl","title":"Simulation result","text":"","category":"section"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"(Image: Comparison with OpenFOAM)","category":"page"},{"location":"user_guide/0_introduction_and_workflow/#Introduction","page":"Introduction","title":"Introduction","text":"","category":"section"},{"location":"user_guide/0_introduction_and_workflow/","page":"Introduction","title":"Introduction","text":"This page explains the overarching workflow in XCALibre.jl and provides a list of contents","category":"page"},{"location":"user_guide/0_introduction_and_workflow/#Workflow-overview","page":"Introduction","title":"Workflow overview","text":"","category":"section"},{"location":"user_guide/0_introduction_and_workflow/","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"user_guide/0_introduction_and_workflow/","page":"Introduction","title":"Introduction","text":"XCALibre.jl has been designed to incorporate a logical workflow, that is, the sequence of setup steps that would take a user naturally from the start of a simulation to its final post-processing. The key steps are listed below","category":"page"},{"location":"user_guide/0_introduction_and_workflow/","page":"Introduction","title":"Introduction","text":"Pre-processing - this step involves defining the computational domain and selecting the corresponding backend to performs the calculations\nPhysics and models - this step involves defining the fluid type, flow properties, selecting appropriate models and setting suitable boundary conditions\nNumerical setup - in this phase of the simulation set up all aspect related to the numerics are chosen, from distretisation schemes all the way to solvers and preconditioners. \nRuntime and solvers - once everything has been set up, the simulation is ready to run, once runtime information such as time steps and solution saving intervals has been selected. The final step is to actually start the simulation.\nPost-processing - the final step is to enjoy all the pretty pictures!","category":"page"},{"location":"user_guide/0_introduction_and_workflow/","page":"Introduction","title":"Introduction","text":"The user guide is structured such that the information provided is grouped following the workflow illustrated above. For convenience the contents of the user guide are included below, with links to the relevant sections.","category":"page"},{"location":"user_guide/0_introduction_and_workflow/#Contents","page":"Introduction","title":"Contents","text":"","category":"section"},{"location":"user_guide/0_introduction_and_workflow/","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"user_guide/0_introduction_and_workflow/","page":"Introduction","title":"Introduction","text":"Pages = Main.USER_GUIDE_PAGES\nDepth = 2","category":"page"},{"location":"user_guide/3_numerical_setup/#Numerical-setup","page":"Numerical setup","title":"Numerical setup","text":"","category":"section"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"Available discretisation schemes, linear solvers and preconditioners","category":"page"},{"location":"user_guide/3_numerical_setup/#Discretisation-schemes","page":"Numerical setup","title":"Discretisation schemes","text":"","category":"section"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"Part of the methodology to solve the various model equations using the Finite Volume Method (FVM) is to discretise each equation term, essentially, this process linearises the partial differential equation so that it can be represented as a system of linear equations, which can be solved using linear algebra along with iterative solvers. This section presents the discretisation schemes currently available in XCALibre.jl.","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"Discretisation schemes in XCALibre.jl are organised under the abstract type AbstractScheme. As shown previously, a list of available schemes can be found using the subtypes function:","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"using XCALibre # hide\nusing AbstractTrees # hide\n# import Main.subtypes as subtypes # hide\n using InteractiveUtils # hide\nAbstractTrees.children(d::DataType) = Main.subtypes(d) # hide\nprint_tree(AbstractScheme) # hide","category":"page"},{"location":"user_guide/3_numerical_setup/#Schemes-available","page":"Numerical setup","title":"Schemes available","text":"","category":"section"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"","category":"page"},{"location":"user_guide/3_numerical_setup/#Time-schemes","page":"Numerical setup","title":"Time schemes","text":"","category":"section"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"Scheme Description\nSteadyState sets the time derivative to zero\nEuler First order implicit Euler scheme\nCrankNicolson Second order central scheme (not implemented yet)","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"","category":"page"},{"location":"user_guide/3_numerical_setup/#Laplacian-schemes","page":"Numerical setup","title":"Laplacian schemes","text":"","category":"section"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"Scheme Description\nLinear 2nd order Gauss gradient scheme with linear interpolation","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"","category":"page"},{"location":"user_guide/3_numerical_setup/#Divergence-schemes","page":"Numerical setup","title":"Divergence schemes","text":"","category":"section"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"Scheme Description\nLinear 2nd order central difference\nUpwind 1st order upwind scheme\nBoundedUpwind Bounded version of the Upwind scheme\nLUST 1st/2nd order mixed scheme (fixed at 75% Linear - 25% Upwind)","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"","category":"page"},{"location":"user_guide/3_numerical_setup/#Gradient-schemes","page":"Numerical setup","title":"Gradient schemes","text":"","category":"section"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"Scheme Description\nOrthogonal Green-Gauss uncorrected gradient scheme\nMidpoint Green-Gauss skew corrected scheme (2 iterations - hardcoded)","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"","category":"page"},{"location":"user_guide/3_numerical_setup/#Specifying-schemes","page":"Numerical setup","title":"Specifying schemes","text":"","category":"section"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"XCALibre.jl flow solvers offer considerable flexibility to users for defining discretisation schemes. However, this means that discretisation schemes must be specified for every term of every equation solved. The schemes must be provided as a NamedTuple where each keyword corresponds to the fields being solved, e.g. (U = ..., p = ..., k = ..., = ...). To facilitate this process, the set_schemes function is provided. Used without any inputs set_schemes uses the default values provided (see details below).","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"set_schemes","category":"page"},{"location":"user_guide/3_numerical_setup/#XCALibre.Discretise.set_schemes-user_guide-3_numerical_setup","page":"Numerical setup","title":"XCALibre.Discretise.set_schemes","text":"set_schemes(;\n # keyword arguments and their default values\n time=SteadyState,\n divergence=Linear, \n laplacian=Linear, \n gradient=Orthogonal) = begin\n \n # Returns NamedTuple definition for scheme \n (\n time=time,\n divergence=divergence,\n laplacian=laplacian,\n gradient=gradient\n )\nend\n\nThe set_schemes function is used at the top-level API to help users define discretisation schemes for every field solved. It offers default values, thus users can pick and choose which entry they wish to modify.\n\ninputs\n\ntime is used to set the time schemes (default is SteadyState)\ndivergence is used to set the divergence scheme (default is Linear) \nlaplacian is used to set the laplacian scheme (default is Linear)\ngradient is used to set the gradient scheme (default is Orthogonal)\n\n\n\n\n\n","category":"function"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"For example, below we set the schemes for the U and p fields. Notice that in the first case the schemes will take their default values (entry for p). In the case of U, we are only changing the setting for the divergence scheme to Upwind.","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"using XCALibre\nschemes = (\n p = set_schemes(), # no input provided (will use defaults)\n U = set_schemes(divergence = Upwind),\n)","category":"page"},{"location":"user_guide/3_numerical_setup/#Linear-solvers","page":"Numerical setup","title":"Linear solvers","text":"","category":"section"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"Linear solvers in XCALibre.jl are provided by Krylov.jl. The following solvers types are re-exported in XCALibre.jl","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"BicgstabSolver is a general purpose linear solver. Works well with non-symmetric matrices e.g. for U.\nCgSolver is particular strong with symmetric matrices e.g to solve the pressure equation.\nGmresSolver is a general solver. We have found it works best on the CPU backend.","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"For more information on these solvers you can review the excellent documentation provided by the Krylov.jl team. ","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"XCALibre.jl provides the set_solver convenience function for setting solvers. See details below. ","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"set_solver","category":"page"},{"location":"user_guide/3_numerical_setup/#XCALibre.Solve.set_solver-user_guide-3_numerical_setup","page":"Numerical setup","title":"XCALibre.Solve.set_solver","text":"set_solver( \n field::AbstractField;\n # keyword arguments and defaults\n solver::S, \n preconditioner::PT, \n convergence, \n relax,\n limit=(),\n itmax::Integer=100, \n atol=(eps(_get_float(field.mesh)))^0.9,\n rtol=_get_float(field.mesh)(1e-3)\n ) where {S,PT<:PreconditionerType} = begin\n\n # return NamedTuple\n TF = _get_float(field.mesh)\n (\n solver=solver, \n preconditioner=preconditioner, \n convergence=convergence |> TF, \n relax=relax |> TF, \n limit=limit,\n itmax=itmax, \n atol=atol |> TF, \n rtol=rtol |> TF\n )\nend\n\nThis function is used to provide solver settings that will be used internally in XCALibre.jl. It returns a NamedTuple with solver settings that are used internally by the flow solvers. \n\nInput arguments\n\nfield reference to the field to which the solver settings will apply (used to provide integer and float types required)\nsolver solver object from Krylov.jl and it could be one of BicgstabSolver, CgSolver, GmresSolver which are re-exported in XCALibre.jl\npreconditioner instance of preconditioner to be used e.g. Jacobi()\nconvergence sets the stopping criteria of this field\nrelax specifies the relaxation factor to be used e.g. set to 1 for no relaxation\nlimit used in some solvers to bound the solution within this limits e.g. (min, max). It defaults to ()\nitmax maximum number of iterations in a single solver pass (defaults to 100) \natol absolute tolerance for the solver (default to eps(FloatType)^0.9)\nrtol set relative tolerance for the solver (defaults to 1e-3)\n\n\n\n\n\n","category":"function"},{"location":"user_guide/3_numerical_setup/#Preconditioners","page":"Numerical setup","title":"Preconditioners","text":"","category":"section"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"XCALibre.jl offers a range of preconditioners which are subtypes of the abstrac type PreconditionerType, exploring its subtypes we can find a list of the currently available preconditioners: ","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"using XCALibre # hide\nusing AbstractTrees # hide\n# import Main.subtypes as subtypes # hide\n using InteractiveUtils # hide\nAbstractTrees.children(d::DataType) = Main.subtypes(d) # hide\nprint_tree(PreconditionerType) # hide","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"note: Note\nOnly the Jacobi and NormDiagonal preconditioners have GPU ready implementations. At present these have the most robust implementation and they can be used with both CPU and GPU backends. The other preconditioners can only be used on the CPU. Notice that on our tests the LDL preconditioner only works when paired with the GmresSolver on the CPU. Also notice that the implementation of the DILU preconditioner, although functions, is only experimental. Work on improving the offering of preconditioners is ongoing.","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"Below an example is provided in context. Here, we are setting solvers for both the velocity field U and the pressure field p and packing them into a NamedTuple \"solvers\". The Jacobi preconditioner is used in both solvers. Notice that preconditioners are specified with an instance of their type i.e. Jacobi(). Internally, the preconditioner instance is used for dispatch. This tupple will then be passed on to create the final Configuration object.","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"DocTestSetup = quote\n using XCALibre\n grids_dir = pkgdir(XCALibre, \"examples/0_GRIDS\")\n grid = \"backwardFacingStep_10mm.unv\"\n mesh_file = joinpath(grids_dir, grid)\n mesh = UNV2D_mesh(mesh_file, scale=0.001)\n mesh_dev = mesh # use this line to run on CPU\n nu = 1e-3\n model = Physics(\n time = Steady(),\n fluid = Fluid{Incompressible}(nu = nu),\n turbulence = RANS{Laminar}(),\n energy = Energy{Isothermal}(),\n domain = mesh_dev\n )\nend","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"using XCALibre\n\n# Note: this example assumes a Physics object named `model` already exists\n\nsolvers = (\n U = set_solver(\n model.momentum.U;\n solver = BicgstabSolver, # GmresSolver\n preconditioner = Jacobi(),\n convergence = 1e-7,\n relax = 0.7,\n rtol = 1e-4,\n atol = 1e-10\n ),\n p = set_solver(\n model.momentum.p;\n solver = CgSolver, # BicgstabSolver, GmresSolver\n preconditioner = Jacobi(),\n convergence = 1e-7,\n relax = 0.7,\n rtol = 1e-4,\n atol = 1e-10\n )\n)","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"DocTestSetup = nothing","category":"page"},{"location":"user_guide/2_physics_and_models/#Physics-and-models","page":"Physics and models","title":"Physics and models","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Information about setting up a Physics object and boundary conditions to represent the flow physics","category":"page"},{"location":"user_guide/2_physics_and_models/#Physics-model-definition","page":"Physics and models","title":"Physics model definition","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"The Physics object is part of the highest level API in XCALibre.jl. Physics objects are a means for users to set up the physics and models that are relevant to their particular CFD simulation. Internally, the Physics model created is passed to solvers and is used for dispatch (solvers, algorithms and models). Thus, it is important to ensure that the information provided to this object is correct and representative of the user's intentions. Physics models consist of a struct with the fields shown below. All fields must be provided to the solvers otherwise the construction of the object will fail.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"struct Physics{T,F,M,Tu,E,D,BI}\n time::T\n fluid::F\n momentum::M \n turbulence::Tu \n energy::E\n domain::D\n boundary_info::BI\nend ","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"For convenience, XCALibre.jl provides a more user-friendly constructor that will automatically take care of the construction of derived fields. This constructor uses keyword arguments and has the following signature (follow the link for more information)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Physics(; time, fluid, turbulence, energy, domain)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"At this point, it is worth reminding users that one of the benefits of working with Julia is its dynamic nature. This means that objects can be dynamically interrogated. For example:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"using XCALibre\nfieldnames(Physics)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"This will provide users with all the fields that make up the Physics object. This is a nice way to explore the makeup of any object in Julia (and by extension XCALibre.jl). The rest of this page will provide details of the physics models available in XCALibre.jl, including:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Time models\nFluid types\nTurbulence models\nEnergy models","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"warning: Warning\nThe mesh provided to the domain field must already be adapted to the required backend device. See Backend selection for detail. ","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"note: Note\nIn the next version of XCALibre.jl the field boundary_info will be likely removed outside of the Physics object in order to improve on the current performance (avoiding unnecessary memory movement between GPU backends and the host devices).","category":"page"},{"location":"user_guide/2_physics_and_models/#Time-models","page":"Physics and models","title":"Time models","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Earlier in this section, the dynamic nature of Julia was mentioned in the context of extracting fields for the Physics model used in XCALibre.jl. In the following sections this benefit of using Julia will be exploited further. XCALibre.jl takes advantage of Julia's rich type system and we define Abstract types to organise major functionality. For example, time models are subtypes of the abstract type AbstractTimeModel. Therefore, out-of-the-box we get for free a means to explore implemented features in XCALibre.jl. For example, to identify the time models implemented, we simply need to type the following in the REPL:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"using XCALibre\n# import Main.subtypes as subtypes # hide\nusing InteractiveUtils # Load from standard library\nMain.subtypes(AbstractTimeModel)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"From the output it can be seen that there are two time models in XCALibre.jl for Steady or Transient simulations. These are singleton types and contain (at present) no internal fields or data. They are largely used by XCALibre.jl to dispatch either steady or transient solvers. We are starting to get a picture of how the Physics object is constructed. For example, to specify a Steady simulation","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"The time model can be specified as Steady as follows:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Physics(\n time = Steady()\n ...\n)","category":"page"},{"location":"user_guide/2_physics_and_models/#Fluid-types","page":"Physics and models","title":"Fluid types","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Following from the idea of using Julia's dynamic features to explore the types available in XCALibre.jl, in this section we will explore the fluid types available. This time, we will use a helper package AbstractTrees (which can be installed in the usual way, by entering into package mode in the REPL and typing add AbstractTrees). In XCALibre.jl all fluid types are subtypes of AbstractFluid. The types available are shown in the example below:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"begin\n # Note: this code snippet will not be shown later for succinctness\n using XCALibre\n using InteractiveUtils # Load from standard library\n # using Pkg; Pkg.add(\"AbstractTrees\") # run to install AbstractTrees\n using AbstractTrees \n # import Main.subtypes as subtypes # hide\n AbstractTrees.children(d::DataType) = Main.subtypes(d)\n print_tree(AbstractFluid)\nend","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"From the subtype tree above, we can see that XCALibre.jl offers 2 major abstract fluid types, AbstractIncompressible and AbstractCompressible. There are 3 concrete fluid types:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Incompressible - for simulations were the fluid density does not change with pressure\nWeaklyCompressible - for simulation were the fluid density is allowed to change (no shockwaves)\nCompressible - for simulations were discontinuities may appear (not available for general use yet)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"To specify a given fluid type, the Fluid wrapper type is used as a general constructor which is specialised depending depending on the fluid type from the list above provided by the user. The constructors require the following inputs:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"For incompressible fluid flow","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Fluid{Incompressible}(; nu, rho=1.0) ","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"For compressible fluids (weak formulation)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Fluid{WeaklyCompressible}(; nu, cp, gamma, Pr)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"where the input variables represent the following:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"nu - kinematic viscosity\nrho - fluid density\ngamma - specific heat ratio\nPr - Prandlt number\ncp - specific heat at constant pressure","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"For example, an incompressible fluid can be specified as follows","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Physics(\n time = Steady(),\n fluid = Fluid{Incompressible}(nu=1e-5),\n ...\n)","category":"page"},{"location":"user_guide/2_physics_and_models/#Turbulence-models","page":"Physics and models","title":"Turbulence models","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Below is a representation of the AbstractTurbulenceModel inheritance tree. It shows turbulence models available. Turbulence models are defined using the RANS and LES constructors and passing a specific turbulence model type. As it will be illustrated in the flowing sections.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"using XCALibre # hide\nusing AbstractTrees # hide\n# import Main.subtypes as subtypes # hide\n using InteractiveUtils # hide\nAbstractTrees.children(d::DataType) = Main.subtypes(d) # hide\nprint_tree(AbstractTurbulenceModel) # hide","category":"page"},{"location":"user_guide/2_physics_and_models/#RANS-models-constructors","page":"Physics and models","title":"RANS models constructors","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Laminar model: no user input is required. This is a dummy model that does not contribute to the momentum equation.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"RANS{Laminar}() # only constructor needed","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"KOmega model: the standard 2 equation Wilcox model coefficients are passed by default. This model solves 2 transport equations for the turbulent kinetic energy and the specific dissipation rate, k and omega, respectively. Subsequently, k and omega are used to update the turbulent eddy viscosity, nut. These 3 fields must be provided with boundary conditions. ","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"RANS{KOmega}() # will set the default coefficient values shown below\nRANS{KOmega}(; β⁺=0.09, α1=0.52, β1=0.072, σk=0.5, σω=0.5) # set defaults\nRANS{KOmega}(β1=0.075) # user can choose to change a single coefficient","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"KOmegaLKE model: the user must provide a reference turbulence intensity (Tu) and a tuple of symbols specifying wall boundaries. This model uses 3 equations (k, kl, omega) to update the eddy viscosity (nut). These fields must be provided with boundary conditions.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"RANS{KOmegaLKE}(; Tu::Number, walls::Tuple) # no defaults defined\nRANS{KOmegaLKE}(Tu = 0.01, walls=(:cylinder,)) # user should provide information for Tu and walls","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"For example, a steady, incompressible simulation using the KOmega model can be specified as","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Physics(\n time = Steady(),\n fluid = Fluid{Incompressible}(nu=1e-5),\n turbulence = RANS{KOmega}(),\n ...\n)","category":"page"},{"location":"user_guide/2_physics_and_models/#LES-models","page":"Physics and models","title":"LES models","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Smagorinsky model: the standard model constant is passed by default. Boundary conditions for nut must be provided, generally zero gradient conditions work well. No special wall functions for nut in LES mode are available.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"LES{Smagorinsky}() # default constructor will use value below\nLES{Smagorinsky}(; C=0.15) # default value provided by default\nLES{Smagorinsky}(C=0.1) # user selected value","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"For example, an incompressible LES simulation with the Smagorinsky model can be specified as","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Physics(\n time = Transient(),\n fluid = Fluid{Incompressible}(nu=1e-5),\n turbulence = LES{Smagorinsky}(),\n)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"note: Note\nIn the specification above the time model was set as Transient since LES models are strictly time-resolving. A simulation might run when the Steady model is chosen, but the results would likely not be reliable. XCALibre.jl by design offers flexibility for users to customise their setup, the consequence is that it falls on users to define a combination of models that is appropriate. Likewise, in the example above an Isothermal energy model would have to be selected. See Energy models","category":"page"},{"location":"user_guide/2_physics_and_models/#Energy-models","page":"Physics and models","title":"Energy models","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Currently, XCALibre.jl offers two options to model the energy equation. A tree of the AbstractEnergyModel is shown below. The top-level constructor for energy models is the Energy type. Specific constructor signatures are also illustrated below.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"using XCALibre # hide\nusing AbstractTrees # hide\n# import Main.subtypes as subtypes # hide\n using InteractiveUtils # hide\nAbstractTrees.children(d::DataType) = Main.subtypes(d) # hide\nprint_tree(AbstractEnergyModel) # hide","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Isothermal model: assumes temperature effects are negligible. Used for incompressible solvers.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Energy{Isothermal}() # default constructor","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"SensibleEnthalpy model: uses the sensible enthalpy model for the energy equation. Required for the compressible solvers.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Energy{SensibleEnthalpy}(; Tref) # constructor definition. No default values given to Tref keyword\nEnergy{SensibleEnthalpy}(Tref=300) # Users must provide a referent temperature value","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"For example, a steady, compressible RANS simulation with the KOmegaLKE model can be specified as","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Physics(\n time = Steady(),\n fluid = Fluid{WeaklyCompressible}(nu=1e-5, cp=1005, gamma=1.4, Pr=0.7),\n turbulence = RANS{KOmegaLKE}(),\n energy = Energy{SensibleEnthalpy}(Tref=300),\n ...\n)","category":"page"},{"location":"user_guide/2_physics_and_models/#Domain-definition","page":"Physics and models","title":"Domain definition","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"The final step when defining a Physics model is to specify the domain on which the various models will be used. This is simply a reference to the mesh object.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Continuing from the previous example, a steady, compressible RANS simulation with the KOmegaLKE model can be specified as","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Physics(\n time = Steady(),\n fluid = Fluid{WeaklyCompressible}(nu=1e-5, cp=1005, gamma=1.4, Pr=0.7),\n turbulence = RANS{KOmegaLKE}(),\n energy = Energy{SensibleEnthalpy}(Tref=300),\n domain = mesh_dev\n)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"warning: Warning\nWhen passing the mesh objective to complete the definition of the Physics object, the mesh must be adapted to the target device where the computation will be performed. See Backend selection for more details.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Notice that the transfer to the target compute backend can also be done inline. For example,","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Physics(\n time = Steady(),\n fluid = Fluid{WeaklyCompressible}(nu=1e-5, cp=1005, gamma=1.4, Pr=0.7),\n turbulence = RANS{KOmegaLKE}(),\n energy = Energy{SensibleEnthalpy}(Tref=300),\n domain = adapt(CUDABackend(), mesh) # for Nvidia GPUs\n)","category":"page"},{"location":"user_guide/2_physics_and_models/#Boundary-conditions","page":"Physics and models","title":"Boundary conditions","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"The final step to completely capture the physics for the simulation is to define boundary conditions in order to find a concrete solution of the model equations being solved. XCALibre.jl offers a range of boundary conditions. As before, boundary conditions are specified by type and the are classified under the AbstractBoundary type and subdivided into 4 additional abstract types AbstractDirichlet, AbstractNeumann, AbstractPhysicalConstraint and AbstractWallFunction. The complete abstract tree is illustrated below.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"using XCALibre # hide\nusing AbstractTrees # hide\n# import Main.subtypes as subtypes # hide\n using InteractiveUtils # hide\nAbstractTrees.children(d::DataType) = Main.subtypes(d) # hide\nprint_tree(AbstractBoundary) # hide","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Philosophically, the four subtypes represent different physical types of boundary conditions:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"AbstractDirichlet boundary conditions are used to assign a concrete value to field at the boundary.\nAbstractNeumann boundaries are used to fix the field gradient at the boundary.\nAbstractPhysicalConstraint boundaries represent physical constraints imposed on the domain.\nAbstractWallFunction represent models for treating flow or turbulence quantities in wall regions.","category":"page"},{"location":"user_guide/2_physics_and_models/#AbstractDirichlet-conditions","page":"Physics and models","title":"AbstractDirichlet conditions","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Dirichlet(name, value)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"name is a symbol providing the boundary name\nvalue is a vector or scalar defining desired value at the boundary","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"FixedTemperature(name; T, model::EnergyModel<:AbstractEnergyModel)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"name is a symbol providing the boundary name\nT is a keyword argument to define the temperate value to be assigned at the boundary\nmodel is a keyword argument that expects an instance of the energy model to be used e.g. SensibleEnergy","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"DirichletFunction(name, func)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"name is a symbol providing the boundary name\nfunc is a function identifier. func is a user-defined function (but can also be a neural network) that returns a scalar or vector as a function of time and space.\nfunc must adhere to an internal contract. See XCALibre.Discretise.DirichletFunction for more details.","category":"page"},{"location":"user_guide/2_physics_and_models/#AbstractNeumann-conditions","page":"Physics and models","title":"AbstractNeumann conditions","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Neumann(name, value)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"name is a symbol providing the boundary name\nvalue is a scalar defining the gradient normal to the boundary","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"warning: Warning\nAt present the Neumann boundary should be treated as providing a zero gradient condition only. Internally, a zero gradient value is hard-coded. This behaviour will be extended in the near future to allow arbitrary gradients to be defined.","category":"page"},{"location":"user_guide/2_physics_and_models/#AbstractPhysicalConstraint-conditions","page":"Physics and models","title":"AbstractPhysicalConstraint conditions","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Wall boundary conditions can be used to provide a boundary with a wall constraint. This boundary type, at present, can only be used to define vectors. For scalar quantities in wall regions a Neumann (zero gradient) should be imposed.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Wall(name, value)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"name is a symbol providing the boundary name\nvalue is a vector defining wall velocity e.g. [0, 0, 0]","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"note: Note\nCurrently, the value provided at the wall is not used internally. This mean that this boundary condition currently acts as a no slip boundary. This will be extended to allow slip boundaries or moving walls.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Symmetry boundary condition can be used to assign a symmetry constraint to a given boundary patch in the domain. It can be used for both vector and scalar quantities.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Symmetry(name)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"name is a symbol providing the boundary name","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Periodic boundaries consist of a pair of boundary patches that behave as if they are physically connected. The periodic boundary essentially provides a mapping between these patches and helps in calculating the face values at the interface. The construction of periodic boundaries is different to other boundary conditions because the addressing between each face for the patch pair needs to be calculated and stored. Periodic boundary can be constructed as follows:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"periodic::Tuple = construct_periodic(mesh, backend, patch1::Symbol, patch2::Symbol)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"mesh is a reference to the mesh object\nbackend defines the expected backend e.g. CPU(), CUDABackend, etc.\npatch1 and patch2 symbols of the two patch pair we would like to flag as periodic","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"The output is a tuple containing two Periodic boundary types with information relevant to each boundary patch pair and it can be used directly to assign a periodic boundary for both patches (by splatting into the assignment macro e.g. periodic...)","category":"page"},{"location":"user_guide/2_physics_and_models/#AbstractWallFunction-conditions","page":"Physics and models","title":"AbstractWallFunction conditions","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"KWallFunction provides a turbulent kinetic energy boundary condition for high-Reynolds models.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"KWallFunction(name)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"name is a symbol providing the boundary name","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"OmegaWallFunction provides a value for the specific dissipation rate for both low- and high-Reynolds model.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"OmegaWallFunction(name)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"name is a symbol providing the boundary name","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"NutWallFunction provides a value for the eddy viscosity for high-Reynolds models","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"NutWallFunction(name)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"name is a symbol providing the boundary name","category":"page"},{"location":"user_guide/2_physics_and_models/#Assigning-conditions-(macro)","page":"Physics and models","title":"Assigning conditions (macro)","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"XCALibre.jl requires that a boundary condition is assigned to every single patch in the domain (as defined within the mesh object) for every field that is part of the solution. To facilitate this process, XCALibre.jl provides the @assign macro for convenience. The @assign macro has the following signature:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"@assign! model::Physics (\n , \n , \n ...\n )","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"For example, for a laminar incompressible simulation, only the momentum equation is being solved. Therefore, users need to provide conditions for every patch for the U and p fields in the momentum model:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"using XCALibre\n\ngrids_dir = pkgdir(XCALibre, \"examples/0_GRIDS\")\ngrid = \"backwardFacingStep_10mm.unv\"\nmesh_file = joinpath(grids_dir, grid)\nmesh = UNV2D_mesh(mesh_file, scale=0.001)\n\nbackend = CPU() # run on CPU\nhardware = set_hardware(backend=backend, workgroup=4)\nmesh_dev = mesh # dummy assignment \n\n# Flow conditions\nvelocity = [1.5, 0.0, 0.0]\nnu = 1e-3\nRe = velocity[1]*0.1/nu # Reynolds number\n\n# Physics models\nmodel = Physics(\n time = Steady(),\n fluid = Fluid{Incompressible}(nu = nu),\n turbulence = RANS{Laminar}(),\n energy = Energy{Isothermal}(),\n domain = mesh_dev\n )\n\n# Define boundary conditions\n@assign! model momentum U (\n Dirichlet(:inlet, velocity),\n Neumann(:outlet, 0.0),\n Wall(:wall, [0.0, 0.0, 0.0]),\n Wall(:top, [0.0, 0.0, 0.0]),\n)\n\n@assign! model momentum p (\n Neumann(:inlet, 0.0),\n Dirichlet(:outlet, 0.0),\n Neumann(:wall, 0.0), # scalar wall - set up as zero gradient\n Neumann(:top, 0.0) # scalar wall - set up as zero gradient\n)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"hint: Hint\nJulia is a dynamic language and objects can be interrogated on the fly (dynamically). Say you created a Physics model named mymodel, you can interrogate the contents of any of the fields in the Physics structure using the fieldnames function, e.g. fieldnames(mymodel.momentum), to find which fields need to be provided with boundary conditions. Any fields not ending in f should be set. ","category":"page"},{"location":"quick_start/#Quick-Start","page":"Quick Start","title":"Quick Start","text":"","category":"section"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"Read this section for information about how to install XCALibre.jl and an example showcasing the API","category":"page"},{"location":"quick_start/#Installation","page":"Quick Start","title":"Installation","text":"","category":"section"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"First, you need to download and install Julia on your system. Once you have a working installation of Julia, XCALibre.jl can be installed using the built-in package manager. ","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"XCALibre.jl is available directly from the the General Julia Registry. Thus, to install XCALibre.jl open a Julia REPL, press ] to enter the package manager. The REPL prompt icon will change from julia> (green) to pkg> (and change colour to blue) or (myenvironment) pkg> where myenvironment is the name of the currently active Julia environment. Once you have activated the package manager mode enter","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"pkg> add XCALibre","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"To install XCALibre.jl directly from Github enter the following command (for the latest release)","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"pkg> add XCALibre https://github.com/mberto79/XCALibre.jl.git","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"A specific branch can be installed by providing the branch name precided by a #, for example, to install the dev-0.3-main branch enter","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"pkg> add XCALibre https://github.com/mberto79/XCALibre.jl.git#dev-0.3-main","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"note: Note\nTo enable GPU acceleration you will also need to install the corresponding GPU package for your hardware. See CUDA.jl, AMD.jl, oneAPI.jl for more details. XCALibre.jl will automatically precompile and load the relevant backend specific functionality (using Julia extensions)","category":"page"},{"location":"quick_start/#Example","page":"Quick Start","title":"Example","text":"","category":"section"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"The example below illustrates the top-level API used in XCALibre.jl. It shows the key steps a user needs to follow to set up a simulation:","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"Pre-processing (steps 1 and 2)\nPhysics and models (steps 3 to 5)\nNumerical setup (steps 6 and 7)\nRuntime and solvers setup (steps 8 to 11)\nPost-processing (step 12)","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"Once you have installed Julia and XCALibre.jl, the example below can be run by copying the contents shown below and pasting them in a file. The file can be executed within vscode, the Julia REPL or from a system terminal. ","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"To run in vscode check the information for using Julia in vscode\nTo run in the Julia REPL, simply launch Julia and type include(\"name_of_your_file.jl\")\nTo run from a system terminal (bash or cmd, for example), simply type path/to/julia name_of_your_file.jl","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"In most cases, it is preferable to run simulations from within the Julia REPL because, in Julia, there is often a cost associated to the first run due to compilation time. By relaunching a simulation in the REPL, all previously compiled code will not be recompiled. This is particularly helpful in the prototyping stages. For long running simulations, the compilation time is normally negligible compared to the actual time needed to complete the simulation.","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"\n# Step 0. Load libraries\nusing XCALibre\n# using CUDA # Uncomment to run on NVIDIA GPUs\n# using AMDGPU # Uncomment to run on AMD GPUs\n\n\n# Step 1. Define mesh\ngrids_dir = pkgdir(XCALibre, \"examples/0_GRIDS\")\ngrid = \"backwardFacingStep_10mm.unv\"\nmesh_file = joinpath(grids_dir, grid)\n\nmesh = UNV2D_mesh(mesh_file, scale=0.001) # convert mesh\n\n# Step 2. Select backend and setup hardware\nbackend = CPU()\n# backend = CUDABackend() # ru non NVIDIA GPUs\n# backend = ROCBackend() # run on AMD GPUs\n\nhardware = set_hardware(backend=backend, workgroup=4)\n# hardware = set_hardware(backend=backend, workgroup=32) # use for GPU backends\n\nmesh_dev = mesh # use this line to run on CPU\n# mesh_dev = adapt(backend, mesh) # Uncomment to run on GPU \n\n# Step 3. Flow conditions\nvelocity = [1.5, 0.0, 0.0]\nnu = 1e-3\nRe = velocity[1]*0.1/nu\n\n# Step 4. Define physics\nmodel = Physics(\n time = Steady(),\n fluid = Fluid{Incompressible}(nu = nu),\n turbulence = RANS{Laminar}(),\n energy = Energy{Isothermal}(),\n domain = mesh_dev\n )\n\n# Step 5. Define boundary conditions\n@assign! model momentum U (\n Dirichlet(:inlet, velocity),\n Neumann(:outlet, 0.0),\n Wall(:wall, [0.0, 0.0, 0.0]),\n Wall(:top, [0.0, 0.0, 0.0]),\n)\n\n@assign! model momentum p (\n Neumann(:inlet, 0.0),\n Dirichlet(:outlet, 0.0),\n Neumann(:wall, 0.0),\n Neumann(:top, 0.0)\n)\n\n# Step 6. Choose discretisation schemes\nschemes = (\n U = set_schemes(divergence = Linear),\n p = set_schemes() # no input provided (will use defaults)\n)\n\n# Step 7. Set up linear solvers and preconditioners\nsolvers = (\n U = set_solver(\n model.momentum.U;\n solver = BicgstabSolver, # Options: GmresSolver\n preconditioner = Jacobi(), # Options: NormDiagonal(), DILU(), ILU0()\n convergence = 1e-7,\n relax = 0.7,\n rtol = 1e-4,\n atol = 1e-10\n ),\n p = set_solver(\n model.momentum.p;\n solver = CgSolver, # Options: CgSolver, BicgstabSolver, GmresSolver\n preconditioner = Jacobi(), # Options: NormDiagonal(), LDL() (with GmresSolver)\n convergence = 1e-7,\n relax = 0.7,\n rtol = 1e-4,\n atol = 1e-10\n )\n)\n\n# Step 8. Specify runtime requirements\nruntime = set_runtime(\n iterations=2000, time_step=1, write_interval=2000)\n\n# Step 9. Construct Configuration object\nconfig = Configuration(\n solvers=solvers, schemes=schemes, runtime=runtime, hardware=hardware)\n\n# Step 10. Initialise fields (initial guess)\ninitialise!(model.momentum.U, velocity)\ninitialise!(model.momentum.p, 0.0)\n\n# Step 11. Run simulation\nresiduals = run!(model, config);\n\n# Step 12. Post-process\npwd() # find active directory where the file \"iteration_002000.vtk\" was saved","category":"page"},{"location":"quick_start/#Output","page":"Quick Start","title":"Output","text":"","category":"section"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"If you chose to run the example above, XCALibre.jl would have written a simulation result file to your computer. The name of the file is iteration_002000.vtk. The file will be located in your current active directory (you can check this by running pwd()). This file can be open directly in ParaView for further post-processing. You can find out more about ParaView on their website. The image below is the output solution generated by XCALibre.jl to the example simulation above.","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"(Image: Simulation result visualisation in ParaView)","category":"page"},{"location":"examples/01_2d-isothermal-backward-facing-step/#Verification:-2D-incompressible-backward-facing-step","page":"Verification: 2D incompressible backward-facing step","title":"Verification: 2D incompressible backward-facing step","text":"","category":"section"},{"location":"examples/01_2d-isothermal-backward-facing-step/#Introduction","page":"Verification: 2D incompressible backward-facing step","title":"Introduction","text":"","category":"section"},{"location":"examples/01_2d-isothermal-backward-facing-step/","page":"Verification: 2D incompressible backward-facing step","title":"Verification: 2D incompressible backward-facing step","text":"","category":"page"},{"location":"examples/01_2d-isothermal-backward-facing-step/","page":"Verification: 2D incompressible backward-facing step","title":"Verification: 2D incompressible backward-facing step","text":"The correct implementation of the laminar solver in XCALibre.jl has been verified by quantitatively comparing results with those obtained with OpenFOAM. The simulation set up and mesh file used to run the simulation with XCALibre.jl are available in this repository.","category":"page"},{"location":"examples/01_2d-isothermal-backward-facing-step/#Simulation-setup","page":"Verification: 2D incompressible backward-facing step","title":"Simulation setup","text":"","category":"section"},{"location":"examples/01_2d-isothermal-backward-facing-step/","page":"Verification: 2D incompressible backward-facing step","title":"Verification: 2D incompressible backward-facing step","text":"","category":"page"},{"location":"examples/01_2d-isothermal-backward-facing-step/","page":"Verification: 2D incompressible backward-facing step","title":"Verification: 2D incompressible backward-facing step","text":"\nusing XCALibre\n# using CUDA # Uncomment to run on NVIDIA GPUs\n# using AMDGPU # Uncomment to run on AMD GPUs\n\ngrids_dir = pkgdir(XCALibre, \"examples/0_GRIDS\")\ngrid = \"backwardFacingStep_10mm.unv\"\nmesh_file = joinpath(grids_dir, grid)\n\nmesh = UNV2D_mesh(mesh_file, scale=0.001)\n\n# Select backend and setup hardware\nbackend = CPU()\n# backend = CUDABackend() # ru non NVIDIA GPUs\n# backend = ROCBackend() # run on AMD GPUs\n\nhardware = set_hardware(backend=backend, workgroup=4)\n# hardware = set_hardware(backend=backend, workgroup=32) # use for GPU backends\n\nmesh_dev = mesh # use this line to run on CPU\n# mesh_dev = adapt(backend, mesh) # Uncomment to run on GPU \n\nvelocity = [1.5, 0.0, 0.0]\nnu = 1e-3\nRe = velocity[1]*0.1/nu\n\nmodel = Physics(\n time = Steady(),\n fluid = Fluid{Incompressible}(nu = nu),\n turbulence = RANS{Laminar}(),\n energy = Energy{Isothermal}(),\n domain = mesh_dev\n )\n\n@assign! model momentum U (\n Dirichlet(:inlet, velocity),\n Neumann(:outlet, 0.0),\n Wall(:wall, [0.0, 0.0, 0.0]),\n Wall(:top, [0.0, 0.0, 0.0]),\n)\n\n@assign! model momentum p (\n Neumann(:inlet, 0.0),\n Dirichlet(:outlet, 0.0),\n Neumann(:wall, 0.0),\n Neumann(:top, 0.0)\n)\n\nschemes = (\n U = set_schemes(divergence = Linear),\n p = set_schemes() # no input provided (will use defaults)\n)\n\nsolvers = (\n U = set_solver(\n model.momentum.U;\n solver = BicgstabSolver, # Options: GmresSolver\n preconditioner = Jacobi(), # Options: NormDiagonal(), DILU(), ILU0()\n convergence = 1e-7,\n relax = 0.7,\n rtol = 1e-4,\n atol = 1e-10\n ),\n p = set_solver(\n model.momentum.p;\n solver = CgSolver, # Options: CgSolver, BicgstabSolver, GmresSolver\n preconditioner = Jacobi(), # Options: NormDiagonal(), LDL() (with GmresSolver)\n convergence = 1e-7,\n relax = 0.7,\n rtol = 1e-4,\n atol = 1e-10\n )\n)\n\nruntime = set_runtime(iterations=2000, time_step=1, write_interval=2000)\nruntime = set_runtime(iterations=1, time_step=1, write_interval=-1) # hide\n\nconfig = Configuration(\n solvers=solvers, schemes=schemes, runtime=runtime, hardware=hardware)\n\ninitialise!(model.momentum.U, velocity)\ninitialise!(model.momentum.p, 0.0)\n\nresiduals = run!(model, config);","category":"page"},{"location":"examples/01_2d-isothermal-backward-facing-step/#Results","page":"Verification: 2D incompressible backward-facing step","title":"Results","text":"","category":"section"},{"location":"examples/01_2d-isothermal-backward-facing-step/","page":"Verification: 2D incompressible backward-facing step","title":"Verification: 2D incompressible backward-facing step","text":"","category":"page"},{"location":"examples/01_2d-isothermal-backward-facing-step/#Domain-and-mesh","page":"Verification: 2D incompressible backward-facing step","title":"Domain and mesh","text":"","category":"section"},{"location":"examples/01_2d-isothermal-backward-facing-step/","page":"Verification: 2D incompressible backward-facing step","title":"Verification: 2D incompressible backward-facing step","text":"(Image: Simulation domain)","category":"page"},{"location":"examples/01_2d-isothermal-backward-facing-step/#OpenFoam-solution","page":"Verification: 2D incompressible backward-facing step","title":"OpenFoam solution","text":"","category":"section"},{"location":"examples/01_2d-isothermal-backward-facing-step/","page":"Verification: 2D incompressible backward-facing step","title":"Verification: 2D incompressible backward-facing step","text":"(Image: Simulation domain)","category":"page"},{"location":"examples/01_2d-isothermal-backward-facing-step/#XCALibre-solution","page":"Verification: 2D incompressible backward-facing step","title":"XCALibre solution","text":"","category":"section"},{"location":"examples/01_2d-isothermal-backward-facing-step/","page":"Verification: 2D incompressible backward-facing step","title":"Verification: 2D incompressible backward-facing step","text":"(Image: Simulation domain)","category":"page"},{"location":"examples/01_2d-isothermal-backward-facing-step/#Quantitative-comparision","page":"Verification: 2D incompressible backward-facing step","title":"Quantitative comparision","text":"","category":"section"},{"location":"examples/01_2d-isothermal-backward-facing-step/","page":"Verification: 2D incompressible backward-facing step","title":"Verification: 2D incompressible backward-facing step","text":"The figure below compares the results obtained with OpenFOAM and XCALibre.jl. The profiles are extracted along the y-direction at x = 0.5 m. (Image: Comparison with OpenFOAM)","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Validation:-2D-Constant-temperature-flat-plate","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Introduction","page":"Validation: 2D Constant temperature flat plate","title":"Introduction","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"A 2D constant temperature laminar flat plate case has been used to validate the weakly compressible solver. The case provides a constant temperature boundary condition along the wall of the domain. ","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"The Nusselt number values obtained from the simulation are compared against the theoretical local Nusselt number correlation for forced convection on constant temperature flat plate:","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"Nu_x = 0332 Re_x^12 Pr^13","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"The correlation is valid for Prandtl numbers greater than 0.6.","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Boundary-conditions","page":"Validation: 2D Constant temperature flat plate","title":"Boundary conditions","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Inlet","page":"Validation: 2D Constant temperature flat plate","title":"Inlet","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"Field Boundary condition\nU Dirichlet ([0.2, 0.0, 0.0] m/s)\np Neumann (Zero-gradient)\nT FixedTemperature (300.0 K)","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Wall","page":"Validation: 2D Constant temperature flat plate","title":"Wall","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"Field Boundary condition\nU No-slip wall\np Neumann (Zero-gradient)\nT FixedTemperature (310.0 K)","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Outlet","page":"Validation: 2D Constant temperature flat plate","title":"Outlet","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"Field Boundary condition\nU Neumann (Zero-gradient)\np Dirichlet (0.0 Pa)\nT Neumann (Zero-gradient)","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Top","page":"Validation: 2D Constant temperature flat plate","title":"Top","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"Field Boundary condition\nU Neumann (Zero-gradient)\np Neumann (Zero-gradient)\nT Neumann (Zero-gradient)","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Fluid-Properties","page":"Validation: 2D Constant temperature flat plate","title":"Fluid Properties","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"Property value\nnu 0.0001\nPr 0.71\nc_p 1005.0\ngamma 1.4","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Mesh","page":"Validation: 2D Constant temperature flat plate","title":"Mesh","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"The mesh is shown in the figure below. The plate is represented by the \"wall\" boundary. The flow moves from left to right (\"inlet\" to \"outlet\" boundaries). The x-axis is aligned with the wall boundary and the y-axis is position in the direction perpendicular to the wall.","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"(Image: Figure 1)","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"The streamwise cell length is 2mm with a total domain length of 1m. The near-wall cell height is 0.049mm with a domain height of 0.2m.","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Case-file","page":"Validation: 2D Constant temperature flat plate","title":"Case file","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"using XCALibre\n\ngrids_dir = pkgdir(XCALibre, \"examples/0_GRIDS\")\ngrid = \"flatplate_2D_laminar.unv\"\nmesh_file = joinpath(grids_dir, grid)\n\nmesh = UNV2D_mesh(mesh_file, scale=0.001)\n\nvelocity = [0.2, 0.0, 0.0]\nnu = 1e-4\nRe = velocity[1]*1/nu\ncp = 1005.0\ngamma = 1.4\nPr = 0.7\n\nmodel = Physics(\n time = Steady(),\n fluid = Fluid{WeaklyCompressible}(\n nu = nu,\n cp = cp,\n gamma = gamma,\n Pr = Pr\n ),\n turbulence = RANS{Laminar}(),\n energy = Energy{SensibleEnthalpy}(Tref = 288.15),\n domain = mesh # mesh_dev # use mesh_dev for GPU backend\n )\n\n@assign! model momentum U (\n Dirichlet(:inlet, velocity),\n Neumann(:outlet, 0.0),\n Wall(:wall, [0.0, 0.0, 0.0]),\n Symmetry(:top, 0.0)\n)\n\n @assign! model momentum p (\n Neumann(:inlet, 0.0),\n Dirichlet(:outlet, 100000.0),\n Neumann(:wall, 0.0),\n Neumann(:top, 0.0)\n)\n\n@assign! model energy h (\n FixedTemperature(:inlet, T=300.0, model=model.energy),\n Neumann(:outlet, 0.0),\n FixedTemperature(:wall, T=310.0, model=model.energy),\n Neumann(:top, 0.0)\n)\n\nschemes = (\n U = set_schemes(divergence=Linear),\n p = set_schemes(divergence=Linear),\n h = set_schemes(divergence=Linear)\n)\n\nsolvers = (\n U = set_solver(\n model.momentum.U;\n solver = BicgstabSolver,\n preconditioner = Jacobi(),\n convergence = 1e-7,\n relax = 0.7,\n ),\n p = set_solver(\n model.momentum.p;\n solver = CgSolver,\n preconditioner = Jacobi(),\n convergence = 1e-7,\n relax = 0.3,\n ),\n h = set_solver(\n model.energy.h;\n solver = BicgstabSolver,\n preconditioner = Jacobi(),\n convergence = 1e-7,\n relax = 0.7,\n rtol = 1e-2,\n atol = 1e-4\n )\n)\n\nruntime = set_runtime(iterations=1000, write_interval=1000, time_step=1)\nruntime = set_runtime(iterations=1, write_interval=-1, time_step=1) # hide\n\nhardware = set_hardware(backend=CPU(), workgroup=4)\n\nconfig = Configuration(\n solvers=solvers, schemes=schemes, runtime=runtime, hardware=hardware)\n\nGC.gc()\n\ninitialise!(model.momentum.U, velocity)\ninitialise!(model.momentum.p, 100000.0)\ninitialise!(model.energy.T, 300.0)\n\nresiduals = run!(model, config)","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Results","page":"Validation: 2D Constant temperature flat plate","title":"Results","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"The results of the model are compared to the theoretical correlation in the figure below:","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"(Image: Nusselt number distribution results.)","category":"page"},{"location":"contributor_guide/#Contributor-Guide","page":"Contributor Guide","title":"Contributor Guide","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"Guidelines and practical information for contributing to XCALibre.jl","category":"page"},{"location":"contributor_guide/#Introduction","page":"Contributor Guide","title":"Introduction","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"In time, our ambition is to document the internal API completely, however, this will take some time and it is an ongoing process. Since XCALibre.jl uses a modular approach and the current functionality covers a good portion of the CFD stack, those interested in working with the internal API should be able to work from existing implementations. In this page we provide key information for those users who want to customise, refine, improve, or extend XCALibre.jl.","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"From its humble beginning as a 1D diffusion example code to explore the features of the Julia programming language (and speed claims which turned out to be true 😄), XCALibre.jl was meant to be shared and used to help students understand the Finite Volume Method and as an entry point to explore the implementation details underpinning CFD. As the code base has grown, this original purpose remains. However, XCALibre.jl is now a more complete CFD software stack which can be used by both researchers and students to test out new ideas, even on complex geometry with acceptable performance. XCALibre.jl will hopefully continue to grow and offer more functionality as it has been the case since work on XCALibre.jl started. In the sharing spirit of open-source software we also welcome code contributions, and we hope to make this process as simple as possible. However, we ask contributors to follow a few guidelines to ensure that we grow XCALibre.jl in a sustainable and maintainable manner.","category":"page"},{"location":"contributor_guide/#Some-guidelines","page":"Contributor Guide","title":"Some guidelines","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"To help use keep the codebase consistent and allow us to merge future Pull Requests (PRs) more easily, we kindly request that contributors adhere to some basic guidelines. We are trying to strike a balance between consistency and ease of contribution by aiming not to be overly demanding on contributors. A minimum set of guidelines is provided below (subject to review as the codebase evolves), in no particular order:","category":"page"},{"location":"contributor_guide/#Code-style","page":"Contributor Guide","title":"Code style","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"Follow the style guide recommended in the official Julia documentation\nUse camel case format for custom types e.g. MyType\nWe prefer easy-to-read function names e.g. use calculate_flux over calf or similar. All in lower case and words separated with an underscore\nFor internal variables feel free to use Unicode symbols, or camel case identifiers. However, please refrain from doing this for any top-level or user-facing API variables.\nAlthough Julia allows some impressive one-liners, please avoid. These can be hard to reason sometimes, aim to strike a balance between succinctness and clarity. ","category":"page"},{"location":"contributor_guide/#Code-contribution","page":"Contributor Guide","title":"Code contribution","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"Please open a PR for any code contributions against our main branch if your are contributing top level functionality that builds on existing code e.g. a new turbulence model or a new boundary condition (these contributions will typically be included inside one of the existing sub modules)\nFor contributions that may require code reorganisation please do get in touch to ensure this aligns with any planned changes (open an issue). PRs will likely be requested against the current dev branch\nIdeally, all contributions will also include basic documentation and tests.","category":"page"},{"location":"contributor_guide/#Help-wanted","page":"Contributor Guide","title":"Help wanted","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"If you have specific expertise in MPI or Multi-GPU implementation and wish to get involved please get in touch.","category":"page"},{"location":"contributor_guide/#Module-organisation","page":"Contributor Guide","title":"Module organisation","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"Module Description\nXCALibre.Mesh This module defines all types required to construct the mesh object used by the flow solvers. Two main mesh types are used Mesh2 and Mesh3 used for 2D and 3D simulations, respectively. Some access functions are also included in this module.\nXCALibre.Fields This module defines the fields used to hold and represent the flow variable. Scalar, vector and tensor fields are defined e.g. ScalarField, etc. Information is stored at cell centres. These fields also have face variant where information is stored at face centres e.g. FaceVectorField. These fields are generally used to store fluxes. A limited set of field operations are also defined e.g. getfield to allow indexing field object directly.\nXCALibre.ModelFramework This module provides the framework used to define scalar and vector model equations whilst storing information about the operators used. The data structure also defines sparse matrices used to store discretisation information.\nXCALibre.Discretise This module defines the various operators needed to represent each terms in a model equation and the main discretisation loop that linearises each term according to the schemes available. Boundary conditions are also implemented in this module.\nXCALibre.Solve This module includes all functions and logic needed to solve the linear system of equations that follows the equation discretisation. The internal API to solve these systems of equations is included in this module.\nXCALibre.Calculate Implementation of functions use to carry out calculations essential to the implementation of flow solvers is included in this module. This includes interpolation of variables from cell centroid to cell faces, gradient calculation, surface normals, etc.\nXCALibre.ModelPhysics This module includes the implementations of all the physical models i.e. fluid, turbulence and energy models.\nXCALibre.Simulate This model contains information needed to set up a simulation, including the Configuration type used by all flow solvers.\nXCALibre.Solvers Implementations of the SIMPLE and PISO flow solvers from steady and unsteady solutions, including their compressible variant.\nXCALibre.Postprocess A limited set of functions for postprocessing are implemented in this module.\nXCALibre.VTK Functions to write 2D (.vtk) and 3D (.vtu) simulation results compatible with ParaView for postprocessing are implemented in this module.\nXCALibre.FoamMesh Stand alone module to parse, process (geometry calculation) and import OpenFOAM mesh files into XCALibre.jl\nXCALibre.UNV3 Stand alone module to parse, process (geometry calculation) and import UNV (3D) mesh files into XCALibre.jl\nXCALibre.UNV2 Stand alone module to parse, process (geometry calculation) and import UNV (2D) mesh files into XCALibre.jl","category":"page"},{"location":"contributor_guide/#Key-types-and-structures","page":"Contributor Guide","title":"Key types and structures","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"","category":"page"},{"location":"contributor_guide/#Mesh-type-and-format","page":"Contributor Guide","title":"Mesh type and format","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"The definitions of the data structures used to define Mesh3 objects is given below. Note that for succinctness only 3D structures are shown since all the 2D structures are identical. The type is only used for dispatching solvers to operate in 2D or 3D. ","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"Mesh3\nNode\nFace3D\nCell\nBoundary","category":"page"},{"location":"contributor_guide/#XCALibre.Mesh.Mesh3-contributor_guide","page":"Contributor Guide","title":"XCALibre.Mesh.Mesh3","text":"struct Mesh3{VC, VI, VF<:AbstractArray{<:Face3D}, VB, VN, SV3, UR} <: AbstractMesh\n cells::VC # vector of cells\n cell_nodes::VI # vector of indices to access cell nodes\n cell_faces::VI # vector of indices to access cell faces\n cell_neighbours::VI # vector of indices to access cell neighbours\n cell_nsign::VI # vector of indices to with face normal correction (1 or -1 )\n faces::VF # vector of faces\n face_nodes::VI # vector of indices to access face nodes\n boundaries::VB # vector of boundaries\n nodes::VN # vector of nodes\n node_cells::VI # vector of indices to access node cells\n get_float::SV3 # store mesh float type\n get_int::UR # store mesh integer type\n boundary_cellsID::VI # vector of indices of boundary cell IDs\nend\n\n\n\n\n\n","category":"type"},{"location":"contributor_guide/#XCALibre.Mesh.Node-contributor_guide","page":"Contributor Guide","title":"XCALibre.Mesh.Node","text":"struct Node{SV3<:SVector{3,<:AbstractFloat}, UR<:UnitRange{<:Integer}}\n coords::SV3 # node coordinates\n cells_range::UR # range to access neighbour cells in Mesh3.node_cells\nend\n\n\n\n\n\n","category":"type"},{"location":"contributor_guide/#XCALibre.Mesh.Face3D-contributor_guide","page":"Contributor Guide","title":"XCALibre.Mesh.Face3D","text":"struct Face3D{\n F<:AbstractFloat, \n SV2<:SVector{2,<:Integer},\n SV3<:SVector{3,F}, \n UR<:UnitRange{<:Integer}\n }\n \n nodes_range::UR # range to access face nodes in Mesh3.face_nodes\n ownerCells::SV2 # IDs of face owner cells (always 2)\n centre::SV3 # coordinates of face centre\n normal::SV3 # face normal unit vector\n e::SV3 # unit vector in the direction between owner cells\n area::F # face area\n delta::F # distance between owner cells centres\n weight::F # linear interpolation weight\nend\n\n\n\n\n\n","category":"type"},{"location":"contributor_guide/#XCALibre.Mesh.Cell-contributor_guide","page":"Contributor Guide","title":"XCALibre.Mesh.Cell","text":"struct Cell{F<:AbstractFloat, SV3<:SVector{3,F},UR<:UnitRange{<:Integer}}\n centre::SV3 # coordinate of cell centroid\n volume::F # cell volume\n nodes_range::UR # range to access cell nodes in Mesh3.cell_nodes\n faces_range::UR # range to access cell faces info (faces, neighbours cells, etc.)\nend\n\n\n\n\n\n","category":"type"},{"location":"contributor_guide/#XCALibre.Mesh.Boundary-contributor_guide","page":"Contributor Guide","title":"XCALibre.Mesh.Boundary","text":"struct Boundary{S<:Symbol, UR<:UnitRange{<:Integer}} name::S # Boundary patch name IDsrange::UR # range to access boundary info (faces and boundarycellsID) end\n\n\n\n\n\n","category":"type"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"To fully characterise how mesh information is represented in XCALibre.jl, it is important to highlight the following \"contracts\" that are exploited throughout:","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"Node, face and cell IDs correspond to the index where they are stored in their corresponding vector in the Mesh3 structure e.g. Mesh3.Faces[10] would return information for the face whose ID is 10. These vectors are 1-indexed as standard in Julia.\nFace normals at boundary faces is always pointing outside the domain e.g. they point in the direction expected in the FVM\nFace normals for internal faces is always pointing in the direction from the ownerCell with the smallest ID to the largest. Since the discretisation loop is cell based, for the cell with the highest ID the direction must be reversed. This information is tracked in Mesh3.nsign which stores 1 if the face normal is correctly aligned or -1 if the normal needs to be reversed.\nBoundary faces (e.g. patches) are stored consecutively in Mesh3.Faces starting at the beginning of the array followed by all the internal faces.\nBoundary faces are those connected only to 1 Cell, thus, for these faces the entry Face3D.ownerCells is a 2-element vector with a repeated index e.g. [3, 3]\nBoundary cells only store information for internal faces. This improves performance for the main discretisation loop (cell based) since it can always been assumed that none of the faces will be a boundary face, which are dealt with in a separate loop.","category":"page"},{"location":"contributor_guide/#Field-types","page":"Contributor Guide","title":"Field types","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"After the Mesh2 and Mesh3 objects, the most fundamental data structure in XCALibre.jl are fields used to represent the flow variables. In the current implementation, the prime field is the ScalarField for storing information at cell centres, and the corresponding FaceScalarField to store information at cell faces (normally fluxes). Internally, both are identical, therefore, the internal structure of the \"Face\" variants will not be discussed. ScalarFields have the following definition:","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"ScalarField","category":"page"},{"location":"contributor_guide/#XCALibre.Fields.ScalarField-contributor_guide","page":"Contributor Guide","title":"XCALibre.Fields.ScalarField","text":"struct ScalarField{VF,M<:AbstractMesh,BC} <: AbstractScalarField\n values::VF # scalar values at cell centre\n mesh::M # reference to mesh\n BCs::BC # store user-provided boundary conditions\nend\n\n\n\n\n\n","category":"type"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"Vector and tensors are represented internally by their individual components, as an illustration the VectorField type is shown below. Notice that each component of both vector and tensor fields are themselves represented by the same ScalarField type shown above. This has some implementation benefits, i.e. reducing duplication and allowing for rapid development. However, the performance of other means of storing these fields is being investigated. Thus, these internals may change if we identify performance gains.","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"VectorField","category":"page"},{"location":"contributor_guide/#XCALibre.Fields.VectorField-contributor_guide","page":"Contributor Guide","title":"XCALibre.Fields.VectorField","text":"struct VectorField{S1<:ScalarField,S2,S3,M<:AbstractMesh,BC} <: AbstractVectorField\n x::S1 # x-component is itself a `ScalarField`\n y::S2 # y-component is itself a `ScalarField`\n z::S3 # z-component is itself a `ScalarField`\n mesh::M\n BCs::BC\nend\n\n\n\n\n\n","category":"type"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"All fields behave (mostly) like regular arrays and can be indexed using the standard Julia syntax e.g. say U is a VectorField, then U[3] would return the vector stored in cell with ID = 3 (as a SVector{3} for improved performance).","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"note: Note\nThe implementation of broadcasting operations has been put on hold until a more thorough investigation of alternative data structures for vector and tensor fields has been completed. This is ongoing work. ","category":"page"},{"location":"contributor_guide/#Boundary-conditions","page":"Contributor Guide","title":"Boundary conditions","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"To implement a new boundary condition the following elements are required (see source code for Dirichlet, for example):","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"type definition: a structure containing the fields :ID and :value\nfixedValue function: used to check that user provided information is suitable for this boundary being implemented\nImplementation of the boundary face value: functor defining the boundary condition implementation, facilitated by a macro (see details below)\nScalar and vector face value interpolation: kernels to specify how to transfer cell information to the boundary. ","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"Developers and contributors are encouraged to explore the source code for examples on existing implementations of boundary conditions. To ease their implementation the XCALibre.Discretise.@define_boundary is provided.","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"XCALibre.Discretise.@define_boundary","category":"page"},{"location":"contributor_guide/#XCALibre.Discretise.@define_boundary-contributor_guide","page":"Contributor Guide","title":"XCALibre.Discretise.@define_boundary","text":"macro define_boundary(boundary, operator, definition)\n quote\n @inline (bc::$boundary)(\n term::Operator{F,P,I,$operator}, cellID, zcellID, cell, face, fID, i, component, time\n ) where {F,P,I} = $definition\n end |> esc\nend\n\nMacro to reduce boilerplate code when defining boundary conditions (implemented as functors) and provides access to key fields needed in the implementation of boundary conditions, such as the boundary cell and face objects (more details below)\n\nInput arguments\n\nboundary specifies the boundary type being defined\noperator specifies the operator to which the condition applies e.g. Laplacian\ndefinition provides the implementation details\n\nAvailable fields\n\nterm reference to operator on which the boundary applies (gives access to the field and mesh) \ncellID ID of the corresponding boundary cell\nzcellID sparse matrix linear index for the cell\ncell gives access to boundary cell object and corresponding information\nface gives access to boundary face object and corresponding information\nfID ID of the boundary face (to index Mesh2.faces vector)\ni local index of the boundary faces within a kernel or loop\ncomponent for vectors this specifies the components being evaluated (access as component.value). For scalars component = nothing\ntime provides the current simulation time. This only applies to time dependent boundary implementation defined as functions or neural networks.\n\nExample\n\nBelow the use of this macro is illustrated for the implementation of a Dirichlet boundary condition acting on the Laplacian using the Linear scheme:\n\n@define_boundary Dirichlet Laplacian{Linear} begin\n J = term.flux[fID] # extract operator flux\n (; area, delta) = face # extract boundary face information\n flux = J*area/delta # calculate the face flux\n ap = term.sign*(-flux) # diagonal (cell) matrix coefficient\n ap, ap*bc.value # return `ap` and `an`\nend\n\nWhen called, this functor will return two values ap and an, where ap is the cell contribution for approximating the boundary face value, and an is the explicit part of the face value approximation i.e. ap contributes to the diagonal of the sparse matrix (left-hand side) and an is the explicit contribution assigned to the solution vector b on the right-hand of the linear system of equations Ax = b\n\n\n\n\n\n","category":"macro"},{"location":"contributor_guide/#Implementing-new-models","page":"Contributor Guide","title":"Implementing new models","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"The internal API for models is still somewhat experimental, thus, it is more instructive to explore the source code. Although not fully finalised, the implementation is reasonably straight forward to follow thanks to the abstractions that have been adopted, some of which are described above, as well as the use of descriptive names for internal functions. If you need help on any aspect of the internals, for now, it is recommended to contact us by opening an issue.","category":"page"},{"location":"user_guide/5_postprocessing/#Post-processing","page":"Post-processing","title":"Post-processing","text":"","category":"section"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"Information about postprocessing XCALibre.jl results","category":"page"},{"location":"user_guide/5_postprocessing/#ParaView","page":"Post-processing","title":"ParaView","text":"","category":"section"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"","category":"page"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"All solvers in XCALibre.jl will write simulation results in formats that can be loaded directly in ParaView, which is the leading open-source project for scientific visualisation and postprocessing. More information about how to use ParaView can be found in the resources page on their website.","category":"page"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"XCALibre.jl uses two different VTK formats depending on the type of flow solver used. For 2D simulations, the results are written to file using the .vtk file format. 3D simulations are written using the unstructured VTK file format, .vtu. ","category":"page"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"note: Note\nA limitation of the current VTK writers in XCALibre.jl is that boundary information is stored along with internal mesh cell information, and result are stored at cell centres only. Thus, care must be taken when visualising results at boundary faces. In future releases a separation of boundary and internal mesh results is planned. ","category":"page"},{"location":"user_guide/5_postprocessing/#Available-functions","page":"Post-processing","title":"Available functions","text":"","category":"section"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"","category":"page"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"Although ParaView offers considerable flexibility for postprocessing results, users may also wish to carry out more advanced or different analyses on their CFD results. At present XCALibre.jl offers a limited set of pre-defined postprocessing functions, however, defining new custom postprocessing functions is reasonably straight-forward since these can be written in pure Julia. In this section, examples of postprocessing functions will be provided as an illustration. ","category":"page"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"note: Note\nAt present all postprocessing functions available in XCALibre.jl will only execute on CPUs and should be considered experimental. Once we settle on a \"sensible\" (maintainable and extensible) API, we plan to offer a larger selection of postprocessing tools which are likely to include options for runtime postprocessing.","category":"page"},{"location":"user_guide/5_postprocessing/#Example:-Calculate-boundary-average","page":"Post-processing","title":"Example: Calculate boundary average","text":"","category":"section"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"In this example, a function is shown that can be used to calculate the average on a user-provided boundary. ","category":"page"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"boundary_average","category":"page"},{"location":"user_guide/5_postprocessing/#XCALibre.Postprocess.boundary_average-user_guide-5_postprocessing","page":"Post-processing","title":"XCALibre.Postprocess.boundary_average","text":"function boundary_average(patch::Symbol, field, config; time=0)\n # Extract mesh object\n mesh = field.mesh\n\n # Determine ID (index) of the boundary patch \n ID = boundary_index(mesh.boundaries, patch)\n @info \"calculating average on patch: $patch at index $ID\"\n boundary = mesh.boundaries[ID]\n (; IDs_range) = boundary\n\n # Create face field of same type provided by user (scalar or vector)\n sum = nothing\n if typeof(field) <: VectorField \n faceField = FaceVectorField(mesh)\n sum = zeros(_get_float(mesh), 3) # create zero vector\n else\n faceField = FaceScalarField(mesh)\n sum = zero(_get_float(mesh)) # create zero\n end\n\n # Interpolate CFD results to boundary\n interpolate!(faceField, field, config)\n correct_boundaries!(faceField, field, field.BCs, time, config)\n\n # Calculate the average\n for fID ∈ IDs_range\n sum += faceField[fID]\n end\n ave = sum/length(IDs_range)\n\n # return average\n return ave\nend\n\n\n\n\n\n","category":"function"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"To calculate pressure and viscous forces, the following functions are available:","category":"page"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"pressure_force\nviscous_force","category":"page"},{"location":"user_guide/5_postprocessing/#XCALibre.Postprocess.pressure_force-user_guide-5_postprocessing","page":"Post-processing","title":"XCALibre.Postprocess.pressure_force","text":"pressure_force(patch::Symbol, p::ScalarField, rho)\n\nFunction to calculate the pressure force acting on a given patch/boundary.\n\nInput arguments\n\npatch::Symbol name of the boundary of interest (as a Symbol)\np::ScalarField pressure field\nrho density. Set to 1 for incompressible solvers\n\n\n\n\n\n","category":"function"},{"location":"user_guide/5_postprocessing/#XCALibre.Postprocess.viscous_force-user_guide-5_postprocessing","page":"Post-processing","title":"XCALibre.Postprocess.viscous_force","text":"viscous_force(patch::Symbol, U::VectorField, rho, ν, νt)\n\nFunction to calculate the pressure force acting on a given patch/boundary.\n\nInput arguments\n\npatch::Symbol name of the boundary of interest (as a Symbol)\nU::VectorField pressure field\nrho density. Set to 1 for incompressible solvers\nν laminar viscosity of the fluid\nνt eddy viscosity from turbulence models. Pass ConstantScalar(0) for laminar flows\n\n\n\n\n\n","category":"function"},{"location":"reference/#Reference","page":"Reference","title":"Reference","text":"","category":"section"},{"location":"reference/","page":"Reference","title":"Reference","text":"Modules = [\n XCALibre, \n XCALibre.Mesh, \n XCALibre.UNV2, \n XCALibre.UNV3, \n XCALibre.FoamMesh, \n XCALibre.Fields,\n XCALibre.ModelFramework,\n XCALibre.Discretise, \n XCALibre.Solve,\n XCALibre.Calculate, \n XCALibre.ModelPhysics,\n XCALibre.Simulate,\n XCALibre.Solvers,\n XCALibre.Postprocess\n ]","category":"page"},{"location":"reference/#XCALibre.Mesh.Boundary","page":"Reference","title":"XCALibre.Mesh.Boundary","text":"struct Boundary{S<:Symbol, UR<:UnitRange{<:Integer}} name::S # Boundary patch name IDsrange::UR # range to access boundary info (faces and boundarycellsID) end\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Mesh.Cell","page":"Reference","title":"XCALibre.Mesh.Cell","text":"struct Cell{F<:AbstractFloat, SV3<:SVector{3,F},UR<:UnitRange{<:Integer}}\n centre::SV3 # coordinate of cell centroid\n volume::F # cell volume\n nodes_range::UR # range to access cell nodes in Mesh3.cell_nodes\n faces_range::UR # range to access cell faces info (faces, neighbours cells, etc.)\nend\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Mesh.Face3D","page":"Reference","title":"XCALibre.Mesh.Face3D","text":"struct Face3D{\n F<:AbstractFloat, \n SV2<:SVector{2,<:Integer},\n SV3<:SVector{3,F}, \n UR<:UnitRange{<:Integer}\n }\n \n nodes_range::UR # range to access face nodes in Mesh3.face_nodes\n ownerCells::SV2 # IDs of face owner cells (always 2)\n centre::SV3 # coordinates of face centre\n normal::SV3 # face normal unit vector\n e::SV3 # unit vector in the direction between owner cells\n area::F # face area\n delta::F # distance between owner cells centres\n weight::F # linear interpolation weight\nend\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Mesh.Mesh3","page":"Reference","title":"XCALibre.Mesh.Mesh3","text":"struct Mesh3{VC, VI, VF<:AbstractArray{<:Face3D}, VB, VN, SV3, UR} <: AbstractMesh\n cells::VC # vector of cells\n cell_nodes::VI # vector of indices to access cell nodes\n cell_faces::VI # vector of indices to access cell faces\n cell_neighbours::VI # vector of indices to access cell neighbours\n cell_nsign::VI # vector of indices to with face normal correction (1 or -1 )\n faces::VF # vector of faces\n face_nodes::VI # vector of indices to access face nodes\n boundaries::VB # vector of boundaries\n nodes::VN # vector of nodes\n node_cells::VI # vector of indices to access node cells\n get_float::SV3 # store mesh float type\n get_int::UR # store mesh integer type\n boundary_cellsID::VI # vector of indices of boundary cell IDs\nend\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Mesh.Node","page":"Reference","title":"XCALibre.Mesh.Node","text":"struct Node{SV3<:SVector{3,<:AbstractFloat}, UR<:UnitRange{<:Integer}}\n coords::SV3 # node coordinates\n cells_range::UR # range to access neighbour cells in Mesh3.node_cells\nend\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.UNV2.UNV2D_mesh-Tuple{Any}","page":"Reference","title":"XCALibre.UNV2.UNV2D_mesh","text":"UNV2D_mesh(meshFile; scale=1, integer_type=Int64, float_type=Float64)\n\nRead and convert 2D UNV mesh file into XCALibre.jl\n\nInput\n\nmeshFile – path to mesh file.\n\nOptional arguments\n\nscale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling\ninteger_type - select interger type to use in the mesh (Int32 may be useful on GPU runs) \nfloat_type - select interger type to use in the mesh (Float32 may be useful on GPU runs) \n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.UNV3.UNV3D_mesh-Tuple{Any}","page":"Reference","title":"XCALibre.UNV3.UNV3D_mesh","text":"UNV3D_mesh(unv_mesh; scale=1, integer_type=Int64, float_type=Float64)\n\nRead and convert 3D UNV mesh file into XCALibre.jl. Note that a limitation of the .unv mesh format is that it only supports the following 3D cells:\n\nTetahedrals\nPrisms\nHexahedrals\n\nInput\n\nunv_mesh – path to mesh file.\n\nOptional arguments\n\nscale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling\ninteger_type - select interger type to use in the mesh (Int32 may be useful on GPU runs) \nfloat_type - select interger type to use in the mesh (Float32 may be useful on GPU runs) \n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.FoamMesh.FOAM3D_mesh-Tuple{Any}","page":"Reference","title":"XCALibre.FoamMesh.FOAM3D_mesh","text":"FOAM3D_mesh(mesh_file; scale=1, integer_type=Int64, float_type=Float64)\n\nRead and convert 3D OpenFOAM mesh file into XCALibre.jl. Note that, at present, it is not recommended to run 2D cases using meshes imported using this function.\n\nInput\n\nmesh_file – path to mesh file.\n\nOptional arguments\n\nscale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling\ninteger_type - select interger type to use in the mesh (Int32 may be useful on GPU runs) \nfloat_type - select interger type to use in the mesh (Float32 may be useful on GPU runs) \n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Fields.ScalarField","page":"Reference","title":"XCALibre.Fields.ScalarField","text":"struct ScalarField{VF,M<:AbstractMesh,BC} <: AbstractScalarField\n values::VF # scalar values at cell centre\n mesh::M # reference to mesh\n BCs::BC # store user-provided boundary conditions\nend\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Fields.VectorField","page":"Reference","title":"XCALibre.Fields.VectorField","text":"struct VectorField{S1<:ScalarField,S2,S3,M<:AbstractMesh,BC} <: AbstractVectorField\n x::S1 # x-component is itself a `ScalarField`\n y::S2 # y-component is itself a `ScalarField`\n z::S3 # z-component is itself a `ScalarField`\n mesh::M\n BCs::BC\nend\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Fields.initialise!-Tuple{Any, Any}","page":"Reference","title":"XCALibre.Fields.initialise!","text":"function initialise!(field, value) # dummy function for documentation\n # Assign `value` to field in-place\n nothing\nend\n\nThis function will set the given field to the value provided in-place. Useful for initialising fields prior to running a simulation.\n\nInput arguments\n\nfield specifies the field to be initialised. The field must be either a AbractScalarField or AbstractVectorField\nvalue defines the value to be set. This should be a scalar or vector (3 components) depending on the field to be modified e.g. for an AbstractVectorField we can specify as value=[10,0,0]\n\nNote: in most cases the fields to be modified are stored within a physics model i.e. a Physics object. Thus, the argument value must fully qualify the model. For example, if we have created a Physics model named mymodel to set the velocity field, U, we would set the argument field to mymodel.momentum.U. See the example below.\n\nExample\n\ninitialise!(mymodel.momentum.U, [2.5, 0, 0])\ninitialise!(mymodel.momentum.p, 1.25)\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Discretise.Dirichlet","page":"Reference","title":"XCALibre.Discretise.Dirichlet","text":"Dirichlet <: AbstractDirichlet\n\nDirichlet boundary condition model.\n\nFields\n\n'ID' – Boundary ID\nvalue – Scalar or Vector value for Dirichlet boundary condition.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Discretise.DirichletFunction","page":"Reference","title":"XCALibre.Discretise.DirichletFunction","text":"DirichletFunction(ID, value) <: AbstractDirichlet\n\nDirichlet boundary condition defined with user-provided function.\n\nInput\n\nID Boundary name provided as symbol e.g. :inlet\nvalue Custom function for Dirichlet boundary condition.\n\nFunction requirements\n\nThe function passed to this boundary condition must have the following signature:\n\nf(coords, time, index) = SVector{3}(ux, uy, uz)\n\nWhere, coords is a vector containing the coordinates of a face, time is the current time in transient simulations (and the iteration number in steady simulations), and index is the local face index (from 1 to N, where N is the number of faces in a given boundary). The function must return an SVector (from StaticArrays.jl) representing the velocity vector. \n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Discretise.FixedTemperature","page":"Reference","title":"XCALibre.Discretise.FixedTemperature","text":"FixedTemperature <: AbstractDirichlet\n\nFixed temperature boundary condition model, which allows the user to specify wall temperature that can be translated to the energy specific model, such as sensivle enthalpy.\n\nFields\n\n'ID' – Boundary ID\nvalue – Scalar or Vector value for Dirichlet boundary condition.\nT - Temperature value in Kelvin.\nmodel - Energy physics model for case.\n\nExamples\n\nFixedTemperature(:inlet, T=300.0, model=model.energy),\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Discretise.Neumann","page":"Reference","title":"XCALibre.Discretise.Neumann","text":"Neumann <: AbstractNeumann\n\nNeumann boundary condition model (currently only configured for zero gradient)\n\nFields\n\n'ID' – Boundary ID\nvalue – Scalar or Vector value for Neumann boundary condition.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Discretise.Periodic","page":"Reference","title":"XCALibre.Discretise.Periodic","text":"struct Periodic{I,V} <: AbstractPhysicalConstraint\n ID::I\n value::V\nend\n\nPeriodic boundary condition model.\n\nFields\n\n'ID' – Boundary ID\nvalue – tuple containing information needed to apply this boundary\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Discretise.Symmetry","page":"Reference","title":"XCALibre.Discretise.Symmetry","text":"Symmetry <: AbstractBoundary\n\nSymmetry boundary condition vector fields. For scalar fields use Neumann\n\nFields\n\n'ID' – Boundary ID\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Discretise.Wall","page":"Reference","title":"XCALibre.Discretise.Wall","text":"Wall <: AbstractDirichlet\n\nWall boundary condition model for no-slip wall condition.\n\nFields\n\n'ID' – Boundary ID\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Discretise.construct_periodic-Tuple{Any, Any, Symbol, Symbol}","page":"Reference","title":"XCALibre.Discretise.construct_periodic","text":"construct_periodic(mesh, backend, patch1::Symbol, patch2::Symbol)\n\nFunction for construction of periodic boundary conditions.\n\nInput\n\nmesh – Mesh.\nbackend – Backend configuraton.\npatch1 – Primary periodic patch ID.\npatch2 – Neighbour periodic patch ID.\n\nOutput\n\nperiodic::Tuple - tuple containing boundary defintions for patch1 and patch2 i.e. (periodic1, periodic2). The fields of periodic1 and periodic2 are \nID – Index to access boundary information in mesh object\nvalue – represents a NamedTuple with the following keyword arguments:\nindex – ID used to find boundary geometry information in the mesh object\ndistance – perpendicular distance between the patches\nface_map – vector providing indeces to faces of match patch\nismaster – flat to identify one of the patch pairs as the main patch\n\nExample\n\n- `periodic = construct_periodic(mesh, CPU(), :top, :bottom)` - Example using CPU \nbackend with periodic boundaries named `top` and `bottom`.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Discretise.set_schemes-Tuple{}","page":"Reference","title":"XCALibre.Discretise.set_schemes","text":"set_schemes(;\n # keyword arguments and their default values\n time=SteadyState,\n divergence=Linear, \n laplacian=Linear, \n gradient=Orthogonal) = begin\n \n # Returns NamedTuple definition for scheme \n (\n time=time,\n divergence=divergence,\n laplacian=laplacian,\n gradient=gradient\n )\nend\n\nThe set_schemes function is used at the top-level API to help users define discretisation schemes for every field solved. It offers default values, thus users can pick and choose which entry they wish to modify.\n\ninputs\n\ntime is used to set the time schemes (default is SteadyState)\ndivergence is used to set the divergence scheme (default is Linear) \nlaplacian is used to set the laplacian scheme (default is Linear)\ngradient is used to set the gradient scheme (default is Orthogonal)\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Discretise.@define_boundary-Tuple{Any, Any, Any}","page":"Reference","title":"XCALibre.Discretise.@define_boundary","text":"macro define_boundary(boundary, operator, definition)\n quote\n @inline (bc::$boundary)(\n term::Operator{F,P,I,$operator}, cellID, zcellID, cell, face, fID, i, component, time\n ) where {F,P,I} = $definition\n end |> esc\nend\n\nMacro to reduce boilerplate code when defining boundary conditions (implemented as functors) and provides access to key fields needed in the implementation of boundary conditions, such as the boundary cell and face objects (more details below)\n\nInput arguments\n\nboundary specifies the boundary type being defined\noperator specifies the operator to which the condition applies e.g. Laplacian\ndefinition provides the implementation details\n\nAvailable fields\n\nterm reference to operator on which the boundary applies (gives access to the field and mesh) \ncellID ID of the corresponding boundary cell\nzcellID sparse matrix linear index for the cell\ncell gives access to boundary cell object and corresponding information\nface gives access to boundary face object and corresponding information\nfID ID of the boundary face (to index Mesh2.faces vector)\ni local index of the boundary faces within a kernel or loop\ncomponent for vectors this specifies the components being evaluated (access as component.value). For scalars component = nothing\ntime provides the current simulation time. This only applies to time dependent boundary implementation defined as functions or neural networks.\n\nExample\n\nBelow the use of this macro is illustrated for the implementation of a Dirichlet boundary condition acting on the Laplacian using the Linear scheme:\n\n@define_boundary Dirichlet Laplacian{Linear} begin\n J = term.flux[fID] # extract operator flux\n (; area, delta) = face # extract boundary face information\n flux = J*area/delta # calculate the face flux\n ap = term.sign*(-flux) # diagonal (cell) matrix coefficient\n ap, ap*bc.value # return `ap` and `an`\nend\n\nWhen called, this functor will return two values ap and an, where ap is the cell contribution for approximating the boundary face value, and an is the explicit part of the face value approximation i.e. ap contributes to the diagonal of the sparse matrix (left-hand side) and an is the explicit contribution assigned to the solution vector b on the right-hand of the linear system of equations Ax = b\n\n\n\n\n\n","category":"macro"},{"location":"reference/#XCALibre.Solve.set_runtime-Union{Tuple{}, Tuple{N}, Tuple{I}} where {I<:Integer, N<:Number}","page":"Reference","title":"XCALibre.Solve.set_runtime","text":"set_runtime(; \n # keyword arguments\n iterations::I, \n write_interval::I, \n time_step::N\n ) where {I<:Integer,N<:Number} = begin\n \n # returned `NamedTuple``\n (\n iterations=iterations, \n dt=time_step, \n write_interval=write_interval)\nend\n\nThis is a convenience function to set the top-level runtime information. The inputs are all keyword arguments and provide basic information to flow solvers just before running a simulation.\n\nInput arguments\n\niterations::Integer specifies the number of iterations in a simulation run.\nwrite_interval::Integer defines how often simulation results are written to file (on the current working directory). The interval is currently based on number of iterations. Set to -1 to run without writing results to file.\ntime_step::Number the time step to use in the simulation. Notice that for steady solvers this is simply a counter and it is recommended to simply use 1.\n\nExample\n\nruntime = set_runtime(\n iterations=2000, time_step=1, write_interval=2000)\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Solve.set_solver-Union{Tuple{AbstractField}, Tuple{PT}, Tuple{S}} where {S, PT<:PreconditionerType}","page":"Reference","title":"XCALibre.Solve.set_solver","text":"set_solver( \n field::AbstractField;\n # keyword arguments and defaults\n solver::S, \n preconditioner::PT, \n convergence, \n relax,\n limit=(),\n itmax::Integer=100, \n atol=(eps(_get_float(field.mesh)))^0.9,\n rtol=_get_float(field.mesh)(1e-3)\n ) where {S,PT<:PreconditionerType} = begin\n\n # return NamedTuple\n TF = _get_float(field.mesh)\n (\n solver=solver, \n preconditioner=preconditioner, \n convergence=convergence |> TF, \n relax=relax |> TF, \n limit=limit,\n itmax=itmax, \n atol=atol |> TF, \n rtol=rtol |> TF\n )\nend\n\nThis function is used to provide solver settings that will be used internally in XCALibre.jl. It returns a NamedTuple with solver settings that are used internally by the flow solvers. \n\nInput arguments\n\nfield reference to the field to which the solver settings will apply (used to provide integer and float types required)\nsolver solver object from Krylov.jl and it could be one of BicgstabSolver, CgSolver, GmresSolver which are re-exported in XCALibre.jl\npreconditioner instance of preconditioner to be used e.g. Jacobi()\nconvergence sets the stopping criteria of this field\nrelax specifies the relaxation factor to be used e.g. set to 1 for no relaxation\nlimit used in some solvers to bound the solution within this limits e.g. (min, max). It defaults to ()\nitmax maximum number of iterations in a single solver pass (defaults to 100) \natol absolute tolerance for the solver (default to eps(FloatType)^0.9)\nrtol set relative tolerance for the solver (defaults to 1e-3)\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.Compressible","page":"Reference","title":"XCALibre.ModelPhysics.Compressible","text":"Compressible <: AbstractCompressible\n\nCompressible fluid model containing fluid field parameters for compressible flows with constant parameters - ideal gas with constant viscosity.\n\nFields\n\n'nu' – Fluid kinematic viscosity.\n'cp' – Fluid specific heat capacity.\ngamma – Ratio of specific heats.\nPr – Fluid Prantl number.\n\nExamples\n\nFluid{Compressible}(; nu=1E-5, cp=1005.0, gamma=1.4, Pr=0.7) - Constructur with default values.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.Fluid","page":"Reference","title":"XCALibre.ModelPhysics.Fluid","text":"Fluid <: AbstractFluid\n\nAbstract fluid model type for constructing new fluid models.\n\nFields\n\n'args' – Model arguments.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.Incompressible","page":"Reference","title":"XCALibre.ModelPhysics.Incompressible","text":"Incompressible <: AbstractIncompressible\n\nIncompressible fluid model containing fluid field parameters for incompressible flows.\n\nFields\n\n'nu' – Fluid kinematic viscosity.\n'rho' – Fluid density.\n\nExamples\n\nFluid{Incompressible}(nu=0.001, rho=1.0) - Constructor with default values.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.KOmega","page":"Reference","title":"XCALibre.ModelPhysics.KOmega","text":"KOmega <: AbstractTurbulenceModel\n\nkOmega model containing all kOmega field parameters.\n\nFields\n\n'k' – Turbulent kinetic energy ScalarField.\n'omega' – Specific dissipation rate ScalarField.\n'nut' – Eddy viscosity ScalarField.\n'kf' – Turbulent kinetic energy FaceScalarField.\n'omegaf' – Specific dissipation rate FaceScalarField.\n'nutf' – Eddy viscosity FaceScalarField.\n'coeffs' – Model coefficients.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.KOmegaLKE","page":"Reference","title":"XCALibre.ModelPhysics.KOmegaLKE","text":"KOmegaLKE <: AbstractTurbulenceModel\n\nkOmega model containing all kOmega field parameters.\n\nFields\n\n'k' – Turbulent kinetic energy ScalarField.\n'omega' – Specific dissipation rate ScalarField.\n'kl' – ScalarField.\n'nut' – Eddy viscosity ScalarField.\n'kf' – Turbulent kinetic energy FaceScalarField.\n'omegaf' – Specific dissipation rate FaceScalarField.\n'klf' – FaceScalarField.\n'nutf' – Eddy viscosity FaceScalarField.\n'coeffs' – Model coefficients.\n'Tu' – Freestream turbulence intensity for model.\n'y' – Near-wall distance for model.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.LES","page":"Reference","title":"XCALibre.ModelPhysics.LES","text":"LES <: AbstractLESModel\n\nAbstract LES model type for constructing LES models.\n\nFields\n\n'args' – Model arguments.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.Laminar","page":"Reference","title":"XCALibre.ModelPhysics.Laminar","text":"Laminar <: AbstractTurbulenceModel\n\nLaminar model definition for physics API.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.Momentum","page":"Reference","title":"XCALibre.ModelPhysics.Momentum","text":"struct Momentum{V,S,SS} <: AbstractMomentumModel\n U::V \n p::S \n sources::SS\nend\n\nMomentum model containing key momentum fields.\n\nFields\n\n'U' – Velocity VectorField.\n'p' – Pressure ScalarField.\n'sources' – Momentum model sources.\n\nExamples\n\n`Momentum(mesh::AbstractMesh)\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.Physics","page":"Reference","title":"XCALibre.ModelPhysics.Physics","text":"struct Physics{T,F,M,Tu,E,D,BI}\n time::T\n fluid::F\n momentum::M \n turbulence::Tu \n energy::E\n domain::D\n boundary_info::BI\nend\n\nXCALibre's parametric Physics type for user-level API. Also used to dispatch flow solvers.\n\nFields\n\n'time::Union{Steady, Transient}' – User-provided time model.\n'fluid::AbstractFluid' – User-provided Fluid` model.\n'momentum' – Momentum model. Currently this is auto-generated by the Physics constructor\n'turbulence::AbstractTurbulenceModel' – User-provided Turbulence` model.\n'energy:AbstractEnergyModel' – User-provided Energy model.\n'domain::AbstractMesh ' – User-provided Mesh. Must be adapted to target device before constructing a Physics object.\n'boundaryinfo::boundaryinfo' – Mesh boundary information. Auto-generated by the Physics constructor\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.Physics-Tuple{}","page":"Reference","title":"XCALibre.ModelPhysics.Physics","text":"Physics(; time, fluid, turbulence, energy, domain)::Physics{T,F,M,Tu,E,D,BI}\n\nPhysics constructor part of the top-level API. It can be used to define the Physics and models relevant to a simulation. This constructor uses keyword arguments to allow users to fine-tune their simulations, whilst some fields are auto-generated behind the scenes for convenience (Momentum and boundary_info). Where:\n\ntime - specified the time model (Steady or Transient)\nfluid - specifies the type of fluid (Incompressible, etc.)\nturbulence - specified the Turbulence model\nenergy - specifies the Energy treatment\ndomain - provides the mesh to used (must be adapted to the target backend device)\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.RANS","page":"Reference","title":"XCALibre.ModelPhysics.RANS","text":"RANS <: AbstractRANSModel\n\nAbstract RANS model type for consturcting RANS models.\n\nFields\n\n'args' – Model arguments.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.SensibleEnthalpy","page":"Reference","title":"XCALibre.ModelPhysics.SensibleEnthalpy","text":"SensibleEnthalpy <: AbstractEnergyModel\n\nType that represents energy model, coefficients and respective fields.\n\nFields\n\n'h' – Sensible enthalpy ScalarField.\n'T' – Temperature ScalarField.\n'hf' – Sensible enthalpy FaceScalarField.\n'Tf' – Temperature FaceScalarField.\n'K' – Specific kinetic energy ScalarField.\n'dpdt' – Pressure time derivative ScalarField.\n'updated_BC' – Boundary condition function to convert temperature to sensible enthalp on on a fixed value boudary.\n'coeffs' – A tuple of model coefficients.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.Smagorinsky","page":"Reference","title":"XCALibre.ModelPhysics.Smagorinsky","text":"Smagorinsky <: AbstractTurbulenceModel\n\nSmagorinsky LES model containing all Smagorinksy field parameters.\n\nFields\n\n'nut' – Eddy viscosity ScalarField.\n'nutf' – Eddy viscosity FaceScalarField.\n'coeffs' – Model coefficients.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.Steady","page":"Reference","title":"XCALibre.ModelPhysics.Steady","text":"Steady\n\nSteady model for Physics model API.\n\nExamples\n\nSteady()\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.Transient","page":"Reference","title":"XCALibre.ModelPhysics.Transient","text":"Transient\n\nTransient model for Physics model API.\n\nExamples\n\nTransient()\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.WeaklyCompressible","page":"Reference","title":"XCALibre.ModelPhysics.WeaklyCompressible","text":"WeaklyCompressible <: AbstractCompressible\n\nWeakly compressible fluid model containing fluid field parameters for weakly compressible flows with constant parameters - ideal gas with constant viscosity.\n\nFields\n\n'nu' – Fluid kinematic viscosity.\n'cp' – Fluid specific heat capacity.\ngamma – Ratio of specific heats.\nPr – Fluid Prandtl number.\n\nExamples\n\nFluid{WeaklyCompressible}(; nu=1E-5, cp=1005.0, gamma=1.4, Pr=0.7) - Constructor with \n\ndefault values.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.Ttoh!-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T1}, Tuple{Physics{T1, F, M, Tu, E, D, BI}, ScalarField, ScalarField}} where {T1, F<:AbstractCompressible, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.Ttoh!","text":"Ttoh!(model::Physics{T1,F,M,Tu,E,D,BI}, T::ScalarField, h::ScalarField\n) where {T1,F<:AbstractCompressible,M,Tu,E,D,BI}\n\nFunction coverts temperature ScalarField to sensible enthalpy ScalarField.\n\nInput\n\nmodel – Physics model defined by user.\nT – Temperature ScalarField.\nh – Sensible enthalpy ScalarField.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.change-Tuple{Physics, Any, Any}","page":"Reference","title":"XCALibre.ModelPhysics.change","text":"change(model::Physics, property, value) => updatedModel::Physics\n\nA convenience function to change properties of an exisitng Physics model.\n\nInput arguments\n\nmodel::Physics a Physics model to modify\nproperty is a symbol specifying the property to change \nvalue is the new setting for the specified property\n\nOutput\n\nThis function return a new Physics object\n\nExample\n\nTo change a model to run a transient simulation e.g. after converging in steady state\n\nmodelTransient = change(model, :time, Transient())\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.energy!-Union{Tuple{E1}, Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T1}, Tuple{XCALibre.ModelPhysics.Sensible_Enthalpy_Model{E1}, Physics{T1, F, M, Tu, E, D, BI}, Vararg{Any, 6}}} where {T1, F, M, Tu, E, D, BI, E1}","page":"Reference","title":"XCALibre.ModelPhysics.energy!","text":"energy::Sensible_Enthalpy_Model{E1}, model::Physics{T1,F,M,Tu,E,D,BI}, prev, mdotf, rho, mueff, time, config\n) where {T1,F,M,Tu,E,D,BI,E1}\n\nRun energy transport equations.\n\nInput\n\nenergy – Energy model.\nmodel – Physics model defined by user.\nprev – Previous energy cell values.\nmdtof – Face mass flow.\nrho – Density ScalarField.\nmueff – Effective viscosity FaceScalarField.\ntime –\nconfig – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.htoT!-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T1}, Tuple{Physics{T1, F, M, Tu, E, D, BI}, ScalarField, ScalarField}} where {T1, F<:AbstractCompressible, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.htoT!","text":"htoT!(model::Physics{T1,F,M,Tu,E,D,BI}, h::ScalarField, T::ScalarField\n) where {T1,F<:AbstractCompressible,M,Tu,E,D,BI}\n\nFunction coverts sensible enthalpy ScalarField to temperature ScalarField.\n\nInput\n\nmodel – Physics model defined by user.\nh – Sensible enthalpy ScalarField.\nT – Temperature ScalarField.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.initialise-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T1}, Tuple{SensibleEnthalpy, Physics{T1, F, M, Tu, E, D, BI}, Vararg{Any, 4}}} where {T1, F, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.initialise","text":"initialise(energy::SensibleEnthalpy, model::Physics{T1,F,M,Tu,E,D,BI}, mdotf, rho, peqn, config\n) where {T1,F,M,Tu,E,D,BI})\n\nInitialisation of energy transport equations.\n\nInput\n\nenergy – Energy model.\nmodel – Physics model defined by user.\nmdtof – Face mass flow.\nrho – Density ScalarField.\npeqn – Pressure equation.\nconfig – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.\n\nOutput\n\nSensible_Enthalpy_Model – Energy model struct containing energy equation.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.initialise-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{KOmega, Physics{T, F, M, Tu, E, D, BI}, Any, Any, Any}} where {T, F, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.initialise","text":"initialise(turbulence::KOmega, model::Physics{T,F,M,Tu,E,D,BI}, mdotf, peqn, config\n) where {T,F,M,Tu,E,D,BI}\n\nInitialisation of turbulent transport equations.\n\nInput\n\nturbulence – turbulence model.\nmodel – Physics model defined by user.\nmdtof – Face mass flow.\npeqn – Pressure equation.\nconfig – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.\n\nOutput\n\nKOmegaModel(k_eqn, ω_eqn) – Turbulence model structure.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.initialise-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{KOmegaLKE, Physics{T, F, M, Tu, E, D, BI}, Any, Any, Any}} where {T, F, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.initialise","text":"initialise(turbulence::KOmegaLKE, model::Physics{T,F,M,Tu,E,D,BI}, mdotf, peqn, config\n) where {T,F,M,Tu,E,D,BI}\n\nInitialisation of turbulent transport equations.\n\nInput\n\nturbulence – turbulence model.\nmodel – Physics model defined by user.\nmdtof – Face mass flow.\npeqn – Pressure equation.\nconfig – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.\n\nOutput\n\nKOmegaLKEModel( k_eqn, ω_eqn, kl_eqn, nueffkLS, nueffkS, nueffωS, nuL, nuts, Ω, γ, fv, normU, Reυ, ∇k, ∇ω ) – Turbulence model structure.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.initialise-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{Laminar, Physics{T, F, M, Tu, E, D, BI}, Any, Any, Any}} where {T, F, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.initialise","text":"function initialise(\n turbulence::Laminar, model::Physics{T,F,M,Tu,E,D,BI}, mdotf, peqn, config\n ) where {T,F,M,Tu,E,D,BI}\nreturn LaminarModel()\n\nend\n\nInitialisation of turbulent transport equations.\n\nInput\n\nturbulence – turbulence model.\nmodel – Physics model defined by user.\nmdtof – Face mass flow.\npeqn – Pressure equation.\nconfig – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.\n\nOutput\n\nLaminarModel() – Turbulence model structure.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.initialise-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{Smagorinsky, Physics{T, F, M, Tu, E, D, BI}, Any, Any, Any}} where {T, F, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.initialise","text":"initialise(turbulence::Smagorinsky, model::Physics{T,F,M,Tu,E,D,BI}, mdotf, peqn, config\n) where {T,F,M,Tu,E,D,BI}\n\nInitialisation of turbulent transport equations.\n\nInput\n\nturbulence – turbulence model.\nmodel – Physics model defined by user.\nmdtof – Face mass flow.\npeqn – Pressure equation.\nconfig – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.\n\nOutput\n\nSmagorinskyModel(Δ, magS) – Turbulence model structure.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.thermo_Psi!-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{Physics{T, F, M, Tu, E, D, BI}, FaceScalarField, Any}} where {T, F<:AbstractCompressible, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.thermo_Psi!","text":"thermo_Psi!(model::Physics{T,F,M,Tu,E,D,BI}, Psif::FaceScalarField) \nwhere {T,F<:AbstractCompressible,M,Tu,E,D,BI}\n\nFunction updates the value of Psi.\n\nInput\n\nmodel – Physics model defined by user.\nPsif – Compressibility factor FaceScalarField.\n\nAlgorithm\n\nWeakly compressible currently uses the ideal gas equation for establishing the compressibility factor where rho = p * Psi. Psi is calculated from the sensible enthalpy, reference temperature and fluid model specified C_p and R value where R is calculated from C_p and gamma specified in the fluid model.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.thermo_Psi!-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{Physics{T, F, M, Tu, E, D, BI}, ScalarField}} where {T, F<:AbstractCompressible, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.thermo_Psi!","text":"thermo_Psi!(model::Physics{T,F,M,Tu,E,D,BI}, Psi::ScalarField) \nwhere {T,F<:AbstractCompressible,M,Tu,E,D,BI}\n\nModel updates the value of Psi.\n\nInput\n\nmodel – Physics model defined by user.\nPsi – Compressibility factor ScalarField.\n\nAlgorithm\n\nWeakly compressible currently uses the ideal gas equation for establishing the compressibility factor where rho = p * Psi. Psi is calculated from the sensible enthalpy, reference temperature and fluid model specified C_p and R value where R is calculated from C_p and gamma specified in the fluid model.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.turbulence!-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Turb}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{XCALibre.ModelPhysics.KOmegaLKEModel, Physics{T, F, M, Turb, E, D, BI}, Vararg{Any, 5}}} where {T, F, M, Turb<:KOmegaLKE, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.turbulence!","text":"turbulence!(rans::KOmegaLKEModel, model::Physics{T,F,M,Turb,E,D,BI}, S, S2, prev, time, config ) where {T,F,M,Turb<:KOmegaLKE,E,D,BI}\n\nRun turbulence model transport equations.\n\nInput\n\nrans::KOmegaLKEModel – KOmega turbulence model.\nmodel – Physics model defined by user.\nS – Strain rate tensor.\nS2 – Square of the strain rate magnitude.\nprev – Previous field.\ntime – \nconfig – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.turbulence!-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{XCALibre.ModelPhysics.LaminarModel, Physics{T, F, M, Tu, E, D, BI}, Vararg{Any, 5}}} where {T, F, M, Tu<:Laminar, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.turbulence!","text":"turbulence!(rans::LaminarModel, model::Physics{T,F,M,Tu,E,D,BI}, S, S2, prev, time, config\n) where {T,F,M,Tu<:Laminar,E,D,BI}\n\nRun turbulence model transport equations.\n\nInput\n\nrans::LaminarModel – Laminar turbulence model.\nmodel – Physics model defined by user.\nS – Strain rate tensor.\nS2 – Square of the strain rate magnitude.\nprev – Previous field.\ntime – \nconfig – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.turbulence!-Union{Tuple{E2}, Tuple{E1}, Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{XCALibre.ModelPhysics.KOmegaModel{E1, E2}, Physics{T, F, M, Tu, E, D, BI}, Vararg{Any, 5}}} where {T, F, M, Tu<:KOmega, E, D, BI, E1, E2}","page":"Reference","title":"XCALibre.ModelPhysics.turbulence!","text":"turbulence!(rans::KOmegaModel{E1,E2}, model::Physics{T,F,M,Tu,E,D,BI}, S, S2, prev, time, config\n) where {T,F,M,Tu<:KOmega,E,D,BI,E1,E2}\n\nRun turbulence model transport equations.\n\nInput\n\nrans::KOmegaModel{E1,E2} – KOmega turbulence model.\nmodel – Physics model defined by user.\nS – Strain rate tensor.\nS2 – Square of the strain rate magnitude.\nprev – Previous field.\ntime – \nconfig – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.turbulence!-Union{Tuple{E2}, Tuple{E1}, Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{XCALibre.ModelPhysics.SmagorinskyModel{E1, E2}, Physics{T, F, M, Tu, E, D, BI}, Vararg{Any, 5}}} where {T, F, M, Tu<:Smagorinsky, E, D, BI, E1, E2}","page":"Reference","title":"XCALibre.ModelPhysics.turbulence!","text":"turbulence!(les::SmagorinskyModel{E1,E2}, model::Physics{T,F,M,Tu,E,D,BI}, S, S2, prev, time, config\n) where {T,F,M,Tu<:Smagorinsky,E,D,BI,E1,E2}\n\nRun turbulence model transport equations.\n\nInput\n\nles::SmagorinskyModel{E1,E2} – Smagorinsky LES turbulence model.\nmodel – Physics model defined by user.\nS – Strain rate tensor.\nS2 – Square of the strain rate magnitude.\nprev – Previous field.\ntime – \nconfig – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Simulate.Configuration","page":"Reference","title":"XCALibre.Simulate.Configuration","text":"@kwdef struct Configuration{SC,SL,RT,HW}\n schemes::SC\n solvers::SL\n runtime::RT\n hardware::HW\nend\n\nThe Configuration type is passed to all flow solvers and provides all the relevant information to run a simulation. \n\nInputs\n\nschemes::NamedTuple this keyword argument is used to pass distretisation scheme information to flow solvers. See Numerical setup for details.\nsolvers::NamedTuple this keyword argument is used to pass the configurations for the linear solvers for each field information to flow solvers. See Runtime and solvers for details.\nruntime::NamedTuple this keyword argument is used to pass runtime information to the flow solvers. See Runtime and solvers for details.\nhardware::NamedTuple this keyword argument is used to pass the hardware configuration and backend settings to the flow solvers. See Pre-processing for details.\n\nExample\n\nconfig = Configuration(\n solvers=solvers, schemes=schemes, runtime=runtime, hardware=hardware)\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Simulate.set_hardware-Tuple{}","page":"Reference","title":"XCALibre.Simulate.set_hardware","text":"hardware = set_hardware(backend, workgroup)\n\nFunction used to configure the backend.\n\nInputs\n\nbackend named tuple used to specify the backend e.g. CPU(), CUDABackend() or other backends supported by KernelAbstraction.jl\nworkgroup::Int this is an integer specifying the number of workers that cooperate in a parallel run. For GPUs this could be set to the size of the device's warp e.g. workgroup = 32. On CPUs, the default value in KernelAbstractions.jl is currently workgroup = 1024.\n\nOutput\n\nThis function returns a NamedTuple with the fields backend and workgroup which are accessed by internally in XCALibre.jl to execute a given kernel.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Solvers.cpiso!-Tuple{Any, Any}","page":"Reference","title":"XCALibre.Solvers.cpiso!","text":"cpiso!(model, config; \n limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0)\n\nCompressible and transient variant of the PISO algorithm with a sensible enthalpy transport equation for the energy. \n\nInput arguments\n\nmodel reference to a Physics` model defined by the user.\nconfig Configuration structure defined by the user with solvers, schemes, runtime and hardware structures configuration details.\nlimit_gradient flag use to activate gradient limiters in the solver (default = false)\npref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only (default = nothing)\nncorrectors number of non-orthogonality correction loops (default = 0)\ninner_loops number to inner loops used in transient solver based on PISO algorithm (default = 0)\n\nOutput\n\nUx Vector of x-velocity residuals for each iteration.\nUy Vector of y-velocity residuals for each iteration.\nUz Vector of y-velocity residuals for each iteration.\np Vector of pressure residuals for each iteration.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Solvers.csimple!-Tuple{Any, Any}","page":"Reference","title":"XCALibre.Solvers.csimple!","text":"csimple!(\n model_in, config; \n limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0\n)\n\nCompressible variant of the SIMPLE algorithm with a sensible enthalpy transport equation for the energy. \n\nInput arguments\n\nmodel reference to a Physics` model defined by the user.\nconfig Configuration structure defined by the user with solvers, schemes, runtime and hardware structures configuration details.\nlimit_gradient flag use to activate gradient limiters in the solver (default = false)\npref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only (default = nothing)\nncorrectors number of non-orthogonality correction loops (default = 0)\ninner_loops number to inner loops used in transient solver based on PISO algorithm (default = 0)\n\nOutput\n\nUx Vector of x-velocity residuals for each iteration.\nUy Vector of y-velocity residuals for each iteration.\nUz Vector of y-velocity residuals for each iteration.\np Vector of pressure residuals for each iteration.\ne Vector of energy residuals for each iteration.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Solvers.piso!-Tuple{Any, Any}","page":"Reference","title":"XCALibre.Solvers.piso!","text":"cpiso!(model, config; \n limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0)\n\nIncompressible and transient variant of the SIMPLE algorithm to solving coupled momentum and mass conservation equations. \n\nInput arguments\n\nmodel reference to a Physics` model defined by the user.\nconfig Configuration structure defined by the user with solvers, schemes, runtime and hardware structures configuration details.\nlimit_gradient flag use to activate gradient limiters in the solver (default = false)\npref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only (default = nothing)\nncorrectors number of non-orthogonality correction loops (default = 0)\ninner_loops number to inner loops used in transient solver based on PISO algorithm (default = 0)\n\nOutput\n\nUx Vector of x-velocity residuals for each iteration.\nUy Vector of y-velocity residuals for each iteration.\nUz Vector of y-velocity residuals for each iteration.\np Vector of pressure residuals for each iteration.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Solvers.run!-Tuple{}","page":"Reference","title":"XCALibre.Solvers.run!","text":"function run!(\n model::Physics, config; \n limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0\n )\n\n # here an internal function is used for solver dispatch\n return residuals\nend\n\nThis is the top level API function to initiate a simulation. It uses the user-provided model defined as a Physics object to dispatch to the appropriate solver.\n\nDispatched flow solvers\n\nSteady incompressible (SIMPLE algorithm for coupling)\nTransient incompressible (PISO algorithm for coupling)\nSteady weakly compressible (SIMPLE algorithm for coupling)\nTransient weakly compressible (PISO algorithm for coupling)\n\nInput arguments\n\nmodel reference to a Physics model defined by the user.\nconfig Configuration structure defined by the user with solvers, schemes, runtime and hardware structures configuration details.\nlimit_gradient flag used to activate gradient limiters in the solver (default = false)\npref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only (default = nothing)\nncorrectors number of non-orthogonality correction loops (default = 0)\ninner_loops number to inner loops used in transient solver based on PISO algorithm (default = 0)\n\nOutput\n\nThis function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux). The fields available within the returned residuals tuple depend on the solver used. For example, for an incompressible solver, a x-momentum equation residual can be retrieved accessing the Ux field i.e. residuals.Ux. Look at reference guide for each dispatch method to find out which fields are available.\n\nExample\n\nresiduals = run!(model, config) \n\n# to access the pressure residual\n\nresiduals.p \n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Solvers.run!-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{Physics{T, F, M, Tu, E, D, BI}, Any}} where {T<:Steady, F<:Incompressible, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.Solvers.run!","text":"run!(\n model::Physics{T,F,M,Tu,E,D,BI}, config;\n limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0\n ) where{T<:Steady,F<:Incompressible,M,Tu,E,D,BI} = \nbegin\n residuals = simple!(model, config, pref=pref)\n return residuals\nend\n\nCalls the incompressible steady solver using the SIMPLE algorithm.\n\nInput\n\nmodel represents the Physics` model defined by user.\nconfig Configuration structure defined by user with solvers, schemes, runtime and hardware structures configuration details.\npref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only.\n\nOutput\n\nThis function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux) with the following entries:\n\nUx - Vector of x-velocity residuals for each iteration.\nUy - Vector of y-velocity residuals for each iteration.\nUz - Vector of y-velocity residuals for each iteration.\np - Vector of pressure residuals for each iteration.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Solvers.run!-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{Physics{T, F, M, Tu, E, D, BI}, Any}} where {T<:Steady, F<:WeaklyCompressible, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.Solvers.run!","text":"run!(\n model::Physics{T,F,M,Tu,E,D,BI}, config; \n limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0\n ) where{T<:Steady,F<:WeaklyCompressible,M,Tu,E,D,BI} = \nbegin\n residuals = csimple!(model, config, pref=pref); #, pref=0.0)\n return residuals\nend\n\nCalls the compressible steady solver using the SIMPLE algorithm for weakly compressible fluids.\n\nInput\n\nmodel represents the Physics` model defined by user.\nconfig Configuration structure defined by user with solvers, schemes, runtime and hardware structures configuration details.\npref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only.\n\nOutput\n\nThis function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux) with the following entries:\n\nUx - Vector of x-velocity residuals for each iteration.\nUy - Vector of y-velocity residuals for each iteration.\nUz - Vector of y-velocity residuals for each iteration.\np - Vector of pressure residuals for each iteration.\ne - Vector of energy residuals for each iteration.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Solvers.run!-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{Physics{T, F, M, Tu, E, D, BI}, Any}} where {T<:Transient, F<:Incompressible, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.Solvers.run!","text":"run!(\n model::Physics{T,F,M,Tu,E,D,BI}, config; \n limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0\n ) where{T<:Transient,F<:Incompressible,M,Tu,E,D,BI} = \nbegin\n residuals = piso!(model, config, pref=pref); #, pref=0.0)\n return residuals\nend\n\nCalls the incompressible transient solver using the PISO algorithm.\n\nInput\n\nmodel represents the Physics` model defined by user.\nconfig Configuration structure defined by user with solvers, schemes, runtime and hardware structures configuration details.\npref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only.\n\nOutput\n\nThis function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux) with the following entries:\n\nUx - Vector of x-velocity residuals for each iteration.\nUy - Vector of y-velocity residuals for each iteration.\nUz - Vector of y-velocity residuals for each iteration.\np - Vector of pressure residuals for each iteration.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Solvers.run!-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{Physics{T, F, M, Tu, E, D, BI}, Any}} where {T<:Transient, F<:WeaklyCompressible, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.Solvers.run!","text":"run!(\n model::Physics{T,F,M,Tu,E,D,BI}; \n limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0\n ) where{T<:Transient,F<:WeaklyCompressible,M,Tu,E,D,BI} = \nbegin\n residuals = cpiso!(model, config)\n return residuals\nend\n\nCalls the compressible transient solver using the PISO algorithm for weakly compressible fluids.\n\nInput\n\nmodel represents the Physics` model defined by user.\nconfig Configuration structure defined by user with solvers, schemes, runtime and hardware structures configuration details.\npref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only.\n\nOutput\n\nThis function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux) with the following entries:\n\nUx - Vector of x-velocity residuals for each iteration.\nUy - Vector of y-velocity residuals for each iteration.\nUz - Vector of y-velocity residuals for each iteration.\np - Vector of pressure residuals for each iteration.\ne - Vector of energy residuals for each iteration.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Solvers.simple!-Tuple{Any, Any}","page":"Reference","title":"XCALibre.Solvers.simple!","text":"simple!(model_in, config; \n limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0)\n\nIncompressible variant of the SIMPLE algorithm to solving coupled momentum and mass conservation equations.\n\nInput arguments\n\nmodel reference to a Physics` model defined by the user.\nconfig Configuration structure defined by the user with solvers, schemes, runtime and hardware structures configuration details.\nlimit_gradient flag use to activate gradient limiters in the solver (default = false)\npref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only (default = nothing)\nncorrectors number of non-orthogonality correction loops (default = 0)\ninner_loops number to inner loops used in transient solver based on PISO algorithm (default = 0)\n\nOutput\n\nThis function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux) with the following entries:\n\nUx Vector of x-velocity residuals for each iteration.\nUy Vector of y-velocity residuals for each iteration.\nUz Vector of y-velocity residuals for each iteration.\np Vector of pressure residuals for each iteration.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Postprocess.boundary_average-Tuple{Symbol, Any, Any}","page":"Reference","title":"XCALibre.Postprocess.boundary_average","text":"function boundary_average(patch::Symbol, field, config; time=0)\n # Extract mesh object\n mesh = field.mesh\n\n # Determine ID (index) of the boundary patch \n ID = boundary_index(mesh.boundaries, patch)\n @info \"calculating average on patch: $patch at index $ID\"\n boundary = mesh.boundaries[ID]\n (; IDs_range) = boundary\n\n # Create face field of same type provided by user (scalar or vector)\n sum = nothing\n if typeof(field) <: VectorField \n faceField = FaceVectorField(mesh)\n sum = zeros(_get_float(mesh), 3) # create zero vector\n else\n faceField = FaceScalarField(mesh)\n sum = zero(_get_float(mesh)) # create zero\n end\n\n # Interpolate CFD results to boundary\n interpolate!(faceField, field, config)\n correct_boundaries!(faceField, field, field.BCs, time, config)\n\n # Calculate the average\n for fID ∈ IDs_range\n sum += faceField[fID]\n end\n ave = sum/length(IDs_range)\n\n # return average\n return ave\nend\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Postprocess.pressure_force-Tuple{Symbol, ScalarField, Any}","page":"Reference","title":"XCALibre.Postprocess.pressure_force","text":"pressure_force(patch::Symbol, p::ScalarField, rho)\n\nFunction to calculate the pressure force acting on a given patch/boundary.\n\nInput arguments\n\npatch::Symbol name of the boundary of interest (as a Symbol)\np::ScalarField pressure field\nrho density. Set to 1 for incompressible solvers\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Postprocess.viscous_force-Tuple{Symbol, VectorField, Any, Any, Any}","page":"Reference","title":"XCALibre.Postprocess.viscous_force","text":"viscous_force(patch::Symbol, U::VectorField, rho, ν, νt)\n\nFunction to calculate the pressure force acting on a given patch/boundary.\n\nInput arguments\n\npatch::Symbol name of the boundary of interest (as a Symbol)\nU::VectorField pressure field\nrho density. Set to 1 for incompressible solvers\nν laminar viscosity of the fluid\nνt eddy viscosity from turbulence models. Pass ConstantScalar(0) for laminar flows\n\n\n\n\n\n","category":"method"},{"location":"theory_guide/introduction/#Introduction","page":"Theory Guide","title":"Introduction","text":"","category":"section"},{"location":"theory_guide/introduction/","page":"Theory Guide","title":"Theory Guide","text":"","category":"page"},{"location":"user_guide/1_preprocessing/#Pre-processing","page":"Pre-processing","title":"Pre-processing","text":"","category":"section"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"First steps required to set up a simulation","category":"page"},{"location":"user_guide/1_preprocessing/#Mesh-generation-and-requirements","page":"Pre-processing","title":"Mesh generation and requirements","text":"","category":"section"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"As with all CFD solvers, defining a suitable mesh is one of the most important steps. XCALibre.jl does not provides mesh generation utilities (yet). Thus, the user will have to generate the grids using external mesh generation tools. However, XCALibre.jl does provide a number of mesh conversion tools to allow user to import their grids. ","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"XCALibre.jl is an unstructured Finite Volume Method (FVM) library, therefore, we are able to support grids of arbitrary polyhedral cells. In XCALibre.jl a cell-centred FVM approach has been implemented, which is popular since it allows the representation of complex geometries and it is used by most commercial and many open source CFD solvers.","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"units: Units\nXCALIbre.jl does not enforce units strictly. Units are implicitly provided by the mesh. You can use the scale keyword when importing a mesh to control the units used e.g. if the mesh file was created in millimetres, set scale=0.001 to work in metres. Thus, it is important to ensure that consistent units are used through all configuration entries. It is highly recommended that SI units are used. ","category":"page"},{"location":"user_guide/1_preprocessing/#Mesh-conversion","page":"Pre-processing","title":"Mesh conversion","text":"","category":"section"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"XCALibre.jl at present supports .unv mesh formats (which can be generated using SALOME) for simulations in 2D and 3D domains. XCALibre.jl also supports the OpenFOAM mesh format for simulations in 3D only (for now). ","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"note: Note\nCurrently, XCALibre.jl only supports loading mesh files stored in ASCII format. Please ensure that when saving grid files they are not saved in binary format. Most mesh generation programmes offer the option to export in ASCII (text-based) formats.","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"The following functions are provided for importing mesh files:","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"UNV2D_mesh\nUNV3D_mesh\nFOAM3D_mesh","category":"page"},{"location":"user_guide/1_preprocessing/#XCALibre.UNV2.UNV2D_mesh-user_guide-1_preprocessing","page":"Pre-processing","title":"XCALibre.UNV2.UNV2D_mesh","text":"UNV2D_mesh(meshFile; scale=1, integer_type=Int64, float_type=Float64)\n\nRead and convert 2D UNV mesh file into XCALibre.jl\n\nInput\n\nmeshFile – path to mesh file.\n\nOptional arguments\n\nscale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling\ninteger_type - select interger type to use in the mesh (Int32 may be useful on GPU runs) \nfloat_type - select interger type to use in the mesh (Float32 may be useful on GPU runs) \n\n\n\n\n\n","category":"function"},{"location":"user_guide/1_preprocessing/#XCALibre.UNV3.UNV3D_mesh-user_guide-1_preprocessing","page":"Pre-processing","title":"XCALibre.UNV3.UNV3D_mesh","text":"UNV3D_mesh(unv_mesh; scale=1, integer_type=Int64, float_type=Float64)\n\nRead and convert 3D UNV mesh file into XCALibre.jl. Note that a limitation of the .unv mesh format is that it only supports the following 3D cells:\n\nTetahedrals\nPrisms\nHexahedrals\n\nInput\n\nunv_mesh – path to mesh file.\n\nOptional arguments\n\nscale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling\ninteger_type - select interger type to use in the mesh (Int32 may be useful on GPU runs) \nfloat_type - select interger type to use in the mesh (Float32 may be useful on GPU runs) \n\n\n\n\n\n","category":"function"},{"location":"user_guide/1_preprocessing/#XCALibre.FoamMesh.FOAM3D_mesh-user_guide-1_preprocessing","page":"Pre-processing","title":"XCALibre.FoamMesh.FOAM3D_mesh","text":"FOAM3D_mesh(mesh_file; scale=1, integer_type=Int64, float_type=Float64)\n\nRead and convert 3D OpenFOAM mesh file into XCALibre.jl. Note that, at present, it is not recommended to run 2D cases using meshes imported using this function.\n\nInput\n\nmesh_file – path to mesh file.\n\nOptional arguments\n\nscale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling\ninteger_type - select interger type to use in the mesh (Int32 may be useful on GPU runs) \nfloat_type - select interger type to use in the mesh (Float32 may be useful on GPU runs) \n\n\n\n\n\n","category":"function"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"These conversion functions will read mesh information and generate a mesh object (Mesh2 or Mesh3 depending on whether the mesh is 2D or 3D, respectively) with the following properties:","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"Mesh3","category":"page"},{"location":"user_guide/1_preprocessing/#XCALibre.Mesh.Mesh3-user_guide-1_preprocessing","page":"Pre-processing","title":"XCALibre.Mesh.Mesh3","text":"struct Mesh3{VC, VI, VF<:AbstractArray{<:Face3D}, VB, VN, SV3, UR} <: AbstractMesh\n cells::VC # vector of cells\n cell_nodes::VI # vector of indices to access cell nodes\n cell_faces::VI # vector of indices to access cell faces\n cell_neighbours::VI # vector of indices to access cell neighbours\n cell_nsign::VI # vector of indices to with face normal correction (1 or -1 )\n faces::VF # vector of faces\n face_nodes::VI # vector of indices to access face nodes\n boundaries::VB # vector of boundaries\n nodes::VN # vector of nodes\n node_cells::VI # vector of indices to access node cells\n get_float::SV3 # store mesh float type\n get_int::UR # store mesh integer type\n boundary_cellsID::VI # vector of indices of boundary cell IDs\nend\n\n\n\n\n\n","category":"type"},{"location":"user_guide/1_preprocessing/#Mesh-limitations-and-requirements","page":"Pre-processing","title":"Mesh limitations and requirements","text":"","category":"section"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"In this section we summarise the key limitations of the mesh loaders presented above, and we also highlight specific requirements. ","category":"page"},{"location":"user_guide/1_preprocessing/#UNV-mesh-files","page":"Pre-processing","title":"UNV mesh files","text":"","category":"section"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"Only ASCII files are supported\nFor 2D simulations the mesh must be contained in the X-Y plane only\nIn 3D only hex, tet and prism elements are supported","category":"page"},{"location":"user_guide/1_preprocessing/#OpenFOAM-mesh-files","page":"Pre-processing","title":"OpenFOAM mesh files","text":"","category":"section"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"Only ASCII files are supported\nBoundary groups are not supported (must be deleted manually or the conversion may fail)\nBoundary information is not preserved (walls, symmetry, etc)\n2D setups are not currently supported (but will be)","category":"page"},{"location":"user_guide/1_preprocessing/#Backend-selection","page":"Pre-processing","title":"Backend selection","text":"","category":"section"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"In XCALibre.jl the mesh object is very important, as it will not only provide geometry information about the simulation/s, but it is also used to automatically dispatch methods to run on the appropriate backend. Therefore, users must first select the backend they wish to use for the simulations, and then \"adapt\" the mesh to use the correct backend. ","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"XCALIbre.jl aims to work with all the backends supported by KernelAbstractions.jl. However, since internally XCALibre.jl uses sparse arrays to reduce its memory footprint, some GPU backends are not currently supported since this functionality is not yet available. Thus, currently only a subset of backends are supported:","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"CPU (multithreaded and tested)\nNVidia GPUs (tested)\nAMD GPUs (not tested - feedback welcome)","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"Selecting a given backend is straight-forward. The examples below show how to assign a backend (CPU or GPU) to the symbol backend and converting the mesh object to run a simulation on the corresponding backend. The converted mesh is assigned to the symbol mesh_dev for clarity.","category":"page"},{"location":"user_guide/1_preprocessing/#CPU-backend","page":"Pre-processing","title":"CPU backend","text":"","category":"section"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"Selecting the CPU backend is straight-forward. See the example below. Notice that CPU() is a backend type provided by KernelAbstractions.jl which we re-export for convenience.","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"CPU Example ","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"mesh = # call function to load mesh e.g. UNV2_mesh, UNV3_mesh or FOAM3D_mesh\nbackend = CPU()\nmesh_dev = mesh # dummy reference to emphasise the mesh in on our chosen dev (or backend)","category":"page"},{"location":"user_guide/1_preprocessing/#GPU-backends","page":"Pre-processing","title":"GPU backends","text":"","category":"section"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"To execute the code on GPUS, the process is also quite simple, but does require a few additional steps.","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"Install the corresponding Julia library that supports your hardware. For NVidia GPUs, the CUDA.jl package is required. For AMD GPUs, the AMDGPU.jl package is needed.\nMove the mesh object to the backend device using the adapt method, which for convenience we re-export from Adapt.jl","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"Example for Nvidia GPU","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"mesh = # call function to load mesh e.g. UNV2_mesh, UNV3_mesh or FOAM3D_mesh\nbackend = CUDABackend()\nmesh_dev = adapt(backend, mesh) # make mesh object backend compatible and move to GPU","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"Example for AMD GPU","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"mesh = # call function to load mesh e.g. UNV2_mesh, UNV3_mesh or FOAM3D_mesh\nbackend = ROCBackend()\nmesh_dev = adapt(backend, mesh) # make mesh object backend compatible and move to GPU","category":"page"},{"location":"user_guide/1_preprocessing/#Hardware-configuration","page":"Pre-processing","title":"Hardware configuration","text":"","category":"section"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"In order to configure the backend the set_hardware function can be used. ","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"set_hardware","category":"page"},{"location":"user_guide/1_preprocessing/#XCALibre.Simulate.set_hardware-user_guide-1_preprocessing","page":"Pre-processing","title":"XCALibre.Simulate.set_hardware","text":"hardware = set_hardware(backend, workgroup)\n\nFunction used to configure the backend.\n\nInputs\n\nbackend named tuple used to specify the backend e.g. CPU(), CUDABackend() or other backends supported by KernelAbstraction.jl\nworkgroup::Int this is an integer specifying the number of workers that cooperate in a parallel run. For GPUs this could be set to the size of the device's warp e.g. workgroup = 32. On CPUs, the default value in KernelAbstractions.jl is currently workgroup = 1024.\n\nOutput\n\nThis function returns a NamedTuple with the fields backend and workgroup which are accessed by internally in XCALibre.jl to execute a given kernel.\n\n\n\n\n\n","category":"function"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"EditURL = \"https://github.com/github.com/mberto79/XCALibre.jl/blob/master/CHANGELOG.md\"","category":"page"},{"location":"release_notes/#Release-notes","page":"Release notes","title":"Release notes","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"The format used for this changelog is based on Keep a Changelog, and this project adheres to Semantic Versioning. Notice that until the package reaches version v1.0.0 minor releases are likely to be breaking. Starting from version v3.0.1 breaking changes will be recorded here. ","category":"page"},{"location":"release_notes/#Version-[v0.3.1](https://github.com/github.com/mberto79/XCALibre.jl/releases/tag/v0.3.1)-2024-10-18","page":"Release notes","title":"Version v0.3.1 - 2024-10-18","text":"","category":"section"},{"location":"release_notes/#Added","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Vastly improved documentation with new examples provided\nChangelog added to record changes more clearly. Record kept in Release notes","category":"page"},{"location":"release_notes/#Fixed","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"The calculation of gradients can be limited for stability. This functionality can be activated by passing the key work argument limit_gradient to the run! function. The implementation has been improved for robustness.","category":"page"},{"location":"release_notes/#Changed","page":"Release notes","title":"Changed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Master branch protected and requires PRs to push changes","category":"page"},{"location":"release_notes/#Breaking","page":"Release notes","title":"Breaking","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"No breaking changes","category":"page"},{"location":"release_notes/#Deprecated","page":"Release notes","title":"Deprecated","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"No functions deprecated","category":"page"},{"location":"release_notes/#Removed","page":"Release notes","title":"Removed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"No functionality has been removed","category":"page"},{"location":"release_notes/#Version-[v0.3.0](https://github.com/github.com/mberto79/XCALibre.jl/releases/tag/v0.3.0)-2024-09-21","page":"Release notes","title":"Version v0.3.0 - 2024-09-21","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"New name - XCALibre.jl - which is now registered in the General Julia registry\nCan do 3D and GPU accelerated simulations\nCan read .unv and OpenFOAM mesh files (3D)\nCan do incompressible and compressible simulations\nRANS and LES models available\nUser-provided functions or neural networks for boundary conditions\nReasonably complete \"user\" documentation now provided\nMade repository public (in v0.2 the work was kept in a private repository and could only do 2D simulations)\nTidy up mesh type definitions by @mberto79 in #5\nAdapt code base to work with new mesh format by @mberto79 in #6\nMesh boundary struct changes PR by @TomMazin in #7\nMesh boundary struct changes PR fix by @TomMazin in #8","category":"page"},{"location":"release_notes/#Version-[v0.2.0](https://github.com/github.com/mberto79/XCALibre.jl/releases/tag/v0.2.0)-2023-01-23","page":"Release notes","title":"Version v0.2.0 - 2023-01-23","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"New mesh format and type implemented that are GPU friendly.\nNo functionality changes","category":"page"},{"location":"release_notes/#Version-[v0.1.0](https://github.com/github.com/mberto79/XCALibre.jl/releases/tag/v0.1.0)-2023-01-23","page":"Release notes","title":"Version v0.1.0 - 2023-01-23","text":"","category":"section"},{"location":"release_notes/#Initial-release","page":"Release notes","title":"Initial release","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"2D implementation of classic incompressible solvers for laminar and turbulent flows:","category":"page"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Framework for equation definition\nSIMPLE nad PISO algorithms\nRead UNV meshes in 2D\nCapability for RANS models\nVarious discretisation schemes available\nPlanned extension to 3D and GPU acceleration!","category":"page"},{"location":"#XCALibre.jl","page":"Home","title":"XCALibre.jl","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"XPU CFD Algorithms and libraries","category":"page"},{"location":"#What-is-XCALibre.jl?","page":"Home","title":"What is XCALibre.jl?","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"","category":"page"},{"location":"","page":"Home","title":"Home","text":"XCALibre.jl (pronounced as the mythical sword Excalibur) is a general purpose Computational Fluid Dynamics (CFD) library for 2D and 3D simulations on structured/unstructured grids using the finite volume method. XCALibre.jl has been designed to act as a platform for developing, testing and using XPU CFD Algorithms and Libraries to give researchers in both academia and industry alike a tool that can be used to test out ideas easily within a framework that offers acceptable performance. To this end, XCALibre.jl has been implemented to offer both CPU multi-threaded capabilities or GPU acceleration using the same codebase (thanks to the unified programming framework provided by KernelAbstractions.jl). XCALibre.jl also offers a friendly API for those users who are interested in running CFD simulations with the existing solvers and models built into XCALibre.jl. ","category":"page"},{"location":"#Why-XCALibre.jl?","page":"Home","title":"Why XCALibre.jl?","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"","category":"page"},{"location":"","page":"Home","title":"Home","text":"For CFD researchers whose research involves developing new numerical methods, turbulence models, or novel CFD methodologies, the development process can be taxing when using commercial packages and their imagination might be constrained by having to adhere to either limited access to internal code functionality or exhausted as they reformulate their ideas to fit within any interfaces provided by the code. There are excellent open source CFD packages where access to functionality or internals is available, however, they are either written in static languages such as C/C++ or dynamic languages such as Python. In static languages, the resulting code is likely highly performant but implementation can be slow and often has a high learning curve (especially if the developer/researcher has no prior knowledge of the language). On the other hand, dynamic languages such as Python can offer a nice development experience at the cost of low runtime or reduced performance. The development of XCALibre.jl was motivated when we discovered the Julia programming language, which promises an interactive and enjoyable implementation experience whilst being able to generate performant code. Thanks to the tools available in the Julia ecosystems (see Main dependencies) it is also possible to generate CPU and GPU code using Julia. As an added bonus, XCALibre.jl can also link readily with the entire Julia ecosystem, including machine learning frameworks such as Flux.jl, Lux.jl, Knet.jl, etc. Thanks to a user-friendly API, ultimately, we hope that XCALibre.jl can be useful to anyone who has an interest in CFD. Enjoy and give us feedback.","category":"page"},{"location":"#Main-features","page":"Home","title":"Main features","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"","category":"page"},{"location":"#Multiple-backends","page":"Home","title":"Multiple backends","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"XCALibre.jl embraces parallelism out-of-the-box on all the compute backends supported by KernelAbstractions.jl. That is,","category":"page"},{"location":"","page":"Home","title":"Home","text":"GPU acceleration on Nvidia, AMD, Intel and Apple hardware\nMulti-threaded runs on CPUs","category":"page"},{"location":"","page":"Home","title":"Home","text":"note: Note\nGPU functionality has only been tested on Nvidia hardware due to availability. Although GPUs from other vendors should also work correctly. Please open an issue if this is not the case so we can investigate. Notice that Apple hardware will not work as expected due to support for sparse matrices not being implemented yet on Metal.jl","category":"page"},{"location":"#Mesh-formats","page":"Home","title":"Mesh formats","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"XCALibre.jl uses its own mesh format to allow the geometry and boundary information to be stored in a format that is suitable for both CPU and GPU calculations. XCALibre.jl does not yet provide mesh generation tools. Therefore, some mesh conversion tools for the following mesh formats are provided:","category":"page"},{"location":"","page":"Home","title":"Home","text":"OpenFOAM meshes for 3D simulations (ascii only)\nUNV meshes for 2D simulations (ascii only)\nUNV meshes for 3D simulations (ascii only)","category":"page"},{"location":"","page":"Home","title":"Home","text":"note: Note\nAlthough the mesh conversion tools for the OpenFOAM format can import grids designed for 2D simulations, it is not recommended to use OpenFOAM grids for 2D cases (at present, support for 2D OpenFOAM grids in progress). Instead, use a 2D grid generated in the .unv format. Also for 2D grids some requirements must be met when defining the geometry (see Mesh generation and requirements)","category":"page"},{"location":"#Solvers","page":"Home","title":"Solvers","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"XCALibre.jl ships with fluid solvers for steady and transient simulations, based on the SIMPLE and PISO algorithms. Currently, the following flow solvers are provided:","category":"page"},{"location":"","page":"Home","title":"Home","text":"Steady incompressible flows\nSteady weakly compressible flows\nTransient incompressible flows\nTransient weakly compressible flows","category":"page"},{"location":"","page":"Home","title":"Home","text":"note: Note\nA solver for highly compressible flows (shock capturing) is currently in testing and will be available in the next major release. Currently the compressible solvers use a sensible energy approach for the energy equation.","category":"page"},{"location":"#Turbulence-and-energy-models","page":"Home","title":"Turbulence and energy models","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"The list of turbulence models available is expected to expand. The following turbulence models are already available in XCALibre.jl:","category":"page"},{"location":"","page":"Home","title":"Home","text":"Reynolds-Averaged Navier-Stokes (RANS)\nk-omega - available in low-Reynolds (wall-resolving) and in high-Reynolds (wall functions) mode\nk-omega LKE - transitional model using the Laminar Kinetic Energy concept to model transition onset\nLarge Eddy Simulation (LES with implicit filtering)\nSmagorinsky - classic eddy-viscosity sub-grid scale Smagorinsky model","category":"page"},{"location":"#Boundary-conditions","page":"Home","title":"Boundary conditions","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"User defined functions\nNeural network defined BCs","category":"page"},{"location":"#Numerical-schemes","page":"Home","title":"Numerical schemes","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Linear - second order schemes for gradients, laplacian and divergence terms\nUpwind - first order upwind-biased scheme for divergence terms\nLUST (divergence) - mixed order upwind-biased scheme for divergence terms\nMidpoint - skew-corrected scheme for gradient calculations\nSteadyState - dummy scheme used to dispatch solvers for operation in steady mode\nEuler - first order semi-implicit time scheme","category":"page"},{"location":"#Simple-API-for-transport-equations","page":"Home","title":"Simple API for transport equations","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Code example","category":"page"},{"location":"","page":"Home","title":"Home","text":"U_eqn = (\n Time{schemes.U.time}(U)\n + Divergence{schemes.U.divergence}(mdotf, U) \n - Laplacian{schemes.U.laplacian}(nueff, U) \n == \n -Source(∇p.result)\n\n ) → VectorEquation(mesh)","category":"page"},{"location":"#Planned-development","page":"Home","title":"Planned development","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"","category":"page"},{"location":"#Capabilities,-solvers,-algorithms,-models,-etc.","page":"Home","title":"Capabilities, solvers, algorithms, models, etc.","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Solver for highly compressible flows (including shockwaves)\nConjugate heat transfer\nk-epsilon turbulence model\nImplement parallel versions of more efficient preconditioners","category":"page"},{"location":"#API","page":"Home","title":"API","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Pass boundary conditions as a separate object. The current approach results in some internal methods/objects not being fully compatible with GPU kernels, and results is some performance degradation (due to unnecessary data transfer between GPU and host device when boundary condition information is needed/applied). A separation of boundary conditions from field data (scalar and vector fields primarily) would address both of these issues.\nThere are no immediate plans for changing the user API\nFine-tuning of the public API expected based on of user feedback","category":"page"},{"location":"#Internals","page":"Home","title":"Internals","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Overhaul of field data. Currently, both vectors and tensors are built on the primitive scalar field object. Whilst this was convenient during the early development stage, the package has reached a level of maturity that makes this approach hard to maintain, adding unneeded complexity when working with tensors. We plan to define separate internals (how tensors are defined and stored in memory). It is anticipated that this will ease the implementation of models working with tensors, give some performance gains and allow all fields to participate in Julia's broadcasting framework.","category":"page"},{"location":"#Main-dependencies","page":"Home","title":"Main dependencies","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"","category":"page"},{"location":"","page":"Home","title":"Home","text":"XCALibre.jl is possible (and relies) on the functionality provided by other packages in the Julia ecosystem. For a full list of direct dependencies please refer to the Project.toml file included with this repository. We are thankful to the teams that have helped develop and maintain every single of our dependencies. Major functionally is provided by the following:","category":"page"},{"location":"","page":"Home","title":"Home","text":"KernelAbstractions.jl - provides a unified parallel programming framework for CPUs and GPUs\nKrylov.jl - provide solvers for linear systems at the heart of XCALibre.jl\nLinearOperators.jl - wrappers for matrices and linear operators\nAtomix.jl - enable atomix operations to ensure race conditions are avoided in parallel kernels\nCUDA.jl, AMD.jl, Metal.jl and OneAPI.jl - not direct dependencies but packages enable GPU usage in Julia","category":"page"},{"location":"#Related-projects","page":"Home","title":"Related projects","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"","category":"page"},{"location":"","page":"Home","title":"Home","text":"There are other wonderful fluid simulation packages available in the Julia ecosystem (please let us know if we missed any):","category":"page"},{"location":"","page":"Home","title":"Home","text":"Oceananigans.jl \nWaterlilly.jl \nTrixi.jl","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/#Advanced:-2D-Aerofoil-inflow-optimisation","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"","category":"section"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/#Introduction","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Introduction","text":"","category":"section"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"Here, a simple optimisation is performed on a 2D NACA0012 aerofoil case. The optimal angle of attack for maximum lift-to-drag ratio is found using BayesianOptimization.jl. This example serves to illustrate both how XCALibre.jl can easily integrate with the Julia ecosystem, and the ease with which post-processing functions can be written.","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/#Optimisation-Setup","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Optimisation Setup","text":"","category":"section"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"For those interested in running this example, the optimisation can be replicated by following these steps.","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/#Install-and-load-modules","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Install and load modules","text":"","category":"section"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"To be able to run this example the following modules need to be installed. This can be done by entering into package mode (using \"]\" in the REPL) and typing the following:","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"add Plots, Distributions, LinearAlgebra, GaussianProcesses, BayesianOptimization","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"This will download and install the required packages. Note that \"CUDA\" must also be added for GPU acceleration. Once installed, the packages can be loaded as follows:","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"using Pkg; # hide\ninstalled = \"Flux\" ∈ keys(Pkg.project().dependencies) # hide\ninstalled && Pkg.rm(\"Flux\", io=devnull) #hide\nPkg.add(\"BayesianOptimization\", io=devnull) # hide\n\nusing XCALibre, BayesianOptimization, Plots\nusing LinearAlgebra, GaussianProcesses, Distributions\n# using CUDA # uncomment to run on GPU\n\"done\"\nnothing # hide","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/#Define-post-processing-functions","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Define post processing functions","text":"","category":"section"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"In order to calculate the lift-to-drag ratio, the pressure and viscous forces over the aerofoil must be calculated and summed. The lift and drag components can then be calculated (noting the rotated inflow vector to allow for different aerofoil angles of attack with the same mesh). A function returning the coefficients of lift and drag (not specifically needed for this example) is also presented for convenience.","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"# Lift to drag ratio calculation\nlift_to_drag(patch::Symbol, model, ρ, nu, α) = begin\n Fp = pressure_force(patch, model.momentum.p, ρ)\n Fv = viscous_force(patch, model.momentum.U, ρ, nu, model.turbulence.nut)\n Ft = Fp + Fv\n Ft = [cos(-α*π/180) -sin(-α*π/180) 0; sin(-α*π/180) cos(-α*π/180) 0; 0 0 1]*Ft # Rotation matrix to account for rotated inflow\n aero_eff = Ft[2]/Ft[1]\n print(\"Aerofoil L/D: \",round(aero_eff,sigdigits = 4))\n return aero_eff\nend \n\n# Aerodynamic coefficient calculation\naero_coeffs(patch::Symbol, chord, velocity, model, ρ, nu, α) = begin\n Fp = pressure_force(patch, model.momentum.p, ρ)\n Fv = viscous_force(patch, model.momentum.U, ρ, nu, model.turbulence.nut)\n Ft = Fp + Fv\n Ft = [cos(-α*π/180) -sin(-α*π/180) 0; sin(-α*π/180) cos(-α*π/180) 0; 0 0 1]*Ft # Rotation matrix to account for rotated inflow\n C_l = 2Ft[2]/(ρ*(velocity[1]^2)*chord*0.001)\n C_d = 2Ft[1]/(ρ*(velocity[1]^2)*chord*0.001)\n print(\"Lift Coefficient: \",round(C_l,sigdigits = 4))\n print(\"\\nDrag Coefficient: \",round(C_d,sigdigits = 4))\n return C_l,C_d\nend ","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/#Import-2D-aerofoil-mesh","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Import 2D aerofoil mesh","text":"","category":"section"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"Next, the aerofoil mesh .unv file must be imported. It must also be adapted to work with the GPU, if desired.","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"grids_dir = pkgdir(XCALibre, \"examples/0_GRIDS\")\ngrid = \"NACAMesh.unv\"\nmesh_file = joinpath(grids_dir, grid)\n\nmesh = UNV2D_mesh(mesh_file, scale=0.001)\nmesh_dev = mesh # running on CPU \n# mesh_dev = adapt(CUDABackend(), mesh) # uncomment to run on GPU","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/#Setup-the-CFD-simulation-as-a-function-to-be-optimised","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Setup the CFD simulation as a function to be optimised","text":"","category":"section"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"The BayesianOptimization.jl package can optimise a Julia function that is passed to it. To interface with XCALibre.jl, the entire CFD simulation setup must simply be wrapped within a function, which can then be passed to the optimiser. The function must take the variable to be changed (angle of attack, in this case) as its input, and must return the desired output (lift-to-drag ratio). Therefore, the post-processing step to calculate lift-to-drag ratio is also wrapped in the same function.","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"function foil_optim(α::Vector{Float64})\n println(\"\\nSelected α value: $(α[1])\")\n\n # Parameters\n chord = 250.0\n Re = 500000\n nu, ρ = 1.48e-5, 1.225\n Umag = (Re*nu)/(chord*0.001) # Calculate velocity magnitude for given Reynolds number\n velocity = [Umag*cos(α[1]*π/180), Umag*sin(α[1]*π/180), 0.0] # Velocity calculation\n νR = 10\n Tu = 0.025\n k_inlet = 3/2*(Tu*norm(velocity))^2\n ω_inlet = k_inlet/(νR*nu)\n\n # Boundary Conditions\n noSlip = [0.0, 0.0, 0.0]\n\n model = Physics(\n time = Steady(),\n fluid = Fluid{Incompressible}(nu = nu),\n turbulence = RANS{KOmega}(),\n energy = Energy{Isothermal}(),\n domain = mesh_dev\n )\n\n @assign! model momentum U ( \n XCALibre.Dirichlet(:inlet, velocity),\n XCALibre.Dirichlet(:bottom, velocity),\n Neumann(:outlet, 0.0),\n Neumann(:top, 0.0),\n Wall(:foil, noSlip)\n )\n\n @assign! model momentum p (\n Neumann(:inlet, 0.0),\n Neumann(:bottom, 0.0),\n XCALibre.Dirichlet(:outlet, 0.0),\n XCALibre.Dirichlet(:top, 0.0),\n Neumann(:foil, 0.0)\n )\n\n @assign! model turbulence k (\n XCALibre.Dirichlet(:inlet, k_inlet),\n Neumann(:outlet, 0.0),\n Neumann(:top, 0.0),\n Neumann(:bottom, 0.0),\n XCALibre.Dirichlet(:foil, 1e-15)\n )\n\n @assign! model turbulence omega (\n XCALibre.Dirichlet(:inlet, ω_inlet),\n Neumann(:outlet, 0.0),\n Neumann(:top, 0.0),\n Neumann(:bottom, 0.0),\n OmegaWallFunction(:foil)\n )\n\n @assign! model turbulence nut (\n Neumann(:inlet, 0.0),\n Neumann(:outlet, 0.0),\n Neumann(:top, 0.0),\n Neumann(:bottom, 0.0), \n XCALibre.Dirichlet(:foil, 0.0)\n )\n\n schemes = (\n U = set_schemes(divergence=Upwind, gradient=Midpoint),\n p = set_schemes(divergence=Upwind),\n k = set_schemes(divergence=Upwind, gradient=Midpoint),\n omega = set_schemes(divergence=Upwind, gradient=Midpoint)\n )\n\n solvers = (\n U = set_solver(\n model.momentum.U;\n solver = BicgstabSolver, # BicgstabSolver, GmresSolver\n preconditioner = ILU0(), # Jacobi # ILU0\n convergence = 1e-7,\n relax = 0.6,\n rtol = 1e-1,\n ),\n p = set_solver(\n model.momentum.p;\n solver = GmresSolver, # change to BicgstabSolver for GPU runs\n preconditioner = LDL(), # change to Jacobi() for GPU runs\n convergence = 1e-7,\n relax = 0.2,\n rtol = 1e-2,\n ),\n k = set_solver(\n model.turbulence.k;\n solver = BicgstabSolver,\n preconditioner = ILU0(), # change to Jacobi() for GPU runs\n convergence = 1e-7,\n relax = 0.6,\n rtol = 1e-1,\n ),\n omega = set_solver(\n model.turbulence.omega;\n solver = BicgstabSolver,\n preconditioner = ILU0(), # change to Jacobi() for GPU runs\n convergence = 1e-7,\n relax = 0.6,\n rtol = 1e-1,\n )\n )\n\n runtime = set_runtime(iterations=500, write_interval=500, time_step=1)\n runtime = set_runtime(iterations=20, write_interval=-1, time_step=1) # hide\n\n hardware = set_hardware(backend=CPU(), workgroup=1024)\n # hardware = set_hardware(backend=CUDABackend(), workgroup=32) # uncomment to run on GPU\n\n config = Configuration(solvers=solvers, schemes=schemes, runtime=runtime, hardware=hardware)\n\n GC.gc()\n\n initialise!(model.momentum.U, velocity)\n initialise!(model.momentum.p, 0.0)\n initialise!(model.turbulence.k, k_inlet)\n initialise!(model.turbulence.omega, ω_inlet)\n initialise!(model.turbulence.nut, k_inlet/ω_inlet)\n\n residuals = run!(model, config)\n\n # Residuals Graph\n let\n iterations = 1:length(residuals.Ux)\n plot(; xlims=(0,runtime.iterations), ylims=(1e-10,0))\n plot!(iterations, residuals.Ux, yscale=:log10, label=\"Ux\")\n plot!(iterations, residuals.Uy, yscale=:log10, label=\"Uy\")\n plot!(iterations, residuals.p, yscale=:log10, label=\"p\")\n end\n\n aero_eff = lift_to_drag(:foil, model, ρ, nu, α[1]) # Calculates lift-to-drag ratio\n\n # relocate XCALibre.jl vtk output files\n aero_eff_out = round(aero_eff,digits=3)\n α_out = round(α[1],digits=3)\n vtk_files = filter(x->endswith(x,\".vtk\"), readdir())\n for file ∈ vtk_files\n dest = \"vtk_results/LD_Ratio = $(aero_eff_out), Alpha = $(α_out).vtk\"\n mv(file, dest, force=true)\n end\n\n return aero_eff\nend","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"Note that this code saves a single .vtk file of the last CFD iteration each time the optimiser samples the function. This .vtk file is then automatically renamed with that sample's results, and sorted into a /vtk_results subfolder (which must be created before the optimisation is run).","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/#Configure-and-run-the-Bayesian-optimisation","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Configure and run the Bayesian optimisation","text":"","category":"section"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"Finally, the Bayesian optimiser must be configured before the optimisation can be performed. This example follows the BayesianOptimization.jl default configuration for the Gaussian process surrogate model, limiting input dimensions to 1 (the angle of attack). The surrogate model is then set to be optimised every 10 iterations. The inputs are limited to between 0 and 15 degrees. The problem is configured as a maximisation problem, with an initial sample period of 10 iterations and 50 maximum allowed iterations. The final line of the following code block is then run to perform the optimisation.","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"# Bayesian Optimisation (using BayesianOptimization.jl)\nisdir(\"vtk_results\") || mkdir(\"vtk_results\")\n\n# Initialises the Gaussian process surrogate model\nmodel = ElasticGPE(1, #1 input dimension (α)\n mean = MeanConst(0.0),\n kernel = SEArd([0.0], 5.0),\n capacity = 3000)\nset_priors!(model.mean, [Normal(1, 2)])\n\nmodeloptimizer = MAPGPOptimizer(every = 10, maxeval = 40) # Optimises the Gaussian process every 10 iterations\n\n# Optimisation Case Setup\nopt = BOpt(foil_optim, # Function to be optimised - encloses the CFD case\n model, # Gaussian process surrogate model defined above\n UpperConfidenceBound(),\n modeloptimizer, # Model optimiser defined above\n [0.0], [15.0], # Minimum and maximum α constraints \n repetitions = 1, # No repititions as CFD data is not noisy\n maxiterations = 50, # Maximum iterations\n sense = Max, # Maximisation problem\n initializer_iterations = 10, # No. of initial random samples\n verbosity = Progress)\n\nopt = BOpt(foil_optim, # hide\n model, # hide\n UpperConfidenceBound(),\n modeloptimizer, # hide\n [0.0], [15.0], # hide \n repetitions = 1, # hide\n maxiterations = 5, # hide\n sense = Max, # hide\n initializer_iterations = 2, # hide\n verbosity = Progress) # hide\n\nresult = boptimize!(opt) # Runs the optimisation procedure\n\nusing Pkg; Pkg.rm(\"BayesianOptimization\", io=devnull) # hide\n\nnothing # hide\n\"done\"","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/#Example-Optimisation-Results","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Example Optimisation Results","text":"","category":"section"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"using Plots\n\nalpha_in = [2.8125, 10.3125, 14.0625, 6.5625, 4.6875, 12.1875, 8.4375, 0.9375, 1.40625, 8.90625, 6.779625965220729, 6.77968472431049, 6.7797314426495054, 6.77976068608606, 6.779786764662929, 6.7798083933298825, 6.779824452011973, 6.779839305833187, 6.779851985125758, 6.779864532650939, 6.7799660687298875, 6.7799701746255465, 6.779970295228141, 6.77997431759257, 6.779983415563036, 6.7799837395243685, 6.779983935151504, 6.779987648165338, 6.779990776177305, 6.779984858208577, 6.779969245384916, 6.779974853301299, 6.77996639334403, 6.779975137863877, 6.77996588653741, 6.7799787767924995, 6.779980463194295, 6.779982645115559, 6.779984123782711, 6.779985756585738, 6.780065815803057, 6.780066942543943, 6.780081725020423, 6.780063344501922, 6.780112623430458, 6.780065445290062, 6.780112028947505, 6.780088979322628, 6.78008982572309, 6.780090816324224, 6.852129317102274, 15.0, 6.755034985210623, 6.761466922699926, 6.766457867346942, 6.7701094609872365, 6.772562674953314, 6.774340290374087, 6.775562986686579, 6.776273742423618, 13.474012044415156, 12.361866906130413, 8.195985025525076, 5.334843671454779, 4.308592858166856, 2.6894603132241217, 2.858340694577276, 3.9867902638528654, 9.814658247047763, 1.932233467710785, 14.719640732627886, 9.682863385862596, 10.90134524899545, 12.877578634990728, 4.343344626917736]\n\naeroeff_out = [12.28662476568946, 15.996066573412422, 12.086660285887401, 18.095030718054726, 16.684759975625713, 14.101557983835567, 17.514651235093766, 4.6215245234556415, 6.787202918357864, 17.203294519181156, 18.1170435016882, 18.116757960309155, 18.117178450363166, 18.116980351431625, 18.116775418289507, 18.117332562156935, 18.116999501527403, 18.116946514089875, 18.11690912331511, 18.117181857003985, 18.117047847973517, 18.117081881041535, 18.117198176532845, 18.1172141350244, 18.117151423600156, 18.11701162747253, 18.117196229004325, 18.117302063623146, 18.117642349199684, 18.117122449593182, 18.11704990315254, 18.11745842192904, 18.1171359979369, 18.117344466780477, 18.117133217540022, 18.117057989337816, 18.116782216736464, 18.11721596351545, 18.117119958415003, 18.117170377304056, 18.117352502260307, 18.117163143088185, 18.117300338277143, 18.117066185177936, 18.11722389239519, 18.11713622798166, 18.116993107467152, 18.116991271960444, 18.117083277331048, 18.11714354615574, 18.097362115270933, 11.114298598972901, 18.108943497471795, 18.108780485320025, 18.108790519425263, 18.109037299059956, 18.108833040375593, 18.108767451351685, 18.1084445814309, 18.10857933786505, 12.690741887963036, 9.845212599830074, 17.636745115382112, 17.47574058124154, 16.058798546800677, 11.877430534208012, 12.4272778301407, 15.41709457750829, 16.462303743958294, 9.053215612096695, 11.382140258128832, 16.578166324395593, 15.519321514686421, 13.356080135399708, 16.116845772757824]\n\niteration = [1:25;]\n\nscatter(\n alpha_in[1:25],aeroeff_out[1:25],xlabel=\"Angle of Attack, α [°]\", ylabel=\"Aerodynamic Efficiency, Cl/Cd [-]\",label=\"\",\n legend=true,\n # marker=(:cross,4),\n zcolor=iteration,\n c=:linear_ternary_red_0_50_c52_n256,\n colorbar_title=\"Optimiser Iteration\",\n xlims=[0,15.15], ylims=[0,20], clim=(0,25),\n frame_style=:box\n )\n\nmax_exp_alpha = ([6.479310344827586,6.479310344827586],[0,19])\n\nplot!(max_exp_alpha,line=(:dash,:black),label=\"\")\n\nplot!(\n sort(alpha_in[1:50]), aeroeff_out[sortperm(alpha_in[1:50])],\n label=\"\", line=(:solid,:black,0.5)\n )\nannotate!(8.25, 2.5, Plots.text(\"Experimental\\noptimum α\", 10))\nsavefig(\"optimisation_iterations_vs_experiment.svg\"); nothing # hide\nnothing\n\nfig1 = scatter(\n iteration[1:15],aeroeff_out[1:15],xlabel=\"Optimiser Iteration [-]\", ylabel=\"Aerodynamic Efficiency, Cl/Cd [-]\",label=\"\",\n ylim = (0,20),\n legend=true,# marker=(:cross,4,:black)\n ) #L/D against iteration number graph\n\nfig2 = scatter(iteration[1:15],alpha_in[1:15],xlabel=\"Optimiser Iteration [-]\", ylabel=\"Angle of Attack, α [°]\",label=\"\",\nylim = (0,15),\nlegend=true, #marker=(:cross,4,:black)\n) #α against iteration number graph\n\n\n# exp_alpha = [0.1724137931034484, 2.068965517241379, 4.482758620689655, 6.479310344827586, 8.441064638783269, 10.344827586206897, 11.206896551724139, 12.551020408163264, 14.13793103448276]\n# exp_aeroeff = [8.872377622377625, 36.656207598371786, 52.94361173623201, 53.41160498793243, 53.10395622895623, 50.95347249317206, 48.78298051001016, 4.906565656565657, 3.354085331846068]\n# fig2 = scatter(exp_alpha,exp_aeroeff,xlabel=\"Angle of Attack, α [°]\", ylabel=\"Aerodynamic Efficiency, Cl/Cd [-]\",title=\"Experimental Data (NACA0012, Re=500,000)\",\n# legend=false,marker=(:circle,4,:black)) #Experimental data\n\nplot(fig1, fig2, frame_style=:box)\n\nsavefig(\"optimisation_vs_iteration.svg\"); nothing # hide\nnothing\n\n# output\n","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"(Image: )","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"(Image: )","category":"page"},{"location":"examples/02_2d-incompressible-transient-cylinder/#Verification:-2D-Unsteady-incompressible-cylinder","page":"Verification: 2D Unsteady incompressible cylinder","title":"Verification: 2D Unsteady incompressible cylinder","text":"","category":"section"},{"location":"examples/02_2d-incompressible-transient-cylinder/#Introduction","page":"Verification: 2D Unsteady incompressible cylinder","title":"Introduction","text":"","category":"section"},{"location":"examples/02_2d-incompressible-transient-cylinder/","page":"Verification: 2D Unsteady incompressible cylinder","title":"Verification: 2D Unsteady incompressible cylinder","text":"","category":"page"},{"location":"examples/02_2d-incompressible-transient-cylinder/","page":"Verification: 2D Unsteady incompressible cylinder","title":"Verification: 2D Unsteady incompressible cylinder","text":"To verify the correct implementation of the laminar flow solver, a simulation of a transient, laminar and incompressible cylinder was carried out and compared with OpenFOAM. The results show that the solver in XCALibre.jl generates similar results compared to the laminar solver in OpenFOAM. Simulation set up, grid and OpenFOAM case will all be made available here.","category":"page"},{"location":"examples/02_2d-incompressible-transient-cylinder/#Results","page":"Verification: 2D Unsteady incompressible cylinder","title":"Results","text":"","category":"section"},{"location":"examples/02_2d-incompressible-transient-cylinder/","page":"Verification: 2D Unsteady incompressible cylinder","title":"Verification: 2D Unsteady incompressible cylinder","text":"(Image: vorticity comparison with OpenFOAM)","category":"page"},{"location":"examples/02_2d-incompressible-transient-cylinder/#Simulation-setup","page":"Verification: 2D Unsteady incompressible cylinder","title":"Simulation setup","text":"","category":"section"},{"location":"examples/02_2d-incompressible-transient-cylinder/","page":"Verification: 2D Unsteady incompressible cylinder","title":"Verification: 2D Unsteady incompressible cylinder","text":"For those interested in running this case, this simulation can be replicated as follows.","category":"page"},{"location":"examples/02_2d-incompressible-transient-cylinder/","page":"Verification: 2D Unsteady incompressible cylinder","title":"Verification: 2D Unsteady incompressible cylinder","text":"\nusing XCALibre\n# using CUDA # uncomment to run on GPU\n\ngrids_dir = pkgdir(XCALibre, \"examples/0_GRIDS\")\ngrid = \"cylinder_d10mm_5mm.unv\"\nmesh_file = joinpath(grids_dir, grid)\n\nmesh = UNV2D_mesh(mesh_file, scale=0.001)\n\nmesh_dev = mesh\n# mesh_dev = adapt(CUDABackend(), mesh) # uncomment to run on GPU\n\n# Inlet conditions\nvelocity = [0.5, 0.0, 0.0]\nnoSlip = [0.0, 0.0, 0.0]\nnu = 1e-3\nRe = (0.2*velocity[1])/nu\n\nmodel = Physics(\n time = Transient(),\n fluid = Fluid{Incompressible}(nu = nu),\n turbulence = RANS{Laminar}(),\n energy = Energy{Isothermal}(),\n domain = mesh_dev\n )\n\n@assign! model momentum U ( \n Dirichlet(:inlet, velocity),\n Neumann(:outlet, 0.0),\n Wall(:cylinder, noSlip),\n Neumann(:bottom, 0.0),\n Neumann(:top, 0.0)\n)\n\n@assign! model momentum p (\n Neumann(:inlet, 0.0),\n Dirichlet(:outlet, 0.0),\n Neumann(:cylinder, 0.0),\n Neumann(:bottom, 0.0),\n Neumann(:top, 0.0)\n)\n\nsolvers = (\n U = set_solver(\n model.momentum.U;\n solver = BicgstabSolver, # BicgstabSolver, GmresSolver\n preconditioner = Jacobi(),\n convergence = 1e-7,\n relax = 1.0,\n rtol = 1e-4,\n atol = 1e-5\n ),\n p = set_solver(\n model.momentum.p;\n solver = CgSolver, # BicgstabSolver, GmresSolver\n preconditioner = Jacobi(), #NormDiagonal(),\n convergence = 1e-7,\n relax = 0.8,\n rtol = 1e-4,\n atol = 1e-5\n )\n)\n\nschemes = (\n U = set_schemes(time=Euler, divergence=LUST, gradient=Midpoint),\n p = set_schemes(time=Euler, gradient=Midpoint)\n)\n\n\nruntime = set_runtime(iterations=1000, write_interval=50, time_step=0.005) \nruntime = set_runtime(iterations=1, write_interval=-1, time_step=0.005) # hide\n\n\nhardware = set_hardware(backend=CPU(), workgroup=1024)\n# hardware = set_hardware(backend=CUDABackend(), workgroup=32) # uncomment to run on GPU\n\nconfig = Configuration(\n solvers=solvers, schemes=schemes, runtime=runtime, hardware=hardware)\n\nGC.gc(true)\n\ninitialise!(model.momentum.U, velocity)\ninitialise!(model.momentum.p, 0.0)\n\nresiduals = run!(model, config)","category":"page"}] +[{"location":"user_guide/4_runtime_and_solvers/#Runtime-and-solvers","page":"Runtime and solvers","title":"Runtime and solvers","text":"","category":"section"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"Final steps before launching a simulation","category":"page"},{"location":"user_guide/4_runtime_and_solvers/#Runtime-setup","page":"Runtime and solvers","title":"Runtime setup","text":"","category":"section"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"At this stage in the setup workflow, the user defines the runtime information to configure the runtime behaviour of the flow solver, including the time step to use (only meaningful for transient solutions), as well as information about how often to write results to disk. XCALibre.jl provides a the set_runtime to perform this operation. ","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"set_runtime","category":"page"},{"location":"user_guide/4_runtime_and_solvers/#XCALibre.Solve.set_runtime-user_guide-4_runtime_and_solvers","page":"Runtime and solvers","title":"XCALibre.Solve.set_runtime","text":"set_runtime(; \n # keyword arguments\n iterations::I, \n write_interval::I, \n time_step::N\n ) where {I<:Integer,N<:Number} = begin\n \n # returned `NamedTuple``\n (\n iterations=iterations, \n dt=time_step, \n write_interval=write_interval)\nend\n\nThis is a convenience function to set the top-level runtime information. The inputs are all keyword arguments and provide basic information to flow solvers just before running a simulation.\n\nInput arguments\n\niterations::Integer specifies the number of iterations in a simulation run.\nwrite_interval::Integer defines how often simulation results are written to file (on the current working directory). The interval is currently based on number of iterations. Set to -1 to run without writing results to file.\ntime_step::Number the time step to use in the simulation. Notice that for steady solvers this is simply a counter and it is recommended to simply use 1.\n\nExample\n\nruntime = set_runtime(\n iterations=2000, time_step=1, write_interval=2000)\n\n\n\n\n\n","category":"function"},{"location":"user_guide/4_runtime_and_solvers/#Configuration-object","page":"Runtime and solvers","title":"Configuration object","text":"","category":"section"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"Once all the simulation configuration information has been defined, from discretisation scheme to runtime information, all settings must be wrapped in a Configuration object. The definition, including expected input arguments, for the Configuration object are detailed below.","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"Configuration","category":"page"},{"location":"user_guide/4_runtime_and_solvers/#XCALibre.Simulate.Configuration-user_guide-4_runtime_and_solvers","page":"Runtime and solvers","title":"XCALibre.Simulate.Configuration","text":"@kwdef struct Configuration{SC,SL,RT,HW}\n schemes::SC\n solvers::SL\n runtime::RT\n hardware::HW\nend\n\nThe Configuration type is passed to all flow solvers and provides all the relevant information to run a simulation. \n\nInputs\n\nschemes::NamedTuple this keyword argument is used to pass distretisation scheme information to flow solvers. See Numerical setup for details.\nsolvers::NamedTuple this keyword argument is used to pass the configurations for the linear solvers for each field information to flow solvers. See Runtime and solvers for details.\nruntime::NamedTuple this keyword argument is used to pass runtime information to the flow solvers. See Runtime and solvers for details.\nhardware::NamedTuple this keyword argument is used to pass the hardware configuration and backend settings to the flow solvers. See Pre-processing for details.\n\nExample\n\nconfig = Configuration(\n solvers=solvers, schemes=schemes, runtime=runtime, hardware=hardware)\n\n\n\n\n\n","category":"type"},{"location":"user_guide/4_runtime_and_solvers/#Initialising-fields","page":"Runtime and solvers","title":"Initialising fields","text":"","category":"section"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"The last (optional) step before running the simulation is to provide an initial guess for all the fields being solved. Although this step is optional, in most cases the flow solvers will perform better when initialised. To set an initial value for a field, the initialise! function is provided, which assigns a starting value to a given field.","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"initialise!","category":"page"},{"location":"user_guide/4_runtime_and_solvers/#XCALibre.Fields.initialise!-user_guide-4_runtime_and_solvers","page":"Runtime and solvers","title":"XCALibre.Fields.initialise!","text":"function initialise!(field, value) # dummy function for documentation\n # Assign `value` to field in-place\n nothing\nend\n\nThis function will set the given field to the value provided in-place. Useful for initialising fields prior to running a simulation.\n\nInput arguments\n\nfield specifies the field to be initialised. The field must be either a AbractScalarField or AbstractVectorField\nvalue defines the value to be set. This should be a scalar or vector (3 components) depending on the field to be modified e.g. for an AbstractVectorField we can specify as value=[10,0,0]\n\nNote: in most cases the fields to be modified are stored within a physics model i.e. a Physics object. Thus, the argument value must fully qualify the model. For example, if we have created a Physics model named mymodel to set the velocity field, U, we would set the argument field to mymodel.momentum.U. See the example below.\n\nExample\n\ninitialise!(mymodel.momentum.U, [2.5, 0, 0])\ninitialise!(mymodel.momentum.p, 1.25)\n\n\n\n\n\n","category":"function"},{"location":"user_guide/4_runtime_and_solvers/#Launching-flow-solvers","page":"Runtime and solvers","title":"Launching flow solvers","text":"","category":"section"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"In XCALibre.jl the run! function is used to start a simulation, which will dispatch to the appropriate flow solver for execution. Once the simulation is complete a NamedTuple containing residual information is returned for users to explore the convergence history of the simulation. ","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"run!()","category":"page"},{"location":"user_guide/4_runtime_and_solvers/#XCALibre.Solvers.run!-Tuple{}-user_guide-4_runtime_and_solvers","page":"Runtime and solvers","title":"XCALibre.Solvers.run!","text":"function run!(\n model::Physics, config; \n limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0\n )\n\n # here an internal function is used for solver dispatch\n return residuals\nend\n\nThis is the top level API function to initiate a simulation. It uses the user-provided model defined as a Physics object to dispatch to the appropriate solver.\n\nDispatched flow solvers\n\nSteady incompressible (SIMPLE algorithm for coupling)\nTransient incompressible (PISO algorithm for coupling)\nSteady weakly compressible (SIMPLE algorithm for coupling)\nTransient weakly compressible (PISO algorithm for coupling)\n\nInput arguments\n\nmodel reference to a Physics model defined by the user.\nconfig Configuration structure defined by the user with solvers, schemes, runtime and hardware structures configuration details.\nlimit_gradient flag used to activate gradient limiters in the solver (default = false)\npref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only (default = nothing)\nncorrectors number of non-orthogonality correction loops (default = 0)\ninner_loops number to inner loops used in transient solver based on PISO algorithm (default = 0)\n\nOutput\n\nThis function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux). The fields available within the returned residuals tuple depend on the solver used. For example, for an incompressible solver, a x-momentum equation residual can be retrieved accessing the Ux field i.e. residuals.Ux. Look at reference guide for each dispatch method to find out which fields are available.\n\nExample\n\nresiduals = run!(model, config) \n\n# to access the pressure residual\n\nresiduals.p \n\n\n\n\n\n","category":"method"},{"location":"user_guide/4_runtime_and_solvers/#Restarting-simulations","page":"Runtime and solvers","title":"Restarting simulations","text":"","category":"section"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"It should be noted that when running a simulation with run!, the solution fields in the Physics model are mutated. Thus, running the simulation from the previous solution is simply a matter of reissuing the run! function. At present, this has the side effect of overwriting any existing solution files (.vtk or .vtu). Users must be aware of this behaviour.","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"In some cases, it may be desirable to solve a problem with a steady solver and use the solution to run transient simulations. This is possible using the change function.","category":"page"},{"location":"user_guide/4_runtime_and_solvers/","page":"Runtime and solvers","title":"Runtime and solvers","text":"XCALibre.ModelPhysics.change","category":"page"},{"location":"user_guide/4_runtime_and_solvers/#XCALibre.ModelPhysics.change-user_guide-4_runtime_and_solvers","page":"Runtime and solvers","title":"XCALibre.ModelPhysics.change","text":"change(model::Physics, property, value) => updatedModel::Physics\n\nA convenience function to change properties of an exisitng Physics model.\n\nInput arguments\n\nmodel::Physics a Physics model to modify\nproperty is a symbol specifying the property to change \nvalue is the new setting for the specified property\n\nOutput\n\nThis function return a new Physics object\n\nExample\n\nTo change a model to run a transient simulation e.g. after converging in steady state\n\nmodelTransient = change(model, :time, Transient())\n\n\n\n\n\n","category":"function"},{"location":"examples/04_2d-inflow-using-Flux/#Advanced:-2D-inflow-using-Flux.jl","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"","category":"section"},{"location":"examples/04_2d-inflow-using-Flux/#Introduction","page":"Advanced: 2D inflow using Flux.jl","title":"Introduction","text":"","category":"section"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"In this example a simple neural network is constructed and used to define an inlet boundary condition for the x-component of the velocity vector. This example serves to illustrate how other packages from the Julia ecosystem can be integrated into XCALibre.jl to extend its functionality. In particular, this example will show how to build a basic neural network using Flux.jl to represent a parabolic velocity profile and how this neural network can be used to define an inlet condition in XCALibre.jl. ","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"The boundary condition is injected into the solution using the builtin DirichletFunction boundary condition, which is designed to pass arbitrary Julia functions to a given boundary.","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"XCALibre.Discretise.DirichletFunction","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/#XCALibre.Discretise.DirichletFunction-examples-04_2d-inflow-using-Flux","page":"Advanced: 2D inflow using Flux.jl","title":"XCALibre.Discretise.DirichletFunction","text":"DirichletFunction(ID, value) <: AbstractDirichlet\n\nDirichlet boundary condition defined with user-provided function.\n\nInput\n\nID Boundary name provided as symbol e.g. :inlet\nvalue Custom function for Dirichlet boundary condition.\n\nFunction requirements\n\nThe function passed to this boundary condition must have the following signature:\n\nf(coords, time, index) = SVector{3}(ux, uy, uz)\n\nWhere, coords is a vector containing the coordinates of a face, time is the current time in transient simulations (and the iteration number in steady simulations), and index is the local face index (from 1 to N, where N is the number of faces in a given boundary). The function must return an SVector (from StaticArrays.jl) representing the velocity vector. \n\n\n\n\n\n","category":"type"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"In this example, instead of passing a Julia function, the boundary velocity profile will be given via a simple neural network. ","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"note: Note\nThis interface is experimental and subject to change. Currently it can only be used for vectors.","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/#Set-up-steps","page":"Advanced: 2D inflow using Flux.jl","title":"Set up steps","text":"","category":"section"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/#Install-and-load-modules","page":"Advanced: 2D inflow using Flux.jl","title":"Install and load modules","text":"","category":"section"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"To be able to run this example the following modules need to be installed. This can be done by entering into package mode (using \"]\" in the REPL) and typing the following:","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"add Plots, XCALibre, Flux, StaticArrays, LinearAlgebra, KernelAbstractions, Adapt","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"This will download and install the required packages. Once installed, the packages can be loaded as follows:","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"# using Logging; Logging.disable_logging(Logging.Info) # hide\nusing Pkg; # hide\ninstalled = \"BayesianOptimization\" ∈ keys(Pkg.project().dependencies) # hide\ninstalled && Pkg.rm(\"BayesianOptimization\", io=devnull) #hide\nPkg.add(\"Flux\", io=devnull) # hide\n\nusing Plots\nusing XCALibre\nusing Flux\nusing StaticArrays\nusing Statistics\nusing LinearAlgebra\nusing KernelAbstractions\nnothing # hide","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/#Build-a-neural-network-model","page":"Advanced: 2D inflow using Flux.jl","title":"Build a neural network model","text":"","category":"section"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"Next, a neural network will be created to return a parabolic velocity profile. In this case, the training data will be generated using an analytical expression. ","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"\nactual(y) = begin\n H = 1 # channel height\n H2 = H/2\n h = y - H2\n vx = (1 - (h/H2)^2)\n return vx\nend\n","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"And define a simple 2-layer neural network to model the inlet function:","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"inflowNetwork = Chain(\n Dense(1 => 6, sigmoid),\n Dense(6 => 1)) |> f64","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"Now, we generate the training and testing datasets using the analytical function. The neural network is not yet trained but it can already be used (of course, the prediction is not yet very useful). The various datasets, and initial model predictions are shown in the figure below.","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"\ny_actual = [0:0.01:1;] # array of y-values for plotting\nvx_actual = actual.(y_actual)\n\n# Generate training dataset\ny_train = hcat(rand(0:(0.1/100):0.1, 100)...)./0.1\nvx_train = actual.(y_train)\n\n# Test locations selected randomly\ny_test = hcat(rand(0:(0.1/100):0.1, 100)...)./0.1\nvx_untrained = inflowNetwork(y_test)\n\nplot(\n y_actual, vx_actual, label=\"Actual\", \n frame_style=:box, foreground_color_legend = nothing,\n xlabel=\"Dimensionless distance\", ylabel=\"Normalised velocity\")\nscatter!(y_train', vx_train', label=\"Training data\")\nscatter!(y_test', vx_untrained', label=\"Untrained output\")\nsavefig(\"flux_comparison_untrained.svg\"); nothing # hide","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"(Image: )","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"The next step is to train the model as shown below. Finally, to make sure that the model has trained correctly, it is tested with at randomly generated points and the output compared with the analytical function as shown in the figure below.","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"\nloss(inflowNetwork, y, vx) = mean(abs2.(inflowNetwork(y) .- vx))\n\nopt = Flux.setup(Adam(), inflowNetwork)\ndata = [(y_train, vx_train)]\nfor epoch in 1:20000\n Flux.train!(loss, inflowNetwork, data, opt)\nend\nloss(inflowNetwork, data[1]...,)\n\nvx_trained = inflowNetwork(y_test)\n\n\nplot(\n y_actual, vx_actual, label=\"Actual\", \n frame_style=:box, foreground_color_legend = nothing,\n xlabel=\"Dimensionless distance\", ylabel=\"Normalised velocity\")\nscatter!(y_test', vx_trained', label=\"Trained output\")\nsavefig(\"flux_comparison.svg\"); nothing # hide","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"(Image: )","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/#Define-inlet-condition-and-interface","page":"Advanced: 2D inflow using Flux.jl","title":"Define inlet condition and interface","text":"","category":"section"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"The next step is to define some interfaces to allow passing the model as if it was a simple Julia function. This requires only 3 key ingredients. First, a struct is defined that will contain any user data needed as well as the model itself. In this case, the following structure has been used (but users are completely free to define their own structures). The only requirements are that the structure should be a subtype of XCALibreUserFunctor and it must contain the steady property.","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"struct Inflow{F,I,O,N,V,T} <: XCALibreUserFunctor\n U::F # maximum velocity\n H::F # inlet height\n input::I # vector to hold input coordinates\n output::O # vector to hold model inferred values\n network::N # model itself\n xdir::V # struct used to define x-direction unit vector\n steady::T # required field! (Bool)\nend","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"Second, the struct above is used as a functor, defined following the requirements set by the DirichletFunction boundary condition. Essentially, this allows for external data to be stored in the Inflow object, which is then made \"callable\" to behave as a simple Julia function that returns the velocity vector at a given coordinate (vec) and time (t).","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"(bc::Inflow)(vec, t, i) = begin\n velocity = @view bc.output[:,i]\n return @inbounds SVector{3}(velocity[1], velocity[2], velocity[3])\nend","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"The third step is to define a new method for the update_user_boundary! function from the Discretise module. This function offers a mechanism to update the internals of the previously defined structure by calling the user-provided neural network model. In this particular example, this is not required since the boundary values are not changing in time (it would have been sufficient to do a single inference round and to simply store the values inside the Inflow struct). However, this function is implemented here to illustrate the interface, and provide an example of a user-defined kernel. Notice that, in this particular example, the only purpose of this function is to scale the velocity field inferred by the neural network (since it was defined with values between 0 and 1).","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"\nXCALibre.Discretise.update_user_boundary!(\n BC::DirichletFunction{I,V}, faces, cells, facesID_range, time, config\n ) where{I,V<:Inflow} = \nbegin\n\n (; hardware) = config\n (; backend, workgroup) = hardware\n\n kernel_range = length(facesID_range)\n kernel! = _update_user_boundary!(backend, workgroup, kernel_range)\n kernel!(BC, faces, cells, facesID_range, time, ndrange=kernel_range)\n KernelAbstractions.synchronize(backend)\n\n (; output, input, U, network, xdir) = BC.value\n output .= U.*network(input).*xdir # convert to vector\nend\n\n@kernel function _update_user_boundary!(BC, faces, cells, facesID_range, time)\n i = @index(Global)\n startID = facesID_range[1]\n fID = i + startID - 1\n coords = faces[fID].centre\n BC.value.input[i] = coords[2]/BC.value.H # scale coordinates\nend\n","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/#Create-an-instance-of-Inflow","page":"Advanced: 2D inflow using Flux.jl","title":"Create an instance of Inflow","text":"","category":"section"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"An instance of the Inflow object is now created. Notice that the input and output fields contain vectors to hold the boundary face information, thus, they must be of the same size as the number of boundary faces. The mesh is, therefore, loaded first.","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"\ngrids_dir = pkgdir(XCALibre, \"examples/0_GRIDS\")\ngrid = \"backwardFacingStep_5mm.unv\"\nmesh_file = joinpath(grids_dir, grid)\n\nmesh = UNV2D_mesh(mesh_file, scale=0.001)\n\nnfaces = mesh.boundaries[1].IDs_range |> length","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"The Inflow functor is now constructed.","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"\nU = 0.5 # maximum velocity\nH = 0.1 # inlet height\ninput = zeros(1,nfaces)\ninput .= (H/2)/H\noutput = U.*inflowNetwork(input).*[1 0 0]'\n@view output[:,2]\n\ninlet_profile= Inflow(\n 0.5,\n 0.1,\n input,\n output,\n inflowNetwork,\n [1,0,0],\n true\n)\n","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/#Run-simulation","page":"Advanced: 2D inflow using Flux.jl","title":"Run simulation","text":"","category":"section"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"The final step is simply to set up and run a simulation in XCALibre.jl. Notice that this does not require any special considerations, only to remember to use the DirichletFunction boundary condition when setting the inlet velocity. The inlet_profile functor object is then passed to the boundary. ","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"\nvelocity = [0.5, 0.0, 0.0]\nnu = 1e-3\nRe = velocity[1]*0.1/nu\n\nmodel = Physics(\n time = Steady(),\n fluid = Fluid{Incompressible}(nu = nu),\n turbulence = RANS{Laminar}(),\n energy = Energy{Isothermal}(),\n domain = mesh\n )\n\n@assign! model momentum U (\n DirichletFunction(:inlet, inlet_profile), # Pass functor\n Neumann(:outlet, 0.0),\n Dirichlet(:wall, [0.0, 0.0, 0.0]),\n Dirichlet(:top, [0.0, 0.0, 0.0]),\n)\n\n@assign! model momentum p (\n Neumann(:inlet, 0.0),\n Dirichlet(:outlet, 0.0),\n Neumann(:wall, 0.0),\n Neumann(:top, 0.0)\n)\n\nschemes = (\n U = set_schemes(divergence = Linear),\n p = set_schemes()\n)\n\n\nsolvers = (\n U = set_solver(\n model.momentum.U;\n solver = BicgstabSolver,\n preconditioner = Jacobi(),\n convergence = 1e-7,\n relax = 0.7,\n rtol = 1e-4,\n atol = 1e-10\n ),\n p = set_solver(\n model.momentum.p;\n solver = CgSolver,\n preconditioner = Jacobi(),\n convergence = 1e-7,\n relax = 0.3,\n rtol = 1e-4,\n atol = 1e-10\n )\n)\n\nruntime = set_runtime(iterations=500, time_step=1, write_interval=500)\nruntime = set_runtime(iterations=1, time_step=1, write_interval=-1) # hide\n\nhardware = set_hardware(backend=CPU(), workgroup=1024)\n\nconfig = Configuration(\n solvers=solvers, schemes=schemes, runtime=runtime, hardware=hardware)\n\nGC.gc()\n\ninitialise!(model.momentum.U, velocity)\ninitialise!(model.momentum.p, 0.0)\n\nresiduals = run!(model, config)\n\nPkg.rm(\"Flux\", io=devnull) # hide\nnothing # hide\n\"done\"","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/#Simulation-result","page":"Advanced: 2D inflow using Flux.jl","title":"Simulation result","text":"","category":"section"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"","category":"page"},{"location":"examples/04_2d-inflow-using-Flux/","page":"Advanced: 2D inflow using Flux.jl","title":"Advanced: 2D inflow using Flux.jl","text":"(Image: Comparison with OpenFOAM)","category":"page"},{"location":"user_guide/0_introduction_and_workflow/#Introduction","page":"Introduction","title":"Introduction","text":"","category":"section"},{"location":"user_guide/0_introduction_and_workflow/","page":"Introduction","title":"Introduction","text":"This page explains the overarching workflow in XCALibre.jl and provides a list of contents","category":"page"},{"location":"user_guide/0_introduction_and_workflow/#Workflow-overview","page":"Introduction","title":"Workflow overview","text":"","category":"section"},{"location":"user_guide/0_introduction_and_workflow/","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"user_guide/0_introduction_and_workflow/","page":"Introduction","title":"Introduction","text":"XCALibre.jl has been designed to incorporate a logical workflow, that is, the sequence of setup steps that would take a user naturally from the start of a simulation to its final post-processing. The key steps are listed below","category":"page"},{"location":"user_guide/0_introduction_and_workflow/","page":"Introduction","title":"Introduction","text":"Pre-processing - this step involves defining the computational domain and selecting the corresponding backend to performs the calculations\nPhysics and models - this step involves defining the fluid type, flow properties, selecting appropriate models and setting suitable boundary conditions\nNumerical setup - in this phase of the simulation set up all aspect related to the numerics are chosen, from distretisation schemes all the way to solvers and preconditioners. \nRuntime and solvers - once everything has been set up, the simulation is ready to run, once runtime information such as time steps and solution saving intervals has been selected. The final step is to actually start the simulation.\nPost-processing - the final step is to enjoy all the pretty pictures!","category":"page"},{"location":"user_guide/0_introduction_and_workflow/","page":"Introduction","title":"Introduction","text":"The user guide is structured such that the information provided is grouped following the workflow illustrated above. For convenience the contents of the user guide are included below, with links to the relevant sections.","category":"page"},{"location":"user_guide/0_introduction_and_workflow/#Contents","page":"Introduction","title":"Contents","text":"","category":"section"},{"location":"user_guide/0_introduction_and_workflow/","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"user_guide/0_introduction_and_workflow/","page":"Introduction","title":"Introduction","text":"Pages = Main.USER_GUIDE_PAGES\nDepth = 2","category":"page"},{"location":"user_guide/3_numerical_setup/#Numerical-setup","page":"Numerical setup","title":"Numerical setup","text":"","category":"section"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"Available discretisation schemes, linear solvers and preconditioners","category":"page"},{"location":"user_guide/3_numerical_setup/#Discretisation-schemes","page":"Numerical setup","title":"Discretisation schemes","text":"","category":"section"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"Part of the methodology to solve the various model equations using the Finite Volume Method (FVM) is to discretise each equation term, essentially, this process linearises the partial differential equation so that it can be represented as a system of linear equations, which can be solved using linear algebra along with iterative solvers. This section presents the discretisation schemes currently available in XCALibre.jl.","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"Discretisation schemes in XCALibre.jl are organised under the abstract type AbstractScheme. As shown previously, a list of available schemes can be found using the subtypes function:","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"using XCALibre # hide\nusing AbstractTrees # hide\n# import Main.subtypes as subtypes # hide\n using InteractiveUtils # hide\nAbstractTrees.children(d::DataType) = Main.subtypes(d) # hide\nprint_tree(AbstractScheme) # hide","category":"page"},{"location":"user_guide/3_numerical_setup/#Schemes-available","page":"Numerical setup","title":"Schemes available","text":"","category":"section"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"","category":"page"},{"location":"user_guide/3_numerical_setup/#Time-schemes","page":"Numerical setup","title":"Time schemes","text":"","category":"section"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"Scheme Description\nSteadyState sets the time derivative to zero\nEuler First order implicit Euler scheme\nCrankNicolson Second order central scheme (not implemented yet)","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"","category":"page"},{"location":"user_guide/3_numerical_setup/#Laplacian-schemes","page":"Numerical setup","title":"Laplacian schemes","text":"","category":"section"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"Scheme Description\nLinear 2nd order Gauss gradient scheme with linear interpolation","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"","category":"page"},{"location":"user_guide/3_numerical_setup/#Divergence-schemes","page":"Numerical setup","title":"Divergence schemes","text":"","category":"section"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"Scheme Description\nLinear 2nd order central difference\nUpwind 1st order upwind scheme\nBoundedUpwind Bounded version of the Upwind scheme\nLUST 1st/2nd order mixed scheme (fixed at 75% Linear - 25% Upwind)","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"","category":"page"},{"location":"user_guide/3_numerical_setup/#Gradient-schemes","page":"Numerical setup","title":"Gradient schemes","text":"","category":"section"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"Scheme Description\nOrthogonal Green-Gauss uncorrected gradient scheme\nMidpoint Green-Gauss skew corrected scheme (2 iterations - hardcoded)","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"","category":"page"},{"location":"user_guide/3_numerical_setup/#Specifying-schemes","page":"Numerical setup","title":"Specifying schemes","text":"","category":"section"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"XCALibre.jl flow solvers offer considerable flexibility to users for defining discretisation schemes. However, this means that discretisation schemes must be specified for every term of every equation solved. The schemes must be provided as a NamedTuple where each keyword corresponds to the fields being solved, e.g. (U = ..., p = ..., k = ..., = ...). To facilitate this process, the set_schemes function is provided. Used without any inputs set_schemes uses the default values provided (see details below).","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"set_schemes","category":"page"},{"location":"user_guide/3_numerical_setup/#XCALibre.Discretise.set_schemes-user_guide-3_numerical_setup","page":"Numerical setup","title":"XCALibre.Discretise.set_schemes","text":"set_schemes(;\n # keyword arguments and their default values\n time=SteadyState,\n divergence=Linear, \n laplacian=Linear, \n gradient=Orthogonal) = begin\n \n # Returns NamedTuple definition for scheme \n (\n time=time,\n divergence=divergence,\n laplacian=laplacian,\n gradient=gradient\n )\nend\n\nThe set_schemes function is used at the top-level API to help users define discretisation schemes for every field solved. It offers default values, thus users can pick and choose which entry they wish to modify.\n\ninputs\n\ntime is used to set the time schemes (default is SteadyState)\ndivergence is used to set the divergence scheme (default is Linear) \nlaplacian is used to set the laplacian scheme (default is Linear)\ngradient is used to set the gradient scheme (default is Orthogonal)\n\n\n\n\n\n","category":"function"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"For example, below we set the schemes for the U and p fields. Notice that in the first case the schemes will take their default values (entry for p). In the case of U, we are only changing the setting for the divergence scheme to Upwind.","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"using XCALibre\nschemes = (\n p = set_schemes(), # no input provided (will use defaults)\n U = set_schemes(divergence = Upwind),\n)","category":"page"},{"location":"user_guide/3_numerical_setup/#Linear-solvers","page":"Numerical setup","title":"Linear solvers","text":"","category":"section"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"Linear solvers in XCALibre.jl are provided by Krylov.jl. The following solvers types are re-exported in XCALibre.jl","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"BicgstabSolver is a general purpose linear solver. Works well with non-symmetric matrices e.g. for U.\nCgSolver is particular strong with symmetric matrices e.g to solve the pressure equation.\nGmresSolver is a general solver. We have found it works best on the CPU backend.","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"For more information on these solvers you can review the excellent documentation provided by the Krylov.jl team. ","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"XCALibre.jl provides the set_solver convenience function for setting solvers. See details below. ","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"set_solver","category":"page"},{"location":"user_guide/3_numerical_setup/#XCALibre.Solve.set_solver-user_guide-3_numerical_setup","page":"Numerical setup","title":"XCALibre.Solve.set_solver","text":"set_solver( \n field::AbstractField;\n # keyword arguments and defaults\n solver::S, \n preconditioner::PT, \n convergence, \n relax,\n limit=(),\n itmax::Integer=100, \n atol=(eps(_get_float(field.mesh)))^0.9,\n rtol=_get_float(field.mesh)(1e-3)\n ) where {S,PT<:PreconditionerType} = begin\n\n # return NamedTuple\n TF = _get_float(field.mesh)\n (\n solver=solver, \n preconditioner=preconditioner, \n convergence=convergence |> TF, \n relax=relax |> TF, \n limit=limit,\n itmax=itmax, \n atol=atol |> TF, \n rtol=rtol |> TF\n )\nend\n\nThis function is used to provide solver settings that will be used internally in XCALibre.jl. It returns a NamedTuple with solver settings that are used internally by the flow solvers. \n\nInput arguments\n\nfield reference to the field to which the solver settings will apply (used to provide integer and float types required)\nsolver solver object from Krylov.jl and it could be one of BicgstabSolver, CgSolver, GmresSolver which are re-exported in XCALibre.jl\npreconditioner instance of preconditioner to be used e.g. Jacobi()\nconvergence sets the stopping criteria of this field\nrelax specifies the relaxation factor to be used e.g. set to 1 for no relaxation\nlimit used in some solvers to bound the solution within this limits e.g. (min, max). It defaults to ()\nitmax maximum number of iterations in a single solver pass (defaults to 100) \natol absolute tolerance for the solver (default to eps(FloatType)^0.9)\nrtol set relative tolerance for the solver (defaults to 1e-3)\n\n\n\n\n\n","category":"function"},{"location":"user_guide/3_numerical_setup/#Preconditioners","page":"Numerical setup","title":"Preconditioners","text":"","category":"section"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"XCALibre.jl offers a range of preconditioners which are subtypes of the abstrac type PreconditionerType, exploring its subtypes we can find a list of the currently available preconditioners: ","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"using XCALibre # hide\nusing AbstractTrees # hide\n# import Main.subtypes as subtypes # hide\n using InteractiveUtils # hide\nAbstractTrees.children(d::DataType) = Main.subtypes(d) # hide\nprint_tree(PreconditionerType) # hide","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"note: Note\nOnly the Jacobi and NormDiagonal preconditioners have GPU ready implementations. At present these have the most robust implementation and they can be used with both CPU and GPU backends. The other preconditioners can only be used on the CPU. Notice that on our tests the LDL preconditioner only works when paired with the GmresSolver on the CPU. Also notice that the implementation of the DILU preconditioner, although functions, is only experimental. Work on improving the offering of preconditioners is ongoing.","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"Below an example is provided in context. Here, we are setting solvers for both the velocity field U and the pressure field p and packing them into a NamedTuple \"solvers\". The Jacobi preconditioner is used in both solvers. Notice that preconditioners are specified with an instance of their type i.e. Jacobi(). Internally, the preconditioner instance is used for dispatch. This tupple will then be passed on to create the final Configuration object.","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"DocTestSetup = quote\n using XCALibre\n grids_dir = pkgdir(XCALibre, \"examples/0_GRIDS\")\n grid = \"backwardFacingStep_10mm.unv\"\n mesh_file = joinpath(grids_dir, grid)\n mesh = UNV2D_mesh(mesh_file, scale=0.001)\n mesh_dev = mesh # use this line to run on CPU\n nu = 1e-3\n model = Physics(\n time = Steady(),\n fluid = Fluid{Incompressible}(nu = nu),\n turbulence = RANS{Laminar}(),\n energy = Energy{Isothermal}(),\n domain = mesh_dev\n )\nend","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"using XCALibre\n\n# Note: this example assumes a Physics object named `model` already exists\n\nsolvers = (\n U = set_solver(\n model.momentum.U;\n solver = BicgstabSolver, # GmresSolver\n preconditioner = Jacobi(),\n convergence = 1e-7,\n relax = 0.7,\n rtol = 1e-4,\n atol = 1e-10\n ),\n p = set_solver(\n model.momentum.p;\n solver = CgSolver, # BicgstabSolver, GmresSolver\n preconditioner = Jacobi(),\n convergence = 1e-7,\n relax = 0.7,\n rtol = 1e-4,\n atol = 1e-10\n )\n)","category":"page"},{"location":"user_guide/3_numerical_setup/","page":"Numerical setup","title":"Numerical setup","text":"DocTestSetup = nothing","category":"page"},{"location":"user_guide/2_physics_and_models/#Physics-and-models","page":"Physics and models","title":"Physics and models","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Information about setting up a Physics object and boundary conditions to represent the flow physics","category":"page"},{"location":"user_guide/2_physics_and_models/#Physics-model-definition","page":"Physics and models","title":"Physics model definition","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"The Physics object is part of the highest level API in XCALibre.jl. Physics objects are a means for users to set up the physics and models that are relevant to their particular CFD simulation. Internally, the Physics model created is passed to solvers and is used for dispatch (solvers, algorithms and models). Thus, it is important to ensure that the information provided to this object is correct and representative of the user's intentions. Physics models consist of a struct with the fields shown below. All fields must be provided to the solvers otherwise the construction of the object will fail.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"struct Physics{T,F,M,Tu,E,D,BI}\n time::T\n fluid::F\n momentum::M \n turbulence::Tu \n energy::E\n domain::D\n boundary_info::BI\nend ","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"For convenience, XCALibre.jl provides a more user-friendly constructor that will automatically take care of the construction of derived fields. This constructor uses keyword arguments and has the following signature (follow the link for more information)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Physics(; time, fluid, turbulence, energy, domain)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"At this point, it is worth reminding users that one of the benefits of working with Julia is its dynamic nature. This means that objects can be dynamically interrogated. For example:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"using XCALibre\nfieldnames(Physics)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"This will provide users with all the fields that make up the Physics object. This is a nice way to explore the makeup of any object in Julia (and by extension XCALibre.jl). The rest of this page will provide details of the physics models available in XCALibre.jl, including:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Time models\nFluid types\nTurbulence models\nEnergy models","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"warning: Warning\nThe mesh provided to the domain field must already be adapted to the required backend device. See Backend selection for detail. ","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"note: Note\nIn the next version of XCALibre.jl the field boundary_info will be likely removed outside of the Physics object in order to improve on the current performance (avoiding unnecessary memory movement between GPU backends and the host devices).","category":"page"},{"location":"user_guide/2_physics_and_models/#Time-models","page":"Physics and models","title":"Time models","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Earlier in this section, the dynamic nature of Julia was mentioned in the context of extracting fields for the Physics model used in XCALibre.jl. In the following sections this benefit of using Julia will be exploited further. XCALibre.jl takes advantage of Julia's rich type system and we define Abstract types to organise major functionality. For example, time models are subtypes of the abstract type AbstractTimeModel. Therefore, out-of-the-box we get for free a means to explore implemented features in XCALibre.jl. For example, to identify the time models implemented, we simply need to type the following in the REPL:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"using XCALibre\n# import Main.subtypes as subtypes # hide\nusing InteractiveUtils # Load from standard library\nMain.subtypes(AbstractTimeModel)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"From the output it can be seen that there are two time models in XCALibre.jl for Steady or Transient simulations. These are singleton types and contain (at present) no internal fields or data. They are largely used by XCALibre.jl to dispatch either steady or transient solvers. We are starting to get a picture of how the Physics object is constructed. For example, to specify a Steady simulation","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"The time model can be specified as Steady as follows:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Physics(\n time = Steady()\n ...\n)","category":"page"},{"location":"user_guide/2_physics_and_models/#Fluid-types","page":"Physics and models","title":"Fluid types","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Following from the idea of using Julia's dynamic features to explore the types available in XCALibre.jl, in this section we will explore the fluid types available. This time, we will use a helper package AbstractTrees (which can be installed in the usual way, by entering into package mode in the REPL and typing add AbstractTrees). In XCALibre.jl all fluid types are subtypes of AbstractFluid. The types available are shown in the example below:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"begin\n # Note: this code snippet will not be shown later for succinctness\n using XCALibre\n using InteractiveUtils # Load from standard library\n # using Pkg; Pkg.add(\"AbstractTrees\") # run to install AbstractTrees\n using AbstractTrees \n # import Main.subtypes as subtypes # hide\n AbstractTrees.children(d::DataType) = Main.subtypes(d)\n print_tree(AbstractFluid)\nend","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"From the subtype tree above, we can see that XCALibre.jl offers 2 major abstract fluid types, AbstractIncompressible and AbstractCompressible. There are 3 concrete fluid types:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Incompressible - for simulations were the fluid density does not change with pressure\nWeaklyCompressible - for simulation were the fluid density is allowed to change (no shockwaves)\nCompressible - for simulations were discontinuities may appear (not available for general use yet)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"To specify a given fluid type, the Fluid wrapper type is used as a general constructor which is specialised depending depending on the fluid type from the list above provided by the user. The constructors require the following inputs:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"For incompressible fluid flow","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Fluid{Incompressible}(; nu, rho=1.0) ","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"For compressible fluids (weak formulation)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Fluid{WeaklyCompressible}(; nu, cp, gamma, Pr)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"where the input variables represent the following:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"nu - kinematic viscosity\nrho - fluid density\ngamma - specific heat ratio\nPr - Prandlt number\ncp - specific heat at constant pressure","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"For example, an incompressible fluid can be specified as follows","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Physics(\n time = Steady(),\n fluid = Fluid{Incompressible}(nu=1e-5),\n ...\n)","category":"page"},{"location":"user_guide/2_physics_and_models/#Turbulence-models","page":"Physics and models","title":"Turbulence models","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Below is a representation of the AbstractTurbulenceModel inheritance tree. It shows turbulence models available. Turbulence models are defined using the RANS and LES constructors and passing a specific turbulence model type. As it will be illustrated in the flowing sections.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"using XCALibre # hide\nusing AbstractTrees # hide\n# import Main.subtypes as subtypes # hide\n using InteractiveUtils # hide\nAbstractTrees.children(d::DataType) = Main.subtypes(d) # hide\nprint_tree(AbstractTurbulenceModel) # hide","category":"page"},{"location":"user_guide/2_physics_and_models/#RANS-models-constructors","page":"Physics and models","title":"RANS models constructors","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Laminar model: no user input is required. This is a dummy model that does not contribute to the momentum equation.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"RANS{Laminar}() # only constructor needed","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"KOmega model: the standard 2 equation Wilcox model coefficients are passed by default. This model solves 2 transport equations for the turbulent kinetic energy and the specific dissipation rate, k and omega, respectively. Subsequently, k and omega are used to update the turbulent eddy viscosity, nut. These 3 fields must be provided with boundary conditions. ","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"RANS{KOmega}() # will set the default coefficient values shown below\nRANS{KOmega}(; β⁺=0.09, α1=0.52, β1=0.072, σk=0.5, σω=0.5) # set defaults\nRANS{KOmega}(β1=0.075) # user can choose to change a single coefficient","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"KOmegaLKE model: the user must provide a reference turbulence intensity (Tu) and a tuple of symbols specifying wall boundaries. This model uses 3 equations (k, kl, omega) to update the eddy viscosity (nut). These fields must be provided with boundary conditions.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"RANS{KOmegaLKE}(; Tu::Number, walls::Tuple) # no defaults defined\nRANS{KOmegaLKE}(Tu = 0.01, walls=(:cylinder,)) # user should provide information for Tu and walls","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"For example, a steady, incompressible simulation using the KOmega model can be specified as","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Physics(\n time = Steady(),\n fluid = Fluid{Incompressible}(nu=1e-5),\n turbulence = RANS{KOmega}(),\n ...\n)","category":"page"},{"location":"user_guide/2_physics_and_models/#LES-models","page":"Physics and models","title":"LES models","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Smagorinsky model: the standard model constant is passed by default. Boundary conditions for nut must be provided, generally zero gradient conditions work well. No special wall functions for nut in LES mode are available.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"LES{Smagorinsky}() # default constructor will use value below\nLES{Smagorinsky}(; C=0.15) # default value provided by default\nLES{Smagorinsky}(C=0.1) # user selected value","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"For example, an incompressible LES simulation with the Smagorinsky model can be specified as","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Physics(\n time = Transient(),\n fluid = Fluid{Incompressible}(nu=1e-5),\n turbulence = LES{Smagorinsky}(),\n)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"note: Note\nIn the specification above the time model was set as Transient since LES models are strictly time-resolving. A simulation might run when the Steady model is chosen, but the results would likely not be reliable. XCALibre.jl by design offers flexibility for users to customise their setup, the consequence is that it falls on users to define a combination of models that is appropriate. Likewise, in the example above an Isothermal energy model would have to be selected. See Energy models","category":"page"},{"location":"user_guide/2_physics_and_models/#Energy-models","page":"Physics and models","title":"Energy models","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Currently, XCALibre.jl offers two options to model the energy equation. A tree of the AbstractEnergyModel is shown below. The top-level constructor for energy models is the Energy type. Specific constructor signatures are also illustrated below.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"using XCALibre # hide\nusing AbstractTrees # hide\n# import Main.subtypes as subtypes # hide\n using InteractiveUtils # hide\nAbstractTrees.children(d::DataType) = Main.subtypes(d) # hide\nprint_tree(AbstractEnergyModel) # hide","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Isothermal model: assumes temperature effects are negligible. Used for incompressible solvers.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Energy{Isothermal}() # default constructor","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"SensibleEnthalpy model: uses the sensible enthalpy model for the energy equation. Required for the compressible solvers.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Energy{SensibleEnthalpy}(; Tref) # constructor definition. No default values given to Tref keyword\nEnergy{SensibleEnthalpy}(Tref=300) # Users must provide a referent temperature value","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"For example, a steady, compressible RANS simulation with the KOmegaLKE model can be specified as","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Physics(\n time = Steady(),\n fluid = Fluid{WeaklyCompressible}(nu=1e-5, cp=1005, gamma=1.4, Pr=0.7),\n turbulence = RANS{KOmegaLKE}(),\n energy = Energy{SensibleEnthalpy}(Tref=300),\n ...\n)","category":"page"},{"location":"user_guide/2_physics_and_models/#Domain-definition","page":"Physics and models","title":"Domain definition","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"The final step when defining a Physics model is to specify the domain on which the various models will be used. This is simply a reference to the mesh object.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Continuing from the previous example, a steady, compressible RANS simulation with the KOmegaLKE model can be specified as","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Physics(\n time = Steady(),\n fluid = Fluid{WeaklyCompressible}(nu=1e-5, cp=1005, gamma=1.4, Pr=0.7),\n turbulence = RANS{KOmegaLKE}(),\n energy = Energy{SensibleEnthalpy}(Tref=300),\n domain = mesh_dev\n)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"warning: Warning\nWhen passing the mesh objective to complete the definition of the Physics object, the mesh must be adapted to the target device where the computation will be performed. See Backend selection for more details.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Notice that the transfer to the target compute backend can also be done inline. For example,","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Physics(\n time = Steady(),\n fluid = Fluid{WeaklyCompressible}(nu=1e-5, cp=1005, gamma=1.4, Pr=0.7),\n turbulence = RANS{KOmegaLKE}(),\n energy = Energy{SensibleEnthalpy}(Tref=300),\n domain = adapt(CUDABackend(), mesh) # for Nvidia GPUs\n)","category":"page"},{"location":"user_guide/2_physics_and_models/#Boundary-conditions","page":"Physics and models","title":"Boundary conditions","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"The final step to completely capture the physics for the simulation is to define boundary conditions in order to find a concrete solution of the model equations being solved. XCALibre.jl offers a range of boundary conditions. As before, boundary conditions are specified by type and the are classified under the AbstractBoundary type and subdivided into 4 additional abstract types AbstractDirichlet, AbstractNeumann, AbstractPhysicalConstraint and AbstractWallFunction. The complete abstract tree is illustrated below.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"using XCALibre # hide\nusing AbstractTrees # hide\n# import Main.subtypes as subtypes # hide\n using InteractiveUtils # hide\nAbstractTrees.children(d::DataType) = Main.subtypes(d) # hide\nprint_tree(AbstractBoundary) # hide","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Philosophically, the four subtypes represent different physical types of boundary conditions:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"AbstractDirichlet boundary conditions are used to assign a concrete value to field at the boundary.\nAbstractNeumann boundaries are used to fix the field gradient at the boundary.\nAbstractPhysicalConstraint boundaries represent physical constraints imposed on the domain.\nAbstractWallFunction represent models for treating flow or turbulence quantities in wall regions.","category":"page"},{"location":"user_guide/2_physics_and_models/#AbstractDirichlet-conditions","page":"Physics and models","title":"AbstractDirichlet conditions","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Dirichlet(name, value)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"name is a symbol providing the boundary name\nvalue is a vector or scalar defining desired value at the boundary","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"FixedTemperature(name; T, model::EnergyModel<:AbstractEnergyModel)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"name is a symbol providing the boundary name\nT is a keyword argument to define the temperate value to be assigned at the boundary\nmodel is a keyword argument that expects an instance of the energy model to be used e.g. SensibleEnergy","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"DirichletFunction(name, func)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"name is a symbol providing the boundary name\nfunc is a function identifier. func is a user-defined function (but can also be a neural network) that returns a scalar or vector as a function of time and space.\nfunc must adhere to an internal contract. See XCALibre.Discretise.DirichletFunction for more details.","category":"page"},{"location":"user_guide/2_physics_and_models/#AbstractNeumann-conditions","page":"Physics and models","title":"AbstractNeumann conditions","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Neumann(name, value)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"name is a symbol providing the boundary name\nvalue is a scalar defining the gradient normal to the boundary","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"warning: Warning\nAt present the Neumann boundary should be treated as providing a zero gradient condition only. Internally, a zero gradient value is hard-coded. This behaviour will be extended in the near future to allow arbitrary gradients to be defined.","category":"page"},{"location":"user_guide/2_physics_and_models/#AbstractPhysicalConstraint-conditions","page":"Physics and models","title":"AbstractPhysicalConstraint conditions","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Wall boundary conditions can be used to provide a boundary with a wall constraint. This boundary type, at present, can only be used to define vectors. For scalar quantities in wall regions a Neumann (zero gradient) should be imposed.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Wall(name, value)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"name is a symbol providing the boundary name\nvalue is a vector defining wall velocity e.g. [0, 0, 0]","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"note: Note\nCurrently, the value provided at the wall is not used internally. This mean that this boundary condition currently acts as a no slip boundary. This will be extended to allow slip boundaries or moving walls.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Symmetry boundary condition can be used to assign a symmetry constraint to a given boundary patch in the domain. It can be used for both vector and scalar quantities.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Symmetry(name)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"name is a symbol providing the boundary name","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"Periodic boundaries consist of a pair of boundary patches that behave as if they are physically connected. The periodic boundary essentially provides a mapping between these patches and helps in calculating the face values at the interface. The construction of periodic boundaries is different to other boundary conditions because the addressing between each face for the patch pair needs to be calculated and stored. Periodic boundary can be constructed as follows:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"periodic::Tuple = construct_periodic(mesh, backend, patch1::Symbol, patch2::Symbol)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"mesh is a reference to the mesh object\nbackend defines the expected backend e.g. CPU(), CUDABackend, etc.\npatch1 and patch2 symbols of the two patch pair we would like to flag as periodic","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"The output is a tuple containing two Periodic boundary types with information relevant to each boundary patch pair and it can be used directly to assign a periodic boundary for both patches (by splatting into the assignment macro e.g. periodic...)","category":"page"},{"location":"user_guide/2_physics_and_models/#AbstractWallFunction-conditions","page":"Physics and models","title":"AbstractWallFunction conditions","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"KWallFunction provides a turbulent kinetic energy boundary condition for high-Reynolds models.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"KWallFunction(name)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"name is a symbol providing the boundary name","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"OmegaWallFunction provides a value for the specific dissipation rate for both low- and high-Reynolds model.","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"OmegaWallFunction(name)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"name is a symbol providing the boundary name","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"NutWallFunction provides a value for the eddy viscosity for high-Reynolds models","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"NutWallFunction(name)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"name is a symbol providing the boundary name","category":"page"},{"location":"user_guide/2_physics_and_models/#Assigning-conditions-(macro)","page":"Physics and models","title":"Assigning conditions (macro)","text":"","category":"section"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"XCALibre.jl requires that a boundary condition is assigned to every single patch in the domain (as defined within the mesh object) for every field that is part of the solution. To facilitate this process, XCALibre.jl provides the @assign macro for convenience. The @assign macro has the following signature:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"@assign! model::Physics (\n , \n , \n ...\n )","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"For example, for a laminar incompressible simulation, only the momentum equation is being solved. Therefore, users need to provide conditions for every patch for the U and p fields in the momentum model:","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"using XCALibre\n\ngrids_dir = pkgdir(XCALibre, \"examples/0_GRIDS\")\ngrid = \"backwardFacingStep_10mm.unv\"\nmesh_file = joinpath(grids_dir, grid)\nmesh = UNV2D_mesh(mesh_file, scale=0.001)\n\nbackend = CPU() # run on CPU\nhardware = set_hardware(backend=backend, workgroup=4)\nmesh_dev = mesh # dummy assignment \n\n# Flow conditions\nvelocity = [1.5, 0.0, 0.0]\nnu = 1e-3\nRe = velocity[1]*0.1/nu # Reynolds number\n\n# Physics models\nmodel = Physics(\n time = Steady(),\n fluid = Fluid{Incompressible}(nu = nu),\n turbulence = RANS{Laminar}(),\n energy = Energy{Isothermal}(),\n domain = mesh_dev\n )\n\n# Define boundary conditions\n@assign! model momentum U (\n Dirichlet(:inlet, velocity),\n Neumann(:outlet, 0.0),\n Wall(:wall, [0.0, 0.0, 0.0]),\n Wall(:top, [0.0, 0.0, 0.0]),\n)\n\n@assign! model momentum p (\n Neumann(:inlet, 0.0),\n Dirichlet(:outlet, 0.0),\n Neumann(:wall, 0.0), # scalar wall - set up as zero gradient\n Neumann(:top, 0.0) # scalar wall - set up as zero gradient\n)","category":"page"},{"location":"user_guide/2_physics_and_models/","page":"Physics and models","title":"Physics and models","text":"hint: Hint\nJulia is a dynamic language and objects can be interrogated on the fly (dynamically). Say you created a Physics model named mymodel, you can interrogate the contents of any of the fields in the Physics structure using the fieldnames function, e.g. fieldnames(mymodel.momentum), to find which fields need to be provided with boundary conditions. Any fields not ending in f should be set. ","category":"page"},{"location":"quick_start/#Quick-Start","page":"Quick Start","title":"Quick Start","text":"","category":"section"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"Read this section for information about how to install XCALibre.jl and an example showcasing the API","category":"page"},{"location":"quick_start/#Installation","page":"Quick Start","title":"Installation","text":"","category":"section"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"First, you need to download and install Julia on your system. Once you have a working installation of Julia, XCALibre.jl can be installed using the built-in package manager. ","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"XCALibre.jl is available directly from the the General Julia Registry. Thus, to install XCALibre.jl open a Julia REPL, press ] to enter the package manager. The REPL prompt icon will change from julia> (green) to pkg> (and change colour to blue) or (myenvironment) pkg> where myenvironment is the name of the currently active Julia environment. Once you have activated the package manager mode enter","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"pkg> add XCALibre","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"To install XCALibre.jl directly from Github enter the following command (for the latest release)","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"pkg> add XCALibre https://github.com/mberto79/XCALibre.jl.git","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"A specific branch can be installed by providing the branch name precided by a #, for example, to install the dev-0.3-main branch enter","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"pkg> add XCALibre https://github.com/mberto79/XCALibre.jl.git#dev-0.3-main","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"note: Note\nTo enable GPU acceleration you will also need to install the corresponding GPU package for your hardware. See CUDA.jl, AMD.jl, oneAPI.jl for more details. XCALibre.jl will automatically precompile and load the relevant backend specific functionality (using Julia extensions)","category":"page"},{"location":"quick_start/#Example","page":"Quick Start","title":"Example","text":"","category":"section"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"The example below illustrates the top-level API used in XCALibre.jl. It shows the key steps a user needs to follow to set up a simulation:","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"Pre-processing (steps 1 and 2)\nPhysics and models (steps 3 to 5)\nNumerical setup (steps 6 and 7)\nRuntime and solvers setup (steps 8 to 11)\nPost-processing (step 12)","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"Once you have installed Julia and XCALibre.jl, the example below can be run by copying the contents shown below and pasting them in a file. The file can be executed within vscode, the Julia REPL or from a system terminal. ","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"To run in vscode check the information for using Julia in vscode\nTo run in the Julia REPL, simply launch Julia and type include(\"name_of_your_file.jl\")\nTo run from a system terminal (bash or cmd, for example), simply type path/to/julia name_of_your_file.jl","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"In most cases, it is preferable to run simulations from within the Julia REPL because, in Julia, there is often a cost associated to the first run due to compilation time. By relaunching a simulation in the REPL, all previously compiled code will not be recompiled. This is particularly helpful in the prototyping stages. For long running simulations, the compilation time is normally negligible compared to the actual time needed to complete the simulation.","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"\n# Step 0. Load libraries\nusing XCALibre\n# using CUDA # Uncomment to run on NVIDIA GPUs\n# using AMDGPU # Uncomment to run on AMD GPUs\n\n\n# Step 1. Define mesh\ngrids_dir = pkgdir(XCALibre, \"examples/0_GRIDS\")\ngrid = \"backwardFacingStep_10mm.unv\"\nmesh_file = joinpath(grids_dir, grid)\n\nmesh = UNV2D_mesh(mesh_file, scale=0.001) # convert mesh\n\n# Step 2. Select backend and setup hardware\nbackend = CPU()\n# backend = CUDABackend() # ru non NVIDIA GPUs\n# backend = ROCBackend() # run on AMD GPUs\n\nhardware = set_hardware(backend=backend, workgroup=4)\n# hardware = set_hardware(backend=backend, workgroup=32) # use for GPU backends\n\nmesh_dev = mesh # use this line to run on CPU\n# mesh_dev = adapt(backend, mesh) # Uncomment to run on GPU \n\n# Step 3. Flow conditions\nvelocity = [1.5, 0.0, 0.0]\nnu = 1e-3\nRe = velocity[1]*0.1/nu\n\n# Step 4. Define physics\nmodel = Physics(\n time = Steady(),\n fluid = Fluid{Incompressible}(nu = nu),\n turbulence = RANS{Laminar}(),\n energy = Energy{Isothermal}(),\n domain = mesh_dev\n )\n\n# Step 5. Define boundary conditions\n@assign! model momentum U (\n Dirichlet(:inlet, velocity),\n Neumann(:outlet, 0.0),\n Wall(:wall, [0.0, 0.0, 0.0]),\n Wall(:top, [0.0, 0.0, 0.0]),\n)\n\n@assign! model momentum p (\n Neumann(:inlet, 0.0),\n Dirichlet(:outlet, 0.0),\n Neumann(:wall, 0.0),\n Neumann(:top, 0.0)\n)\n\n# Step 6. Choose discretisation schemes\nschemes = (\n U = set_schemes(divergence = Linear),\n p = set_schemes() # no input provided (will use defaults)\n)\n\n# Step 7. Set up linear solvers and preconditioners\nsolvers = (\n U = set_solver(\n model.momentum.U;\n solver = BicgstabSolver, # Options: GmresSolver\n preconditioner = Jacobi(), # Options: NormDiagonal(), DILU(), ILU0()\n convergence = 1e-7,\n relax = 0.7,\n rtol = 1e-4,\n atol = 1e-10\n ),\n p = set_solver(\n model.momentum.p;\n solver = CgSolver, # Options: CgSolver, BicgstabSolver, GmresSolver\n preconditioner = Jacobi(), # Options: NormDiagonal(), LDL() (with GmresSolver)\n convergence = 1e-7,\n relax = 0.7,\n rtol = 1e-4,\n atol = 1e-10\n )\n)\n\n# Step 8. Specify runtime requirements\nruntime = set_runtime(\n iterations=2000, time_step=1, write_interval=2000)\n\n# Step 9. Construct Configuration object\nconfig = Configuration(\n solvers=solvers, schemes=schemes, runtime=runtime, hardware=hardware)\n\n# Step 10. Initialise fields (initial guess)\ninitialise!(model.momentum.U, velocity)\ninitialise!(model.momentum.p, 0.0)\n\n# Step 11. Run simulation\nresiduals = run!(model, config);\n\n# Step 12. Post-process\npwd() # find active directory where the file \"iteration_002000.vtk\" was saved","category":"page"},{"location":"quick_start/#Output","page":"Quick Start","title":"Output","text":"","category":"section"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"If you chose to run the example above, XCALibre.jl would have written a simulation result file to your computer. The name of the file is iteration_002000.vtk. The file will be located in your current active directory (you can check this by running pwd()). This file can be open directly in ParaView for further post-processing. You can find out more about ParaView on their website. The image below is the output solution generated by XCALibre.jl to the example simulation above.","category":"page"},{"location":"quick_start/","page":"Quick Start","title":"Quick Start","text":"(Image: Simulation result visualisation in ParaView)","category":"page"},{"location":"examples/01_2d-isothermal-backward-facing-step/#Verification:-2D-incompressible-backward-facing-step","page":"Verification: 2D incompressible backward-facing step","title":"Verification: 2D incompressible backward-facing step","text":"","category":"section"},{"location":"examples/01_2d-isothermal-backward-facing-step/#Introduction","page":"Verification: 2D incompressible backward-facing step","title":"Introduction","text":"","category":"section"},{"location":"examples/01_2d-isothermal-backward-facing-step/","page":"Verification: 2D incompressible backward-facing step","title":"Verification: 2D incompressible backward-facing step","text":"","category":"page"},{"location":"examples/01_2d-isothermal-backward-facing-step/","page":"Verification: 2D incompressible backward-facing step","title":"Verification: 2D incompressible backward-facing step","text":"The correct implementation of the laminar solver in XCALibre.jl has been verified by quantitatively comparing results with those obtained with OpenFOAM. The simulation set up and mesh file used to run the simulation with XCALibre.jl are available in this repository.","category":"page"},{"location":"examples/01_2d-isothermal-backward-facing-step/#Simulation-setup","page":"Verification: 2D incompressible backward-facing step","title":"Simulation setup","text":"","category":"section"},{"location":"examples/01_2d-isothermal-backward-facing-step/","page":"Verification: 2D incompressible backward-facing step","title":"Verification: 2D incompressible backward-facing step","text":"","category":"page"},{"location":"examples/01_2d-isothermal-backward-facing-step/","page":"Verification: 2D incompressible backward-facing step","title":"Verification: 2D incompressible backward-facing step","text":"\nusing XCALibre\n# using CUDA # Uncomment to run on NVIDIA GPUs\n# using AMDGPU # Uncomment to run on AMD GPUs\n\ngrids_dir = pkgdir(XCALibre, \"examples/0_GRIDS\")\ngrid = \"backwardFacingStep_10mm.unv\"\nmesh_file = joinpath(grids_dir, grid)\n\nmesh = UNV2D_mesh(mesh_file, scale=0.001)\n\n# Select backend and setup hardware\nbackend = CPU()\n# backend = CUDABackend() # ru non NVIDIA GPUs\n# backend = ROCBackend() # run on AMD GPUs\n\nhardware = set_hardware(backend=backend, workgroup=4)\n# hardware = set_hardware(backend=backend, workgroup=32) # use for GPU backends\n\nmesh_dev = mesh # use this line to run on CPU\n# mesh_dev = adapt(backend, mesh) # Uncomment to run on GPU \n\nvelocity = [1.5, 0.0, 0.0]\nnu = 1e-3\nRe = velocity[1]*0.1/nu\n\nmodel = Physics(\n time = Steady(),\n fluid = Fluid{Incompressible}(nu = nu),\n turbulence = RANS{Laminar}(),\n energy = Energy{Isothermal}(),\n domain = mesh_dev\n )\n\n@assign! model momentum U (\n Dirichlet(:inlet, velocity),\n Neumann(:outlet, 0.0),\n Wall(:wall, [0.0, 0.0, 0.0]),\n Wall(:top, [0.0, 0.0, 0.0]),\n)\n\n@assign! model momentum p (\n Neumann(:inlet, 0.0),\n Dirichlet(:outlet, 0.0),\n Neumann(:wall, 0.0),\n Neumann(:top, 0.0)\n)\n\nschemes = (\n U = set_schemes(divergence = Linear),\n p = set_schemes() # no input provided (will use defaults)\n)\n\nsolvers = (\n U = set_solver(\n model.momentum.U;\n solver = BicgstabSolver, # Options: GmresSolver\n preconditioner = Jacobi(), # Options: NormDiagonal(), DILU(), ILU0()\n convergence = 1e-7,\n relax = 0.7,\n rtol = 1e-4,\n atol = 1e-10\n ),\n p = set_solver(\n model.momentum.p;\n solver = CgSolver, # Options: CgSolver, BicgstabSolver, GmresSolver\n preconditioner = Jacobi(), # Options: NormDiagonal(), LDL() (with GmresSolver)\n convergence = 1e-7,\n relax = 0.7,\n rtol = 1e-4,\n atol = 1e-10\n )\n)\n\nruntime = set_runtime(iterations=2000, time_step=1, write_interval=2000)\nruntime = set_runtime(iterations=1, time_step=1, write_interval=-1) # hide\n\nconfig = Configuration(\n solvers=solvers, schemes=schemes, runtime=runtime, hardware=hardware)\n\ninitialise!(model.momentum.U, velocity)\ninitialise!(model.momentum.p, 0.0)\n\nresiduals = run!(model, config);","category":"page"},{"location":"examples/01_2d-isothermal-backward-facing-step/#Results","page":"Verification: 2D incompressible backward-facing step","title":"Results","text":"","category":"section"},{"location":"examples/01_2d-isothermal-backward-facing-step/","page":"Verification: 2D incompressible backward-facing step","title":"Verification: 2D incompressible backward-facing step","text":"","category":"page"},{"location":"examples/01_2d-isothermal-backward-facing-step/#Domain-and-mesh","page":"Verification: 2D incompressible backward-facing step","title":"Domain and mesh","text":"","category":"section"},{"location":"examples/01_2d-isothermal-backward-facing-step/","page":"Verification: 2D incompressible backward-facing step","title":"Verification: 2D incompressible backward-facing step","text":"(Image: Simulation domain)","category":"page"},{"location":"examples/01_2d-isothermal-backward-facing-step/#OpenFoam-solution","page":"Verification: 2D incompressible backward-facing step","title":"OpenFoam solution","text":"","category":"section"},{"location":"examples/01_2d-isothermal-backward-facing-step/","page":"Verification: 2D incompressible backward-facing step","title":"Verification: 2D incompressible backward-facing step","text":"(Image: Simulation domain)","category":"page"},{"location":"examples/01_2d-isothermal-backward-facing-step/#XCALibre-solution","page":"Verification: 2D incompressible backward-facing step","title":"XCALibre solution","text":"","category":"section"},{"location":"examples/01_2d-isothermal-backward-facing-step/","page":"Verification: 2D incompressible backward-facing step","title":"Verification: 2D incompressible backward-facing step","text":"(Image: Simulation domain)","category":"page"},{"location":"examples/01_2d-isothermal-backward-facing-step/#Quantitative-comparision","page":"Verification: 2D incompressible backward-facing step","title":"Quantitative comparision","text":"","category":"section"},{"location":"examples/01_2d-isothermal-backward-facing-step/","page":"Verification: 2D incompressible backward-facing step","title":"Verification: 2D incompressible backward-facing step","text":"The figure below compares the results obtained with OpenFOAM and XCALibre.jl. The profiles are extracted along the y-direction at x = 0.5 m. (Image: Comparison with OpenFOAM)","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Validation:-2D-Constant-temperature-flat-plate","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Introduction","page":"Validation: 2D Constant temperature flat plate","title":"Introduction","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"A 2D constant temperature laminar flat plate case has been used to validate the weakly compressible solver. The case provides a constant temperature boundary condition along the wall of the domain. ","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"The Nusselt number values obtained from the simulation are compared against the theoretical local Nusselt number correlation for forced convection on constant temperature flat plate:","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"Nu_x = 0332 Re_x^12 Pr^13","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"The correlation is valid for Prandtl numbers greater than 0.6.","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Boundary-conditions","page":"Validation: 2D Constant temperature flat plate","title":"Boundary conditions","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Inlet","page":"Validation: 2D Constant temperature flat plate","title":"Inlet","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"Field Boundary condition\nU Dirichlet ([0.2, 0.0, 0.0] m/s)\np Neumann (Zero-gradient)\nT FixedTemperature (300.0 K)","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Wall","page":"Validation: 2D Constant temperature flat plate","title":"Wall","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"Field Boundary condition\nU No-slip wall\np Neumann (Zero-gradient)\nT FixedTemperature (310.0 K)","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Outlet","page":"Validation: 2D Constant temperature flat plate","title":"Outlet","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"Field Boundary condition\nU Neumann (Zero-gradient)\np Dirichlet (0.0 Pa)\nT Neumann (Zero-gradient)","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Top","page":"Validation: 2D Constant temperature flat plate","title":"Top","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"Field Boundary condition\nU Neumann (Zero-gradient)\np Neumann (Zero-gradient)\nT Neumann (Zero-gradient)","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Fluid-Properties","page":"Validation: 2D Constant temperature flat plate","title":"Fluid Properties","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"Property value\nnu 0.0001\nPr 0.71\nc_p 1005.0\ngamma 1.4","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Mesh","page":"Validation: 2D Constant temperature flat plate","title":"Mesh","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"The mesh is shown in the figure below. The plate is represented by the \"wall\" boundary. The flow moves from left to right (\"inlet\" to \"outlet\" boundaries). The x-axis is aligned with the wall boundary and the y-axis is position in the direction perpendicular to the wall.","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"(Image: Figure 1)","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"The streamwise cell length is 2mm with a total domain length of 1m. The near-wall cell height is 0.049mm with a domain height of 0.2m.","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Case-file","page":"Validation: 2D Constant temperature flat plate","title":"Case file","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"using XCALibre\n\ngrids_dir = pkgdir(XCALibre, \"examples/0_GRIDS\")\ngrid = \"flatplate_2D_laminar.unv\"\nmesh_file = joinpath(grids_dir, grid)\n\nmesh = UNV2D_mesh(mesh_file, scale=0.001)\n\nvelocity = [0.2, 0.0, 0.0]\nnu = 1e-4\nRe = velocity[1]*1/nu\ncp = 1005.0\ngamma = 1.4\nPr = 0.7\n\nmodel = Physics(\n time = Steady(),\n fluid = Fluid{WeaklyCompressible}(\n nu = nu,\n cp = cp,\n gamma = gamma,\n Pr = Pr\n ),\n turbulence = RANS{Laminar}(),\n energy = Energy{SensibleEnthalpy}(Tref = 288.15),\n domain = mesh # mesh_dev # use mesh_dev for GPU backend\n )\n\n@assign! model momentum U (\n Dirichlet(:inlet, velocity),\n Neumann(:outlet, 0.0),\n Wall(:wall, [0.0, 0.0, 0.0]),\n Symmetry(:top, 0.0)\n)\n\n @assign! model momentum p (\n Neumann(:inlet, 0.0),\n Dirichlet(:outlet, 100000.0),\n Neumann(:wall, 0.0),\n Neumann(:top, 0.0)\n)\n\n@assign! model energy h (\n FixedTemperature(:inlet, T=300.0, model=model.energy),\n Neumann(:outlet, 0.0),\n FixedTemperature(:wall, T=310.0, model=model.energy),\n Neumann(:top, 0.0)\n)\n\nschemes = (\n U = set_schemes(divergence=Linear),\n p = set_schemes(divergence=Linear),\n h = set_schemes(divergence=Linear)\n)\n\nsolvers = (\n U = set_solver(\n model.momentum.U;\n solver = BicgstabSolver,\n preconditioner = Jacobi(),\n convergence = 1e-7,\n relax = 0.7,\n ),\n p = set_solver(\n model.momentum.p;\n solver = CgSolver,\n preconditioner = Jacobi(),\n convergence = 1e-7,\n relax = 0.3,\n ),\n h = set_solver(\n model.energy.h;\n solver = BicgstabSolver,\n preconditioner = Jacobi(),\n convergence = 1e-7,\n relax = 0.7,\n rtol = 1e-2,\n atol = 1e-4\n )\n)\n\nruntime = set_runtime(iterations=1000, write_interval=1000, time_step=1)\nruntime = set_runtime(iterations=1, write_interval=-1, time_step=1) # hide\n\nhardware = set_hardware(backend=CPU(), workgroup=4)\n\nconfig = Configuration(\n solvers=solvers, schemes=schemes, runtime=runtime, hardware=hardware)\n\nGC.gc()\n\ninitialise!(model.momentum.U, velocity)\ninitialise!(model.momentum.p, 100000.0)\ninitialise!(model.energy.T, 300.0)\n\nresiduals = run!(model, config)","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/#Results","page":"Validation: 2D Constant temperature flat plate","title":"Results","text":"","category":"section"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"The results of the model are compared to the theoretical correlation in the figure below:","category":"page"},{"location":"examples/03_2d-constant-temperature-flat-plate/","page":"Validation: 2D Constant temperature flat plate","title":"Validation: 2D Constant temperature flat plate","text":"(Image: Nusselt number distribution results.)","category":"page"},{"location":"contributor_guide/#Contributor-Guide","page":"Contributor Guide","title":"Contributor Guide","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"Guidelines and practical information for contributing to XCALibre.jl","category":"page"},{"location":"contributor_guide/#Introduction","page":"Contributor Guide","title":"Introduction","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"In time, our ambition is to document the internal API completely, however, this will take some time and it is an ongoing process. Since XCALibre.jl uses a modular approach and the current functionality covers a good portion of the CFD stack, those interested in working with the internal API should be able to work from existing implementations. In this page we provide key information for those users who want to customise, refine, improve, or extend XCALibre.jl.","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"From its humble beginning as a 1D diffusion example code to explore the features of the Julia programming language (and speed claims which turned out to be true 😄), XCALibre.jl was meant to be shared and used to help students understand the Finite Volume Method and as an entry point to explore the implementation details underpinning CFD. As the code base has grown, this original purpose remains. However, XCALibre.jl is now a more complete CFD software stack which can be used by both researchers and students to test out new ideas, even on complex geometry with acceptable performance. XCALibre.jl will hopefully continue to grow and offer more functionality as it has been the case since work on XCALibre.jl started. In the sharing spirit of open-source software we also welcome code contributions, and we hope to make this process as simple as possible. However, we ask contributors to follow a few guidelines to ensure that we grow XCALibre.jl in a sustainable and maintainable manner.","category":"page"},{"location":"contributor_guide/#Some-guidelines","page":"Contributor Guide","title":"Some guidelines","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"To help use keep the codebase consistent and allow us to merge future Pull Requests (PRs) more easily, we kindly request that contributors adhere to some basic guidelines. We are trying to strike a balance between consistency and ease of contribution by aiming not to be overly demanding on contributors. A minimum set of guidelines is provided below (subject to review as the codebase evolves), in no particular order:","category":"page"},{"location":"contributor_guide/#Code-style","page":"Contributor Guide","title":"Code style","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"Follow the style guide recommended in the official Julia documentation\nUse camel case format for custom types e.g. MyType\nWe prefer easy-to-read function names e.g. use calculate_flux over calf or similar. All in lower case and words separated with an underscore\nFor internal variables feel free to use Unicode symbols, or camel case identifiers. However, please refrain from doing this for any top-level or user-facing API variables.\nAlthough Julia allows some impressive one-liners, please avoid. These can be hard to reason sometimes, aim to strike a balance between succinctness and clarity. ","category":"page"},{"location":"contributor_guide/#Code-contribution","page":"Contributor Guide","title":"Code contribution","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"Please open a PR for any code contributions against our main branch if your are contributing top level functionality that builds on existing code e.g. a new turbulence model or a new boundary condition (these contributions will typically be included inside one of the existing sub modules)\nFor contributions that may require code reorganisation please do get in touch to ensure this aligns with any planned changes (open an issue). PRs will likely be requested against the current dev branch\nIdeally, all contributions will also include basic documentation and tests.","category":"page"},{"location":"contributor_guide/#Help-wanted","page":"Contributor Guide","title":"Help wanted","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"If you have specific expertise in MPI or Multi-GPU implementation and wish to get involved please get in touch.","category":"page"},{"location":"contributor_guide/#Module-organisation","page":"Contributor Guide","title":"Module organisation","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"Module Description\nXCALibre.Mesh This module defines all types required to construct the mesh object used by the flow solvers. Two main mesh types are used Mesh2 and Mesh3 used for 2D and 3D simulations, respectively. Some access functions are also included in this module.\nXCALibre.Fields This module defines the fields used to hold and represent the flow variable. Scalar, vector and tensor fields are defined e.g. ScalarField, etc. Information is stored at cell centres. These fields also have face variant where information is stored at face centres e.g. FaceVectorField. These fields are generally used to store fluxes. A limited set of field operations are also defined e.g. getfield to allow indexing field object directly.\nXCALibre.ModelFramework This module provides the framework used to define scalar and vector model equations whilst storing information about the operators used. The data structure also defines sparse matrices used to store discretisation information.\nXCALibre.Discretise This module defines the various operators needed to represent each terms in a model equation and the main discretisation loop that linearises each term according to the schemes available. Boundary conditions are also implemented in this module.\nXCALibre.Solve This module includes all functions and logic needed to solve the linear system of equations that follows the equation discretisation. The internal API to solve these systems of equations is included in this module.\nXCALibre.Calculate Implementation of functions use to carry out calculations essential to the implementation of flow solvers is included in this module. This includes interpolation of variables from cell centroid to cell faces, gradient calculation, surface normals, etc.\nXCALibre.ModelPhysics This module includes the implementations of all the physical models i.e. fluid, turbulence and energy models.\nXCALibre.Simulate This model contains information needed to set up a simulation, including the Configuration type used by all flow solvers.\nXCALibre.Solvers Implementations of the SIMPLE and PISO flow solvers from steady and unsteady solutions, including their compressible variant.\nXCALibre.Postprocess A limited set of functions for postprocessing are implemented in this module.\nXCALibre.VTK Functions to write 2D (.vtk) and 3D (.vtu) simulation results compatible with ParaView for postprocessing are implemented in this module.\nXCALibre.FoamMesh Stand alone module to parse, process (geometry calculation) and import OpenFOAM mesh files into XCALibre.jl\nXCALibre.UNV3 Stand alone module to parse, process (geometry calculation) and import UNV (3D) mesh files into XCALibre.jl\nXCALibre.UNV2 Stand alone module to parse, process (geometry calculation) and import UNV (2D) mesh files into XCALibre.jl","category":"page"},{"location":"contributor_guide/#Key-types-and-structures","page":"Contributor Guide","title":"Key types and structures","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"","category":"page"},{"location":"contributor_guide/#Mesh-type-and-format","page":"Contributor Guide","title":"Mesh type and format","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"The definitions of the data structures used to define Mesh3 objects is given below. Note that for succinctness only 3D structures are shown since all the 2D structures are identical. The type is only used for dispatching solvers to operate in 2D or 3D. ","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"Mesh3\nNode\nFace3D\nCell\nBoundary","category":"page"},{"location":"contributor_guide/#XCALibre.Mesh.Mesh3-contributor_guide","page":"Contributor Guide","title":"XCALibre.Mesh.Mesh3","text":"struct Mesh3{VC, VI, VF<:AbstractArray{<:Face3D}, VB, VN, SV3, UR} <: AbstractMesh\n cells::VC # vector of cells\n cell_nodes::VI # vector of indices to access cell nodes\n cell_faces::VI # vector of indices to access cell faces\n cell_neighbours::VI # vector of indices to access cell neighbours\n cell_nsign::VI # vector of indices to with face normal correction (1 or -1 )\n faces::VF # vector of faces\n face_nodes::VI # vector of indices to access face nodes\n boundaries::VB # vector of boundaries\n nodes::VN # vector of nodes\n node_cells::VI # vector of indices to access node cells\n get_float::SV3 # store mesh float type\n get_int::UR # store mesh integer type\n boundary_cellsID::VI # vector of indices of boundary cell IDs\nend\n\n\n\n\n\n","category":"type"},{"location":"contributor_guide/#XCALibre.Mesh.Node-contributor_guide","page":"Contributor Guide","title":"XCALibre.Mesh.Node","text":"struct Node{SV3<:SVector{3,<:AbstractFloat}, UR<:UnitRange{<:Integer}}\n coords::SV3 # node coordinates\n cells_range::UR # range to access neighbour cells in Mesh3.node_cells\nend\n\n\n\n\n\n","category":"type"},{"location":"contributor_guide/#XCALibre.Mesh.Face3D-contributor_guide","page":"Contributor Guide","title":"XCALibre.Mesh.Face3D","text":"struct Face3D{\n F<:AbstractFloat, \n SV2<:SVector{2,<:Integer},\n SV3<:SVector{3,F}, \n UR<:UnitRange{<:Integer}\n }\n \n nodes_range::UR # range to access face nodes in Mesh3.face_nodes\n ownerCells::SV2 # IDs of face owner cells (always 2)\n centre::SV3 # coordinates of face centre\n normal::SV3 # face normal unit vector\n e::SV3 # unit vector in the direction between owner cells\n area::F # face area\n delta::F # distance between owner cells centres\n weight::F # linear interpolation weight\nend\n\n\n\n\n\n","category":"type"},{"location":"contributor_guide/#XCALibre.Mesh.Cell-contributor_guide","page":"Contributor Guide","title":"XCALibre.Mesh.Cell","text":"struct Cell{F<:AbstractFloat, SV3<:SVector{3,F},UR<:UnitRange{<:Integer}}\n centre::SV3 # coordinate of cell centroid\n volume::F # cell volume\n nodes_range::UR # range to access cell nodes in Mesh3.cell_nodes\n faces_range::UR # range to access cell faces info (faces, neighbours cells, etc.)\nend\n\n\n\n\n\n","category":"type"},{"location":"contributor_guide/#XCALibre.Mesh.Boundary-contributor_guide","page":"Contributor Guide","title":"XCALibre.Mesh.Boundary","text":"struct Boundary{S<:Symbol, UR<:UnitRange{<:Integer}} name::S # Boundary patch name IDsrange::UR # range to access boundary info (faces and boundarycellsID) end\n\n\n\n\n\n","category":"type"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"To fully characterise how mesh information is represented in XCALibre.jl, it is important to highlight the following \"contracts\" that are exploited throughout:","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"Node, face and cell IDs correspond to the index where they are stored in their corresponding vector in the Mesh3 structure e.g. Mesh3.Faces[10] would return information for the face whose ID is 10. These vectors are 1-indexed as standard in Julia.\nFace normals at boundary faces is always pointing outside the domain e.g. they point in the direction expected in the FVM\nFace normals for internal faces is always pointing in the direction from the ownerCell with the smallest ID to the largest. Since the discretisation loop is cell based, for the cell with the highest ID the direction must be reversed. This information is tracked in Mesh3.nsign which stores 1 if the face normal is correctly aligned or -1 if the normal needs to be reversed.\nBoundary faces (e.g. patches) are stored consecutively in Mesh3.Faces starting at the beginning of the array followed by all the internal faces.\nBoundary faces are those connected only to 1 Cell, thus, for these faces the entry Face3D.ownerCells is a 2-element vector with a repeated index e.g. [3, 3]\nBoundary cells only store information for internal faces. This improves performance for the main discretisation loop (cell based) since it can always been assumed that none of the faces will be a boundary face, which are dealt with in a separate loop.","category":"page"},{"location":"contributor_guide/#Field-types","page":"Contributor Guide","title":"Field types","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"After the Mesh2 and Mesh3 objects, the most fundamental data structure in XCALibre.jl are fields used to represent the flow variables. In the current implementation, the prime field is the ScalarField for storing information at cell centres, and the corresponding FaceScalarField to store information at cell faces (normally fluxes). Internally, both are identical, therefore, the internal structure of the \"Face\" variants will not be discussed. ScalarFields have the following definition:","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"ScalarField","category":"page"},{"location":"contributor_guide/#XCALibre.Fields.ScalarField-contributor_guide","page":"Contributor Guide","title":"XCALibre.Fields.ScalarField","text":"struct ScalarField{VF,M<:AbstractMesh,BC} <: AbstractScalarField\n values::VF # scalar values at cell centre\n mesh::M # reference to mesh\n BCs::BC # store user-provided boundary conditions\nend\n\n\n\n\n\n","category":"type"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"Vector and tensors are represented internally by their individual components, as an illustration the VectorField type is shown below. Notice that each component of both vector and tensor fields are themselves represented by the same ScalarField type shown above. This has some implementation benefits, i.e. reducing duplication and allowing for rapid development. However, the performance of other means of storing these fields is being investigated. Thus, these internals may change if we identify performance gains.","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"VectorField","category":"page"},{"location":"contributor_guide/#XCALibre.Fields.VectorField-contributor_guide","page":"Contributor Guide","title":"XCALibre.Fields.VectorField","text":"struct VectorField{S1<:ScalarField,S2,S3,M<:AbstractMesh,BC} <: AbstractVectorField\n x::S1 # x-component is itself a `ScalarField`\n y::S2 # y-component is itself a `ScalarField`\n z::S3 # z-component is itself a `ScalarField`\n mesh::M\n BCs::BC\nend\n\n\n\n\n\n","category":"type"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"All fields behave (mostly) like regular arrays and can be indexed using the standard Julia syntax e.g. say U is a VectorField, then U[3] would return the vector stored in cell with ID = 3 (as a SVector{3} for improved performance).","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"note: Note\nThe implementation of broadcasting operations has been put on hold until a more thorough investigation of alternative data structures for vector and tensor fields has been completed. This is ongoing work. ","category":"page"},{"location":"contributor_guide/#Boundary-conditions","page":"Contributor Guide","title":"Boundary conditions","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"To implement a new boundary condition the following elements are required (see source code for Dirichlet, for example):","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"type definition: a structure containing the fields :ID and :value\nfixedValue function: used to check that user provided information is suitable for this boundary being implemented\nImplementation of the boundary face value: functor defining the boundary condition implementation, facilitated by a macro (see details below)\nScalar and vector face value interpolation: kernels to specify how to transfer cell information to the boundary. ","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"Developers and contributors are encouraged to explore the source code for examples on existing implementations of boundary conditions. To ease their implementation the XCALibre.Discretise.@define_boundary is provided.","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"XCALibre.Discretise.@define_boundary","category":"page"},{"location":"contributor_guide/#XCALibre.Discretise.@define_boundary-contributor_guide","page":"Contributor Guide","title":"XCALibre.Discretise.@define_boundary","text":"macro define_boundary(boundary, operator, definition)\n quote\n @inline (bc::$boundary)(\n term::Operator{F,P,I,$operator}, cellID, zcellID, cell, face, fID, i, component, time\n ) where {F,P,I} = $definition\n end |> esc\nend\n\nMacro to reduce boilerplate code when defining boundary conditions (implemented as functors) and provides access to key fields needed in the implementation of boundary conditions, such as the boundary cell and face objects (more details below)\n\nInput arguments\n\nboundary specifies the boundary type being defined\noperator specifies the operator to which the condition applies e.g. Laplacian\ndefinition provides the implementation details\n\nAvailable fields\n\nterm reference to operator on which the boundary applies (gives access to the field and mesh) \ncellID ID of the corresponding boundary cell\nzcellID sparse matrix linear index for the cell\ncell gives access to boundary cell object and corresponding information\nface gives access to boundary face object and corresponding information\nfID ID of the boundary face (to index Mesh2.faces vector)\ni local index of the boundary faces within a kernel or loop\ncomponent for vectors this specifies the components being evaluated (access as component.value). For scalars component = nothing\ntime provides the current simulation time. This only applies to time dependent boundary implementation defined as functions or neural networks.\n\nExample\n\nBelow the use of this macro is illustrated for the implementation of a Dirichlet boundary condition acting on the Laplacian using the Linear scheme:\n\n@define_boundary Dirichlet Laplacian{Linear} begin\n J = term.flux[fID] # extract operator flux\n (; area, delta) = face # extract boundary face information\n flux = J*area/delta # calculate the face flux\n ap = term.sign*(-flux) # diagonal (cell) matrix coefficient\n ap, ap*bc.value # return `ap` and `an`\nend\n\nWhen called, this functor will return two values ap and an, where ap is the cell contribution for approximating the boundary face value, and an is the explicit part of the face value approximation i.e. ap contributes to the diagonal of the sparse matrix (left-hand side) and an is the explicit contribution assigned to the solution vector b on the right-hand of the linear system of equations Ax = b\n\n\n\n\n\n","category":"macro"},{"location":"contributor_guide/#Implementing-new-models","page":"Contributor Guide","title":"Implementing new models","text":"","category":"section"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"","category":"page"},{"location":"contributor_guide/","page":"Contributor Guide","title":"Contributor Guide","text":"The internal API for models is still somewhat experimental, thus, it is more instructive to explore the source code. Although not fully finalised, the implementation is reasonably straight forward to follow thanks to the abstractions that have been adopted, some of which are described above, as well as the use of descriptive names for internal functions. If you need help on any aspect of the internals, for now, it is recommended to contact us by opening an issue.","category":"page"},{"location":"user_guide/5_postprocessing/#Post-processing","page":"Post-processing","title":"Post-processing","text":"","category":"section"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"Information about postprocessing XCALibre.jl results","category":"page"},{"location":"user_guide/5_postprocessing/#ParaView","page":"Post-processing","title":"ParaView","text":"","category":"section"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"","category":"page"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"All solvers in XCALibre.jl will write simulation results in formats that can be loaded directly in ParaView, which is the leading open-source project for scientific visualisation and postprocessing. More information about how to use ParaView can be found in the resources page on their website.","category":"page"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"XCALibre.jl uses two different VTK formats depending on the type of flow solver used. For 2D simulations, the results are written to file using the .vtk file format. 3D simulations are written using the unstructured VTK file format, .vtu. ","category":"page"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"note: Note\nA limitation of the current VTK writers in XCALibre.jl is that boundary information is stored along with internal mesh cell information, and result are stored at cell centres only. Thus, care must be taken when visualising results at boundary faces. In future releases a separation of boundary and internal mesh results is planned. ","category":"page"},{"location":"user_guide/5_postprocessing/#Available-functions","page":"Post-processing","title":"Available functions","text":"","category":"section"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"","category":"page"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"Although ParaView offers considerable flexibility for postprocessing results, users may also wish to carry out more advanced or different analyses on their CFD results. At present XCALibre.jl offers a limited set of pre-defined postprocessing functions, however, defining new custom postprocessing functions is reasonably straight-forward since these can be written in pure Julia. In this section, examples of postprocessing functions will be provided as an illustration. ","category":"page"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"note: Note\nAt present all postprocessing functions available in XCALibre.jl will only execute on CPUs and should be considered experimental. Once we settle on a \"sensible\" (maintainable and extensible) API, we plan to offer a larger selection of postprocessing tools which are likely to include options for runtime postprocessing.","category":"page"},{"location":"user_guide/5_postprocessing/#Example:-Calculate-boundary-average","page":"Post-processing","title":"Example: Calculate boundary average","text":"","category":"section"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"In this example, a function is shown that can be used to calculate the average on a user-provided boundary. ","category":"page"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"boundary_average","category":"page"},{"location":"user_guide/5_postprocessing/#XCALibre.Postprocess.boundary_average-user_guide-5_postprocessing","page":"Post-processing","title":"XCALibre.Postprocess.boundary_average","text":"function boundary_average(patch::Symbol, field, config; time=0)\n # Extract mesh object\n mesh = field.mesh\n\n # Determine ID (index) of the boundary patch \n ID = boundary_index(mesh.boundaries, patch)\n @info \"calculating average on patch: $patch at index $ID\"\n boundary = mesh.boundaries[ID]\n (; IDs_range) = boundary\n\n # Create face field of same type provided by user (scalar or vector)\n sum = nothing\n if typeof(field) <: VectorField \n faceField = FaceVectorField(mesh)\n sum = zeros(_get_float(mesh), 3) # create zero vector\n else\n faceField = FaceScalarField(mesh)\n sum = zero(_get_float(mesh)) # create zero\n end\n\n # Interpolate CFD results to boundary\n interpolate!(faceField, field, config)\n correct_boundaries!(faceField, field, field.BCs, time, config)\n\n # Calculate the average\n for fID ∈ IDs_range\n sum += faceField[fID]\n end\n ave = sum/length(IDs_range)\n\n # return average\n return ave\nend\n\n\n\n\n\n","category":"function"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"To calculate pressure and viscous forces, the following functions are available:","category":"page"},{"location":"user_guide/5_postprocessing/","page":"Post-processing","title":"Post-processing","text":"pressure_force\nviscous_force","category":"page"},{"location":"user_guide/5_postprocessing/#XCALibre.Postprocess.pressure_force-user_guide-5_postprocessing","page":"Post-processing","title":"XCALibre.Postprocess.pressure_force","text":"pressure_force(patch::Symbol, p::ScalarField, rho)\n\nFunction to calculate the pressure force acting on a given patch/boundary.\n\nInput arguments\n\npatch::Symbol name of the boundary of interest (as a Symbol)\np::ScalarField pressure field\nrho density. Set to 1 for incompressible solvers\n\n\n\n\n\n","category":"function"},{"location":"user_guide/5_postprocessing/#XCALibre.Postprocess.viscous_force-user_guide-5_postprocessing","page":"Post-processing","title":"XCALibre.Postprocess.viscous_force","text":"viscous_force(patch::Symbol, U::VectorField, rho, ν, νt)\n\nFunction to calculate the pressure force acting on a given patch/boundary.\n\nInput arguments\n\npatch::Symbol name of the boundary of interest (as a Symbol)\nU::VectorField pressure field\nrho density. Set to 1 for incompressible solvers\nν laminar viscosity of the fluid\nνt eddy viscosity from turbulence models. Pass ConstantScalar(0) for laminar flows\n\n\n\n\n\n","category":"function"},{"location":"reference/#Reference","page":"Reference","title":"Reference","text":"","category":"section"},{"location":"reference/","page":"Reference","title":"Reference","text":"Modules = [\n XCALibre, \n XCALibre.Mesh, \n XCALibre.UNV2, \n XCALibre.UNV3, \n XCALibre.FoamMesh, \n XCALibre.Fields,\n XCALibre.ModelFramework,\n XCALibre.Discretise, \n XCALibre.Solve,\n XCALibre.Calculate, \n XCALibre.ModelPhysics,\n XCALibre.Simulate,\n XCALibre.Solvers,\n XCALibre.Postprocess\n ]","category":"page"},{"location":"reference/#XCALibre.Mesh.Boundary","page":"Reference","title":"XCALibre.Mesh.Boundary","text":"struct Boundary{S<:Symbol, UR<:UnitRange{<:Integer}} name::S # Boundary patch name IDsrange::UR # range to access boundary info (faces and boundarycellsID) end\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Mesh.Cell","page":"Reference","title":"XCALibre.Mesh.Cell","text":"struct Cell{F<:AbstractFloat, SV3<:SVector{3,F},UR<:UnitRange{<:Integer}}\n centre::SV3 # coordinate of cell centroid\n volume::F # cell volume\n nodes_range::UR # range to access cell nodes in Mesh3.cell_nodes\n faces_range::UR # range to access cell faces info (faces, neighbours cells, etc.)\nend\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Mesh.Face3D","page":"Reference","title":"XCALibre.Mesh.Face3D","text":"struct Face3D{\n F<:AbstractFloat, \n SV2<:SVector{2,<:Integer},\n SV3<:SVector{3,F}, \n UR<:UnitRange{<:Integer}\n }\n \n nodes_range::UR # range to access face nodes in Mesh3.face_nodes\n ownerCells::SV2 # IDs of face owner cells (always 2)\n centre::SV3 # coordinates of face centre\n normal::SV3 # face normal unit vector\n e::SV3 # unit vector in the direction between owner cells\n area::F # face area\n delta::F # distance between owner cells centres\n weight::F # linear interpolation weight\nend\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Mesh.Mesh3","page":"Reference","title":"XCALibre.Mesh.Mesh3","text":"struct Mesh3{VC, VI, VF<:AbstractArray{<:Face3D}, VB, VN, SV3, UR} <: AbstractMesh\n cells::VC # vector of cells\n cell_nodes::VI # vector of indices to access cell nodes\n cell_faces::VI # vector of indices to access cell faces\n cell_neighbours::VI # vector of indices to access cell neighbours\n cell_nsign::VI # vector of indices to with face normal correction (1 or -1 )\n faces::VF # vector of faces\n face_nodes::VI # vector of indices to access face nodes\n boundaries::VB # vector of boundaries\n nodes::VN # vector of nodes\n node_cells::VI # vector of indices to access node cells\n get_float::SV3 # store mesh float type\n get_int::UR # store mesh integer type\n boundary_cellsID::VI # vector of indices of boundary cell IDs\nend\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Mesh.Node","page":"Reference","title":"XCALibre.Mesh.Node","text":"struct Node{SV3<:SVector{3,<:AbstractFloat}, UR<:UnitRange{<:Integer}}\n coords::SV3 # node coordinates\n cells_range::UR # range to access neighbour cells in Mesh3.node_cells\nend\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.UNV2.UNV2D_mesh-Tuple{Any}","page":"Reference","title":"XCALibre.UNV2.UNV2D_mesh","text":"UNV2D_mesh(meshFile; scale=1, integer_type=Int64, float_type=Float64)\n\nRead and convert 2D UNV mesh file into XCALibre.jl\n\nInput\n\nmeshFile – path to mesh file.\n\nOptional arguments\n\nscale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling\ninteger_type - select interger type to use in the mesh (Int32 may be useful on GPU runs) \nfloat_type - select interger type to use in the mesh (Float32 may be useful on GPU runs) \n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.UNV3.UNV3D_mesh-Tuple{Any}","page":"Reference","title":"XCALibre.UNV3.UNV3D_mesh","text":"UNV3D_mesh(unv_mesh; scale=1, integer_type=Int64, float_type=Float64)\n\nRead and convert 3D UNV mesh file into XCALibre.jl. Note that a limitation of the .unv mesh format is that it only supports the following 3D cells:\n\nTetahedrals\nPrisms\nHexahedrals\n\nInput\n\nunv_mesh – path to mesh file.\n\nOptional arguments\n\nscale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling\ninteger_type - select interger type to use in the mesh (Int32 may be useful on GPU runs) \nfloat_type - select interger type to use in the mesh (Float32 may be useful on GPU runs) \n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.FoamMesh.FOAM3D_mesh-Tuple{Any}","page":"Reference","title":"XCALibre.FoamMesh.FOAM3D_mesh","text":"FOAM3D_mesh(mesh_file; scale=1, integer_type=Int64, float_type=Float64)\n\nRead and convert 3D OpenFOAM mesh file into XCALibre.jl. Note that, at present, it is not recommended to run 2D cases using meshes imported using this function.\n\nInput\n\nmesh_file – path to mesh file.\n\nOptional arguments\n\nscale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling\ninteger_type - select interger type to use in the mesh (Int32 may be useful on GPU runs) \nfloat_type - select interger type to use in the mesh (Float32 may be useful on GPU runs) \n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Fields.ScalarField","page":"Reference","title":"XCALibre.Fields.ScalarField","text":"struct ScalarField{VF,M<:AbstractMesh,BC} <: AbstractScalarField\n values::VF # scalar values at cell centre\n mesh::M # reference to mesh\n BCs::BC # store user-provided boundary conditions\nend\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Fields.VectorField","page":"Reference","title":"XCALibre.Fields.VectorField","text":"struct VectorField{S1<:ScalarField,S2,S3,M<:AbstractMesh,BC} <: AbstractVectorField\n x::S1 # x-component is itself a `ScalarField`\n y::S2 # y-component is itself a `ScalarField`\n z::S3 # z-component is itself a `ScalarField`\n mesh::M\n BCs::BC\nend\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Fields.initialise!-Tuple{Any, Any}","page":"Reference","title":"XCALibre.Fields.initialise!","text":"function initialise!(field, value) # dummy function for documentation\n # Assign `value` to field in-place\n nothing\nend\n\nThis function will set the given field to the value provided in-place. Useful for initialising fields prior to running a simulation.\n\nInput arguments\n\nfield specifies the field to be initialised. The field must be either a AbractScalarField or AbstractVectorField\nvalue defines the value to be set. This should be a scalar or vector (3 components) depending on the field to be modified e.g. for an AbstractVectorField we can specify as value=[10,0,0]\n\nNote: in most cases the fields to be modified are stored within a physics model i.e. a Physics object. Thus, the argument value must fully qualify the model. For example, if we have created a Physics model named mymodel to set the velocity field, U, we would set the argument field to mymodel.momentum.U. See the example below.\n\nExample\n\ninitialise!(mymodel.momentum.U, [2.5, 0, 0])\ninitialise!(mymodel.momentum.p, 1.25)\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Discretise.Dirichlet","page":"Reference","title":"XCALibre.Discretise.Dirichlet","text":"Dirichlet <: AbstractDirichlet\n\nDirichlet boundary condition model.\n\nFields\n\n'ID' – Boundary ID\nvalue – Scalar or Vector value for Dirichlet boundary condition.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Discretise.DirichletFunction","page":"Reference","title":"XCALibre.Discretise.DirichletFunction","text":"DirichletFunction(ID, value) <: AbstractDirichlet\n\nDirichlet boundary condition defined with user-provided function.\n\nInput\n\nID Boundary name provided as symbol e.g. :inlet\nvalue Custom function for Dirichlet boundary condition.\n\nFunction requirements\n\nThe function passed to this boundary condition must have the following signature:\n\nf(coords, time, index) = SVector{3}(ux, uy, uz)\n\nWhere, coords is a vector containing the coordinates of a face, time is the current time in transient simulations (and the iteration number in steady simulations), and index is the local face index (from 1 to N, where N is the number of faces in a given boundary). The function must return an SVector (from StaticArrays.jl) representing the velocity vector. \n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Discretise.FixedTemperature","page":"Reference","title":"XCALibre.Discretise.FixedTemperature","text":"FixedTemperature <: AbstractDirichlet\n\nFixed temperature boundary condition model, which allows the user to specify wall temperature that can be translated to the energy specific model, such as sensivle enthalpy.\n\nFields\n\n'ID' – Boundary ID\nvalue – Scalar or Vector value for Dirichlet boundary condition.\nT - Temperature value in Kelvin.\nmodel - Energy physics model for case.\n\nExamples\n\nFixedTemperature(:inlet, T=300.0, model=model.energy),\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Discretise.Neumann","page":"Reference","title":"XCALibre.Discretise.Neumann","text":"Neumann <: AbstractNeumann\n\nNeumann boundary condition model (currently only configured for zero gradient)\n\nFields\n\n'ID' – Boundary ID\nvalue – Scalar or Vector value for Neumann boundary condition.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Discretise.Periodic","page":"Reference","title":"XCALibre.Discretise.Periodic","text":"struct Periodic{I,V} <: AbstractPhysicalConstraint\n ID::I\n value::V\nend\n\nPeriodic boundary condition model.\n\nFields\n\n'ID' – Boundary ID\nvalue – tuple containing information needed to apply this boundary\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Discretise.Symmetry","page":"Reference","title":"XCALibre.Discretise.Symmetry","text":"Symmetry <: AbstractBoundary\n\nSymmetry boundary condition vector fields. For scalar fields use Neumann\n\nFields\n\n'ID' – Boundary ID\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Discretise.Wall","page":"Reference","title":"XCALibre.Discretise.Wall","text":"Wall <: AbstractDirichlet\n\nWall boundary condition model for no-slip wall condition.\n\nFields\n\n'ID' – Boundary ID\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Discretise.construct_periodic-Tuple{Any, Any, Symbol, Symbol}","page":"Reference","title":"XCALibre.Discretise.construct_periodic","text":"construct_periodic(mesh, backend, patch1::Symbol, patch2::Symbol)\n\nFunction for construction of periodic boundary conditions.\n\nInput\n\nmesh – Mesh.\nbackend – Backend configuraton.\npatch1 – Primary periodic patch ID.\npatch2 – Neighbour periodic patch ID.\n\nOutput\n\nperiodic::Tuple - tuple containing boundary defintions for patch1 and patch2 i.e. (periodic1, periodic2). The fields of periodic1 and periodic2 are \nID – Index to access boundary information in mesh object\nvalue – represents a NamedTuple with the following keyword arguments:\nindex – ID used to find boundary geometry information in the mesh object\ndistance – perpendicular distance between the patches\nface_map – vector providing indeces to faces of match patch\nismaster – flat to identify one of the patch pairs as the main patch\n\nExample\n\n- `periodic = construct_periodic(mesh, CPU(), :top, :bottom)` - Example using CPU \nbackend with periodic boundaries named `top` and `bottom`.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Discretise.set_schemes-Tuple{}","page":"Reference","title":"XCALibre.Discretise.set_schemes","text":"set_schemes(;\n # keyword arguments and their default values\n time=SteadyState,\n divergence=Linear, \n laplacian=Linear, \n gradient=Orthogonal) = begin\n \n # Returns NamedTuple definition for scheme \n (\n time=time,\n divergence=divergence,\n laplacian=laplacian,\n gradient=gradient\n )\nend\n\nThe set_schemes function is used at the top-level API to help users define discretisation schemes for every field solved. It offers default values, thus users can pick and choose which entry they wish to modify.\n\ninputs\n\ntime is used to set the time schemes (default is SteadyState)\ndivergence is used to set the divergence scheme (default is Linear) \nlaplacian is used to set the laplacian scheme (default is Linear)\ngradient is used to set the gradient scheme (default is Orthogonal)\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Discretise.@define_boundary-Tuple{Any, Any, Any}","page":"Reference","title":"XCALibre.Discretise.@define_boundary","text":"macro define_boundary(boundary, operator, definition)\n quote\n @inline (bc::$boundary)(\n term::Operator{F,P,I,$operator}, cellID, zcellID, cell, face, fID, i, component, time\n ) where {F,P,I} = $definition\n end |> esc\nend\n\nMacro to reduce boilerplate code when defining boundary conditions (implemented as functors) and provides access to key fields needed in the implementation of boundary conditions, such as the boundary cell and face objects (more details below)\n\nInput arguments\n\nboundary specifies the boundary type being defined\noperator specifies the operator to which the condition applies e.g. Laplacian\ndefinition provides the implementation details\n\nAvailable fields\n\nterm reference to operator on which the boundary applies (gives access to the field and mesh) \ncellID ID of the corresponding boundary cell\nzcellID sparse matrix linear index for the cell\ncell gives access to boundary cell object and corresponding information\nface gives access to boundary face object and corresponding information\nfID ID of the boundary face (to index Mesh2.faces vector)\ni local index of the boundary faces within a kernel or loop\ncomponent for vectors this specifies the components being evaluated (access as component.value). For scalars component = nothing\ntime provides the current simulation time. This only applies to time dependent boundary implementation defined as functions or neural networks.\n\nExample\n\nBelow the use of this macro is illustrated for the implementation of a Dirichlet boundary condition acting on the Laplacian using the Linear scheme:\n\n@define_boundary Dirichlet Laplacian{Linear} begin\n J = term.flux[fID] # extract operator flux\n (; area, delta) = face # extract boundary face information\n flux = J*area/delta # calculate the face flux\n ap = term.sign*(-flux) # diagonal (cell) matrix coefficient\n ap, ap*bc.value # return `ap` and `an`\nend\n\nWhen called, this functor will return two values ap and an, where ap is the cell contribution for approximating the boundary face value, and an is the explicit part of the face value approximation i.e. ap contributes to the diagonal of the sparse matrix (left-hand side) and an is the explicit contribution assigned to the solution vector b on the right-hand of the linear system of equations Ax = b\n\n\n\n\n\n","category":"macro"},{"location":"reference/#XCALibre.Solve.set_runtime-Union{Tuple{}, Tuple{N}, Tuple{I}} where {I<:Integer, N<:Number}","page":"Reference","title":"XCALibre.Solve.set_runtime","text":"set_runtime(; \n # keyword arguments\n iterations::I, \n write_interval::I, \n time_step::N\n ) where {I<:Integer,N<:Number} = begin\n \n # returned `NamedTuple``\n (\n iterations=iterations, \n dt=time_step, \n write_interval=write_interval)\nend\n\nThis is a convenience function to set the top-level runtime information. The inputs are all keyword arguments and provide basic information to flow solvers just before running a simulation.\n\nInput arguments\n\niterations::Integer specifies the number of iterations in a simulation run.\nwrite_interval::Integer defines how often simulation results are written to file (on the current working directory). The interval is currently based on number of iterations. Set to -1 to run without writing results to file.\ntime_step::Number the time step to use in the simulation. Notice that for steady solvers this is simply a counter and it is recommended to simply use 1.\n\nExample\n\nruntime = set_runtime(\n iterations=2000, time_step=1, write_interval=2000)\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Solve.set_solver-Union{Tuple{AbstractField}, Tuple{PT}, Tuple{S}} where {S, PT<:PreconditionerType}","page":"Reference","title":"XCALibre.Solve.set_solver","text":"set_solver( \n field::AbstractField;\n # keyword arguments and defaults\n solver::S, \n preconditioner::PT, \n convergence, \n relax,\n limit=(),\n itmax::Integer=100, \n atol=(eps(_get_float(field.mesh)))^0.9,\n rtol=_get_float(field.mesh)(1e-3)\n ) where {S,PT<:PreconditionerType} = begin\n\n # return NamedTuple\n TF = _get_float(field.mesh)\n (\n solver=solver, \n preconditioner=preconditioner, \n convergence=convergence |> TF, \n relax=relax |> TF, \n limit=limit,\n itmax=itmax, \n atol=atol |> TF, \n rtol=rtol |> TF\n )\nend\n\nThis function is used to provide solver settings that will be used internally in XCALibre.jl. It returns a NamedTuple with solver settings that are used internally by the flow solvers. \n\nInput arguments\n\nfield reference to the field to which the solver settings will apply (used to provide integer and float types required)\nsolver solver object from Krylov.jl and it could be one of BicgstabSolver, CgSolver, GmresSolver which are re-exported in XCALibre.jl\npreconditioner instance of preconditioner to be used e.g. Jacobi()\nconvergence sets the stopping criteria of this field\nrelax specifies the relaxation factor to be used e.g. set to 1 for no relaxation\nlimit used in some solvers to bound the solution within this limits e.g. (min, max). It defaults to ()\nitmax maximum number of iterations in a single solver pass (defaults to 100) \natol absolute tolerance for the solver (default to eps(FloatType)^0.9)\nrtol set relative tolerance for the solver (defaults to 1e-3)\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.Compressible","page":"Reference","title":"XCALibre.ModelPhysics.Compressible","text":"Compressible <: AbstractCompressible\n\nCompressible fluid model containing fluid field parameters for compressible flows with constant parameters - ideal gas with constant viscosity.\n\nFields\n\n'nu' – Fluid kinematic viscosity.\n'cp' – Fluid specific heat capacity.\ngamma – Ratio of specific heats.\nPr – Fluid Prantl number.\n\nExamples\n\nFluid{Compressible}(; nu=1E-5, cp=1005.0, gamma=1.4, Pr=0.7) - Constructur with default values.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.Fluid","page":"Reference","title":"XCALibre.ModelPhysics.Fluid","text":"Fluid <: AbstractFluid\n\nAbstract fluid model type for constructing new fluid models.\n\nFields\n\n'args' – Model arguments.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.Incompressible","page":"Reference","title":"XCALibre.ModelPhysics.Incompressible","text":"Incompressible <: AbstractIncompressible\n\nIncompressible fluid model containing fluid field parameters for incompressible flows.\n\nFields\n\n'nu' – Fluid kinematic viscosity.\n'rho' – Fluid density.\n\nExamples\n\nFluid{Incompressible}(nu=0.001, rho=1.0) - Constructor with default values.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.KOmega","page":"Reference","title":"XCALibre.ModelPhysics.KOmega","text":"KOmega <: AbstractTurbulenceModel\n\nkOmega model containing all kOmega field parameters.\n\nFields\n\n'k' – Turbulent kinetic energy ScalarField.\n'omega' – Specific dissipation rate ScalarField.\n'nut' – Eddy viscosity ScalarField.\n'kf' – Turbulent kinetic energy FaceScalarField.\n'omegaf' – Specific dissipation rate FaceScalarField.\n'nutf' – Eddy viscosity FaceScalarField.\n'coeffs' – Model coefficients.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.KOmegaLKE","page":"Reference","title":"XCALibre.ModelPhysics.KOmegaLKE","text":"KOmegaLKE <: AbstractTurbulenceModel\n\nkOmega model containing all kOmega field parameters.\n\nFields\n\n'k' – Turbulent kinetic energy ScalarField.\n'omega' – Specific dissipation rate ScalarField.\n'kl' – ScalarField.\n'nut' – Eddy viscosity ScalarField.\n'kf' – Turbulent kinetic energy FaceScalarField.\n'omegaf' – Specific dissipation rate FaceScalarField.\n'klf' – FaceScalarField.\n'nutf' – Eddy viscosity FaceScalarField.\n'coeffs' – Model coefficients.\n'Tu' – Freestream turbulence intensity for model.\n'y' – Near-wall distance for model.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.LES","page":"Reference","title":"XCALibre.ModelPhysics.LES","text":"LES <: AbstractLESModel\n\nAbstract LES model type for constructing LES models.\n\nFields\n\n'args' – Model arguments.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.Laminar","page":"Reference","title":"XCALibre.ModelPhysics.Laminar","text":"Laminar <: AbstractTurbulenceModel\n\nLaminar model definition for physics API.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.Momentum","page":"Reference","title":"XCALibre.ModelPhysics.Momentum","text":"struct Momentum{V,S,SS} <: AbstractMomentumModel\n U::V \n p::S \n sources::SS\nend\n\nMomentum model containing key momentum fields.\n\nFields\n\n'U' – Velocity VectorField.\n'p' – Pressure ScalarField.\n'sources' – Momentum model sources.\n\nExamples\n\n`Momentum(mesh::AbstractMesh)\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.Physics","page":"Reference","title":"XCALibre.ModelPhysics.Physics","text":"struct Physics{T,F,M,Tu,E,D,BI}\n time::T\n fluid::F\n momentum::M \n turbulence::Tu \n energy::E\n domain::D\n boundary_info::BI\nend\n\nXCALibre's parametric Physics type for user-level API. Also used to dispatch flow solvers.\n\nFields\n\n'time::Union{Steady, Transient}' – User-provided time model.\n'fluid::AbstractFluid' – User-provided Fluid` model.\n'momentum' – Momentum model. Currently this is auto-generated by the Physics constructor\n'turbulence::AbstractTurbulenceModel' – User-provided Turbulence` model.\n'energy:AbstractEnergyModel' – User-provided Energy model.\n'domain::AbstractMesh ' – User-provided Mesh. Must be adapted to target device before constructing a Physics object.\n'boundaryinfo::boundaryinfo' – Mesh boundary information. Auto-generated by the Physics constructor\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.Physics-Tuple{}","page":"Reference","title":"XCALibre.ModelPhysics.Physics","text":"Physics(; time, fluid, turbulence, energy, domain)::Physics{T,F,M,Tu,E,D,BI}\n\nPhysics constructor part of the top-level API. It can be used to define the Physics and models relevant to a simulation. This constructor uses keyword arguments to allow users to fine-tune their simulations, whilst some fields are auto-generated behind the scenes for convenience (Momentum and boundary_info). Where:\n\ntime - specified the time model (Steady or Transient)\nfluid - specifies the type of fluid (Incompressible, etc.)\nturbulence - specified the Turbulence model\nenergy - specifies the Energy treatment\ndomain - provides the mesh to used (must be adapted to the target backend device)\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.RANS","page":"Reference","title":"XCALibre.ModelPhysics.RANS","text":"RANS <: AbstractRANSModel\n\nAbstract RANS model type for consturcting RANS models.\n\nFields\n\n'args' – Model arguments.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.SensibleEnthalpy","page":"Reference","title":"XCALibre.ModelPhysics.SensibleEnthalpy","text":"SensibleEnthalpy <: AbstractEnergyModel\n\nType that represents energy model, coefficients and respective fields.\n\nFields\n\n'h' – Sensible enthalpy ScalarField.\n'T' – Temperature ScalarField.\n'hf' – Sensible enthalpy FaceScalarField.\n'Tf' – Temperature FaceScalarField.\n'K' – Specific kinetic energy ScalarField.\n'dpdt' – Pressure time derivative ScalarField.\n'updated_BC' – Boundary condition function to convert temperature to sensible enthalp on on a fixed value boudary.\n'coeffs' – A tuple of model coefficients.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.Smagorinsky","page":"Reference","title":"XCALibre.ModelPhysics.Smagorinsky","text":"Smagorinsky <: AbstractTurbulenceModel\n\nSmagorinsky LES model containing all Smagorinksy field parameters.\n\nFields\n\n'nut' – Eddy viscosity ScalarField.\n'nutf' – Eddy viscosity FaceScalarField.\n'coeffs' – Model coefficients.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.Steady","page":"Reference","title":"XCALibre.ModelPhysics.Steady","text":"Steady\n\nSteady model for Physics model API.\n\nExamples\n\nSteady()\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.Transient","page":"Reference","title":"XCALibre.ModelPhysics.Transient","text":"Transient\n\nTransient model for Physics model API.\n\nExamples\n\nTransient()\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.WeaklyCompressible","page":"Reference","title":"XCALibre.ModelPhysics.WeaklyCompressible","text":"WeaklyCompressible <: AbstractCompressible\n\nWeakly compressible fluid model containing fluid field parameters for weakly compressible flows with constant parameters - ideal gas with constant viscosity.\n\nFields\n\n'nu' – Fluid kinematic viscosity.\n'cp' – Fluid specific heat capacity.\ngamma – Ratio of specific heats.\nPr – Fluid Prandtl number.\n\nExamples\n\nFluid{WeaklyCompressible}(; nu=1E-5, cp=1005.0, gamma=1.4, Pr=0.7) - Constructor with \n\ndefault values.\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.ModelPhysics.Ttoh!-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T1}, Tuple{Physics{T1, F, M, Tu, E, D, BI}, ScalarField, ScalarField}} where {T1, F<:AbstractCompressible, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.Ttoh!","text":"Ttoh!(model::Physics{T1,F,M,Tu,E,D,BI}, T::ScalarField, h::ScalarField\n) where {T1,F<:AbstractCompressible,M,Tu,E,D,BI}\n\nFunction coverts temperature ScalarField to sensible enthalpy ScalarField.\n\nInput\n\nmodel – Physics model defined by user.\nT – Temperature ScalarField.\nh – Sensible enthalpy ScalarField.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.change-Tuple{Physics, Any, Any}","page":"Reference","title":"XCALibre.ModelPhysics.change","text":"change(model::Physics, property, value) => updatedModel::Physics\n\nA convenience function to change properties of an exisitng Physics model.\n\nInput arguments\n\nmodel::Physics a Physics model to modify\nproperty is a symbol specifying the property to change \nvalue is the new setting for the specified property\n\nOutput\n\nThis function return a new Physics object\n\nExample\n\nTo change a model to run a transient simulation e.g. after converging in steady state\n\nmodelTransient = change(model, :time, Transient())\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.energy!-Union{Tuple{E1}, Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T1}, Tuple{XCALibre.ModelPhysics.Sensible_Enthalpy_Model{E1}, Physics{T1, F, M, Tu, E, D, BI}, Vararg{Any, 6}}} where {T1, F, M, Tu, E, D, BI, E1}","page":"Reference","title":"XCALibre.ModelPhysics.energy!","text":"energy::Sensible_Enthalpy_Model{E1}, model::Physics{T1,F,M,Tu,E,D,BI}, prev, mdotf, rho, mueff, time, config\n) where {T1,F,M,Tu,E,D,BI,E1}\n\nRun energy transport equations.\n\nInput\n\nenergy – Energy model.\nmodel – Physics model defined by user.\nprev – Previous energy cell values.\nmdtof – Face mass flow.\nrho – Density ScalarField.\nmueff – Effective viscosity FaceScalarField.\ntime –\nconfig – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.htoT!-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T1}, Tuple{Physics{T1, F, M, Tu, E, D, BI}, ScalarField, ScalarField}} where {T1, F<:AbstractCompressible, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.htoT!","text":"htoT!(model::Physics{T1,F,M,Tu,E,D,BI}, h::ScalarField, T::ScalarField\n) where {T1,F<:AbstractCompressible,M,Tu,E,D,BI}\n\nFunction coverts sensible enthalpy ScalarField to temperature ScalarField.\n\nInput\n\nmodel – Physics model defined by user.\nh – Sensible enthalpy ScalarField.\nT – Temperature ScalarField.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.initialise-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T1}, Tuple{SensibleEnthalpy, Physics{T1, F, M, Tu, E, D, BI}, Vararg{Any, 4}}} where {T1, F, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.initialise","text":"initialise(energy::SensibleEnthalpy, model::Physics{T1,F,M,Tu,E,D,BI}, mdotf, rho, peqn, config\n) where {T1,F,M,Tu,E,D,BI})\n\nInitialisation of energy transport equations.\n\nInput\n\nenergy – Energy model.\nmodel – Physics model defined by user.\nmdtof – Face mass flow.\nrho – Density ScalarField.\npeqn – Pressure equation.\nconfig – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.\n\nOutput\n\nSensible_Enthalpy_Model – Energy model struct containing energy equation.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.initialise-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{KOmega, Physics{T, F, M, Tu, E, D, BI}, Any, Any, Any}} where {T, F, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.initialise","text":"initialise(turbulence::KOmega, model::Physics{T,F,M,Tu,E,D,BI}, mdotf, peqn, config\n) where {T,F,M,Tu,E,D,BI}\n\nInitialisation of turbulent transport equations.\n\nInput\n\nturbulence – turbulence model.\nmodel – Physics model defined by user.\nmdtof – Face mass flow.\npeqn – Pressure equation.\nconfig – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.\n\nOutput\n\nKOmegaModel(k_eqn, ω_eqn) – Turbulence model structure.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.initialise-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{KOmegaLKE, Physics{T, F, M, Tu, E, D, BI}, Any, Any, Any}} where {T, F, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.initialise","text":"initialise(turbulence::KOmegaLKE, model::Physics{T,F,M,Tu,E,D,BI}, mdotf, peqn, config\n) where {T,F,M,Tu,E,D,BI}\n\nInitialisation of turbulent transport equations.\n\nInput\n\nturbulence – turbulence model.\nmodel – Physics model defined by user.\nmdtof – Face mass flow.\npeqn – Pressure equation.\nconfig – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.\n\nOutput\n\nKOmegaLKEModel( k_eqn, ω_eqn, kl_eqn, nueffkLS, nueffkS, nueffωS, nuL, nuts, Ω, γ, fv, normU, Reυ, ∇k, ∇ω ) – Turbulence model structure.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.initialise-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{Laminar, Physics{T, F, M, Tu, E, D, BI}, Any, Any, Any}} where {T, F, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.initialise","text":"function initialise(\n turbulence::Laminar, model::Physics{T,F,M,Tu,E,D,BI}, mdotf, peqn, config\n ) where {T,F,M,Tu,E,D,BI}\nreturn LaminarModel()\n\nend\n\nInitialisation of turbulent transport equations.\n\nInput\n\nturbulence – turbulence model.\nmodel – Physics model defined by user.\nmdtof – Face mass flow.\npeqn – Pressure equation.\nconfig – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.\n\nOutput\n\nLaminarModel() – Turbulence model structure.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.initialise-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{Smagorinsky, Physics{T, F, M, Tu, E, D, BI}, Any, Any, Any}} where {T, F, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.initialise","text":"initialise(turbulence::Smagorinsky, model::Physics{T,F,M,Tu,E,D,BI}, mdotf, peqn, config\n) where {T,F,M,Tu,E,D,BI}\n\nInitialisation of turbulent transport equations.\n\nInput\n\nturbulence – turbulence model.\nmodel – Physics model defined by user.\nmdtof – Face mass flow.\npeqn – Pressure equation.\nconfig – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.\n\nOutput\n\nSmagorinskyModel(Δ, magS) – Turbulence model structure.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.thermo_Psi!-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{Physics{T, F, M, Tu, E, D, BI}, FaceScalarField, Any}} where {T, F<:AbstractCompressible, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.thermo_Psi!","text":"thermo_Psi!(model::Physics{T,F,M,Tu,E,D,BI}, Psif::FaceScalarField) \nwhere {T,F<:AbstractCompressible,M,Tu,E,D,BI}\n\nFunction updates the value of Psi.\n\nInput\n\nmodel – Physics model defined by user.\nPsif – Compressibility factor FaceScalarField.\n\nAlgorithm\n\nWeakly compressible currently uses the ideal gas equation for establishing the compressibility factor where rho = p * Psi. Psi is calculated from the sensible enthalpy, reference temperature and fluid model specified C_p and R value where R is calculated from C_p and gamma specified in the fluid model.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.thermo_Psi!-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{Physics{T, F, M, Tu, E, D, BI}, ScalarField}} where {T, F<:AbstractCompressible, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.thermo_Psi!","text":"thermo_Psi!(model::Physics{T,F,M,Tu,E,D,BI}, Psi::ScalarField) \nwhere {T,F<:AbstractCompressible,M,Tu,E,D,BI}\n\nModel updates the value of Psi.\n\nInput\n\nmodel – Physics model defined by user.\nPsi – Compressibility factor ScalarField.\n\nAlgorithm\n\nWeakly compressible currently uses the ideal gas equation for establishing the compressibility factor where rho = p * Psi. Psi is calculated from the sensible enthalpy, reference temperature and fluid model specified C_p and R value where R is calculated from C_p and gamma specified in the fluid model.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.turbulence!-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Turb}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{XCALibre.ModelPhysics.KOmegaLKEModel, Physics{T, F, M, Turb, E, D, BI}, Vararg{Any, 5}}} where {T, F, M, Turb<:KOmegaLKE, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.turbulence!","text":"turbulence!(rans::KOmegaLKEModel, model::Physics{T,F,M,Turb,E,D,BI}, S, S2, prev, time, config ) where {T,F,M,Turb<:KOmegaLKE,E,D,BI}\n\nRun turbulence model transport equations.\n\nInput\n\nrans::KOmegaLKEModel – KOmega turbulence model.\nmodel – Physics model defined by user.\nS – Strain rate tensor.\nS2 – Square of the strain rate magnitude.\nprev – Previous field.\ntime – \nconfig – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.turbulence!-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{XCALibre.ModelPhysics.LaminarModel, Physics{T, F, M, Tu, E, D, BI}, Vararg{Any, 5}}} where {T, F, M, Tu<:Laminar, E, D, BI}","page":"Reference","title":"XCALibre.ModelPhysics.turbulence!","text":"turbulence!(rans::LaminarModel, model::Physics{T,F,M,Tu,E,D,BI}, S, S2, prev, time, config\n) where {T,F,M,Tu<:Laminar,E,D,BI}\n\nRun turbulence model transport equations.\n\nInput\n\nrans::LaminarModel – Laminar turbulence model.\nmodel – Physics model defined by user.\nS – Strain rate tensor.\nS2 – Square of the strain rate magnitude.\nprev – Previous field.\ntime – \nconfig – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.turbulence!-Union{Tuple{E2}, Tuple{E1}, Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{XCALibre.ModelPhysics.KOmegaModel{E1, E2}, Physics{T, F, M, Tu, E, D, BI}, Vararg{Any, 5}}} where {T, F, M, Tu<:KOmega, E, D, BI, E1, E2}","page":"Reference","title":"XCALibre.ModelPhysics.turbulence!","text":"turbulence!(rans::KOmegaModel{E1,E2}, model::Physics{T,F,M,Tu,E,D,BI}, S, S2, prev, time, config\n) where {T,F,M,Tu<:KOmega,E,D,BI,E1,E2}\n\nRun turbulence model transport equations.\n\nInput\n\nrans::KOmegaModel{E1,E2} – KOmega turbulence model.\nmodel – Physics model defined by user.\nS – Strain rate tensor.\nS2 – Square of the strain rate magnitude.\nprev – Previous field.\ntime – \nconfig – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.ModelPhysics.turbulence!-Union{Tuple{E2}, Tuple{E1}, Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{XCALibre.ModelPhysics.SmagorinskyModel{E1, E2}, Physics{T, F, M, Tu, E, D, BI}, Vararg{Any, 5}}} where {T, F, M, Tu<:Smagorinsky, E, D, BI, E1, E2}","page":"Reference","title":"XCALibre.ModelPhysics.turbulence!","text":"turbulence!(les::SmagorinskyModel{E1,E2}, model::Physics{T,F,M,Tu,E,D,BI}, S, S2, prev, time, config\n) where {T,F,M,Tu<:Smagorinsky,E,D,BI,E1,E2}\n\nRun turbulence model transport equations.\n\nInput\n\nles::SmagorinskyModel{E1,E2} – Smagorinsky LES turbulence model.\nmodel – Physics model defined by user.\nS – Strain rate tensor.\nS2 – Square of the strain rate magnitude.\nprev – Previous field.\ntime – \nconfig – Configuration structure defined by user with solvers, schemes, runtime and hardware structures set.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Simulate.Configuration","page":"Reference","title":"XCALibre.Simulate.Configuration","text":"@kwdef struct Configuration{SC,SL,RT,HW}\n schemes::SC\n solvers::SL\n runtime::RT\n hardware::HW\nend\n\nThe Configuration type is passed to all flow solvers and provides all the relevant information to run a simulation. \n\nInputs\n\nschemes::NamedTuple this keyword argument is used to pass distretisation scheme information to flow solvers. See Numerical setup for details.\nsolvers::NamedTuple this keyword argument is used to pass the configurations for the linear solvers for each field information to flow solvers. See Runtime and solvers for details.\nruntime::NamedTuple this keyword argument is used to pass runtime information to the flow solvers. See Runtime and solvers for details.\nhardware::NamedTuple this keyword argument is used to pass the hardware configuration and backend settings to the flow solvers. See Pre-processing for details.\n\nExample\n\nconfig = Configuration(\n solvers=solvers, schemes=schemes, runtime=runtime, hardware=hardware)\n\n\n\n\n\n","category":"type"},{"location":"reference/#XCALibre.Simulate.set_hardware-Tuple{}","page":"Reference","title":"XCALibre.Simulate.set_hardware","text":"hardware = set_hardware(backend, workgroup)\n\nFunction used to configure the backend.\n\nInputs\n\nbackend named tuple used to specify the backend e.g. CPU(), CUDABackend() or other backends supported by KernelAbstraction.jl\nworkgroup::Int this is an integer specifying the number of workers that cooperate in a parallel run. For GPUs this could be set to the size of the device's warp e.g. workgroup = 32. On CPUs, the default value in KernelAbstractions.jl is currently workgroup = 1024.\n\nOutput\n\nThis function returns a NamedTuple with the fields backend and workgroup which are accessed by internally in XCALibre.jl to execute a given kernel.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Solvers.cpiso!-Tuple{Any, Any}","page":"Reference","title":"XCALibre.Solvers.cpiso!","text":"cpiso!(model, config; \n limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0)\n\nCompressible and transient variant of the PISO algorithm with a sensible enthalpy transport equation for the energy. \n\nInput arguments\n\nmodel reference to a Physics` model defined by the user.\nconfig Configuration structure defined by the user with solvers, schemes, runtime and hardware structures configuration details.\nlimit_gradient flag use to activate gradient limiters in the solver (default = false)\npref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only (default = nothing)\nncorrectors number of non-orthogonality correction loops (default = 0)\ninner_loops number to inner loops used in transient solver based on PISO algorithm (default = 0)\n\nOutput\n\nUx Vector of x-velocity residuals for each iteration.\nUy Vector of y-velocity residuals for each iteration.\nUz Vector of y-velocity residuals for each iteration.\np Vector of pressure residuals for each iteration.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Solvers.csimple!-Tuple{Any, Any}","page":"Reference","title":"XCALibre.Solvers.csimple!","text":"csimple!(\n model_in, config; \n limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0\n)\n\nCompressible variant of the SIMPLE algorithm with a sensible enthalpy transport equation for the energy. \n\nInput arguments\n\nmodel reference to a Physics` model defined by the user.\nconfig Configuration structure defined by the user with solvers, schemes, runtime and hardware structures configuration details.\nlimit_gradient flag use to activate gradient limiters in the solver (default = false)\npref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only (default = nothing)\nncorrectors number of non-orthogonality correction loops (default = 0)\ninner_loops number to inner loops used in transient solver based on PISO algorithm (default = 0)\n\nOutput\n\nUx Vector of x-velocity residuals for each iteration.\nUy Vector of y-velocity residuals for each iteration.\nUz Vector of y-velocity residuals for each iteration.\np Vector of pressure residuals for each iteration.\ne Vector of energy residuals for each iteration.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Solvers.piso!-Tuple{Any, Any}","page":"Reference","title":"XCALibre.Solvers.piso!","text":"cpiso!(model, config; \n limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0)\n\nIncompressible and transient variant of the SIMPLE algorithm to solving coupled momentum and mass conservation equations. \n\nInput arguments\n\nmodel reference to a Physics` model defined by the user.\nconfig Configuration structure defined by the user with solvers, schemes, runtime and hardware structures configuration details.\nlimit_gradient flag use to activate gradient limiters in the solver (default = false)\npref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only (default = nothing)\nncorrectors number of non-orthogonality correction loops (default = 0)\ninner_loops number to inner loops used in transient solver based on PISO algorithm (default = 0)\n\nOutput\n\nUx Vector of x-velocity residuals for each iteration.\nUy Vector of y-velocity residuals for each iteration.\nUz Vector of y-velocity residuals for each iteration.\np Vector of pressure residuals for each iteration.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Solvers.run!-Tuple{}","page":"Reference","title":"XCALibre.Solvers.run!","text":"function run!(\n model::Physics, config; \n limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0\n )\n\n # here an internal function is used for solver dispatch\n return residuals\nend\n\nThis is the top level API function to initiate a simulation. It uses the user-provided model defined as a Physics object to dispatch to the appropriate solver.\n\nDispatched flow solvers\n\nSteady incompressible (SIMPLE algorithm for coupling)\nTransient incompressible (PISO algorithm for coupling)\nSteady weakly compressible (SIMPLE algorithm for coupling)\nTransient weakly compressible (PISO algorithm for coupling)\n\nInput arguments\n\nmodel reference to a Physics model defined by the user.\nconfig Configuration structure defined by the user with solvers, schemes, runtime and hardware structures configuration details.\nlimit_gradient flag used to activate gradient limiters in the solver (default = false)\npref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only (default = nothing)\nncorrectors number of non-orthogonality correction loops (default = 0)\ninner_loops number to inner loops used in transient solver based on PISO algorithm (default = 0)\n\nOutput\n\nThis function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux). The fields available within the returned residuals tuple depend on the solver used. For example, for an incompressible solver, a x-momentum equation residual can be retrieved accessing the Ux field i.e. residuals.Ux. Look at reference guide for each dispatch method to find out which fields are available.\n\nExample\n\nresiduals = run!(model, config) \n\n# to access the pressure residual\n\nresiduals.p \n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Solvers.run!-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{Physics{T, F, M, Tu, E, D, BI}, Any}} where {T<:Steady, F<:Incompressible, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.Solvers.run!","text":"run!(\n model::Physics{T,F,M,Tu,E,D,BI}, config;\n limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0\n ) where{T<:Steady,F<:Incompressible,M,Tu,E,D,BI} = \nbegin\n residuals = simple!(model, config, pref=pref)\n return residuals\nend\n\nCalls the incompressible steady solver using the SIMPLE algorithm.\n\nInput\n\nmodel represents the Physics` model defined by user.\nconfig Configuration structure defined by user with solvers, schemes, runtime and hardware structures configuration details.\npref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only.\n\nOutput\n\nThis function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux) with the following entries:\n\nUx - Vector of x-velocity residuals for each iteration.\nUy - Vector of y-velocity residuals for each iteration.\nUz - Vector of y-velocity residuals for each iteration.\np - Vector of pressure residuals for each iteration.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Solvers.run!-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{Physics{T, F, M, Tu, E, D, BI}, Any}} where {T<:Steady, F<:WeaklyCompressible, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.Solvers.run!","text":"run!(\n model::Physics{T,F,M,Tu,E,D,BI}, config; \n limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0\n ) where{T<:Steady,F<:WeaklyCompressible,M,Tu,E,D,BI} = \nbegin\n residuals = csimple!(model, config, pref=pref); #, pref=0.0)\n return residuals\nend\n\nCalls the compressible steady solver using the SIMPLE algorithm for weakly compressible fluids.\n\nInput\n\nmodel represents the Physics` model defined by user.\nconfig Configuration structure defined by user with solvers, schemes, runtime and hardware structures configuration details.\npref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only.\n\nOutput\n\nThis function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux) with the following entries:\n\nUx - Vector of x-velocity residuals for each iteration.\nUy - Vector of y-velocity residuals for each iteration.\nUz - Vector of y-velocity residuals for each iteration.\np - Vector of pressure residuals for each iteration.\ne - Vector of energy residuals for each iteration.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Solvers.run!-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{Physics{T, F, M, Tu, E, D, BI}, Any}} where {T<:Transient, F<:Incompressible, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.Solvers.run!","text":"run!(\n model::Physics{T,F,M,Tu,E,D,BI}, config; \n limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0\n ) where{T<:Transient,F<:Incompressible,M,Tu,E,D,BI} = \nbegin\n residuals = piso!(model, config, pref=pref); #, pref=0.0)\n return residuals\nend\n\nCalls the incompressible transient solver using the PISO algorithm.\n\nInput\n\nmodel represents the Physics` model defined by user.\nconfig Configuration structure defined by user with solvers, schemes, runtime and hardware structures configuration details.\npref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only.\n\nOutput\n\nThis function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux) with the following entries:\n\nUx - Vector of x-velocity residuals for each iteration.\nUy - Vector of y-velocity residuals for each iteration.\nUz - Vector of y-velocity residuals for each iteration.\np - Vector of pressure residuals for each iteration.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Solvers.run!-Union{Tuple{BI}, Tuple{D}, Tuple{E}, Tuple{Tu}, Tuple{M}, Tuple{F}, Tuple{T}, Tuple{Physics{T, F, M, Tu, E, D, BI}, Any}} where {T<:Transient, F<:WeaklyCompressible, M, Tu, E, D, BI}","page":"Reference","title":"XCALibre.Solvers.run!","text":"run!(\n model::Physics{T,F,M,Tu,E,D,BI}; \n limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0\n ) where{T<:Transient,F<:WeaklyCompressible,M,Tu,E,D,BI} = \nbegin\n residuals = cpiso!(model, config)\n return residuals\nend\n\nCalls the compressible transient solver using the PISO algorithm for weakly compressible fluids.\n\nInput\n\nmodel represents the Physics` model defined by user.\nconfig Configuration structure defined by user with solvers, schemes, runtime and hardware structures configuration details.\npref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only.\n\nOutput\n\nThis function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux) with the following entries:\n\nUx - Vector of x-velocity residuals for each iteration.\nUy - Vector of y-velocity residuals for each iteration.\nUz - Vector of y-velocity residuals for each iteration.\np - Vector of pressure residuals for each iteration.\ne - Vector of energy residuals for each iteration.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Solvers.simple!-Tuple{Any, Any}","page":"Reference","title":"XCALibre.Solvers.simple!","text":"simple!(model_in, config; \n limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0)\n\nIncompressible variant of the SIMPLE algorithm to solving coupled momentum and mass conservation equations.\n\nInput arguments\n\nmodel reference to a Physics` model defined by the user.\nconfig Configuration structure defined by the user with solvers, schemes, runtime and hardware structures configuration details.\nlimit_gradient flag use to activate gradient limiters in the solver (default = false)\npref Reference pressure value for cases that do not have a pressure defining BC. Incompressible solvers only (default = nothing)\nncorrectors number of non-orthogonality correction loops (default = 0)\ninner_loops number to inner loops used in transient solver based on PISO algorithm (default = 0)\n\nOutput\n\nThis function returns a NamedTuple for accessing the residuals (e.g. residuals.Ux) with the following entries:\n\nUx Vector of x-velocity residuals for each iteration.\nUy Vector of y-velocity residuals for each iteration.\nUz Vector of y-velocity residuals for each iteration.\np Vector of pressure residuals for each iteration.\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Postprocess.boundary_average-Tuple{Symbol, Any, Any}","page":"Reference","title":"XCALibre.Postprocess.boundary_average","text":"function boundary_average(patch::Symbol, field, config; time=0)\n # Extract mesh object\n mesh = field.mesh\n\n # Determine ID (index) of the boundary patch \n ID = boundary_index(mesh.boundaries, patch)\n @info \"calculating average on patch: $patch at index $ID\"\n boundary = mesh.boundaries[ID]\n (; IDs_range) = boundary\n\n # Create face field of same type provided by user (scalar or vector)\n sum = nothing\n if typeof(field) <: VectorField \n faceField = FaceVectorField(mesh)\n sum = zeros(_get_float(mesh), 3) # create zero vector\n else\n faceField = FaceScalarField(mesh)\n sum = zero(_get_float(mesh)) # create zero\n end\n\n # Interpolate CFD results to boundary\n interpolate!(faceField, field, config)\n correct_boundaries!(faceField, field, field.BCs, time, config)\n\n # Calculate the average\n for fID ∈ IDs_range\n sum += faceField[fID]\n end\n ave = sum/length(IDs_range)\n\n # return average\n return ave\nend\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Postprocess.pressure_force-Tuple{Symbol, ScalarField, Any}","page":"Reference","title":"XCALibre.Postprocess.pressure_force","text":"pressure_force(patch::Symbol, p::ScalarField, rho)\n\nFunction to calculate the pressure force acting on a given patch/boundary.\n\nInput arguments\n\npatch::Symbol name of the boundary of interest (as a Symbol)\np::ScalarField pressure field\nrho density. Set to 1 for incompressible solvers\n\n\n\n\n\n","category":"method"},{"location":"reference/#XCALibre.Postprocess.viscous_force-Tuple{Symbol, VectorField, Any, Any, Any}","page":"Reference","title":"XCALibre.Postprocess.viscous_force","text":"viscous_force(patch::Symbol, U::VectorField, rho, ν, νt)\n\nFunction to calculate the pressure force acting on a given patch/boundary.\n\nInput arguments\n\npatch::Symbol name of the boundary of interest (as a Symbol)\nU::VectorField pressure field\nrho density. Set to 1 for incompressible solvers\nν laminar viscosity of the fluid\nνt eddy viscosity from turbulence models. Pass ConstantScalar(0) for laminar flows\n\n\n\n\n\n","category":"method"},{"location":"theory_guide/introduction/#Introduction","page":"Theory Guide","title":"Introduction","text":"","category":"section"},{"location":"theory_guide/introduction/","page":"Theory Guide","title":"Theory Guide","text":"","category":"page"},{"location":"user_guide/1_preprocessing/#Pre-processing","page":"Pre-processing","title":"Pre-processing","text":"","category":"section"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"First steps required to set up a simulation","category":"page"},{"location":"user_guide/1_preprocessing/#Mesh-generation-and-requirements","page":"Pre-processing","title":"Mesh generation and requirements","text":"","category":"section"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"As with all CFD solvers, defining a suitable mesh is one of the most important steps. XCALibre.jl does not provides mesh generation utilities (yet). Thus, the user will have to generate the grids using external mesh generation tools. However, XCALibre.jl does provide a number of mesh conversion tools to allow user to import their grids. ","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"XCALibre.jl is an unstructured Finite Volume Method (FVM) library, therefore, we are able to support grids of arbitrary polyhedral cells. In XCALibre.jl a cell-centred FVM approach has been implemented, which is popular since it allows the representation of complex geometries and it is used by most commercial and many open source CFD solvers.","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"units: Units\nXCALIbre.jl does not enforce units strictly. Units are implicitly provided by the mesh. You can use the scale keyword when importing a mesh to control the units used e.g. if the mesh file was created in millimetres, set scale=0.001 to work in metres. Thus, it is important to ensure that consistent units are used through all configuration entries. It is highly recommended that SI units are used. ","category":"page"},{"location":"user_guide/1_preprocessing/#Mesh-conversion","page":"Pre-processing","title":"Mesh conversion","text":"","category":"section"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"XCALibre.jl at present supports .unv mesh formats (which can be generated using SALOME) for simulations in 2D and 3D domains. XCALibre.jl also supports the OpenFOAM mesh format for simulations in 3D only (for now). ","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"note: Note\nCurrently, XCALibre.jl only supports loading mesh files stored in ASCII format. Please ensure that when saving grid files they are not saved in binary format. Most mesh generation programmes offer the option to export in ASCII (text-based) formats.","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"The following functions are provided for importing mesh files:","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"UNV2D_mesh\nUNV3D_mesh\nFOAM3D_mesh","category":"page"},{"location":"user_guide/1_preprocessing/#XCALibre.UNV2.UNV2D_mesh-user_guide-1_preprocessing","page":"Pre-processing","title":"XCALibre.UNV2.UNV2D_mesh","text":"UNV2D_mesh(meshFile; scale=1, integer_type=Int64, float_type=Float64)\n\nRead and convert 2D UNV mesh file into XCALibre.jl\n\nInput\n\nmeshFile – path to mesh file.\n\nOptional arguments\n\nscale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling\ninteger_type - select interger type to use in the mesh (Int32 may be useful on GPU runs) \nfloat_type - select interger type to use in the mesh (Float32 may be useful on GPU runs) \n\n\n\n\n\n","category":"function"},{"location":"user_guide/1_preprocessing/#XCALibre.UNV3.UNV3D_mesh-user_guide-1_preprocessing","page":"Pre-processing","title":"XCALibre.UNV3.UNV3D_mesh","text":"UNV3D_mesh(unv_mesh; scale=1, integer_type=Int64, float_type=Float64)\n\nRead and convert 3D UNV mesh file into XCALibre.jl. Note that a limitation of the .unv mesh format is that it only supports the following 3D cells:\n\nTetahedrals\nPrisms\nHexahedrals\n\nInput\n\nunv_mesh – path to mesh file.\n\nOptional arguments\n\nscale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling\ninteger_type - select interger type to use in the mesh (Int32 may be useful on GPU runs) \nfloat_type - select interger type to use in the mesh (Float32 may be useful on GPU runs) \n\n\n\n\n\n","category":"function"},{"location":"user_guide/1_preprocessing/#XCALibre.FoamMesh.FOAM3D_mesh-user_guide-1_preprocessing","page":"Pre-processing","title":"XCALibre.FoamMesh.FOAM3D_mesh","text":"FOAM3D_mesh(mesh_file; scale=1, integer_type=Int64, float_type=Float64)\n\nRead and convert 3D OpenFOAM mesh file into XCALibre.jl. Note that, at present, it is not recommended to run 2D cases using meshes imported using this function.\n\nInput\n\nmesh_file – path to mesh file.\n\nOptional arguments\n\nscale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling\ninteger_type - select interger type to use in the mesh (Int32 may be useful on GPU runs) \nfloat_type - select interger type to use in the mesh (Float32 may be useful on GPU runs) \n\n\n\n\n\n","category":"function"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"These conversion functions will read mesh information and generate a mesh object (Mesh2 or Mesh3 depending on whether the mesh is 2D or 3D, respectively) with the following properties:","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"Mesh3","category":"page"},{"location":"user_guide/1_preprocessing/#XCALibre.Mesh.Mesh3-user_guide-1_preprocessing","page":"Pre-processing","title":"XCALibre.Mesh.Mesh3","text":"struct Mesh3{VC, VI, VF<:AbstractArray{<:Face3D}, VB, VN, SV3, UR} <: AbstractMesh\n cells::VC # vector of cells\n cell_nodes::VI # vector of indices to access cell nodes\n cell_faces::VI # vector of indices to access cell faces\n cell_neighbours::VI # vector of indices to access cell neighbours\n cell_nsign::VI # vector of indices to with face normal correction (1 or -1 )\n faces::VF # vector of faces\n face_nodes::VI # vector of indices to access face nodes\n boundaries::VB # vector of boundaries\n nodes::VN # vector of nodes\n node_cells::VI # vector of indices to access node cells\n get_float::SV3 # store mesh float type\n get_int::UR # store mesh integer type\n boundary_cellsID::VI # vector of indices of boundary cell IDs\nend\n\n\n\n\n\n","category":"type"},{"location":"user_guide/1_preprocessing/#Mesh-limitations-and-requirements","page":"Pre-processing","title":"Mesh limitations and requirements","text":"","category":"section"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"In this section we summarise the key limitations of the mesh loaders presented above, and we also highlight specific requirements. ","category":"page"},{"location":"user_guide/1_preprocessing/#UNV-mesh-files","page":"Pre-processing","title":"UNV mesh files","text":"","category":"section"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"Only ASCII files are supported\nFor 2D simulations the mesh must be contained in the X-Y plane only\nIn 3D only hex, tet and prism elements are supported","category":"page"},{"location":"user_guide/1_preprocessing/#OpenFOAM-mesh-files","page":"Pre-processing","title":"OpenFOAM mesh files","text":"","category":"section"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"Only ASCII files are supported\nBoundary groups are not supported (must be deleted manually or the conversion may fail)\nBoundary information is not preserved (walls, symmetry, etc)\n2D setups are not currently supported (but will be)","category":"page"},{"location":"user_guide/1_preprocessing/#Backend-selection","page":"Pre-processing","title":"Backend selection","text":"","category":"section"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"In XCALibre.jl the mesh object is very important, as it will not only provide geometry information about the simulation/s, but it is also used to automatically dispatch methods to run on the appropriate backend. Therefore, users must first select the backend they wish to use for the simulations, and then \"adapt\" the mesh to use the correct backend. ","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"XCALIbre.jl aims to work with all the backends supported by KernelAbstractions.jl. However, since internally XCALibre.jl uses sparse arrays to reduce its memory footprint, some GPU backends are not currently supported since this functionality is not yet available. Thus, currently only a subset of backends are supported:","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"CPU (multithreaded and tested)\nNVidia GPUs (tested)\nAMD GPUs (not tested - feedback welcome)","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"Selecting a given backend is straight-forward. The examples below show how to assign a backend (CPU or GPU) to the symbol backend and converting the mesh object to run a simulation on the corresponding backend. The converted mesh is assigned to the symbol mesh_dev for clarity.","category":"page"},{"location":"user_guide/1_preprocessing/#CPU-backend","page":"Pre-processing","title":"CPU backend","text":"","category":"section"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"Selecting the CPU backend is straight-forward. See the example below. Notice that CPU() is a backend type provided by KernelAbstractions.jl which we re-export for convenience.","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"CPU Example ","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"mesh = # call function to load mesh e.g. UNV2_mesh, UNV3_mesh or FOAM3D_mesh\nbackend = CPU()\nmesh_dev = mesh # dummy reference to emphasise the mesh in on our chosen dev (or backend)","category":"page"},{"location":"user_guide/1_preprocessing/#GPU-backends","page":"Pre-processing","title":"GPU backends","text":"","category":"section"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"To execute the code on GPUS, the process is also quite simple, but does require a few additional steps.","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"Install the corresponding Julia library that supports your hardware. For NVidia GPUs, the CUDA.jl package is required. For AMD GPUs, the AMDGPU.jl package is needed.\nMove the mesh object to the backend device using the adapt method, which for convenience we re-export from Adapt.jl","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"Example for Nvidia GPU","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"mesh = # call function to load mesh e.g. UNV2_mesh, UNV3_mesh or FOAM3D_mesh\nbackend = CUDABackend()\nmesh_dev = adapt(backend, mesh) # make mesh object backend compatible and move to GPU","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"Example for AMD GPU","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"mesh = # call function to load mesh e.g. UNV2_mesh, UNV3_mesh or FOAM3D_mesh\nbackend = ROCBackend()\nmesh_dev = adapt(backend, mesh) # make mesh object backend compatible and move to GPU","category":"page"},{"location":"user_guide/1_preprocessing/#Hardware-configuration","page":"Pre-processing","title":"Hardware configuration","text":"","category":"section"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"In order to configure the backend the set_hardware function can be used. ","category":"page"},{"location":"user_guide/1_preprocessing/","page":"Pre-processing","title":"Pre-processing","text":"set_hardware","category":"page"},{"location":"user_guide/1_preprocessing/#XCALibre.Simulate.set_hardware-user_guide-1_preprocessing","page":"Pre-processing","title":"XCALibre.Simulate.set_hardware","text":"hardware = set_hardware(backend, workgroup)\n\nFunction used to configure the backend.\n\nInputs\n\nbackend named tuple used to specify the backend e.g. CPU(), CUDABackend() or other backends supported by KernelAbstraction.jl\nworkgroup::Int this is an integer specifying the number of workers that cooperate in a parallel run. For GPUs this could be set to the size of the device's warp e.g. workgroup = 32. On CPUs, the default value in KernelAbstractions.jl is currently workgroup = 1024.\n\nOutput\n\nThis function returns a NamedTuple with the fields backend and workgroup which are accessed by internally in XCALibre.jl to execute a given kernel.\n\n\n\n\n\n","category":"function"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"EditURL = \"https://github.com/github.com/mberto79/XCALibre.jl/blob/master/CHANGELOG.md\"","category":"page"},{"location":"release_notes/#Release-notes","page":"Release notes","title":"Release notes","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"The format used for this changelog is based on Keep a Changelog, and this project adheres to Semantic Versioning. Notice that until the package reaches version v1.0.0 minor releases are likely to be breaking. Starting from version v3.0.1 breaking changes will be recorded here. ","category":"page"},{"location":"release_notes/#Version-[v0.3.1](https://github.com/github.com/mberto79/XCALibre.jl/releases/tag/v0.3.1)-2024-10-18","page":"Release notes","title":"Version v0.3.1 - 2024-10-18","text":"","category":"section"},{"location":"release_notes/#Added","page":"Release notes","title":"Added","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Vastly improved documentation with new examples provided #12\nChangelog added to record changes more clearly. Record kept in Release notes","category":"page"},{"location":"release_notes/#Fixed","page":"Release notes","title":"Fixed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"The calculation of gradients can be limited for stability. This functionality can be activated by passing the key work argument limit_gradient to the run! function. The implementation has been improved for robustness #12\nRemoved face information being printed when Mesh objects are created to stop printing a ERROR: Scalar indexing is disallowed message #13","category":"page"},{"location":"release_notes/#Changed","page":"Release notes","title":"Changed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Master branch protected and requires PRs to push changes","category":"page"},{"location":"release_notes/#Breaking","page":"Release notes","title":"Breaking","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"No breaking changes","category":"page"},{"location":"release_notes/#Deprecated","page":"Release notes","title":"Deprecated","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"No functions deprecated","category":"page"},{"location":"release_notes/#Removed","page":"Release notes","title":"Removed","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"No functionality has been removed","category":"page"},{"location":"release_notes/#Version-[v0.3.0](https://github.com/github.com/mberto79/XCALibre.jl/releases/tag/v0.3.0)-2024-09-21","page":"Release notes","title":"Version v0.3.0 - 2024-09-21","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"New name - XCALibre.jl - which is now registered in the General Julia registry\nCan do 3D and GPU accelerated simulations\nCan read .unv and OpenFOAM mesh files (3D)\nCan do incompressible and compressible simulations\nRANS and LES models available\nUser-provided functions or neural networks for boundary conditions\nReasonably complete \"user\" documentation now provided\nMade repository public (in v0.2 the work was kept in a private repository and could only do 2D simulations)\nTidy up mesh type definitions by @mberto79 in #5\nAdapt code base to work with new mesh format by @mberto79 in #6\nMesh boundary struct changes PR by @TomMazin in #7\nMesh boundary struct changes PR fix by @TomMazin in #8","category":"page"},{"location":"release_notes/#Version-[v0.2.0](https://github.com/github.com/mberto79/XCALibre.jl/releases/tag/v0.2.0)-2023-01-23","page":"Release notes","title":"Version v0.2.0 - 2023-01-23","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"New mesh format and type implemented that are GPU friendly.\nNo functionality changes","category":"page"},{"location":"release_notes/#Version-[v0.1.0](https://github.com/github.com/mberto79/XCALibre.jl/releases/tag/v0.1.0)-2023-01-23","page":"Release notes","title":"Version v0.1.0 - 2023-01-23","text":"","category":"section"},{"location":"release_notes/#Initial-release","page":"Release notes","title":"Initial release","text":"","category":"section"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"2D implementation of classic incompressible solvers for laminar and turbulent flows:","category":"page"},{"location":"release_notes/","page":"Release notes","title":"Release notes","text":"Framework for equation definition\nSIMPLE nad PISO algorithms\nRead UNV meshes in 2D\nCapability for RANS models\nVarious discretisation schemes available\nPlanned extension to 3D and GPU acceleration!","category":"page"},{"location":"#XCALibre.jl","page":"Home","title":"XCALibre.jl","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"XPU CFD Algorithms and libraries","category":"page"},{"location":"#What-is-XCALibre.jl?","page":"Home","title":"What is XCALibre.jl?","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"","category":"page"},{"location":"","page":"Home","title":"Home","text":"XCALibre.jl (pronounced as the mythical sword Excalibur) is a general purpose Computational Fluid Dynamics (CFD) library for 2D and 3D simulations on structured/unstructured grids using the finite volume method. XCALibre.jl has been designed to act as a platform for developing, testing and using XPU CFD Algorithms and Libraries to give researchers in both academia and industry alike a tool that can be used to test out ideas easily within a framework that offers acceptable performance. To this end, XCALibre.jl has been implemented to offer both CPU multi-threaded capabilities or GPU acceleration using the same codebase (thanks to the unified programming framework provided by KernelAbstractions.jl). XCALibre.jl also offers a friendly API for those users who are interested in running CFD simulations with the existing solvers and models built into XCALibre.jl. ","category":"page"},{"location":"#Why-XCALibre.jl?","page":"Home","title":"Why XCALibre.jl?","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"","category":"page"},{"location":"","page":"Home","title":"Home","text":"For CFD researchers whose research involves developing new numerical methods, turbulence models, or novel CFD methodologies, the development process can be taxing when using commercial packages and their imagination might be constrained by having to adhere to either limited access to internal code functionality or exhausted as they reformulate their ideas to fit within any interfaces provided by the code. There are excellent open source CFD packages where access to functionality or internals is available, however, they are either written in static languages such as C/C++ or dynamic languages such as Python. In static languages, the resulting code is likely highly performant but implementation can be slow and often has a high learning curve (especially if the developer/researcher has no prior knowledge of the language). On the other hand, dynamic languages such as Python can offer a nice development experience at the cost of low runtime or reduced performance. The development of XCALibre.jl was motivated when we discovered the Julia programming language, which promises an interactive and enjoyable implementation experience whilst being able to generate performant code. Thanks to the tools available in the Julia ecosystems (see Main dependencies) it is also possible to generate CPU and GPU code using Julia. As an added bonus, XCALibre.jl can also link readily with the entire Julia ecosystem, including machine learning frameworks such as Flux.jl, Lux.jl, Knet.jl, etc. Thanks to a user-friendly API, ultimately, we hope that XCALibre.jl can be useful to anyone who has an interest in CFD. Enjoy and give us feedback.","category":"page"},{"location":"#Main-features","page":"Home","title":"Main features","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"","category":"page"},{"location":"#Multiple-backends","page":"Home","title":"Multiple backends","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"XCALibre.jl embraces parallelism out-of-the-box on all the compute backends supported by KernelAbstractions.jl. That is,","category":"page"},{"location":"","page":"Home","title":"Home","text":"GPU acceleration on Nvidia, AMD, Intel and Apple hardware\nMulti-threaded runs on CPUs","category":"page"},{"location":"","page":"Home","title":"Home","text":"note: Note\nGPU functionality has only been tested on Nvidia hardware due to availability. Although GPUs from other vendors should also work correctly. Please open an issue if this is not the case so we can investigate. Notice that Apple hardware will not work as expected due to support for sparse matrices not being implemented yet on Metal.jl","category":"page"},{"location":"#Mesh-formats","page":"Home","title":"Mesh formats","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"XCALibre.jl uses its own mesh format to allow the geometry and boundary information to be stored in a format that is suitable for both CPU and GPU calculations. XCALibre.jl does not yet provide mesh generation tools. Therefore, some mesh conversion tools for the following mesh formats are provided:","category":"page"},{"location":"","page":"Home","title":"Home","text":"OpenFOAM meshes for 3D simulations (ascii only)\nUNV meshes for 2D simulations (ascii only)\nUNV meshes for 3D simulations (ascii only)","category":"page"},{"location":"","page":"Home","title":"Home","text":"note: Note\nAlthough the mesh conversion tools for the OpenFOAM format can import grids designed for 2D simulations, it is not recommended to use OpenFOAM grids for 2D cases (at present, support for 2D OpenFOAM grids in progress). Instead, use a 2D grid generated in the .unv format. Also for 2D grids some requirements must be met when defining the geometry (see Mesh generation and requirements)","category":"page"},{"location":"#Solvers","page":"Home","title":"Solvers","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"XCALibre.jl ships with fluid solvers for steady and transient simulations, based on the SIMPLE and PISO algorithms. Currently, the following flow solvers are provided:","category":"page"},{"location":"","page":"Home","title":"Home","text":"Steady incompressible flows\nSteady weakly compressible flows\nTransient incompressible flows\nTransient weakly compressible flows","category":"page"},{"location":"","page":"Home","title":"Home","text":"note: Note\nA solver for highly compressible flows (shock capturing) is currently in testing and will be available in the next major release. Currently the compressible solvers use a sensible energy approach for the energy equation.","category":"page"},{"location":"#Turbulence-and-energy-models","page":"Home","title":"Turbulence and energy models","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"The list of turbulence models available is expected to expand. The following turbulence models are already available in XCALibre.jl:","category":"page"},{"location":"","page":"Home","title":"Home","text":"Reynolds-Averaged Navier-Stokes (RANS)\nk-omega - available in low-Reynolds (wall-resolving) and in high-Reynolds (wall functions) mode\nk-omega LKE - transitional model using the Laminar Kinetic Energy concept to model transition onset\nLarge Eddy Simulation (LES with implicit filtering)\nSmagorinsky - classic eddy-viscosity sub-grid scale Smagorinsky model","category":"page"},{"location":"#Boundary-conditions","page":"Home","title":"Boundary conditions","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"User defined functions\nNeural network defined BCs","category":"page"},{"location":"#Numerical-schemes","page":"Home","title":"Numerical schemes","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Linear - second order schemes for gradients, laplacian and divergence terms\nUpwind - first order upwind-biased scheme for divergence terms\nLUST (divergence) - mixed order upwind-biased scheme for divergence terms\nMidpoint - skew-corrected scheme for gradient calculations\nSteadyState - dummy scheme used to dispatch solvers for operation in steady mode\nEuler - first order semi-implicit time scheme","category":"page"},{"location":"#Simple-API-for-transport-equations","page":"Home","title":"Simple API for transport equations","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Code example","category":"page"},{"location":"","page":"Home","title":"Home","text":"U_eqn = (\n Time{schemes.U.time}(U)\n + Divergence{schemes.U.divergence}(mdotf, U) \n - Laplacian{schemes.U.laplacian}(nueff, U) \n == \n -Source(∇p.result)\n\n ) → VectorEquation(mesh)","category":"page"},{"location":"#Planned-development","page":"Home","title":"Planned development","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"","category":"page"},{"location":"#Capabilities,-solvers,-algorithms,-models,-etc.","page":"Home","title":"Capabilities, solvers, algorithms, models, etc.","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Solver for highly compressible flows (including shockwaves)\nConjugate heat transfer\nk-epsilon turbulence model\nImplement parallel versions of more efficient preconditioners","category":"page"},{"location":"#API","page":"Home","title":"API","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Pass boundary conditions as a separate object. The current approach results in some internal methods/objects not being fully compatible with GPU kernels, and results is some performance degradation (due to unnecessary data transfer between GPU and host device when boundary condition information is needed/applied). A separation of boundary conditions from field data (scalar and vector fields primarily) would address both of these issues.\nThere are no immediate plans for changing the user API\nFine-tuning of the public API expected based on of user feedback","category":"page"},{"location":"#Internals","page":"Home","title":"Internals","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Overhaul of field data. Currently, both vectors and tensors are built on the primitive scalar field object. Whilst this was convenient during the early development stage, the package has reached a level of maturity that makes this approach hard to maintain, adding unneeded complexity when working with tensors. We plan to define separate internals (how tensors are defined and stored in memory). It is anticipated that this will ease the implementation of models working with tensors, give some performance gains and allow all fields to participate in Julia's broadcasting framework.","category":"page"},{"location":"#Main-dependencies","page":"Home","title":"Main dependencies","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"","category":"page"},{"location":"","page":"Home","title":"Home","text":"XCALibre.jl is possible (and relies) on the functionality provided by other packages in the Julia ecosystem. For a full list of direct dependencies please refer to the Project.toml file included with this repository. We are thankful to the teams that have helped develop and maintain every single of our dependencies. Major functionally is provided by the following:","category":"page"},{"location":"","page":"Home","title":"Home","text":"KernelAbstractions.jl - provides a unified parallel programming framework for CPUs and GPUs\nKrylov.jl - provide solvers for linear systems at the heart of XCALibre.jl\nLinearOperators.jl - wrappers for matrices and linear operators\nAtomix.jl - enable atomix operations to ensure race conditions are avoided in parallel kernels\nCUDA.jl, AMD.jl, Metal.jl and OneAPI.jl - not direct dependencies but packages enable GPU usage in Julia","category":"page"},{"location":"#Related-projects","page":"Home","title":"Related projects","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"","category":"page"},{"location":"","page":"Home","title":"Home","text":"There are other wonderful fluid simulation packages available in the Julia ecosystem (please let us know if we missed any):","category":"page"},{"location":"","page":"Home","title":"Home","text":"Oceananigans.jl \nWaterlilly.jl \nTrixi.jl","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/#Advanced:-2D-Aerofoil-inflow-optimisation","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"","category":"section"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/#Introduction","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Introduction","text":"","category":"section"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"Here, a simple optimisation is performed on a 2D NACA0012 aerofoil case. The optimal angle of attack for maximum lift-to-drag ratio is found using BayesianOptimization.jl. This example serves to illustrate both how XCALibre.jl can easily integrate with the Julia ecosystem, and the ease with which post-processing functions can be written.","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/#Optimisation-Setup","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Optimisation Setup","text":"","category":"section"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"For those interested in running this example, the optimisation can be replicated by following these steps.","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/#Install-and-load-modules","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Install and load modules","text":"","category":"section"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"To be able to run this example the following modules need to be installed. This can be done by entering into package mode (using \"]\" in the REPL) and typing the following:","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"add Plots, Distributions, LinearAlgebra, GaussianProcesses, BayesianOptimization","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"This will download and install the required packages. Note that \"CUDA\" must also be added for GPU acceleration. Once installed, the packages can be loaded as follows:","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"using Pkg; # hide\ninstalled = \"Flux\" ∈ keys(Pkg.project().dependencies) # hide\ninstalled && Pkg.rm(\"Flux\", io=devnull) #hide\nPkg.add(\"BayesianOptimization\", io=devnull) # hide\n\nusing XCALibre, BayesianOptimization, Plots\nusing LinearAlgebra, GaussianProcesses, Distributions\n# using CUDA # uncomment to run on GPU\n\"done\"\nnothing # hide","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/#Define-post-processing-functions","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Define post processing functions","text":"","category":"section"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"In order to calculate the lift-to-drag ratio, the pressure and viscous forces over the aerofoil must be calculated and summed. The lift and drag components can then be calculated (noting the rotated inflow vector to allow for different aerofoil angles of attack with the same mesh). A function returning the coefficients of lift and drag (not specifically needed for this example) is also presented for convenience.","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"# Lift to drag ratio calculation\nlift_to_drag(patch::Symbol, model, ρ, nu, α) = begin\n Fp = pressure_force(patch, model.momentum.p, ρ)\n Fv = viscous_force(patch, model.momentum.U, ρ, nu, model.turbulence.nut)\n Ft = Fp + Fv\n Ft = [cos(-α*π/180) -sin(-α*π/180) 0; sin(-α*π/180) cos(-α*π/180) 0; 0 0 1]*Ft # Rotation matrix to account for rotated inflow\n aero_eff = Ft[2]/Ft[1]\n print(\"Aerofoil L/D: \",round(aero_eff,sigdigits = 4))\n return aero_eff\nend \n\n# Aerodynamic coefficient calculation\naero_coeffs(patch::Symbol, chord, velocity, model, ρ, nu, α) = begin\n Fp = pressure_force(patch, model.momentum.p, ρ)\n Fv = viscous_force(patch, model.momentum.U, ρ, nu, model.turbulence.nut)\n Ft = Fp + Fv\n Ft = [cos(-α*π/180) -sin(-α*π/180) 0; sin(-α*π/180) cos(-α*π/180) 0; 0 0 1]*Ft # Rotation matrix to account for rotated inflow\n C_l = 2Ft[2]/(ρ*(velocity[1]^2)*chord*0.001)\n C_d = 2Ft[1]/(ρ*(velocity[1]^2)*chord*0.001)\n print(\"Lift Coefficient: \",round(C_l,sigdigits = 4))\n print(\"\\nDrag Coefficient: \",round(C_d,sigdigits = 4))\n return C_l,C_d\nend ","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/#Import-2D-aerofoil-mesh","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Import 2D aerofoil mesh","text":"","category":"section"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"Next, the aerofoil mesh .unv file must be imported. It must also be adapted to work with the GPU, if desired.","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"grids_dir = pkgdir(XCALibre, \"examples/0_GRIDS\")\ngrid = \"NACAMesh.unv\"\nmesh_file = joinpath(grids_dir, grid)\n\nmesh = UNV2D_mesh(mesh_file, scale=0.001)\nmesh_dev = mesh # running on CPU \n# mesh_dev = adapt(CUDABackend(), mesh) # uncomment to run on GPU","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/#Setup-the-CFD-simulation-as-a-function-to-be-optimised","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Setup the CFD simulation as a function to be optimised","text":"","category":"section"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"The BayesianOptimization.jl package can optimise a Julia function that is passed to it. To interface with XCALibre.jl, the entire CFD simulation setup must simply be wrapped within a function, which can then be passed to the optimiser. The function must take the variable to be changed (angle of attack, in this case) as its input, and must return the desired output (lift-to-drag ratio). Therefore, the post-processing step to calculate lift-to-drag ratio is also wrapped in the same function.","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"function foil_optim(α::Vector{Float64})\n println(\"\\nSelected α value: $(α[1])\")\n\n # Parameters\n chord = 250.0\n Re = 500000\n nu, ρ = 1.48e-5, 1.225\n Umag = (Re*nu)/(chord*0.001) # Calculate velocity magnitude for given Reynolds number\n velocity = [Umag*cos(α[1]*π/180), Umag*sin(α[1]*π/180), 0.0] # Velocity calculation\n νR = 10\n Tu = 0.025\n k_inlet = 3/2*(Tu*norm(velocity))^2\n ω_inlet = k_inlet/(νR*nu)\n\n # Boundary Conditions\n noSlip = [0.0, 0.0, 0.0]\n\n model = Physics(\n time = Steady(),\n fluid = Fluid{Incompressible}(nu = nu),\n turbulence = RANS{KOmega}(),\n energy = Energy{Isothermal}(),\n domain = mesh_dev\n )\n\n @assign! model momentum U ( \n XCALibre.Dirichlet(:inlet, velocity),\n XCALibre.Dirichlet(:bottom, velocity),\n Neumann(:outlet, 0.0),\n Neumann(:top, 0.0),\n Wall(:foil, noSlip)\n )\n\n @assign! model momentum p (\n Neumann(:inlet, 0.0),\n Neumann(:bottom, 0.0),\n XCALibre.Dirichlet(:outlet, 0.0),\n XCALibre.Dirichlet(:top, 0.0),\n Neumann(:foil, 0.0)\n )\n\n @assign! model turbulence k (\n XCALibre.Dirichlet(:inlet, k_inlet),\n Neumann(:outlet, 0.0),\n Neumann(:top, 0.0),\n Neumann(:bottom, 0.0),\n XCALibre.Dirichlet(:foil, 1e-15)\n )\n\n @assign! model turbulence omega (\n XCALibre.Dirichlet(:inlet, ω_inlet),\n Neumann(:outlet, 0.0),\n Neumann(:top, 0.0),\n Neumann(:bottom, 0.0),\n OmegaWallFunction(:foil)\n )\n\n @assign! model turbulence nut (\n Neumann(:inlet, 0.0),\n Neumann(:outlet, 0.0),\n Neumann(:top, 0.0),\n Neumann(:bottom, 0.0), \n XCALibre.Dirichlet(:foil, 0.0)\n )\n\n schemes = (\n U = set_schemes(divergence=Upwind, gradient=Midpoint),\n p = set_schemes(divergence=Upwind),\n k = set_schemes(divergence=Upwind, gradient=Midpoint),\n omega = set_schemes(divergence=Upwind, gradient=Midpoint)\n )\n\n solvers = (\n U = set_solver(\n model.momentum.U;\n solver = BicgstabSolver, # BicgstabSolver, GmresSolver\n preconditioner = ILU0(), # Jacobi # ILU0\n convergence = 1e-7,\n relax = 0.6,\n rtol = 1e-1,\n ),\n p = set_solver(\n model.momentum.p;\n solver = GmresSolver, # change to BicgstabSolver for GPU runs\n preconditioner = LDL(), # change to Jacobi() for GPU runs\n convergence = 1e-7,\n relax = 0.2,\n rtol = 1e-2,\n ),\n k = set_solver(\n model.turbulence.k;\n solver = BicgstabSolver,\n preconditioner = ILU0(), # change to Jacobi() for GPU runs\n convergence = 1e-7,\n relax = 0.6,\n rtol = 1e-1,\n ),\n omega = set_solver(\n model.turbulence.omega;\n solver = BicgstabSolver,\n preconditioner = ILU0(), # change to Jacobi() for GPU runs\n convergence = 1e-7,\n relax = 0.6,\n rtol = 1e-1,\n )\n )\n\n runtime = set_runtime(iterations=500, write_interval=500, time_step=1)\n runtime = set_runtime(iterations=20, write_interval=-1, time_step=1) # hide\n\n hardware = set_hardware(backend=CPU(), workgroup=1024)\n # hardware = set_hardware(backend=CUDABackend(), workgroup=32) # uncomment to run on GPU\n\n config = Configuration(solvers=solvers, schemes=schemes, runtime=runtime, hardware=hardware)\n\n GC.gc()\n\n initialise!(model.momentum.U, velocity)\n initialise!(model.momentum.p, 0.0)\n initialise!(model.turbulence.k, k_inlet)\n initialise!(model.turbulence.omega, ω_inlet)\n initialise!(model.turbulence.nut, k_inlet/ω_inlet)\n\n residuals = run!(model, config)\n\n # Residuals Graph\n let\n iterations = 1:length(residuals.Ux)\n plot(; xlims=(0,runtime.iterations), ylims=(1e-10,0))\n plot!(iterations, residuals.Ux, yscale=:log10, label=\"Ux\")\n plot!(iterations, residuals.Uy, yscale=:log10, label=\"Uy\")\n plot!(iterations, residuals.p, yscale=:log10, label=\"p\")\n end\n\n aero_eff = lift_to_drag(:foil, model, ρ, nu, α[1]) # Calculates lift-to-drag ratio\n\n # relocate XCALibre.jl vtk output files\n aero_eff_out = round(aero_eff,digits=3)\n α_out = round(α[1],digits=3)\n vtk_files = filter(x->endswith(x,\".vtk\"), readdir())\n for file ∈ vtk_files\n dest = \"vtk_results/LD_Ratio = $(aero_eff_out), Alpha = $(α_out).vtk\"\n mv(file, dest, force=true)\n end\n\n return aero_eff\nend","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"Note that this code saves a single .vtk file of the last CFD iteration each time the optimiser samples the function. This .vtk file is then automatically renamed with that sample's results, and sorted into a /vtk_results subfolder (which must be created before the optimisation is run).","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/#Configure-and-run-the-Bayesian-optimisation","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Configure and run the Bayesian optimisation","text":"","category":"section"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"Finally, the Bayesian optimiser must be configured before the optimisation can be performed. This example follows the BayesianOptimization.jl default configuration for the Gaussian process surrogate model, limiting input dimensions to 1 (the angle of attack). The surrogate model is then set to be optimised every 10 iterations. The inputs are limited to between 0 and 15 degrees. The problem is configured as a maximisation problem, with an initial sample period of 10 iterations and 50 maximum allowed iterations. The final line of the following code block is then run to perform the optimisation.","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"# Bayesian Optimisation (using BayesianOptimization.jl)\nisdir(\"vtk_results\") || mkdir(\"vtk_results\")\n\n# Initialises the Gaussian process surrogate model\nmodel = ElasticGPE(1, #1 input dimension (α)\n mean = MeanConst(0.0),\n kernel = SEArd([0.0], 5.0),\n capacity = 3000)\nset_priors!(model.mean, [Normal(1, 2)])\n\nmodeloptimizer = MAPGPOptimizer(every = 10, maxeval = 40) # Optimises the Gaussian process every 10 iterations\n\n# Optimisation Case Setup\nopt = BOpt(foil_optim, # Function to be optimised - encloses the CFD case\n model, # Gaussian process surrogate model defined above\n UpperConfidenceBound(),\n modeloptimizer, # Model optimiser defined above\n [0.0], [15.0], # Minimum and maximum α constraints \n repetitions = 1, # No repititions as CFD data is not noisy\n maxiterations = 50, # Maximum iterations\n sense = Max, # Maximisation problem\n initializer_iterations = 10, # No. of initial random samples\n verbosity = Progress)\n\nopt = BOpt(foil_optim, # hide\n model, # hide\n UpperConfidenceBound(),\n modeloptimizer, # hide\n [0.0], [15.0], # hide \n repetitions = 1, # hide\n maxiterations = 5, # hide\n sense = Max, # hide\n initializer_iterations = 2, # hide\n verbosity = Progress) # hide\n\nresult = boptimize!(opt) # Runs the optimisation procedure\n\nusing Pkg; Pkg.rm(\"BayesianOptimization\", io=devnull) # hide\n\nnothing # hide\n\"done\"","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/#Example-Optimisation-Results","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Example Optimisation Results","text":"","category":"section"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"using Plots\n\nalpha_in = [2.8125, 10.3125, 14.0625, 6.5625, 4.6875, 12.1875, 8.4375, 0.9375, 1.40625, 8.90625, 6.779625965220729, 6.77968472431049, 6.7797314426495054, 6.77976068608606, 6.779786764662929, 6.7798083933298825, 6.779824452011973, 6.779839305833187, 6.779851985125758, 6.779864532650939, 6.7799660687298875, 6.7799701746255465, 6.779970295228141, 6.77997431759257, 6.779983415563036, 6.7799837395243685, 6.779983935151504, 6.779987648165338, 6.779990776177305, 6.779984858208577, 6.779969245384916, 6.779974853301299, 6.77996639334403, 6.779975137863877, 6.77996588653741, 6.7799787767924995, 6.779980463194295, 6.779982645115559, 6.779984123782711, 6.779985756585738, 6.780065815803057, 6.780066942543943, 6.780081725020423, 6.780063344501922, 6.780112623430458, 6.780065445290062, 6.780112028947505, 6.780088979322628, 6.78008982572309, 6.780090816324224, 6.852129317102274, 15.0, 6.755034985210623, 6.761466922699926, 6.766457867346942, 6.7701094609872365, 6.772562674953314, 6.774340290374087, 6.775562986686579, 6.776273742423618, 13.474012044415156, 12.361866906130413, 8.195985025525076, 5.334843671454779, 4.308592858166856, 2.6894603132241217, 2.858340694577276, 3.9867902638528654, 9.814658247047763, 1.932233467710785, 14.719640732627886, 9.682863385862596, 10.90134524899545, 12.877578634990728, 4.343344626917736]\n\naeroeff_out = [12.28662476568946, 15.996066573412422, 12.086660285887401, 18.095030718054726, 16.684759975625713, 14.101557983835567, 17.514651235093766, 4.6215245234556415, 6.787202918357864, 17.203294519181156, 18.1170435016882, 18.116757960309155, 18.117178450363166, 18.116980351431625, 18.116775418289507, 18.117332562156935, 18.116999501527403, 18.116946514089875, 18.11690912331511, 18.117181857003985, 18.117047847973517, 18.117081881041535, 18.117198176532845, 18.1172141350244, 18.117151423600156, 18.11701162747253, 18.117196229004325, 18.117302063623146, 18.117642349199684, 18.117122449593182, 18.11704990315254, 18.11745842192904, 18.1171359979369, 18.117344466780477, 18.117133217540022, 18.117057989337816, 18.116782216736464, 18.11721596351545, 18.117119958415003, 18.117170377304056, 18.117352502260307, 18.117163143088185, 18.117300338277143, 18.117066185177936, 18.11722389239519, 18.11713622798166, 18.116993107467152, 18.116991271960444, 18.117083277331048, 18.11714354615574, 18.097362115270933, 11.114298598972901, 18.108943497471795, 18.108780485320025, 18.108790519425263, 18.109037299059956, 18.108833040375593, 18.108767451351685, 18.1084445814309, 18.10857933786505, 12.690741887963036, 9.845212599830074, 17.636745115382112, 17.47574058124154, 16.058798546800677, 11.877430534208012, 12.4272778301407, 15.41709457750829, 16.462303743958294, 9.053215612096695, 11.382140258128832, 16.578166324395593, 15.519321514686421, 13.356080135399708, 16.116845772757824]\n\niteration = [1:25;]\n\nscatter(\n alpha_in[1:25],aeroeff_out[1:25],xlabel=\"Angle of Attack, α [°]\", ylabel=\"Aerodynamic Efficiency, Cl/Cd [-]\",label=\"\",\n legend=true,\n # marker=(:cross,4),\n zcolor=iteration,\n c=:linear_ternary_red_0_50_c52_n256,\n colorbar_title=\"Optimiser Iteration\",\n xlims=[0,15.15], ylims=[0,20], clim=(0,25),\n frame_style=:box\n )\n\nmax_exp_alpha = ([6.479310344827586,6.479310344827586],[0,19])\n\nplot!(max_exp_alpha,line=(:dash,:black),label=\"\")\n\nplot!(\n sort(alpha_in[1:50]), aeroeff_out[sortperm(alpha_in[1:50])],\n label=\"\", line=(:solid,:black,0.5)\n )\nannotate!(8.25, 2.5, Plots.text(\"Experimental\\noptimum α\", 10))\nsavefig(\"optimisation_iterations_vs_experiment.svg\"); nothing # hide\nnothing\n\nfig1 = scatter(\n iteration[1:15],aeroeff_out[1:15],xlabel=\"Optimiser Iteration [-]\", ylabel=\"Aerodynamic Efficiency, Cl/Cd [-]\",label=\"\",\n ylim = (0,20),\n legend=true,# marker=(:cross,4,:black)\n ) #L/D against iteration number graph\n\nfig2 = scatter(iteration[1:15],alpha_in[1:15],xlabel=\"Optimiser Iteration [-]\", ylabel=\"Angle of Attack, α [°]\",label=\"\",\nylim = (0,15),\nlegend=true, #marker=(:cross,4,:black)\n) #α against iteration number graph\n\n\n# exp_alpha = [0.1724137931034484, 2.068965517241379, 4.482758620689655, 6.479310344827586, 8.441064638783269, 10.344827586206897, 11.206896551724139, 12.551020408163264, 14.13793103448276]\n# exp_aeroeff = [8.872377622377625, 36.656207598371786, 52.94361173623201, 53.41160498793243, 53.10395622895623, 50.95347249317206, 48.78298051001016, 4.906565656565657, 3.354085331846068]\n# fig2 = scatter(exp_alpha,exp_aeroeff,xlabel=\"Angle of Attack, α [°]\", ylabel=\"Aerodynamic Efficiency, Cl/Cd [-]\",title=\"Experimental Data (NACA0012, Re=500,000)\",\n# legend=false,marker=(:circle,4,:black)) #Experimental data\n\nplot(fig1, fig2, frame_style=:box)\n\nsavefig(\"optimisation_vs_iteration.svg\"); nothing # hide\nnothing\n\n# output\n","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"(Image: )","category":"page"},{"location":"examples/05_2d-aerofoil-inflow-optimisation/","page":"Advanced: 2D Aerofoil inflow optimisation","title":"Advanced: 2D Aerofoil inflow optimisation","text":"(Image: )","category":"page"},{"location":"examples/02_2d-incompressible-transient-cylinder/#Verification:-2D-Unsteady-incompressible-cylinder","page":"Verification: 2D Unsteady incompressible cylinder","title":"Verification: 2D Unsteady incompressible cylinder","text":"","category":"section"},{"location":"examples/02_2d-incompressible-transient-cylinder/#Introduction","page":"Verification: 2D Unsteady incompressible cylinder","title":"Introduction","text":"","category":"section"},{"location":"examples/02_2d-incompressible-transient-cylinder/","page":"Verification: 2D Unsteady incompressible cylinder","title":"Verification: 2D Unsteady incompressible cylinder","text":"","category":"page"},{"location":"examples/02_2d-incompressible-transient-cylinder/","page":"Verification: 2D Unsteady incompressible cylinder","title":"Verification: 2D Unsteady incompressible cylinder","text":"To verify the correct implementation of the laminar flow solver, a simulation of a transient, laminar and incompressible cylinder was carried out and compared with OpenFOAM. The results show that the solver in XCALibre.jl generates similar results compared to the laminar solver in OpenFOAM. Simulation set up, grid and OpenFOAM case will all be made available here.","category":"page"},{"location":"examples/02_2d-incompressible-transient-cylinder/#Results","page":"Verification: 2D Unsteady incompressible cylinder","title":"Results","text":"","category":"section"},{"location":"examples/02_2d-incompressible-transient-cylinder/","page":"Verification: 2D Unsteady incompressible cylinder","title":"Verification: 2D Unsteady incompressible cylinder","text":"(Image: vorticity comparison with OpenFOAM)","category":"page"},{"location":"examples/02_2d-incompressible-transient-cylinder/#Simulation-setup","page":"Verification: 2D Unsteady incompressible cylinder","title":"Simulation setup","text":"","category":"section"},{"location":"examples/02_2d-incompressible-transient-cylinder/","page":"Verification: 2D Unsteady incompressible cylinder","title":"Verification: 2D Unsteady incompressible cylinder","text":"For those interested in running this case, this simulation can be replicated as follows.","category":"page"},{"location":"examples/02_2d-incompressible-transient-cylinder/","page":"Verification: 2D Unsteady incompressible cylinder","title":"Verification: 2D Unsteady incompressible cylinder","text":"\nusing XCALibre\n# using CUDA # uncomment to run on GPU\n\ngrids_dir = pkgdir(XCALibre, \"examples/0_GRIDS\")\ngrid = \"cylinder_d10mm_5mm.unv\"\nmesh_file = joinpath(grids_dir, grid)\n\nmesh = UNV2D_mesh(mesh_file, scale=0.001)\n\nmesh_dev = mesh\n# mesh_dev = adapt(CUDABackend(), mesh) # uncomment to run on GPU\n\n# Inlet conditions\nvelocity = [0.5, 0.0, 0.0]\nnoSlip = [0.0, 0.0, 0.0]\nnu = 1e-3\nRe = (0.2*velocity[1])/nu\n\nmodel = Physics(\n time = Transient(),\n fluid = Fluid{Incompressible}(nu = nu),\n turbulence = RANS{Laminar}(),\n energy = Energy{Isothermal}(),\n domain = mesh_dev\n )\n\n@assign! model momentum U ( \n Dirichlet(:inlet, velocity),\n Neumann(:outlet, 0.0),\n Wall(:cylinder, noSlip),\n Neumann(:bottom, 0.0),\n Neumann(:top, 0.0)\n)\n\n@assign! model momentum p (\n Neumann(:inlet, 0.0),\n Dirichlet(:outlet, 0.0),\n Neumann(:cylinder, 0.0),\n Neumann(:bottom, 0.0),\n Neumann(:top, 0.0)\n)\n\nsolvers = (\n U = set_solver(\n model.momentum.U;\n solver = BicgstabSolver, # BicgstabSolver, GmresSolver\n preconditioner = Jacobi(),\n convergence = 1e-7,\n relax = 1.0,\n rtol = 1e-4,\n atol = 1e-5\n ),\n p = set_solver(\n model.momentum.p;\n solver = CgSolver, # BicgstabSolver, GmresSolver\n preconditioner = Jacobi(), #NormDiagonal(),\n convergence = 1e-7,\n relax = 0.8,\n rtol = 1e-4,\n atol = 1e-5\n )\n)\n\nschemes = (\n U = set_schemes(time=Euler, divergence=LUST, gradient=Midpoint),\n p = set_schemes(time=Euler, gradient=Midpoint)\n)\n\n\nruntime = set_runtime(iterations=1000, write_interval=50, time_step=0.005) \nruntime = set_runtime(iterations=1, write_interval=-1, time_step=0.005) # hide\n\n\nhardware = set_hardware(backend=CPU(), workgroup=1024)\n# hardware = set_hardware(backend=CUDABackend(), workgroup=32) # uncomment to run on GPU\n\nconfig = Configuration(\n solvers=solvers, schemes=schemes, runtime=runtime, hardware=hardware)\n\nGC.gc(true)\n\ninitialise!(model.momentum.U, velocity)\ninitialise!(model.momentum.p, 0.0)\n\nresiduals = run!(model, config)","category":"page"}] } diff --git a/dev/theory_guide/introduction/index.html b/dev/theory_guide/introduction/index.html index 492cd084..da761610 100644 --- a/dev/theory_guide/introduction/index.html +++ b/dev/theory_guide/introduction/index.html @@ -1,2 +1,2 @@ -Theory Guide · XCALibre.jl +Theory Guide · XCALibre.jl diff --git a/dev/user_guide/0_introduction_and_workflow/index.html b/dev/user_guide/0_introduction_and_workflow/index.html index b4750fbf..51dec3e3 100644 --- a/dev/user_guide/0_introduction_and_workflow/index.html +++ b/dev/user_guide/0_introduction_and_workflow/index.html @@ -1,2 +1,2 @@ -Introduction · XCALibre.jl

Introduction

This page explains the overarching workflow in XCALibre.jl and provides a list of contents

Workflow overview


XCALibre.jl has been designed to incorporate a logical workflow, that is, the sequence of setup steps that would take a user naturally from the start of a simulation to its final post-processing. The key steps are listed below

  • Pre-processing - this step involves defining the computational domain and selecting the corresponding backend to performs the calculations
  • Physics and models - this step involves defining the fluid type, flow properties, selecting appropriate models and setting suitable boundary conditions
  • Numerical setup - in this phase of the simulation set up all aspect related to the numerics are chosen, from distretisation schemes all the way to solvers and preconditioners.
  • Runtime and solvers - once everything has been set up, the simulation is ready to run, once runtime information such as time steps and solution saving intervals has been selected. The final step is to actually start the simulation.
  • Post-processing - the final step is to enjoy all the pretty pictures!

The user guide is structured such that the information provided is grouped following the workflow illustrated above. For convenience the contents of the user guide are included below, with links to the relevant sections.

Contents


+Introduction · XCALibre.jl

Introduction

This page explains the overarching workflow in XCALibre.jl and provides a list of contents

Workflow overview


XCALibre.jl has been designed to incorporate a logical workflow, that is, the sequence of setup steps that would take a user naturally from the start of a simulation to its final post-processing. The key steps are listed below

  • Pre-processing - this step involves defining the computational domain and selecting the corresponding backend to performs the calculations
  • Physics and models - this step involves defining the fluid type, flow properties, selecting appropriate models and setting suitable boundary conditions
  • Numerical setup - in this phase of the simulation set up all aspect related to the numerics are chosen, from distretisation schemes all the way to solvers and preconditioners.
  • Runtime and solvers - once everything has been set up, the simulation is ready to run, once runtime information such as time steps and solution saving intervals has been selected. The final step is to actually start the simulation.
  • Post-processing - the final step is to enjoy all the pretty pictures!

The user guide is structured such that the information provided is grouped following the workflow illustrated above. For convenience the contents of the user guide are included below, with links to the relevant sections.

Contents


diff --git a/dev/user_guide/1_preprocessing/index.html b/dev/user_guide/1_preprocessing/index.html index 83178ddf..3469cb2c 100644 --- a/dev/user_guide/1_preprocessing/index.html +++ b/dev/user_guide/1_preprocessing/index.html @@ -1,5 +1,5 @@ -Pre-processing · XCALibre.jl

Pre-processing

First steps required to set up a simulation

Mesh generation and requirements


As with all CFD solvers, defining a suitable mesh is one of the most important steps. XCALibre.jl does not provides mesh generation utilities (yet). Thus, the user will have to generate the grids using external mesh generation tools. However, XCALibre.jl does provide a number of mesh conversion tools to allow user to import their grids.

XCALibre.jl is an unstructured Finite Volume Method (FVM) library, therefore, we are able to support grids of arbitrary polyhedral cells. In XCALibre.jl a cell-centred FVM approach has been implemented, which is popular since it allows the representation of complex geometries and it is used by most commercial and many open source CFD solvers.

Units

XCALIbre.jl does not enforce units strictly. Units are implicitly provided by the mesh. You can use the scale keyword when importing a mesh to control the units used e.g. if the mesh file was created in millimetres, set scale=0.001 to work in metres. Thus, it is important to ensure that consistent units are used through all configuration entries. It is highly recommended that SI units are used.

Mesh conversion

XCALibre.jl at present supports .unv mesh formats (which can be generated using SALOME) for simulations in 2D and 3D domains. XCALibre.jl also supports the OpenFOAM mesh format for simulations in 3D only (for now).

Note

Currently, XCALibre.jl only supports loading mesh files stored in ASCII format. Please ensure that when saving grid files they are not saved in binary format. Most mesh generation programmes offer the option to export in ASCII (text-based) formats.

The following functions are provided for importing mesh files:

XCALibre.UNV2.UNV2D_meshFunction
UNV2D_mesh(meshFile; scale=1, integer_type=Int64, float_type=Float64)

Read and convert 2D UNV mesh file into XCALibre.jl

Input

  • meshFile – path to mesh file.

Optional arguments

  • scale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling

  • integer_type - select interger type to use in the mesh (Int32 may be useful on GPU runs)

  • float_type - select interger type to use in the mesh (Float32 may be useful on GPU runs)

source
XCALibre.UNV3.UNV3D_meshFunction
UNV3D_mesh(unv_mesh; scale=1, integer_type=Int64, float_type=Float64)

Read and convert 3D UNV mesh file into XCALibre.jl. Note that a limitation of the .unv mesh format is that it only supports the following 3D cells:

  • Tetahedrals
  • Prisms
  • Hexahedrals

Input

  • unv_mesh – path to mesh file.

Optional arguments

  • scale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling

  • integer_type - select interger type to use in the mesh (Int32 may be useful on GPU runs)

  • float_type - select interger type to use in the mesh (Float32 may be useful on GPU runs)

source
XCALibre.FoamMesh.FOAM3D_meshFunction
FOAM3D_mesh(mesh_file; scale=1, integer_type=Int64, float_type=Float64)

Read and convert 3D OpenFOAM mesh file into XCALibre.jl. Note that, at present, it is not recommended to run 2D cases using meshes imported using this function.

Input

  • mesh_file – path to mesh file.

Optional arguments

  • scale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling

  • integer_type - select interger type to use in the mesh (Int32 may be useful on GPU runs)

  • float_type - select interger type to use in the mesh (Float32 may be useful on GPU runs)

source

These conversion functions will read mesh information and generate a mesh object (Mesh2 or Mesh3 depending on whether the mesh is 2D or 3D, respectively) with the following properties:

XCALibre.Mesh.Mesh3Type
struct Mesh3{VC, VI, VF<:AbstractArray{<:Face3D}, VB, VN, SV3, UR} <: AbstractMesh
+Pre-processing · XCALibre.jl

Pre-processing

First steps required to set up a simulation

Mesh generation and requirements


As with all CFD solvers, defining a suitable mesh is one of the most important steps. XCALibre.jl does not provides mesh generation utilities (yet). Thus, the user will have to generate the grids using external mesh generation tools. However, XCALibre.jl does provide a number of mesh conversion tools to allow user to import their grids.

XCALibre.jl is an unstructured Finite Volume Method (FVM) library, therefore, we are able to support grids of arbitrary polyhedral cells. In XCALibre.jl a cell-centred FVM approach has been implemented, which is popular since it allows the representation of complex geometries and it is used by most commercial and many open source CFD solvers.

Units

XCALIbre.jl does not enforce units strictly. Units are implicitly provided by the mesh. You can use the scale keyword when importing a mesh to control the units used e.g. if the mesh file was created in millimetres, set scale=0.001 to work in metres. Thus, it is important to ensure that consistent units are used through all configuration entries. It is highly recommended that SI units are used.

Mesh conversion

XCALibre.jl at present supports .unv mesh formats (which can be generated using SALOME) for simulations in 2D and 3D domains. XCALibre.jl also supports the OpenFOAM mesh format for simulations in 3D only (for now).

Note

Currently, XCALibre.jl only supports loading mesh files stored in ASCII format. Please ensure that when saving grid files they are not saved in binary format. Most mesh generation programmes offer the option to export in ASCII (text-based) formats.

The following functions are provided for importing mesh files:

XCALibre.UNV2.UNV2D_meshFunction
UNV2D_mesh(meshFile; scale=1, integer_type=Int64, float_type=Float64)

Read and convert 2D UNV mesh file into XCALibre.jl

Input

  • meshFile – path to mesh file.

Optional arguments

  • scale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling

  • integer_type - select interger type to use in the mesh (Int32 may be useful on GPU runs)

  • float_type - select interger type to use in the mesh (Float32 may be useful on GPU runs)

source
XCALibre.UNV3.UNV3D_meshFunction
UNV3D_mesh(unv_mesh; scale=1, integer_type=Int64, float_type=Float64)

Read and convert 3D UNV mesh file into XCALibre.jl. Note that a limitation of the .unv mesh format is that it only supports the following 3D cells:

  • Tetahedrals
  • Prisms
  • Hexahedrals

Input

  • unv_mesh – path to mesh file.

Optional arguments

  • scale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling

  • integer_type - select interger type to use in the mesh (Int32 may be useful on GPU runs)

  • float_type - select interger type to use in the mesh (Float32 may be useful on GPU runs)

source
XCALibre.FoamMesh.FOAM3D_meshFunction
FOAM3D_mesh(mesh_file; scale=1, integer_type=Int64, float_type=Float64)

Read and convert 3D OpenFOAM mesh file into XCALibre.jl. Note that, at present, it is not recommended to run 2D cases using meshes imported using this function.

Input

  • mesh_file – path to mesh file.

Optional arguments

  • scale – used to scale mesh file e.g. scale=0.001 will convert mesh from mm to metres defaults to 1 i.e. no scaling

  • integer_type - select interger type to use in the mesh (Int32 may be useful on GPU runs)

  • float_type - select interger type to use in the mesh (Float32 may be useful on GPU runs)

source

These conversion functions will read mesh information and generate a mesh object (Mesh2 or Mesh3 depending on whether the mesh is 2D or 3D, respectively) with the following properties:

XCALibre.Mesh.Mesh3Type
struct Mesh3{VC, VI, VF<:AbstractArray{<:Face3D}, VB, VN, SV3, UR} <: AbstractMesh
     cells::VC           # vector of cells
     cell_nodes::VI      # vector of indices to access cell nodes
     cell_faces::VI      # vector of indices to access cell faces
@@ -13,10 +13,10 @@
     get_float::SV3      # store mesh float type
     get_int::UR         # store mesh integer type
     boundary_cellsID::VI # vector of indices of boundary cell IDs
-end
source

Mesh limitations and requirements

In this section we summarise the key limitations of the mesh loaders presented above, and we also highlight specific requirements.

UNV mesh files

  • Only ASCII files are supported
  • For 2D simulations the mesh must be contained in the X-Y plane only
  • In 3D only hex, tet and prism elements are supported

OpenFOAM mesh files

  • Only ASCII files are supported
  • Boundary groups are not supported (must be deleted manually or the conversion may fail)
  • Boundary information is not preserved (walls, symmetry, etc)
  • 2D setups are not currently supported (but will be)

Backend selection


In XCALibre.jl the mesh object is very important, as it will not only provide geometry information about the simulation/s, but it is also used to automatically dispatch methods to run on the appropriate backend. Therefore, users must first select the backend they wish to use for the simulations, and then "adapt" the mesh to use the correct backend.

XCALIbre.jl aims to work with all the backends supported by KernelAbstractions.jl. However, since internally XCALibre.jl uses sparse arrays to reduce its memory footprint, some GPU backends are not currently supported since this functionality is not yet available. Thus, currently only a subset of backends are supported:

  • CPU (multithreaded and tested)
  • NVidia GPUs (tested)
  • AMD GPUs (not tested - feedback welcome)

Selecting a given backend is straight-forward. The examples below show how to assign a backend (CPU or GPU) to the symbol backend and converting the mesh object to run a simulation on the corresponding backend. The converted mesh is assigned to the symbol mesh_dev for clarity.

CPU backend

Selecting the CPU backend is straight-forward. See the example below. Notice that CPU() is a backend type provided by KernelAbstractions.jl which we re-export for convenience.

CPU Example

mesh = # call function to load mesh e.g. UNV2_mesh, UNV3_mesh or FOAM3D_mesh
+end
source

Mesh limitations and requirements

In this section we summarise the key limitations of the mesh loaders presented above, and we also highlight specific requirements.

UNV mesh files

  • Only ASCII files are supported
  • For 2D simulations the mesh must be contained in the X-Y plane only
  • In 3D only hex, tet and prism elements are supported

OpenFOAM mesh files

  • Only ASCII files are supported
  • Boundary groups are not supported (must be deleted manually or the conversion may fail)
  • Boundary information is not preserved (walls, symmetry, etc)
  • 2D setups are not currently supported (but will be)

Backend selection


In XCALibre.jl the mesh object is very important, as it will not only provide geometry information about the simulation/s, but it is also used to automatically dispatch methods to run on the appropriate backend. Therefore, users must first select the backend they wish to use for the simulations, and then "adapt" the mesh to use the correct backend.

XCALIbre.jl aims to work with all the backends supported by KernelAbstractions.jl. However, since internally XCALibre.jl uses sparse arrays to reduce its memory footprint, some GPU backends are not currently supported since this functionality is not yet available. Thus, currently only a subset of backends are supported:

  • CPU (multithreaded and tested)
  • NVidia GPUs (tested)
  • AMD GPUs (not tested - feedback welcome)

Selecting a given backend is straight-forward. The examples below show how to assign a backend (CPU or GPU) to the symbol backend and converting the mesh object to run a simulation on the corresponding backend. The converted mesh is assigned to the symbol mesh_dev for clarity.

CPU backend

Selecting the CPU backend is straight-forward. See the example below. Notice that CPU() is a backend type provided by KernelAbstractions.jl which we re-export for convenience.

CPU Example

mesh = # call function to load mesh e.g. UNV2_mesh, UNV3_mesh or FOAM3D_mesh
 backend = CPU()
 mesh_dev = mesh # dummy reference to emphasise the mesh in on our chosen dev (or backend)

GPU backends

To execute the code on GPUS, the process is also quite simple, but does require a few additional steps.

  • Install the corresponding Julia library that supports your hardware. For NVidia GPUs, the CUDA.jl package is required. For AMD GPUs, the AMDGPU.jl package is needed.
  • Move the mesh object to the backend device using the adapt method, which for convenience we re-export from Adapt.jl

Example for Nvidia GPU

mesh = # call function to load mesh e.g. UNV2_mesh, UNV3_mesh or FOAM3D_mesh
 backend = CUDABackend()
 mesh_dev = adapt(backend, mesh) # make mesh object backend compatible and move to GPU

Example for AMD GPU

mesh = # call function to load mesh e.g. UNV2_mesh, UNV3_mesh or FOAM3D_mesh
 backend = ROCBackend()
-mesh_dev = adapt(backend, mesh) # make mesh object backend compatible and move to GPU

Hardware configuration


In order to configure the backend the set_hardware function can be used.

XCALibre.Simulate.set_hardwareFunction
hardware = set_hardware(backend, workgroup)

Function used to configure the backend.

Inputs

  • backend named tuple used to specify the backend e.g. CPU(), CUDABackend() or other backends supported by KernelAbstraction.jl
  • workgroup::Int this is an integer specifying the number of workers that cooperate in a parallel run. For GPUs this could be set to the size of the device's warp e.g. workgroup = 32. On CPUs, the default value in KernelAbstractions.jl is currently workgroup = 1024.

Output

This function returns a NamedTuple with the fields backend and workgroup which are accessed by internally in XCALibre.jl to execute a given kernel.

source
+mesh_dev = adapt(backend, mesh) # make mesh object backend compatible and move to GPU

Hardware configuration


In order to configure the backend the set_hardware function can be used.

XCALibre.Simulate.set_hardwareFunction
hardware = set_hardware(backend, workgroup)

Function used to configure the backend.

Inputs

  • backend named tuple used to specify the backend e.g. CPU(), CUDABackend() or other backends supported by KernelAbstraction.jl
  • workgroup::Int this is an integer specifying the number of workers that cooperate in a parallel run. For GPUs this could be set to the size of the device's warp e.g. workgroup = 32. On CPUs, the default value in KernelAbstractions.jl is currently workgroup = 1024.

Output

This function returns a NamedTuple with the fields backend and workgroup which are accessed by internally in XCALibre.jl to execute a given kernel.

source
diff --git a/dev/user_guide/2_physics_and_models/index.html b/dev/user_guide/2_physics_and_models/index.html index 98c8903e..14e6d671 100644 --- a/dev/user_guide/2_physics_and_models/index.html +++ b/dev/user_guide/2_physics_and_models/index.html @@ -126,4 +126,4 @@ Dirichlet(:outlet, 0.0), Neumann(:wall, 0.0), # scalar wall - set up as zero gradient Neumann(:top, 0.0) # scalar wall - set up as zero gradient -)
Hint

Julia is a dynamic language and objects can be interrogated on the fly (dynamically). Say you created a Physics model named mymodel, you can interrogate the contents of any of the fields in the Physics structure using the fieldnames function, e.g. fieldnames(mymodel.momentum), to find which fields need to be provided with boundary conditions. Any fields not ending in f should be set.

+)
Hint

Julia is a dynamic language and objects can be interrogated on the fly (dynamically). Say you created a Physics model named mymodel, you can interrogate the contents of any of the fields in the Physics structure using the fieldnames function, e.g. fieldnames(mymodel.momentum), to find which fields need to be provided with boundary conditions. Any fields not ending in f should be set.

diff --git a/dev/user_guide/3_numerical_setup/index.html b/dev/user_guide/3_numerical_setup/index.html index 9f6b59e3..7f22d82c 100644 --- a/dev/user_guide/3_numerical_setup/index.html +++ b/dev/user_guide/3_numerical_setup/index.html @@ -22,7 +22,7 @@ laplacian=laplacian, gradient=gradient ) -end

The set_schemes function is used at the top-level API to help users define discretisation schemes for every field solved. It offers default values, thus users can pick and choose which entry they wish to modify.

inputs

  • time is used to set the time schemes (default is SteadyState)
  • divergence is used to set the divergence scheme (default is Linear)
  • laplacian is used to set the laplacian scheme (default is Linear)
  • gradient is used to set the gradient scheme (default is Orthogonal)
source

For example, below we set the schemes for the U and p fields. Notice that in the first case the schemes will take their default values (entry for p). In the case of U, we are only changing the setting for the divergence scheme to Upwind.

using XCALibre
+end

The set_schemes function is used at the top-level API to help users define discretisation schemes for every field solved. It offers default values, thus users can pick and choose which entry they wish to modify.

inputs

  • time is used to set the time schemes (default is SteadyState)
  • divergence is used to set the divergence scheme (default is Linear)
  • laplacian is used to set the laplacian scheme (default is Linear)
  • gradient is used to set the gradient scheme (default is Orthogonal)
source

For example, below we set the schemes for the U and p fields. Notice that in the first case the schemes will take their default values (entry for p). In the case of U, we are only changing the setting for the divergence scheme to Upwind.

using XCALibre
 schemes = (
     p = set_schemes(), # no input provided (will use defaults)
     U = set_schemes(divergence = Upwind),
@@ -51,7 +51,7 @@
         atol=atol |> TF, 
         rtol=rtol |> TF
     )
-end

This function is used to provide solver settings that will be used internally in XCALibre.jl. It returns a NamedTuple with solver settings that are used internally by the flow solvers.

Input arguments

  • field reference to the field to which the solver settings will apply (used to provide integer and float types required)
  • solver solver object from Krylov.jl and it could be one of BicgstabSolver, CgSolver, GmresSolver which are re-exported in XCALibre.jl
  • preconditioner instance of preconditioner to be used e.g. Jacobi()
  • convergence sets the stopping criteria of this field
  • relax specifies the relaxation factor to be used e.g. set to 1 for no relaxation
  • limit used in some solvers to bound the solution within this limits e.g. (min, max). It defaults to ()
  • itmax maximum number of iterations in a single solver pass (defaults to 100)
  • atol absolute tolerance for the solver (default to eps(FloatType)^0.9)
  • rtol set relative tolerance for the solver (defaults to 1e-3)
source

Preconditioners

XCALibre.jl offers a range of preconditioners which are subtypes of the abstrac type PreconditionerType, exploring its subtypes we can find a list of the currently available preconditioners:

PreconditionerType
+end

This function is used to provide solver settings that will be used internally in XCALibre.jl. It returns a NamedTuple with solver settings that are used internally by the flow solvers.

Input arguments

  • field reference to the field to which the solver settings will apply (used to provide integer and float types required)
  • solver solver object from Krylov.jl and it could be one of BicgstabSolver, CgSolver, GmresSolver which are re-exported in XCALibre.jl
  • preconditioner instance of preconditioner to be used e.g. Jacobi()
  • convergence sets the stopping criteria of this field
  • relax specifies the relaxation factor to be used e.g. set to 1 for no relaxation
  • limit used in some solvers to bound the solution within this limits e.g. (min, max). It defaults to ()
  • itmax maximum number of iterations in a single solver pass (defaults to 100)
  • atol absolute tolerance for the solver (default to eps(FloatType)^0.9)
  • rtol set relative tolerance for the solver (defaults to 1e-3)
source

Preconditioners

XCALibre.jl offers a range of preconditioners which are subtypes of the abstrac type PreconditionerType, exploring its subtypes we can find a list of the currently available preconditioners:

PreconditionerType
 ├─ DILU
 ├─ ILU0
 ├─ Jacobi
@@ -79,4 +79,4 @@
         rtol = 1e-4,
         atol = 1e-10
     )
-)
+) diff --git a/dev/user_guide/4_runtime_and_solvers/index.html b/dev/user_guide/4_runtime_and_solvers/index.html index 865f47e3..204778df 100644 --- a/dev/user_guide/4_runtime_and_solvers/index.html +++ b/dev/user_guide/4_runtime_and_solvers/index.html @@ -12,17 +12,17 @@ dt=time_step, write_interval=write_interval) end

This is a convenience function to set the top-level runtime information. The inputs are all keyword arguments and provide basic information to flow solvers just before running a simulation.

Input arguments

  • iterations::Integer specifies the number of iterations in a simulation run.
  • write_interval::Integer defines how often simulation results are written to file (on the current working directory). The interval is currently based on number of iterations. Set to -1 to run without writing results to file.
  • time_step::Number the time step to use in the simulation. Notice that for steady solvers this is simply a counter and it is recommended to simply use 1.

Example

runtime = set_runtime(
-    iterations=2000, time_step=1, write_interval=2000)
source

Configuration object


Once all the simulation configuration information has been defined, from discretisation scheme to runtime information, all settings must be wrapped in a Configuration object. The definition, including expected input arguments, for the Configuration object are detailed below.

Configuration object


Once all the simulation configuration information has been defined, from discretisation scheme to runtime information, all settings must be wrapped in a Configuration object. The definition, including expected input arguments, for the Configuration object are detailed below.

XCALibre.Simulate.ConfigurationType
@kwdef struct Configuration{SC,SL,RT,HW}
     schemes::SC
     solvers::SL
     runtime::RT
     hardware::HW
 end

The Configuration type is passed to all flow solvers and provides all the relevant information to run a simulation.

Inputs

  • schemes::NamedTuple this keyword argument is used to pass distretisation scheme information to flow solvers. See Numerical setup for details.
  • solvers::NamedTuple this keyword argument is used to pass the configurations for the linear solvers for each field information to flow solvers. See Runtime and solvers for details.
  • runtime::NamedTuple this keyword argument is used to pass runtime information to the flow solvers. See Runtime and solvers for details.
  • hardware::NamedTuple this keyword argument is used to pass the hardware configuration and backend settings to the flow solvers. See Pre-processing for details.

Example

config = Configuration(
-    solvers=solvers, schemes=schemes, runtime=runtime, hardware=hardware)
source

Initialising fields


The last (optional) step before running the simulation is to provide an initial guess for all the fields being solved. Although this step is optional, in most cases the flow solvers will perform better when initialised. To set an initial value for a field, the initialise! function is provided, which assigns a starting value to a given field.

XCALibre.Fields.initialise!Function
function initialise!(field, value) # dummy function for documentation
+    solvers=solvers, schemes=schemes, runtime=runtime, hardware=hardware)
source

Initialising fields


The last (optional) step before running the simulation is to provide an initial guess for all the fields being solved. Although this step is optional, in most cases the flow solvers will perform better when initialised. To set an initial value for a field, the initialise! function is provided, which assigns a starting value to a given field.

XCALibre.Fields.initialise!Function
function initialise!(field, value) # dummy function for documentation
     # Assign `value` to field in-place
     nothing
 end

This function will set the given field to the value provided in-place. Useful for initialising fields prior to running a simulation.

Input arguments

  • field specifies the field to be initialised. The field must be either a AbractScalarField or AbstractVectorField
  • value defines the value to be set. This should be a scalar or vector (3 components) depending on the field to be modified e.g. for an AbstractVectorField we can specify as value=[10,0,0]

Note: in most cases the fields to be modified are stored within a physics model i.e. a Physics object. Thus, the argument value must fully qualify the model. For example, if we have created a Physics model named mymodel to set the velocity field, U, we would set the argument field to mymodel.momentum.U. See the example below.

Example

initialise!(mymodel.momentum.U, [2.5, 0, 0])
-initialise!(mymodel.momentum.p, 1.25)
source

Launching flow solvers


In XCALibre.jl the run! function is used to start a simulation, which will dispatch to the appropriate flow solver for execution. Once the simulation is complete a NamedTuple containing residual information is returned for users to explore the convergence history of the simulation.

Launching flow solvers


In XCALibre.jl the run! function is used to start a simulation, which will dispatch to the appropriate flow solver for execution. Once the simulation is complete a NamedTuple containing residual information is returned for users to explore the convergence history of the simulation.

XCALibre.Solvers.run!Method
function run!(
     model::Physics, config; 
     limit_gradient=false, pref=nothing, ncorrectors=0, inner_loops=0
     )
@@ -33,4 +33,4 @@
 
 # to access the pressure residual
 
-residuals.p 
source

Restarting simulations


It should be noted that when running a simulation with run!, the solution fields in the Physics model are mutated. Thus, running the simulation from the previous solution is simply a matter of reissuing the run! function. At present, this has the side effect of overwriting any existing solution files (.vtk or .vtu). Users must be aware of this behaviour.

In some cases, it may be desirable to solve a problem with a steady solver and use the solution to run transient simulations. This is possible using the change function.

XCALibre.ModelPhysics.changeFunction
change(model::Physics, property, value) => updatedModel::Physics

A convenience function to change properties of an exisitng Physics model.

Input arguments

  • model::Physics a Physics model to modify
  • property is a symbol specifying the property to change
  • value is the new setting for the specified property

Output

This function return a new Physics object

Example

To change a model to run a transient simulation e.g. after converging in steady state

modelTransient = change(model, :time, Transient())
source
+residuals.p source

Restarting simulations


It should be noted that when running a simulation with run!, the solution fields in the Physics model are mutated. Thus, running the simulation from the previous solution is simply a matter of reissuing the run! function. At present, this has the side effect of overwriting any existing solution files (.vtk or .vtu). Users must be aware of this behaviour.

In some cases, it may be desirable to solve a problem with a steady solver and use the solution to run transient simulations. This is possible using the change function.

XCALibre.ModelPhysics.changeFunction
change(model::Physics, property, value) => updatedModel::Physics

A convenience function to change properties of an exisitng Physics model.

Input arguments

  • model::Physics a Physics model to modify
  • property is a symbol specifying the property to change
  • value is the new setting for the specified property

Output

This function return a new Physics object

Example

To change a model to run a transient simulation e.g. after converging in steady state

modelTransient = change(model, :time, Transient())
source
diff --git a/dev/user_guide/5_postprocessing/index.html b/dev/user_guide/5_postprocessing/index.html index d2a80f33..016f1909 100644 --- a/dev/user_guide/5_postprocessing/index.html +++ b/dev/user_guide/5_postprocessing/index.html @@ -31,4 +31,4 @@ # return average return ave -endsource

To calculate pressure and viscous forces, the following functions are available:

XCALibre.Postprocess.pressure_forceFunction
pressure_force(patch::Symbol, p::ScalarField, rho)

Function to calculate the pressure force acting on a given patch/boundary.

Input arguments

  • patch::Symbol name of the boundary of interest (as a Symbol)
  • p::ScalarField pressure field
  • rho density. Set to 1 for incompressible solvers
source
XCALibre.Postprocess.viscous_forceFunction
viscous_force(patch::Symbol, U::VectorField, rho, ν, νt)

Function to calculate the pressure force acting on a given patch/boundary.

Input arguments

  • patch::Symbol name of the boundary of interest (as a Symbol)
  • U::VectorField pressure field
  • rho density. Set to 1 for incompressible solvers
  • ν laminar viscosity of the fluid
  • νt eddy viscosity from turbulence models. Pass ConstantScalar(0) for laminar flows
source
+endsource

To calculate pressure and viscous forces, the following functions are available:

XCALibre.Postprocess.pressure_forceFunction
pressure_force(patch::Symbol, p::ScalarField, rho)

Function to calculate the pressure force acting on a given patch/boundary.

Input arguments

  • patch::Symbol name of the boundary of interest (as a Symbol)
  • p::ScalarField pressure field
  • rho density. Set to 1 for incompressible solvers
source
XCALibre.Postprocess.viscous_forceFunction
viscous_force(patch::Symbol, U::VectorField, rho, ν, νt)

Function to calculate the pressure force acting on a given patch/boundary.

Input arguments

  • patch::Symbol name of the boundary of interest (as a Symbol)
  • U::VectorField pressure field
  • rho density. Set to 1 for incompressible solvers
  • ν laminar viscosity of the fluid
  • νt eddy viscosity from turbulence models. Pass ConstantScalar(0) for laminar flows
source