ExaSlang 4 Documentation

Language Structure

Top-Level Statements

The following statements are supported:

Inner Statements

The following statements are supported:

Expressions

The following expressions are supported:

Concepts

TODO

Basic Language Constructs

Comments

Comments are offered with C-like syntax.

Syntax

// comment
/* comment */

Details

Example

// this is a comment
/* this is a
   multi-line
   comment
*/

Data types

Represents a simple data type.

Syntax

dataType

Details

dataType may be one of the following:

Example

cf examples for variable declarations and function declarations.

Literals

Literals.

Syntax

number
boolean
'string'
"string"

Details

number may be integral or real.

boolean may be true or false.

Example

1
1.5
1.0e30
true
'some string'
"some string"

Levels

Level Access

Access to a single level.

Syntax
@level
Details

level may be on of the following

Example
@10

Level Declaration

A group of levels used for declarations.

Syntax
@levels
Details

levels may be on of the following

Example
@10
@(finest - 1)

Relative Level

Access to a level relative to another.

Syntax
(base + offset)
(base - offset)
Details

base must be a constant or a suitable level alias evaluating to a single level.

offset must be an integer constant.

Example
(finest - 1)

Level Alias

Aliases for commonly used cases.

Syntax
alias
Details

alias may be on of the following: Used as level access:

  • current, denoting that the level of the surrounding construct should be used

  • finer, shorthand for @(current + 1)

  • coarser, shorthand for @(current - 1)

Used as level access and level declaration:

  • finest, denoting the finest level as specified by Knowledge.maxLevel

  • coarsest, denoting the coarsest level as specified by Knowledge.minLevel

Used as level declaration:

  • all, denoting all levels as specified by the range between Knowledge.minLevel and Knowledge.maxLevel

Example
@all

Level List

A list of levels used for level declarations.

Syntax
(
  levels
  /* optional */ but exclude
  )
Details

levels must be a non-empty list of levels separated by comma or the and keyword, or a level range.

exclude, if provided, must be a valid level list without any nested exclude. The not keyword may be used instead of the but keyword.

Example
(0, 2, 4)
(all but finest)

Level Range

A range of levels used for level declarations.

Syntax
( begin to end )
Details

begin and end must be constants or suitable level aliases evaluating to single levels.

Example
(coarsest to finest)

Functions

Function Declaration

Declares a new function with the given name, taking the provided arguments and with the given returnType.

Syntax
/* optional */ noinline
  Function name
  /* optional */ levels
  /* optional */ ( arguments )
  /* optional */ : returnType
  { body }
Details

Func may be used instead of Function.

noinline may be used to disallow inlining for this function.

The function declaration is regarded as leveled if levels is specified. Must be a valid level selection for declarations.

arguments, if provided, has to be a list of function arguments. May be empty.

returnType, if provided, has to be a valid language datatype. In this case, at least one return statement must be present in the body. If returnType is not provided, an implicit Unit type is assumed.

body must be a list of suitable statements. May be empty.

Example
Function F ( xPos : Real, yPos : Real ) : Real {
  return sin ( xPos ) * cos ( yPos )
}
Function Smoother@all {
  /* ... */
}

Function Argument

Specifies a function argument with the given name and dataType.

Syntax
name : dataType
Details

dataType must be a valid language datatype.

Example
someParam : Real

Return Statement

Statement used to exit a function and to optionally return a value.

Syntax
return
  /* optional */ returnValue
Details

returnValue may be an arbitrary expression. Its data type must match the surrounding functions return type. In case of Unit returnValue must not be specified.

Example
return
return sin ( xPos ) * cos ( yPos )

Function Call

Call a function with the given name and the provided parameters.

Syntax
name
  /* optional */ levels
  /* optional */ offset
  ( parameters )
Details

If the called function is leveled and levels is not provided, an implicit @current is assumed. levels, if provided, must be a valid level access.

parameter is a list of arbitrary expressions. May be empty.

If the function call is used as a statement, it is implicitly wrapped in an expression statement.

Example
Var res : Real = F ( 0.5, 0.5 )
Smoother@current ( )

Local Declarations

Variable Declaration

Declares a new variable

Syntax
Var name : dataType
  /* optional */ levels
  /* optional */ = initial
Details

Variable may be used instead of Var.

dataType must be a valid language datatype.

The declaration is regarded as leveled if levels is specified. Must be a valid level selection for declarations.

initial may be an arbitrary expression. It is used to initialize the variable in the generated code if provided.

Example
Var cnt : Int = 0
Var curError : Real = 0

Value Declaration

Declares a new constant variable

Syntax
Val name : dataType
  /* optional */ levels
  = initial
Details

Value may be used instead of Val.

dataType must be a valid language datatype.

The declaration is regarded as leveled if levels is specified. Must be a valid level selection for declarations.

initial may be an arbitrary expression.

Right now values are propagated by default and without check for side effects. This effectively means that they work like a C define. Can be controlled via Knowledge.experimental_l4_inlineValueDeclarations.

Example
Val maxNumIts : Int = 128
Val a : Real = 10.5 * 4.

Assignments

Basic Assignment

Assigns src to dest.

Syntax
dest = src
Details

dest must be a valid access.

src maybe an arbitrary expression evaluating to the data type of dest.

Example
Var cnt : Int
cnt = 0

Compound Assignment

Performs a compound assignment from src to dest with the specified operation.

Syntax
dest += src
dest -= src
dest *= src
dest /= src
Details

dest must be a valid access.

src maybe an arbitrary expression evaluating to the data type of dest.

Example
Var cnt : Int = 0
cnt += 1

Unary Operations

Performs basic calculations.

Syntax

op target

Details

target may be arbitrary expressions.

op may be one of the following:

  • for numeric expressions

    • -

  • for boolean expressions

    • !

Example

-1
!true

Binary Operations

Performs basic calculations.

Syntax

left op right

Details

left and right may be arbitrary expressions.

op may be one of the following:

  • for numeric expressions

    • + - * /

    • % for modulo operations

    • ** or ^ for power operations

  • for boolean expressions

    • || or ‘or’

    • && or ‘and’

    • < <= > >= == and != for comparison operations

the precedence is given by:

  • for numeric expressions

    • ** ^

    • * / %

    • + -

  • for boolean expressions

    • || or

    • && and

    • < <= > >= == !=

Example

1 + 2
MyStencil * MyField

Basic Loops

Fixed-Length Loop

Executes statements a constant number of times.

Syntax
repeat n times
  /* optional */ count variable
  { body }
Details

n must be an integral number.

The current iteration number is stored in variable, if provided, which needs to be declared beforehand.

body must be a list of suitable statements. May be empty.

Example
Var cnt : Int = 0
repeat 10 times count cnt {
  print ( 'Iteration', cnt )
}

Conditional Loop

Executes statements while or until a given condition is met.

Syntax
 repeat until condition { body } 
 repeat while condition { body } 
Details

condition may be an arbitrary expression evaluating to a Boolean value.

body must be a list of suitable statements. May be empty.

Example
Var cnt : Int = 0
repeat until 10 == cnt {
  print ( 'Iteration', cnt )
  cnt += 1
}

Conditional

brief

Syntax

if ( condition ) { ifBranch }
  /* optional */ else elseBranch

Details

Exectues ifBranch if condition evaluates to true, elseBranch otherwise (if it is specified).

condition may be an arbitrary expression evaluating to a Boolean.

ifBranch must be a list of suitable statements. May be empty.

elseBranch may be

Example

if ( true ) {
  print ( 'always true' )
} else {
  print ( 'will not be evaluated' )
}
Var someVar : Real = 0.5
if ( 0. == someVar or 1. == someVar ) {
  // ...
}

Index

Constant Index

A constant index which can, e.g., be used as offset or direction.

Syntax
[ i_0 ]
[ i_0 , i_1 ]
[ i_0 , i_1 , i_2 ]
Details

i_n must be integral constants. More than 3 dimensions are supported, but omitted here.

Example
[ 1, 0 ]
[ 0, 1, -1 ]

Expression Index

An index with expressions.

Syntax
[ e_0 ]
[ e_0 , e_1 ]
[ e_0 , e_1 , e_2 ]
Details

e_n may be arbitrary expressions evaluating to Int. More than 3 dimensions are supported, but omitted here.

Example
[ 0, 1, -1 ]
[ ( i0 % 2 ), ( i1 % 2 ) ]

Knowledge Objects

Domains

Domain Declaration

Declares a new domain with the given name.

Syntax
Domain name < lower to upper >
Details

lower and upper are coordinates of the axis-aligned bounding box surrounding the domain. Their dimensionality must match. Currently it must also be identical to Knowledge.dimesionality.

In case of multiple domains, the boundaries of all (sub-)domains must coincide with the domain partitioning.

There must be at least one domain named ‘global’. This domain must include all other domains.

Example
Domain unitSquare < [0., 0.] to [1., 1.] >
Domain global < [0, 0, 0] to [2, 4, 6] >

Fields

Field Layout Declaration

Declares a new field layout with the given name and options.

Syntax
Layout name < dataType , localization > 
  /* optional */ levels
  { options }
Details

Specifies that quantities of the given dataType are stored at specific parts of the grid chosen by localization.

dataType must be a valid language datatype.

localization must be one of the following:

  • Node

  • Cell

  • Face_x

  • Face_y if dimensionality at least 2

  • Face_z if dimensionality at least 3

The declaration is always regarded as leveled. If levels is specified it must be a valid level selection for declarations. If it is not specified, an implicit @all is assumed.

layoutOptions is a list of layout options which may be separated by comma. May be empty.

Example
Layout CellLayout < Real , Cell > @all {
  duplicateLayers = [ 0, 0, 0 ]
  ghostLayers     = [ 1, 1, 1 ] with communication
}

Layout Option

Specification of an option to be used for field layouts.

Syntax
option = index
  /* optional */ with communication
Details

option may be one of the following:

  • duplicateLayers

  • ghostLayers

  • innerPoints

index specifies the number of layers per dimension for the chosen option.

with communication marks the chosen layers for communication. Layers that are not marked here will not be communicated, even when communicate statements are given.

Example

cf example for field layout declarations.

Field Declaration

Declares a new field with the given name and the provided options.

Syntax
Field name < domain , layout , boundaryCondition >
  /* optional */ [ numSlots ]
  /* optional */ levels
Details

Each field is tied to a specific domain accessed through its name.

Data type, localization of the field, etc is controlled by the linked layout. An implicit @current is always assumed. This is only a name - providing a level in addition is not supported.

boundaryCondition may be a valid boundary condition.

If numSlots is specified, the field is slotted with the given number. Must be an integer constant.

The declaration is always regarded as leveled. If levels is specified it must be a valid level selection for declarations. If it is not specified, an implicit @all is assumed.

Example
Field vis < global, CellLayout, None >
Field rho < global, CellLayout, Neumann > [2] @all

Boundary Condition

Specifies the boundary conditions to be used for a given field

Syntax
None
Neumann
  /* optional */ ( order )
dirichlet
bcFunction ( )
Details

None corresponds to no boundary handling.

Neumann corresponds to Neumann-0 boundary conditions. If order is not specified it is defaulted to Knowledge.discr_defaultNeumannOrder.

dirichlet may take the shape of an arbitrary expression evaluating to the data type of the field.

bcFunction is a function reference, with optional level, to a user function implementing the boundary handling routine. The function’s return type must be Unit.

Since dirchlet can be a function call, an thus may look like a call to a bcFunction, the return type of the called function must be known at generation time. It is used to switch both cases.

Example
Neumann ( 1 )
sin ( vf_boundaryPosition_x )
applyBoundaries ( )

External Field Declaration

Declares a new external field with the given name and the provided options.

Syntax
external Field name < layout > => internal
Details

Used to transfer data from external program parts to fields declared in the DSL.

layout must describe the layout of the external counterpart.

internal is a reference to a declared field. A level specification is necessary.

Using this information, copy-in and copy-out functions are set up. These can be called from the external program.

If Knowledge.generateFortranInterface is set, the external counterpart is assumed to be in Fortran-compliant ordering, otherwise lexicographic ordering is assumed.

Example
Layout CellLayout < Real , Cell > { /* ... */ }
Layout ExternalLayout < Real , Cell > @finest { /* ... */ }

Field p < global, CellLayout, Neumann >

external Field p_0 < ExternalLayout > => p@finest

Stencils

Direct Stencil Declaration

Declares a new stencil with the given name and the provided entries.

Syntax
Stencil name
  /* optional */ levels
  { entries }
Details

The declaration is always regarded as leveled. If levels is specified it must be a valid level selection for declarations. If it is not specified, an implicit @all is assumed.

entries is a list of offset entries or mapping entries. May be separated by comma. May be empty.

Example
Stencil FivePoint@all {
  [ 0,  0] =>  4.0
  [-1,  0] => -1.0
  [ 1,  0] => -1.0
  [ 0, -1] => -1.0
  [ 0,  1] => -1.0
}
Stencil RestrictCell {
  [i0, i1] from [ 2 * i0,     2 * i1     ] with 0.25
  [i0, i1] from [ 2 * i0,     2 * i1 + 1 ] with 0.25
  [i0, i1] from [ 2 * i0 + 1, 2 * i1     ] with 0.25
  [i0, i1] from [ 2 * i0 + 1, 2 * i1 + 1 ] with 0.25
}

Stencil Offset Entry

A single stencil entry in offset notation.

Syntax
offset => coefficient
Details

offset must be a const index. coefficient may be an arbitrary expression.

Example
[ 0,  0] =>  4.0 * alpha + epsilon

Stencil Mapping Entry

A single stencil entry in mapping notation.

Syntax
row from col with coefficient
Details

row and col can be interpreted as the corresponding row and column positions for the coefficient were the matrix represented by the stencil constructed explicitly.

coefficient may be an arbitrary expression.

Example
[i0, i1] from [ 2 * i0, 2 * i1 ] with 1.0

Stencil From Expression

Declares a new stencil with the given name and constructs it based on expression

Syntax
Stencil name
  /* optional */ levels
  from expression
Details

expression may be an arbitrary expression evaluating to a stencil. Supported operations on stencils are:

  • scaling

  • addition

  • multiplication

  • transpose

  • kron (Kronecker product)

Example
Stencil Horizontal { /* ... */ }
Stencil Vertical   { /* ... */ }
Stencil Combined from 2.0 * ( Horizontal + Vertical )

Stencil From Default

Declares a new stencil with the given name and constructs it based on the specified default operation.

Syntax
Stencil name
  /* optional */ levels
  from default operation on localization with parameter
Details

operation may be either restriction or prolongation.

localization specifies where the operator will be applied. Allowed values are the same as for field layout declarations.

For restriction and prolongation, parameter specifies the interpolation scheme. It may be ‘linear’ for values of discretized functions and ‘integral_linear’ for values of integrals over discretized functions. The former is usually applied in finite difference contexts, while the latter finds application in finite volume contexts.

Example
RestrictNode from default restriction on Node with 'linear'

Stencil Field Declaration

Declares a new stencil field with the given name, using the shape of stencil and storing the data in field.

Syntax
StencilField name < field => stencil >
  /* optional */ levels
Details

For stencil and field, an implicit @current is always assumed. This is only a name - providing a level in addition is not supported.

The declaration is always regarded as leveled. If levels is specified it must be a valid level selection for declarations. If it is not specified, an implicit @all is assumed.

The order of coefficients in the linked stencil will remain and be mapped to the entries of the linked field’s data.

The data type of the linked field has to be vector. The vector size must match the number of coefficients in the linked stencil.

The coefficients of the stencil are used to initialize the field’s data.

Example
Layout SfLayout < Vector < Real, 5 > , Cell > { /* ... */ }
Field StencilData < global, SfLayout, None >

Stencil FivePointShape { /* ... */ }

StencilField StoredFivePoint < StencilData => FivePointShape >

Domain-Specific Features

Access

Access to a variable, a value or a knowledge object.

Syntax

target
  /* optional */ [ slot ]
  /* optional */ @ level
  /* optional */ @ offet
  /* optional */ : direction
  /* optional */ [ component ]

Details

The actual type of access is deferred by the code generator. Depending on the type, invalid modifiers will be ignored.

slot, if specified, must be a valid slot access. It is only valid if target is a field. The field may be un-slotted.

level, if specified, must be a valid access level. It is only valid if target is leveled.

offset, if specified, must be a valid constant index. It is only valid if target is either a field, a stencil or a stencil field. In this case, target is not evaluated at the current point of iteration, given by the surrounding field loop, but at the current point plus the given offset.

direction, if specified, must be a valid constant index. It is only valid if target is either a stencil or a stencil field. In this case, target is evaluated in the given direction. This effectively means, that the entry of the target stencil (field) is selected that has the direction as offset. This selected entry is used instead of target.

component, if specified, must be an integral constant. If target is a vector field or a stencil field, a component of the vector of target is used instead of target. This feature will be removed in future versions of the language.

direction and component are currently mutually exclusive.

Example

someVar
someField[active]@current@[1, 0]
someStencil@current:[0, 0]
someStencilField@[1, 0]:[0, 0]

Special Loops

Field Loop

Loops over the given field and executes the body at each point.

Syntax
loop over field
  /* optional */ only region
  /* optional */ sequentially
  /* optional */ where condition
  /* optional */ starting offsetBegin
  /* optional */ ending offsetEnd
  /* optional */ stepping stepSize
  /* optional */ with reduction
  /* optional */ preComm
  /* optional */ postComm
  { body }
Details

If no level is provided for field, an implicit @current is assumed. Other modifiers such as slot, offset or direction access are ignored.

only region may be used to restrict iteration to a specific region. If it is not provided, inner is assumed.

sequentially prevents shared memory parallelization. This is only a temporary workaround.

where condition may be used to restrict the execution of body to only cases where condition is fulfilled. Prominent applications are colored kernels.

offsetBegin and offsetEnd may be used to extend or restrict the iteration space. Constant indices are required. offsetBegin is added to the loop start while offsetEnd is subtracted from the loop end.

stepSize may be used to adapt the generated loops’ step size. It must be a positive, non-zero constant indices.

reduction must be a valid reduction.

preComm and postComm, if defined, must be one or more expressions in the form of pre- and postcomm.

body must be a list of suitable statements. May be empty.

If a field loop is not in the scope of a fragment loop, an implicit fragment loop is wrapped around the field loop in the generation processs.

Example
loop over u { /* ... */ }
loop over u where 0 == ( i0 + i1 ) % 2 { /* ... */ }
loop over u only ghost [0, -1] on boundary { /* ... */ }
loop over u starting [1, 0] stepping [2, 1] { /* ... */ }
Var curErr : Real = 0.0
loop over u with reduction ( max, curErr ) { /* ... */ }

Region

Specifies an iteration region for a field loop.

Syntax
target direction
  /* optional */ on boundary
Details

target may be one of the following:

  • inner

  • dup

  • ghost

dup corresponds to duplicate layers. ghost corresponds to ghost layers. inner corresponds to inner layers.

direction specifies which part of the current fragment’s grid is selected. For example, [1, 0] would select the right edge. direction must be a constant indices. In case of inner as target, direction is ignored but should be zero in all dimensions by convention.

If on boundary is specified, the loop is only executed at outer boundaries, i.e., for fragments that don’t have a neighbor in the specified direction.

Example
only dup [0, -1] on boundary

Fragment Loop

Loops over all fragments.

Syntax
loop over fragments
  /* optional */ with reduction
  { body }
Details

reduction must be a valid reduction.

body must be a list of suitable statements. May be empty.

body usually contains at least one field loop. Communicate statements and apply bc statements inside fragment loops are supported.

Example
Var sum : Real = 0.0
loop over fragments with reduction ( + : sum ) {
  loop over u with reduction ( + : sum ) { /* ... */ }
}

Reduction

Specifies a reduction to be performed for an associated special loop.

Syntax
reduction ( op : target )
Details

op may be one of the following:

  • + or *

  • min or max

target must be the name of a previously declared variable.

If Knowledge.experimental_trimBoundsForReductionLoops is enabled, iteration spaces are adapted such that duplicate points are only handled on one fragment. This prevents adding the contribution of the same duplicate point multiple times.

Example
Var sum : Real = 0.0
loop over u with reduction ( + : sum ) { /* ... */ }

Contraction Loop

Contracts the iteration space of a loop with each repetition.

Syntax
repeat n times
  /* optional */ count variable
  with contraction posExtent
  /* optional */ , negExtent
  { body }
Details

n must be an integral number.

The current iteration number is stored in variable, if provided, which needs to be declared beforehand.

posExtent and negExtent must be a const index.

body must be a list of suitable statements. May be empty.

Example
// 2D example

loop over fragments {
  /* contraction: iterate over 
    [0-(5-1)*1, 0] to [32+(5-1)*1, 32]
    [0-(5-2)*1, 0] to [32+(5-2)*1, 32]
    ...
    [0, 0] to [32, 32]
  */
  repeat 5 times with contraction [1, 0 ] {
    // regular: iterate over [0, 0] to [32, 32]
    loop over Solution@finest {
      // ...
    }
  }

  /* contraction: iterate over 
    [0-(3-1)*(-2), 0] to [32+(3-1)*1, 32], 
    [0-(3-2)*(-2), 0] to [32+(3-2)*1, 32],
    [0, 0] to [32, 32]
  */
  repeat 3 times with contraction [1, 0 ], [-2, 0] {
    // regular: iterate over [0, 0] to [32, 32]
    loop over Solution@finest {
      // ...
    }
  }
}

Communication

Communicate

Triggers data exchange for the given field.

Syntax
/* optional */ begin
  /* optional */ finish
  communicate targets of field
  /* optional */ where condition
Details

begin and finish are mutually exclusive. They trigger the start and end of a communication phase. The user is responsible for ensuring that matching pairs exist and are called accordingly. If neither is given, a full communication is performed.

communicating can be used instead of communicate.

targets must be a list of valid communicate targets. It may be empty in which case all is assumed.

field must be a valid reference to a field to be communicated. An implicit @current is assumed if no level specification is given. Slot modifiers are honored. Other modifiers such as offset and direction access are ignored.

condition can be used to restrict exchange to data points fulfilling the given condition. It may be an arbitrary expression evaluating to a Boolean. NOT IMPLEMENTED YET

Example
communicate u[next]@current
begin communicating u
/* ... */
finish communicating u

Communicate Target

brief

Syntax
target
  /* optional */ start 
  /* optional */ to end // inclusive indices
Details

target can be one of the following:

  • all

  • dup

  • ghost

dup corresponds to duplicate layers. ghost corresponds to ghost layers. all corresponds to ghost and duplicate layers.

start and end have to be constant indices. Both are inclusive. If defined, the range of applicable layers to be communicated is restricted to the given range.

Example
examples of usage

Pre- and PostComm

Specifies a communication step to be performed before or after an associated loop.

Syntax
preComm
  /* optional */ op
  target  
  of field
  /* optional */ where condition
postComm
  /* optional */ op
  target  
  of field
  /* optional */ where condition
Details

op can be one of the following:

  • begin

  • finish

If op is not given, a synchronous (w.r.t. the Layer 4 execution path) communication is performed.

target must be a valid communicate target.

condition can be used to restrict the communication to points fulfilling it. This function is not fully implement yet.

Example
precomm all of Solution@current
postcomm dup of Solution where 0 == ( i0 + i1 ) % 2

Field Operations

Apply BC

Applies the boundary conditions of a given field.

Syntax
apply bc to field
Details

field must be a valid reference to a field to be updated. An implicit @current is assumed if no level specification is given. Slot modifiers are honored. Other modifiers such as offset and direction access are ignored.

Example
apply bc to u

Field Iterator Access

Access to the iterator of a surrounding field loop.

Syntax
i0
i1
i2
Details

i0 through i2 access the iterator in the corresponding dimension of a surrounding field loop. Only valid in the scope of a field loop.

x, y and z can be used as well. This feature will be removed in future versions of the language.

Example
0 == ( i0 + i1 + i2 ) % 2

Field Slotting

Slot Access

Selects the slot of a field.

Syntax
target
Details

target may be one of the following:

  • active, activeSlot or currentSlot

  • next or nextSlot

  • previous or previousSlot

  • an integral constant

Example

cf example of access.

Advance

Advances the slot of a given field.

Syntax
advance field
Details

field must be a valid reference to a field. An implicit @current is assumed if no level specification is given. Slot modifiers and other modifiers such as offset and direction access are ignored.

Example
advance u

Solver Extensions

Local Solve

Solves for multiple unknowns at once.

Syntax
solve locally
  /* optional */ with jacobi
  /* optional */ relax omega
  { components }
Details

Internally, a system of equations based on the given components is constructed and solved. The solution to the system is then written back to the unknowns.

with jacobi specifies that the writeback should be performed to the next slot of the unknowns’ fields.

omega, if provided, will be used to relax the found solution to the local system. It may be an arbitrary expression that evaluated to Double.

components must be a list of of valid solve components.

Must be inside the scope of a field loop.

Example
loop over u {
  solve locally relax 0.8 {
    u@[0, 0] => laplace@[0, 0] * u@[0, 0] == rhs_u@[0, 0]
    u@[1, 0] => laplace@[1, 0] * u@[1, 0] == rhs_u@[1, 0]
  }
}

Solve Component

Specifies one component of a local solve block.

Syntax
unknown => lhs == rhs
Details

unknown must be a valid reference to a field. An implicit @current is assumed if no level specification is given. Other modifiers are honored.

lhs and rhs are the left- and right-hand sides of the equation to be solved. They may be arbitrary expressions evaluating to the same data type. Equations not including the unknown are supported.

Example
u => laplace * u == 0.0
u@[1, 0] => laplace@[1, 0] * u@[1, 0] == rhs_u@[1, 0]

Repeat Statement

Repeats a set of statements in a body for given conditions.

Syntax
repeat with { conditions , body }
Details

conditions must be a comma-separated list of arbitrary expressions, each evaluating to Boolean.

body must be a list of suitable statements. May be empty. Currently only field loops are restricted. Other statements remain untouched. In future versions, apply bc and communicate will be handled as well.

During unfolding, the body is duplicated once for each condition. It is then adapted by adding the condition expression to, e.g., field loops.

Example
repeat with {
  ( 0 == ( i0 + i1 ) % 2 ),
  ( 1 == ( i0 + i1 ) % 2 ),
  
  loop over p { /* ... */ }
  communicate p
}

Color Statement

Colors a set of statements in a body with given colors computations.

Syntax
color with { colors , body }
Details

colors must be a comma-separated list of modulo expressions whose divisors are natural numbers. Each expression specifies how one element of the color vector is computed.

body must be a list of suitable statements. May be empty. Currently only field loops are colored. Other statements remain untouched. In future versions, apply bc and communicate will be handled as well.

During unfolding, the body is duplicated once for each color. It is then adapted to the current color by adding the color expression to, e.g., field loops as (potentially additional) condition.

Example
color with {
  i0 % 2,
  i1 % 2,
  
  loop over p { /* ... */ }
  communicate p
}

Language Extensions

Top-Level

Import

Imports the content of another DSL file.

Syntax
import filename
Details

filename is relative to the location of the current DSL file. The location is automatically adapted for nested imports.

Multiple import statements in the same file are supported.

Example
import '../lib/defaultGlobals.exa4'

Inline Knowledge

Allows specifying knowledge parameters in the DSL.

Syntax
Knowledge { parameters }
Details

parameters must be a list of key-value assignments. Separation by comma is not supported. May be empty.

Multiple knowledge inlines in the same file are supported.

Example
Knowledge {
  opt_useAddressPrecalc = true
  opt_unroll            = 2
}

Global Section

Opens a new global section holding declarations of global variables and values.

Syntax
Globals { entries }
Details

entries must be a list of valid variable declarations and value declarations. May be empty.

Multiple global sections in one DSL document are supported.

Example
Globals {
  Var omega     : Real = 0.8
  Val maxNumIts : Int  = 128
}

Function Template

Declares a new function template with the given name.

Syntax
FunctionTemplate name < templateParams > ( functionParams ) : returnType { body }
Details

FuncTemplate can be used instead of FunctionTemplate.

templateParams must be a list of identifiers that must be separated by comma or newline. May be empty.

functionParams must be a list of function arguments. May be separated by comma. May be empty.

returnType must be a valid language data type.

This statement will not map to a function without suitable function instantiations.

body must be a list of suitable statements. May be empty.

Example
FunctionTemplate SetFieldComponent < target > ( value : Real ) : Unit {
  loop over target {
    target = value
  }
}

Function Instantiation

Instantiates a function template as a new function with the given name.

Syntax
Instantiate template < templateArgs > as name
  /* optional */ levels
Details

Inst can be used instead of Instantiate.

template must be the name of a declared function template.

templateArgs must be a list of expressions that must be separated by comma or newline. Its length must match the length on the template parameter list of the linked function template.

name is the name of the newly created function. If a suitable level declaration is given, the new function inherits it.

In the instantiation, occurrences of each function template parameter in the function template body are replaced with the corresponding given argument. Modifiers such as level, offset or direction accesses are merged.

Example
Instantiate SetFieldComponent < u@current > as SetSolution_u@all
Instantiate SetFieldComponent < v@current > as SetSolution_v@all

Layout Transformation

cf. Automatic Data Layout Transformations in the ExaStencils Code Generator

Inner

LevelScope

Conditional execution of statements depending on the surrounding scope’s level.

Syntax
levels { body }
Details

body is only executed if the current level (usually given by a surrounding function) matches the given levels, or, in case of a given range or list, is included in it.

levels must be a valid level declaration.

body must be a list of suitable statements. May be empty.

Example
Function recursive@all () {
  /* ... */

  @(all but coarsest) {
    recursive@coarser ( )
  }
}

TO BE INTEGRATED

Higher-Dimensional Data Types

Vectors

Represents a one-dimensional number of scalar elements

Syntax
{expression, expression, ...  } /* optional */ T
Details

At least one expression is required to construct a one-dimensional vector. T can be used to transpose the defined vector expression.

Example
Var v1 : Vector<Real, 3> = { 1, 2, 3}
Var v2 : Vec3 = [1 2 3] + [4 5 6]
Var v3 : ColumnVector<Int, 3> = {1, 2, 3}T
Built-in functions
  • transpose() to transpose a vector. For anonymous vector definitions, a suffixing T can be used.

  • dot() to calculate dot product of two vectors

  • supported operators for binary expression: +, -, *, /

  • supported element-wise operations: .*, *./, .% (modulo), .^ (power)

Matrices

Represents a two-dimensional number of scalar elements

Declaration Syntax
{{expression, expression, ...  }, {expression, expression, ...  }, ... }
Details

At least one expression is required to construct a 1x1 matrix.

Example
Var m1 : Matrix<Real, 2, 2> = {{1, 2}, {3, 4}}
Var m2 : Matrix<Real, 2, 3> = [1 2 3; 4 5 6]
Access

Vectors and Matrices can be written to and read from via the []-operator:

Var quadMat : Matrix <Real, 2, 23> = {{0., 1.}, {1., 0.}}
Var colVecMat : Matrix <Real, 3, 13> = {{0.}, {1.}, {1337.}}
Var rowVec : RowVector <Real, 33> = {0., 1., 1337.}

quadMat[0][1] = 3
Var tmp : Real = colVecMat[0]
rowVec[1] = 1
Slicing

The following functions can be used to obtain or set a submatrix of a given matrix:

  • getElement(mat : Matrix<T>, j : Int, i : Int) : T returns the (j,i)th entry

  • setElement(mat : Matrix<T>, j : Int, i : Int) : T sets the (j,i)th entry

  • getSlice(mat : Matrix<T>, offsetRows : Int, offsetCols: Int, nRows : Int, nCols : Int) : Matrix<T> reads a submatrix of size (nRows x nCols) from position (offsetRows, offsetCols) in mat

  • setSlice(mat : Matrix<T>, offsetRows : Int, offsetCols: Int, nRows : Int, nCols : Int, val : T) : Matrix<T> writes the value val to a submatrix of size (nRows x nCols) at position (offsetRows, offsetCols) in mat

  • slicing operations can also be executed via the []-operator with index ranges or : for a complete dimension.

Some examples:

setSlice(quadMat,0,1,2,1,5) // quadMat = {{0., 1.}, {5., 5.}}
Var row : Matrix<Real, 1, 2 > = getSlice(quadMat,0,1,1,2) // row = {{5., 5.}}
Var col : Matrix<Real, 2, 1 > = quadMat[:][1] // col = {{1.},{5.}}
rowVec[0:3] = 4. // colVec = {{4.},{4.},{4.}}
Built-in functions
  • transpose() to transpose a matrix

  • dot() and cross() to calculate dot or cross product of two matrices

  • det() to calculate the determinant

  • norm() calculates the frobenius-norm of the matrix

  • trace() calculates the trace

  • transpose() transposes the matrix

  • supported operators for binary expression: +, -, *, /

  • supported element-wise operations: .*, *./, .% (modulo), .^ (power)

Direct solution of linear systems

Small linear systems can be solved directly at runtime or compiletime with the solveMatSys-statement, which takes a system matrix, unknowns and a right-hand-side of fitting dimensions as arguments:

Var A : Matrix<Real, 3, 3> = {{3,2,-1},{2,-2,4},{-1,0.5,-1}}
Var f : Matrix<Real, 3, 1> = {{1},{-2},{0}}
Var u : Matrix<Real, 3, 1>
solveMatSys A,u,f // u = {{1}, {-2}, {-2}}

Additional information about the shape of a matrix can be added:

solveMatSys A2,u2,f2 {shape=blockdiagonal,block=3} // A2 is a blockdiagonal matrix with blocks of size 3x3

The generator will then produce a routine that exploits the shape of the matrix.
Supported shapes are:

  • blockdiagonal with block=… (diagonal block size)

  • diagonal

If experimental_resolveLocalMatSys is set to Runtime, the system will be solved at runtime of the generated application. If experimental_resolveLocalMatSys is set to Compiletime, the system will be solved at generation time with certain restrictions.

Inversion

Matrices can be inverted by the inverse() function.

Var mat_inverse : Matrix<Real, 7, 7> = inverse(mat, "shape=schur", "block=6", "A=blockdiagonal", "Ablock=3")

Additional information about the shape of a matrix can be added as arguments. Next to blockdiagonal and diagonal matrices, also a Schur-shape can be specified, which allows a specialized solution technique. If experimental_resolveInverseFunctionCall is set to Runtime, the inversion will be executed at runtime of the generated application. If experimental_resolveInverseFunctionCall is set to Compiletime, the inversion will be executed at generation time with certain restrictions.

Solve locally extensions

System matrix shapes

The shape of the systems set up by solve locally statements can also be used to speed up the solution:

  • If it is known, it can be communicated to the generator with the knowledge-attribute experimental_locMatShape. (in case of a Schur or blockdiagonal shape, also the attributes experimental_locMatBlocksize, experimental_locMatShapeA and experimental_locMatBlocksizeA can be specified)

  • Another possible way is to provide the shape with the field declaration of the iterated field. Here, the same syntax as in section ‘direct solution of linear systems’ is used.

Execution time
  • experimental_resolveLocalMatSys also determines execution time of solution of solve-locally-systems.

  • if experimental_evalMOpRuntimeExe is set, solve-locally-systems will be solved depending on their size: small systems are feasible for solution at compiletime in order to reduce the runtime of the generated application. Larger systems can only be solved at runtime as they increase the compiletime extremely if executed at compiletime.

Shape classification

An automatic classification of the present shape with all block sizes in a solve-locally-system is done if the knowledge-attribute experimental_classifyLocMat is set to ‘true’. Currently, the three mentioned shapes diagonal, blockdiagonal and Schur are supported for automatic classification.

I/O statements (Layer 4)

Currently, following (parallel) I/O approaches are supported:

  • Single-shared file: Shared file where each process accesses different regions within a shared file.

    • Locking: MPI processes share a common file but there is only one active writer/reader process. Uses the C++ standard I/O library for ASCII or binary in-/output.

    • MPI I/O: MPI processes access different file regions concurrently. Binary format for in-/output.

    • (P)HDF5: MPI processes access different file regions concurrently. HDF5 format (binary incl. meta-data) for in-/output.

    • (P)netCDF: MPI processes access different file regions concurrently. NetCDF format (binary incl. meta-data) for in-/output.

    • SionLib: MPI processes access different file regions concurrently. SIONlib format (binary incl. meta-data) for in-/output.

  • File-per-process: Each MPI process is assigned an unshared file. Uses the C++ standard I/O library for ASCII or binary in-/output.

Data storage and retrieval

For the storage of field data, following statements can be used.

// Locking: Binary or ASCII
writeField_lock ( filename: Expression, field: FieldAccess,
    includeGhost: Boolean = false, useBinary: Boolean = false,
    condition: Expression = true, separator: Expression = " " )
// File-per-process: Binary or ASCII
writeField_fpp ( filename: Expression, field: FieldAccess,
    includeGhost: Boolean = false, useBinary: Boolean = false,
    condition: Expression = true, separator: Expression = " " )
// MPI-I/O: only for MPI parallel applications. Binary
writeField_mpiio ( filename: Expression, field: FieldAccess,
    includeGhost: Boolean = false, canonicalOrder: Boolean = false, repr: String = "native" )
// (P)HDF5
writeField_hdf5 ( filename: Expression, datasetPath: Expression, field: FieldAccess,
    includeGhost: Boolean = false, canonicalOrder: Boolean = false )
// (P)netCDF
writeField_nc ( filename: Expression, varName: Expression, field: FieldAccess,
    includeGhost: Boolean = false, canonicalOrder: Boolean = false )
// SIONlib: serial and parallel
writeField_sion ( filename: Expression, field: FieldAccess,
    includeGhost: Boolean = false, condition: Expression = true )

Likewise, data can be retrieved via readField_xyz with identical function signature.

Visualization

For visualization, two different types of statements can be used:

  • For specific kinds of application (SWE, NS, NNF): Print multiple fields on an unstructured mesh.

// VTK printers: locking (ASCII). Extension: ".vtk"
printVtkSWE(filename: Expression, level: Int, fields : FieldAccess*)
printVtkNS (filename: Expression, level: Int)
printVtkNNF(filename: Expression, level: Int)
// XDMF printers: file-per-process (binary or ASCII). Extension: ".xmf"
printXdmfSWE_fpp(filename: Expression, level: Int, useBinary: Boolean, fields: FieldAccess*)
printXdmfNS_fpp (filename: Expression, level: Int, useBinary: Boolean)
printXdmfNNF_fpp(filename: Expression, level: Int, useBinary: Boolean)
// XDMF printers: single-shared file with either: xyz = mpiio or hdf5
printXdmfSWE_xyz(filename: Expression, level: Int, fields: FieldAccess*)
printXdmfNS_xyz (filename: Expression, level: Int)
printXdmfNNF_xyz(filename: Expression, level: Int)
// ExodusII printers: single-shared file with PnetCDF. Extension: ".e"
printExodusSWE(filename: Expression, level: Int, fields: FieldAccess*)
printExodusNS (filename: Expression, level: Int)
printExodusNNF(filename: Expression, level: Int)
  • For any kind of application: Print one field on a (block-)structured mesh.

// CSV printer: locking (ASCII). Extension: ".csv"
printField_lock (filename: Expression, fieldAccess: FieldAccess, inclGhost: Boolean = false,
    useBin: Boolean = false, cond: Expression = true, separator: Expression = " ")
// XDMF printers: file-per-process (binary or ASCII). Extension: ".xmf"
printField_fpp (filename: Expression, field: FieldAccess, useBinary : Boolean = false)
// XDMF printers: single-shared file with either: xyz = mpiio or hdf5
printField_xyz (filename: Expression, field: FieldAccess, canonicalLayout: Boolean = false)
// netCDF printer. Extension: ".nc"
printField_nc (filename: Expression, field: FieldAccess, canonicalLayout: Boolean = false)