base_backend class defines all the operations that the solver class requires.
For example, transport equation in solver class evaluates the derivatives in x, y, and z directions, and reorders the input fields as required. Then finally, combines all the directional derivatives to obtain the divergence of U*.
All these high level operations solver class executes are defined here. Every backend implementation extends the present backend class to define the specifics of these operations based on the target architecture.
None of the operations is deferred: each one defaults to
not_implemented, which stops the run naming the operation. A
backend therefore overrides only what it actually implements, and
an operation added for one backend does not force a stub into
every other backend. A backend reaching an operation it does not
override fails loudly at the call site instead of silently doing
nothing.
supports_device_field_export has a genuinely correct answer for
a backend that does not override it (.false.), so it defaults to
that rather than to an error.
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | public | :: | n_halo | = | 4 |
DistD2 implementation is hardcoded for 4 halo layers for all backends |
|
| type(mesh_t), | public, | pointer | :: | mesh | |||
| class(allocator_t), | public, | pointer | :: | allocator | |||
| class(poisson_fft_t), | public, | pointer | :: | poisson_fft |
transeq equation obtains the derivatives direction by direction, and the exact algorithm used to obtain these derivatives are decided at runtime. Backend implementations are responsible from directing calls to transeq_x into the correct algorithm.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | du | |||
| class(field_t), | intent(inout) | :: | dv | |||
| class(field_t), | intent(inout) | :: | dw | |||
| class(field_t), | intent(in) | :: | u | |||
| class(field_t), | intent(in) | :: | v | |||
| class(field_t), | intent(in) | :: | w | |||
| real(kind=dp), | intent(in) | :: | nu | |||
| type(dirps_t), | intent(in) | :: | dirps |
As transeq_x, for the y direction.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | du | |||
| class(field_t), | intent(inout) | :: | dv | |||
| class(field_t), | intent(inout) | :: | dw | |||
| class(field_t), | intent(in) | :: | u | |||
| class(field_t), | intent(in) | :: | v | |||
| class(field_t), | intent(in) | :: | w | |||
| real(kind=dp), | intent(in) | :: | nu | |||
| type(dirps_t), | intent(in) | :: | dirps |
As transeq_x, for the z direction.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | du | |||
| class(field_t), | intent(inout) | :: | dv | |||
| class(field_t), | intent(inout) | :: | dw | |||
| class(field_t), | intent(in) | :: | u | |||
| class(field_t), | intent(in) | :: | v | |||
| class(field_t), | intent(in) | :: | w | |||
| real(kind=dp), | intent(in) | :: | nu | |||
| type(dirps_t), | intent(in) | :: | dirps |
As transeq_x, for a scalar species transported by uvw.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | dspec | |||
| class(field_t), | intent(in) | :: | uvw | |||
| class(field_t), | intent(in) | :: | spec | |||
| real(kind=dp), | intent(in) | :: | nu | |||
| type(dirps_t), | intent(in) | :: | dirps | |||
| logical, | intent(in) | :: | sync |
Applies a tridiagonal operator to u, the exact algorithm used being decided at runtime. Backend implementations are responsible from directing calls to tds_solve to the correct algorithm.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | du | |||
| class(field_t), | intent(in) | :: | u | |||
| class(tdsops_t), | intent(in) | :: | tdsops |
As tds_solve, solving the tridiagonal system with the Thomas algorithm.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | du | |||
| class(field_t), | intent(in) | :: | u | |||
| class(tdsops_t), | intent(in) | :: | tdsops |
reorder subroutines are straightforward, they rearrange data into our specialist data structure so that regardless of the direction tridiagonal systems are solved efficiently and fast.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | u_ | |||
| class(field_t), | intent(in) | :: | u | |||
| integer, | intent(in) | :: | direction |
sum_yintox combines a y directional field into the corresponding x directional field.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | u | |||
| class(field_t), | intent(in) | :: | u_ |
As sum_yintox, for a z directional field.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | u | |||
| class(field_t), | intent(in) | :: | u_ |
copy vectors: y = x
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | dst | |||
| class(field_t), | intent(in) | :: | src |
adds two vectors together: y = ax + by
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| real(kind=dp), | intent(in) | :: | a | |||
| class(field_t), | intent(in) | :: | x | |||
| real(kind=dp), | intent(in) | :: | b | |||
| class(field_t), | intent(inout) | :: | y |
pointwise multiplication between two vectors: y(:) = y(:) * x(:)
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | y | |||
| class(field_t), | intent(in) | :: | x |
Calculates the scalar product of two input fields
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(in) | :: | x | |||
| class(field_t), | intent(in) | :: | y |
Computes the global discrete squared norm of a three-component field.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(in) | :: | a | |||
| class(field_t), | intent(in) | :: | b | |||
| class(field_t), | intent(in) | :: | c |
Computes this rank's sums of ga, gb and g*c separately for each
label in a single pass over DIR_X fields. label holds integer values
stored as reals; points labelled l in 1..size(sums, 2) add to
sums(:, l) and all other points are skipped. No MPI reduction is done,
so the caller can reduce all labels together in one MPI call.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| real(kind=dp), | intent(out) | :: | sums(:,:) | |||
| class(field_t), | intent(in) | :: | g | |||
| class(field_t), | intent(in) | :: | label | |||
| class(field_t), | intent(in) | :: | a | |||
| class(field_t), | intent(in) | :: | b | |||
| class(field_t), | intent(in) | :: | c |
Adds coeffs(1, l)g, coeffs(2, l)g and coeffs(3, l)*g to a, b and c at every point of the DIR_X fields labelled l in 1..size(coeffs, 2). Points with any other label are left unchanged.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| real(kind=dp), | intent(in) | :: | coeffs(:,:) | |||
| class(field_t), | intent(in) | :: | g | |||
| class(field_t), | intent(in) | :: | label | |||
| class(field_t), | intent(inout) | :: | a | |||
| class(field_t), | intent(inout) | :: | b | |||
| class(field_t), | intent(inout) | :: | c |
Obtains maximum and mean values in a field
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| real(kind=dp), | intent(out) | :: | max_val | |||
| real(kind=dp), | intent(out) | :: | mean_val | |||
| class(field_t), | intent(in) | :: | f | |||
| integer, | intent(in), | optional | :: | enforced_data_loc |
Reduces a single slice of f at index i_slice along f's DIR axis. Returns signed max (not abs) and signed sum. No division by count. Caller is responsible for MPI_Allreduce across ranks.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| real(kind=dp), | intent(out) | :: | max_val | |||
| real(kind=dp), | intent(out) | :: | sum_val | |||
| class(field_t), | intent(in) | :: | f | |||
| integer, | intent(in) | :: | i_slice | |||
| integer, | intent(in), | optional | :: | enforced_data_loc |
Sum a DIR_X field over x and z on every local y-plane: sums(j) is the sum over the plane of y index j. The order of summation is fixed, so the result is reproducible.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| real(kind=dp), | intent(out) | :: | sums(:) | |||
| class(field_t), | intent(in) | :: | f |
Scales a field by a
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(in) | :: | f | |||
| real(kind=dp), | intent(in) | :: | a |
Shifts a field by a
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(in) | :: | f | |||
| real(kind=dp), | intent(in) | :: | a |
Reduces field to a scalar by integrating over the volume
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(in) | :: | f |
A field is a subdomain with a rectangular cuboid shape. It has 6 faces, and these faces are either a subdomain boundary or a global domain boundary based on the location of the subdomain. This subroutine allows us to set any of these faces to a value, 'c_start' and 'c_end' for faces at opposite sides. 'face' is one of X_FACE, Y_FACE, Z_FACE from common.f90 Optionally, bc_start/bc_end select the BC type (default BC_DIRICHLET).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | f | |||
| real(kind=dp), | intent(in) | :: | c_start | |||
| real(kind=dp), | intent(in) | :: | c_end | |||
| integer, | intent(in) | :: | face | |||
| integer, | intent(in), | optional | :: | bc_start | ||
| integer, | intent(in), | optional | :: | bc_end | ||
| real(kind=dp), | intent(in), | optional | :: | flow_rate_diff |
Set one interior y-plane of a DIR_X field to a constant.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | f | |||
| real(kind=dp), | intent(in) | :: | c | |||
| integer, | intent(in) | :: | plane |
1-based y-vertex index |
Replace one SGS stress plane using the local sampled velocity.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | stress | |||
| class(field_t), | intent(in) | :: | u | |||
| class(field_t), | intent(in) | :: | w | |||
| integer, | intent(in) | :: | sample_plane | |||
| integer, | intent(in) | :: | stress_plane | |||
| real(kind=dp), | intent(in) | :: | drag_coeff | |||
| integer, | intent(in) | :: | component |
As field_set_face but with a spatially-varying inlet face field instead of a scalar c_start.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | f | |||
| class(field_t), | intent(in) | :: | f_start | |||
| real(kind=dp), | intent(in) | :: | c_end | |||
| integer, | intent(in) | :: | face | |||
| integer, | intent(in), | optional | :: | bc_start | ||
| integer, | intent(in), | optional | :: | bc_end | ||
| real(kind=dp), | intent(in), | optional | :: | flow_rate_diff |
Add the face planes of g onto those of f, on Dirichlet faces
only. Both fields are DIR_X; X_FACE and Y_FACE are supported.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | f | |||
| class(field_t), | intent(in) | :: | g | |||
| integer, | intent(in) | :: | face | |||
| integer, | intent(in) | :: | bc_start | |||
| integer, | intent(in) | :: | bc_end |
Adds a uniform constant c to one x-normal face plane of a DIR_X
field, in place. Used to enforce exact outlet mass conservation:
after the convective outflow update, the outlet-plane mean is
shifted uniformly so that it matches the prescribed inlet mean
(mirrors Incompact3d's bxxn = bxxn - ut + ut1).
at_end = .true. -> the x = nx plane (outlet)
at_end = .false. -> the x = 1 plane (inlet)
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | f | |||
| real(kind=dp), | intent(in) | :: | c | |||
| logical, | intent(in) | :: | at_end |
Overwrites the x = 1 plane (pencil index 1) of a DIR_X field with
the host array plane(ny, nz), in local VERT dims. Only the plane
crosses to the device, so a time-varying inlet can be refreshed
without uploading and reordering a full 3D field.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | f | |||
| real(kind=dp), | intent(in), | dimension(:, :) | :: | plane |
Computes the vorticity magnitude from velocity gradients
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | field_out | |||
| class(field_t), | intent(in) | :: | dudx | |||
| class(field_t), | intent(in) | :: | dudy | |||
| class(field_t), | intent(in) | :: | dudz | |||
| class(field_t), | intent(in) | :: | dvdx | |||
| class(field_t), | intent(in) | :: | dvdy | |||
| class(field_t), | intent(in) | :: | dvdz | |||
| class(field_t), | intent(in) | :: | dwdx | |||
| class(field_t), | intent(in) | :: | dwdy | |||
| class(field_t), | intent(in) | :: | dwdz |
Computes the Q-criterion from velocity gradients
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | field_out | |||
| class(field_t), | intent(in) | :: | dudx | |||
| class(field_t), | intent(in) | :: | dudy | |||
| class(field_t), | intent(in) | :: | dudz | |||
| class(field_t), | intent(in) | :: | dvdx | |||
| class(field_t), | intent(in) | :: | dvdy | |||
| class(field_t), | intent(in) | :: | dvdz | |||
| class(field_t), | intent(in) | :: | dwdx | |||
| class(field_t), | intent(in) | :: | dwdy | |||
| class(field_t), | intent(in) | :: | dwdz |
Computes nut=l_s^2sqrt(2S_ij*S_ij) from velocity gradients.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | nut | |||
| class(field_t), | intent(in) | :: | mixing_length_sq | |||
| class(field_t), | intent(in) | :: | dudx | |||
| class(field_t), | intent(in) | :: | dudy | |||
| class(field_t), | intent(in) | :: | dudz | |||
| class(field_t), | intent(in) | :: | dvdx | |||
| class(field_t), | intent(in) | :: | dvdy | |||
| class(field_t), | intent(in) | :: | dvdz | |||
| class(field_t), | intent(in) | :: | dwdx | |||
| class(field_t), | intent(in) | :: | dwdy | |||
| class(field_t), | intent(in) | :: | dwdz |
Forms nut(scale_agradient_a + scale_b*gradient_b).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | stress | |||
| class(field_t), | intent(in) | :: | nut | |||
| class(field_t), | intent(in) | :: | gradient_a | |||
| class(field_t), | intent(in) | :: | gradient_b | |||
| real(kind=dp), | intent(in) | :: | scale_a | |||
| real(kind=dp), | intent(in) | :: | scale_b |
Copy a regular 3D array in host memory into the specialist data structure field that lives on device or host
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t), | intent(inout) | :: | self | |||
| class(field_t), | intent(inout) | :: | f | |||
| real(kind=dp), | intent(in), | dimension(:, :, :) | :: | data |
Copy the specialist data structure from device or host back to a regular 3D data array in host memory.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t), | intent(inout) | :: | self | |||
| real(kind=dp), | intent(out), | dimension(:, :, :) | :: | data | ||
| class(field_t), | intent(in) | :: | f |
Allocates the backend's own tdsops type and fills in the coefficients of the requested operation.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(tdsops_t), | intent(inout), | allocatable | :: | tdsops | ||
| integer, | intent(in) | :: | n_tds | |||
| real(kind=dp), | intent(in) | :: | delta | |||
| character(len=*), | intent(in) | :: | operation | |||
| character(len=*), | intent(in) | :: | scheme | |||
| integer, | intent(in) | :: | bc_start | |||
| integer, | intent(in) | :: | bc_end | |||
| real(kind=dp), | intent(in), | optional | :: | stretch(:) | ||
| real(kind=dp), | intent(in), | optional | :: | stretch_correct(:) | ||
| integer, | intent(in), | optional | :: | n_halo | ||
| character(len=*), | intent(in), | optional | :: | from_to | ||
| logical, | intent(in), | optional | :: | sym | ||
| real(kind=dp), | intent(in), | optional | :: | c_nu | ||
| real(kind=dp), | intent(in), | optional | :: | nu0_nu | ||
| real(kind=dp), | intent(in), | optional | :: | filter_alpha |
Allocates and initialises the backend's FFT based Poisson solver.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| type(mesh_t), | intent(in), | target | :: | mesh | ||
| type(dirps_t), | intent(in) | :: | xdirps | |||
| type(dirps_t), | intent(in) | :: | ydirps | |||
| type(dirps_t), | intent(in) | :: | zdirps | |||
| logical, | intent(in), | optional | :: | lowmem |
Waits for outstanding device work.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self |
Reports the memory clock rate and bus width of the target device, used to work out a theoretical peak bandwidth.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| integer, | intent(out) | :: | mem_clock_rt | |||
| integer, | intent(out) | :: | mem_bus_width | |||
| logical, | intent(out) | :: | available |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self |
Extract data from field f optionally reordering into dir orientation.
To output in same orientation as f, use call ...%get_field_data(data, f, f%dir)
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| real(kind=dp), | intent(out), | dimension(:, :, :) | :: | data |
Output array |
|
| class(field_t), | intent(in) | :: | f |
Field |
||
| integer, | intent(in), | optional | :: | dir |
Desired orientation of output array (defaults to Cartesian) |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| class(field_t), | intent(inout) | :: | f |
Field |
||
| real(kind=dp), | intent(in), | dimension(:, :, :) | :: | data |
Input array |
|
| integer, | intent(in), | optional | :: | dir |
Orientation of input array (defaults to Cartesian) |
Whether export_field_to_device can pack field f without staging
it through host memory. Backends without device memory keep this
default and report no support.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t), | intent(in) | :: | self | |||
| class(field_t), | intent(in) | :: | f |
Pack the first dims Cartesian points of field f into a
contiguous device buffer, in (i, j, k) order without padding.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(base_backend_t) | :: | self | ||||
| type(c_ptr), | intent(in) | :: | buffer | |||
| class(field_t), | intent(in) | :: | f | |||
| integer, | intent(in) | :: | dims(3) | |||
| logical, | intent(in) | :: | to_sp |