## 2 Materials and Methods  
### Taichi Language  
The Taichi programming language [18] is an actively developed open-source [20] just-in-time compiler that translates Python-like source code into binary code for different hardware platforms (various CPUs, CUDA, AMDGPU and others). The language usesthe standard Python syntax extended with decorators marking some functions as _kernels_. During compilation, the kernels are transformed into optimised binary codes, which are then called from the surrounding Python source. Such a solution allows easy binding of efficient, application-specific kernels with a wide variety of available libraries and tools, especially given that Taichi provides a basic GUI system and simple built-in interfaces to NumPy and PyTorch libraries. The kernel compiler applies a few levels of optimisations, including simple template instantiation, loop unrolling and vectorisation, constant folding, and others. Inside kernels, the highest level loops can be automatically parallelised provided that operations are performed on Taichi _fields_.  
Fields are the multidimensional data structures that provide an array-like data access interface via the [] operator. Internally fields use a hierarchy of _structural nodes_ (SNodes) which define dimensions, size and data arrangement in memory. Information from SNodes is used, both during kernel compilation and runtime, to optimise data access to field elements and to distribute workload onto available threads/processors. Compilation-time optimisations allow decreasing overheads caused by traversing nested SNodes but require that the field definition must be known at the moment of kernel compilation and enforce separate kernel compilations for different data structures.  
The types of SNode allow the use of different data layouts. The _dense_ layout is a simple, multidimensional array. The _bitmasked_ layout allows addition of information whether given elements contain valid data or not. This layout does not reduce memory usage because all bitmasked elements must be still placed in memory. However, computational kernels are called only for data elements masked as valid, and thus the _bitmasked_ layout can reduce the number of operations for sparse data. Reduction of memory usage for sparse data is possible with the _pointer_ data layout that can mark pointers to non-existent data as invalid and thus does not require memory allocation in this case.  
The data layout in Taichi can be defined as a hierarchy of different SNodes. For example, _ti.root.pointer (ti.i, 16).bitmasked (ti.i, 8).dense (ti.i, 4)_ defines 16 pointers, each pointing to 8 bitmasked dense blocks of data where each dense block contains 4 data elements (not shown). After definition, this structure can be accessed using a simple _[i]_ operator, where \(\mathrm{i}\in\{0,\ldots,511\}\). The calculations of memory addresses, traversing and checking values of pointers and bitmasks, and launching of the appropriate number of computational kernels are internally handled by Taichi. Additionally, some optimisations are applied to reduce the overheads caused by additional memory accesses required to traverse multi-level, hierarchical data structures.