# ExaSlang 4 Documentation ## Language Structure ### Top-Level Statements The following statements are supported: * [import](#import) * [inline knowledge](#inline-knowledge) * declarations of knowledge objects * [domain declaration](#domain-declaration) * [field layout declaration](#field-layout-declaration) * [field declaration](#field-declaration) * [external field declaration](#external-field-declaration) * [direct stencil declaration](#direct-stencil-declaration) * [stencil declaration from expression](#stencil-from-expression) * [stencil declaration from default](#stencil-from-default) * [stencil field declaration](#stencil-field-declaration) * [global section](#global-section) * function declarations * [function declaration](#function-declaration) * [function template declaration](#function-template) * [function instantiation](#function-instantiation) ### Inner Statements The following statements are supported: * local declarations * [variable declaration](#variable-declaration) * [value declaration](#value-declaration) * [assignment](#basic-assignment) and [compound assignment](#compound-assignment) * loops * [fixed-length loop](#fixed-length-loop) * [conditional loop](#conditional-loop) * [contraction loop](#contraction-loop) * [field loop](#field-loop) * [fragment loop](#fragment-loop) * [conditional](#conditional) * [function call](#function-call); implicitly wrapped in an expression statement * [apply bc](#apply-bc) * [communicate](#communicate) * [advance](#advance) * [return statement](#return-statement) * [level scope](#level-scope) * [local solve](#local-solve) * [repeat statement](#repeat-statement) * [color statement](#color-statement) ### Expressions The following expressions are supported: * [literal](#literals) * [access](#access) * [function call](#function-call) * [unary operations](#unary-operations) and [binary operations](#binary-operations) * [field iterator access](#field-iterator-access) ## 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: * Unit (must not be used in declarations) * Real * Integer or Int * String * Boolean or Bool * a [higher dimensional data type](#higher-dimensional-data-types) ##### Example cf examples for [variable declarations](#variable-declaration) and [function declarations](#function-declaration). ### 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 * a constant * a [relative level](#relative-level) * a suitable [level alias](#level-alias) evaluating to a single level ##### Example
@10#### Level Declaration A group of levels used for declarations. ##### Syntax
@levels##### Details *levels* may be on of the following * a constant * a [relative level](#relative-level) * a [level list](#level-list) * a suitable [level alias](#level-alias) ##### 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](#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](#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](#level-access) and [level declaration](#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](#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](#level-declaration). ##### 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](#level-range). *exclude*, if provided, must be a valid [level list](#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](#level-declaration). ##### Syntax
( begin to end )##### Details *begin* and *end* must be constants or suitable [level aliases](#level-alias) 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](#level-declaration). *arguments*, if provided, has to be a list of [function arguments](#function-argument). May be empty. *returnType*, if provided, has to be a valid [language datatype](#data-types). In this case, at least one [return statement](#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](#inner-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](#data-types). ##### 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](#current) is assumed. *levels*, if provided, must be a valid [level access](#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](#data-types). The declaration is regarded as leveled if *levels* is specified. Must be a valid [level selection for declarations](#level-declaration). *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](#datatype). The declaration is regarded as leveled if *levels* is specified. Must be a valid [level selection for declarations](#level-declaration). *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](#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](#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](#inner-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](#inner-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](#inner-statements). May be empty. *elseBranch* may be * another [conditional](#conditional) * a list of suitable [statements](#inner-statements); may be empty ##### 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](#access). ##### 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](#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](#data-types). *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](#level-declaration). If it is not specified, an implicit [@all](#level-declaration) is assumed. *layoutOptions* is a list of [layout options](#layout-option) 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](#field-layout-declaration). ##### 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-layout-declaration). #### 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](#level-alias) is always assumed. **This is only a name - providing a level in addition is not supported**. *boundaryCondition* may be a valid [boundary condition](#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](#level-declaration). If it is not specified, an implicit [@all](#level-declaration) 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](#field-declaration) ##### 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](#level-declaration). If it is not specified, an implicit [@all](#level-declaration) is assumed. *entries* is a list of [offset entries](#stencil-offset-entry) or [mapping entries](#stencil-mapping-entry). 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](#direct-stencil-declaration) 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](#direct-stencil-declaration) 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](#field-layout-declaration). 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](#level-alias) 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](#level-declaration). If it is not specified, an implicit [@all](#level-declaration) 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](#variable-declaration), a [value](#value-declaration) or a [knowledge object](#knowledge-objects). ##### 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](#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](#access-level). It is only valid if *target* is leveled. *offset*, if specified, must be a valid [constant index](#constant-index). It is only valid if *target* is either a [field](#field-declaration), a [stencil](#stencils) or a [stencil field](#stencil-field). In this case, *target* is not evaluated at the current point of iteration, given by the surrounding [field loop](#field-loop), but at the current point plus the given *offset*. *direction*, if specified, must be a valid [constant index](#constant-index). It is only valid if *target* is either a [stencil](#stencils) or a [stencil field](#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](#level-alias) 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](#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](#color-with). *offsetBegin* and *offsetEnd* may be used to extend or restrict the iteration space. [Constant indices](#constant-index) 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](#constant-index). *reduction* must be a valid [reduction](#reduction). *preComm* and *postComm*, if defined, must be one or more expressions in the form of [pre- and postcomm](#pre-and-postcomm). *body* must be a list of suitable [statements](#inner-statements). May be empty. If a field loop is not in the scope of a [fragment loop](#fragment-loop), an implicit [fragment loop](#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](#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](#constant-index). 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](#reduction). *body* must be a list of suitable [statements](#inner-statements). May be empty. *body* usually contains at least one [field loop](#field-loop). [Communicate statements](#communicate-statement) and [apply bc statements](#apply-bc) 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](#special-loops). ##### 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](#constant-index). *body* must be a list of suitable [statements](#inner-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](#communicate-target). 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](#level-alias) 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](#field-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](#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](#level-alias) 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](#field-loop). ##### Syntax
i0
i1
i2##### Details i0 through i2 access the iterator in the corresponding dimension of a surrounding [field loop](#field-loop). Only valid in the scope of a [field loop](#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](#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](#level-alias) 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](#solve-component). Must be inside the scope of a [field loop](#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](#local-solve). ##### Syntax
unknown => lhs == rhs##### Details *unknown* must be a valid reference to a field. An implicit [@current](#level-alias) 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](#inner-statements). May be empty. Currently only [field loops](#field-loop) are restricted. Other statements remain untouched. In future versions, [apply bc](#apply-bc) and [communicate](#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](#field-loop). ##### 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](#inner-statements). May be empty. Currently only [field loops](#field-loop) are colored. Other statements remain untouched. In future versions, [apply bc](#apply-bc) and [communicate](#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](#field-loop) 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](#variable-declaration) and [values](#value-declaration). ##### Syntax
Globals { entries }##### Details *entries* must be a list of valid [variable declarations](#variable-declaration) and [value declarations](#value-declaration). 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](#function-argument). May be separated by comma. May be empty. *returnType* must be a valid [language data type](#data-types). This statement will not map to a function without suitable [function instantiations](#function-instantiation). *body* must be a list of suitable [statements](#inner-statements). May be empty. ##### Example
FunctionTemplate SetFieldComponent < target > ( value : Real ) : Unit { loop over target { target = value } }#### Function Instantiation Instantiates a [function template](#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](#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](#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](https://www.infosun.fim.uni-passau.de/publications/docs/KKKL2018ppl.pdf) ### 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](#level-declaration). *body* must be a list of suitable [statements](#inner-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
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 3x3The generator will then produce a routine that exploits the shape of the matrix.
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`](https://en.wikipedia.org/wiki/Schur_complement) 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](#local-solve) 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) ```