Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
No results found
Show changes
Showing
with 7003 additions and 1787 deletions
#!/bin/bash
python3 setup.py develop
exec "$@"
\ No newline at end of file
import sympy as sp
import json
import os
try:
from functools import lru_cache as memorycache
except ImportError:
from backports.functools_lru_cache import lru_cache as memorycache
try:
from joblib import Memory
from appdirs import user_cache_dir
if 'PYSTENCILS_CACHE_DIR' in os.environ:
cacheDir = os.environ['PYSTENCILS_CACHE_DIR']
else:
cacheDir = user_cache_dir('pystencils')
diskcache = Memory(cachedir=cacheDir, verbose=False).cache
diskcacheNoFallback = diskcache
except ImportError:
# fallback to in-memory caching if joblib is not available
diskcache = memorycache(maxsize=64)
diskcacheNoFallback = lambda o: o
import os
import runpy
import sys
import tempfile
import warnings
import nbformat
import pytest
from nbconvert import PythonExporter
from pystencils.boundaries.createindexlist import * # NOQA
# Trigger config file reading / creation once - to avoid race conditions when multiple instances are creating it
# at the same time
from pystencils.cpu import cpujit
# trigger cython imports - there seems to be a problem when multiple processes try to compile the same cython file
# at the same time
try:
import pyximport
pyximport.install(language_level=3)
except ImportError:
pass
SCRIPT_FOLDER = os.path.dirname(os.path.realpath(__file__))
sys.path.insert(0, os.path.abspath('pystencils'))
# the Ubuntu pipeline uses an older version of pytest which uses deprecated functionality.
# This leads to many warinings in the test and coverage pipeline.
pytest_numeric_version = [int(x, 10) for x in pytest.__version__.split('.')]
pytest_numeric_version.reverse()
pytest_version = sum(x * (100 ** i) for i, x in enumerate(pytest_numeric_version))
def add_path_to_ignore(path):
if not os.path.exists(path):
return
global collect_ignore
collect_ignore += [os.path.join(SCRIPT_FOLDER, path, f) for f in os.listdir(os.path.join(SCRIPT_FOLDER, path))]
collect_ignore = [os.path.join(SCRIPT_FOLDER, "doc", "conf.py"),
os.path.join(SCRIPT_FOLDER, "src", "pystencils", "opencl", "opencl.autoinit")]
add_path_to_ignore('tests/benchmark')
add_path_to_ignore('_local_tmp')
try:
import cupy
except ImportError:
collect_ignore += [os.path.join(SCRIPT_FOLDER, "tests/test_gpu.py")]
add_path_to_ignore('src/pystencils/gpu')
try:
import waLBerla
except ImportError:
collect_ignore += [os.path.join(SCRIPT_FOLDER, "tests/test_aligned_array.py"),
os.path.join(SCRIPT_FOLDER, "tests/test_datahandling_parallel.py"),
os.path.join(SCRIPT_FOLDER, "doc/notebooks/03_tutorial_datahandling.ipynb"),
os.path.join(SCRIPT_FOLDER, "src/pystencils/datahandling/parallel_datahandling.py"),
os.path.join(SCRIPT_FOLDER, "tests/test_small_block_benchmark.ipynb")]
try:
import blitzdb
except ImportError:
add_path_to_ignore('src/pystencils/runhelper')
collect_ignore += [os.path.join(SCRIPT_FOLDER, "tests/test_parameterstudy.py")]
collect_ignore += [os.path.join(SCRIPT_FOLDER, "tests/test_json_serializer.py")]
try:
import islpy
except ImportError:
collect_ignore += [os.path.join(SCRIPT_FOLDER, "src/pystencils/integer_set_analysis.py")]
try:
import graphviz
except ImportError:
collect_ignore += [os.path.join(SCRIPT_FOLDER, "src/pystencils/backends/dot.py")]
collect_ignore += [os.path.join(SCRIPT_FOLDER, "doc/notebooks/01_tutorial_getting_started.ipynb")]
try:
import pyevtk
except ImportError:
collect_ignore += [os.path.join(SCRIPT_FOLDER, "src/pystencils/datahandling/vtk.py")]
collect_ignore += [os.path.join(SCRIPT_FOLDER, 'setup.py')]
for root, sub_dirs, files in os.walk('.'):
for f in files:
if f.endswith(".ipynb") and not any(f.startswith(k) for k in ['demo', 'tutorial', 'test', 'doc']):
collect_ignore.append(f)
class IPythonMockup:
def run_line_magic(self, *args, **kwargs):
pass
def run_cell_magic(self, *args, **kwargs):
pass
def magic(self, *args, **kwargs):
pass
def __bool__(self):
return False
class IPyNbTest(pytest.Item):
def __init__(self, name, parent, code):
super(IPyNbTest, self).__init__(name, parent)
self.code = code
self.add_marker('notebook')
@pytest.mark.filterwarnings("ignore:IPython.core.inputsplitter is deprecated")
def runtest(self):
global_dict = {'get_ipython': lambda: IPythonMockup(),
'is_test_run': True}
# disable matplotlib output
exec("import matplotlib.pyplot as p; "
"p.switch_backend('Template')", global_dict)
# in notebooks there is an implicit plt.show() - if this is not called a warning is shown when the next
# plot is created. This warning is suppressed here
exec("import warnings;"
"warnings.filterwarnings('ignore', 'Adding an axes using the same arguments as a previous.*')",
global_dict)
with tempfile.NamedTemporaryFile() as f:
f.write(self.code.encode())
f.flush()
runpy.run_path(f.name, init_globals=global_dict, run_name=self.name)
class IPyNbFile(pytest.File):
def collect(self):
exporter = PythonExporter()
exporter.exclude_markdown = True
exporter.exclude_input_prompt = True
notebook_contents = self.fspath.open(encoding='utf-8')
with warnings.catch_warnings():
warnings.filterwarnings("ignore", "IPython.core.inputsplitter is deprecated")
notebook = nbformat.read(notebook_contents, 4)
code, _ = exporter.from_notebook_node(notebook)
if pytest_version >= 50403:
yield IPyNbTest.from_parent(name=self.name, parent=self, code=code)
else:
yield IPyNbTest(self.name, self, code)
def teardown(self):
pass
def pytest_collect_file(path, parent):
glob_exprs = ["*demo*.ipynb", "*tutorial*.ipynb", "test_*.ipynb"]
if any(path.fnmatch(g) for g in glob_exprs):
if pytest_version >= 50403:
return IPyNbFile.from_parent(fspath=path, parent=parent)
else:
return IPyNbFile(path, parent)
from pystencils.cpu.kernelcreation import createKernel, createIndexedKernel, addOpenMP
from pystencils.cpu.cpujit import makePythonFunction
from pystencils.backends.cbackend import generateC
r"""
*pystencils* looks for a configuration file in JSON format at the following locations in the listed order.
1. at the path specified in the environment variable ``PYSTENCILS_CONFIG``
2. in the current working direction for a file named ``pystencils.json``
3. or in your home directory at ``~/.config/pystencils/config.json`` (Linux) or
``%HOMEPATH%\.pystencils\config.json`` (Windows)
If no configuration file is found, a default configuration is created at the above mentioned location in your home.
So run *pystencils* once, then edit the created configuration file.
Compiler Config (Linux)
-----------------------
- **'os'**: should be detected automatically as 'linux'
- **'command'**: path to C++ compiler (defaults to 'g++')
- **'flags'**: space separated list of compiler flags. Make sure to activate OpenMP in your compiler
- **'restrictQualifier'**: the restrict qualifier is not standardized accross compilers.
For most Linux compilers the qualifier is ``__restrict__``
Compiler Config (Windows)
-------------------------
*pystencils* uses the mechanism of *setuptools.msvc* to search for a compilation environment.
Then 'cl.exe' is used to compile.
- **'os'**: should be detected automatically as 'windows'
- **'msvcVersion'**: either a version number, year number, 'auto' or 'latest' for automatic detection of latest
installed version or 'setuptools' for setuptools-based detection. Alternatively path to folder
where Visual Studio is installed. This path has to contain a file called 'vcvarsall.bat'
- **'arch'**: 'x86' or 'x64'
- **'flags'**: flags passed to 'cl.exe', make sure OpenMP is activated
- **'restrictQualifier'**: the restrict qualifier is not standardized across compilers.
For Windows compilers the qualifier should be ``__restrict``
Cache Config
------------
*pystencils* uses a directory to store intermediate files like the generated C++ files, compiled object files and
the shared libraries which are then loaded from Python using ctypes. The file names are SHA hashes of the
generated code. If the same kernel was already compiled, the existing object file is used - no recompilation is done.
If 'sharedLibrary' is specified, all kernels that are currently in the cache are compiled into a single shared library.
This mechanism can be used to run *pystencils* on systems where compilation is not possible, e.g. on clusters where
compilation on the compute nodes is not possible.
First the script is run on a system where compilation is possible (e.g. the login node) with
'readFromSharedLibrary=False' and with 'sharedLibrary' set a valid path.
All kernels generated during the run are put into the cache and at the end
compiled into the shared library. Then, the same script can be run from the compute nodes, with
'readFromSharedLibrary=True', such that kernels are taken from the library instead of compiling them.
- **'readFromSharedLibrary'**: if true kernels are not compiled but assumed to be in the shared library
- **'objectCache'**: path to a folder where intermediate files are stored
- **'clearCacheOnStart'**: when true the cache is cleared on each start of a *pystencils* script
- **'sharedLibrary'**: path to a shared library file, which is created if `readFromSharedLibrary=false`
"""
from __future__ import print_function
import os
import subprocess
import hashlib
import json
import platform
import glob
import atexit
import shutil
from appdirs import user_config_dir, user_cache_dir
from ctypes import cdll
from pystencils.backends.cbackend import generateC, getHeaders
from collections import OrderedDict, Mapping
from pystencils.transformations import symbolNameToVariableName
from pystencils.data_types import toCtypes, getBaseType, StructType
def makePythonFunction(kernelFunctionNode, argumentDict={}):
"""
Creates C code from the abstract syntax tree, compiles it and makes it accessible as Python function
The parameters of the kernel are:
- numpy arrays for each field used in the kernel. The keyword argument name is the name of the field
- all symbols which are not defined in the kernel itself are expected as parameters
:param kernelFunctionNode: the abstract syntax tree
:param argumentDict: parameters passed here are already fixed. Remaining parameters have to be passed to the
returned kernel functor.
:return: kernel functor
"""
# build up list of CType arguments
func = compileAndLoad(kernelFunctionNode)
func.restype = None
try:
args = buildCTypeArgumentList(kernelFunctionNode.parameters, argumentDict)
except KeyError:
# not all parameters specified yet
return makePythonFunctionIncompleteParams(kernelFunctionNode, argumentDict, func)
return lambda: func(*args)
def setCompilerConfig(config):
"""
Override the configuration provided in config file
Configuration of compiler parameters:
If this function is not called the configuration is taken from a config file in JSON format which
is searched in the following locations in the order specified:
- at location provided in environment variable PYSTENCILS_CONFIG (if this variable exists)
- a file called ".pystencils.json" in the current working directory
- ~/.pystencils.json in your home
If none of these files exist a file ~/.pystencils.json is created with a default configuration using
the GNU 'g++'
An example JSON file with all possible keys. If not all keys are specified, default values are used
``
{
'compiler' :
{
"command": "/software/intel/2017/bin/icpc",
"flags": "-Ofast -DNDEBUG -fPIC -march=native -fopenmp",
"env": {
"LM_PROJECT": "iwia",
}
}
}
``
"""
global _config
_config = config.copy()
def _recursiveDictUpdate(d, u):
for k, v in u.items():
if isinstance(v, Mapping):
r = _recursiveDictUpdate(d.get(k, {}), v)
d[k] = r
else:
d[k] = u[k]
return d
def getConfigurationFilePath():
configPathInHome = os.path.join(user_config_dir('pystencils'), 'config.json')
# 1) Read path from environment variable if found
if 'PYSTENCILS_CONFIG' in os.environ:
return os.environ['PYSTENCILS_CONFIG'], True
# 2) Look in current directory for pystencils.json
elif os.path.exists("pystencils.json"):
return "pystencils.json", True
# 3) Try ~/.pystencils.json
elif os.path.exists(configPathInHome):
return configPathInHome, True
else:
return configPathInHome, False
def createFolder(path, isFile):
if isFile:
path = os.path.split(path)[0]
try:
os.makedirs(path)
except os.error:
pass
def readConfig():
if platform.system().lower() == 'linux':
defaultCompilerConfig = OrderedDict([
('os', 'linux'),
('command', 'g++'),
('flags', '-Ofast -DNDEBUG -fPIC -march=native -fopenmp -std=c++11'),
('restrictQualifier', '__restrict__')
])
elif platform.system().lower() == 'windows':
defaultCompilerConfig = OrderedDict([
('os', 'windows'),
('msvcVersion', 'latest'),
('arch', 'x64'),
('flags', '/Ox /fp:fast /openmp /arch:avx'),
('restrictQualifier', '__restrict')
])
defaultCacheConfig = OrderedDict([
('readFromSharedLibrary', False),
('objectCache', os.path.join(user_cache_dir('pystencils'), 'objectcache')),
('clearCacheOnStart', False),
('sharedLibrary', os.path.join(user_cache_dir('pystencils'), 'cache.so')),
])
defaultConfig = OrderedDict([('compiler', defaultCompilerConfig),
('cache', defaultCacheConfig)])
configPath, configExists = getConfigurationFilePath()
config = defaultConfig.copy()
if configExists:
with open(configPath, 'r') as jsonConfigFile:
loadedConfig = json.load(jsonConfigFile)
config = _recursiveDictUpdate(config, loadedConfig)
else:
createFolder(configPath, True)
json.dump(config, open(configPath, 'w'), indent=4)
config['cache']['sharedLibrary'] = os.path.expanduser(config['cache']['sharedLibrary']).format(pid=os.getpid())
config['cache']['objectCache'] = os.path.expanduser(config['cache']['objectCache']).format(pid=os.getpid())
if config['cache']['clearCacheOnStart']:
shutil.rmtree(config['cache']['objectCache'], ignore_errors=True)
createFolder(config['cache']['objectCache'], False)
createFolder(config['cache']['sharedLibrary'], True)
if 'env' not in config['compiler']:
config['compiler']['env'] = {}
if config['compiler']['os'] == 'windows':
from pystencils.cpu.msvc_detection import getEnvironment
msvcEnv = getEnvironment(config['compiler']['msvcVersion'], config['compiler']['arch'])
config['compiler']['env'].update(msvcEnv)
return config
_config = readConfig()
def getCompilerConfig():
return _config['compiler']
def getCacheConfig():
return _config['cache']
def hashToFunctionName(h):
res = "func_%s" % (h,)
return res.replace('-', 'm')
def compileObjectCacheToSharedLibrary():
compilerConfig = getCompilerConfig()
cacheConfig = getCacheConfig()
sharedLibrary = cacheConfig['sharedLibrary']
if len(sharedLibrary) == 0 or cacheConfig['readFromSharedLibrary']:
return
configEnv = compilerConfig['env'] if 'env' in compilerConfig else {}
compileEnvironment = os.environ.copy()
compileEnvironment.update(configEnv)
try:
if compilerConfig['os'] == 'windows':
allObjectFiles = glob.glob(os.path.join(cacheConfig['objectCache'], '*.obj'))
linkCmd = ['link.exe', '/DLL', '/out:' + sharedLibrary]
else:
allObjectFiles = glob.glob(os.path.join(cacheConfig['objectCache'], '*.o'))
linkCmd = [compilerConfig['command'], '-shared', '-o', sharedLibrary]
linkCmd += allObjectFiles
if len(allObjectFiles) > 0:
runCompileStep(linkCmd)
except subprocess.CalledProcessError as e:
print(e.output)
raise e
atexit.register(compileObjectCacheToSharedLibrary)
def generateCode(ast, restrictQualifier, functionPrefix, targetFile):
headers = getHeaders(ast)
headers.update(['<cmath>', '<cstdint>'])
with open(targetFile, 'w') as sourceFile:
code = generateC(ast)
includes = "\n".join(["#include %s" % (includeFile,) for includeFile in headers])
print(includes, file=sourceFile)
print("#define RESTRICT %s" % (restrictQualifier,), file=sourceFile)
print("#define FUNC_PREFIX %s" % (functionPrefix,), file=sourceFile)
print('extern "C" { ', file=sourceFile)
print(code, file=sourceFile)
print('}', file=sourceFile)
def runCompileStep(command):
compilerConfig = getCompilerConfig()
configEnv = compilerConfig['env'] if 'env' in compilerConfig else {}
compileEnvironment = os.environ.copy()
compileEnvironment.update(configEnv)
try:
shell = True if compilerConfig['os'].lower() == 'windows' else False
subprocess.check_output(command, env=compileEnvironment, stderr=subprocess.STDOUT, shell=shell)
except subprocess.CalledProcessError as e:
print(" ".join(command))
print(e.output.decode('utf8'))
raise e
def compileLinux(ast, codeHashStr, srcFile, libFile):
cacheConfig = getCacheConfig()
compilerConfig = getCompilerConfig()
objectFile = os.path.join(cacheConfig['objectCache'], codeHashStr + '.o')
# Compilation
if not os.path.exists(objectFile):
generateCode(ast, compilerConfig['restrictQualifier'], '', srcFile)
compileCmd = [compilerConfig['command'], '-c'] + compilerConfig['flags'].split()
compileCmd += ['-o', objectFile, srcFile]
runCompileStep(compileCmd)
# Linking
runCompileStep([compilerConfig['command'], '-shared', objectFile, '-o', libFile] + compilerConfig['flags'].split())
def compileWindows(ast, codeHashStr, srcFile, libFile):
cacheConfig = getCacheConfig()
compilerConfig = getCompilerConfig()
objectFile = os.path.join(cacheConfig['objectCache'], codeHashStr + '.obj')
# Compilation
if not os.path.exists(objectFile):
generateCode(ast, compilerConfig['restrictQualifier'],
'__declspec(dllexport)', srcFile)
# /c compiles only, /EHsc turns of exception handling in c code
compileCmd = ['cl.exe', '/c', '/EHsc'] + compilerConfig['flags'].split()
compileCmd += [srcFile, '/Fo' + objectFile]
runCompileStep(compileCmd)
# Linking
runCompileStep(['link.exe', '/DLL', '/out:' + libFile, objectFile])
def compileAndLoad(ast):
cacheConfig = getCacheConfig()
codeHashStr = hashlib.sha256(generateC(ast).encode()).hexdigest()
ast.functionName = hashToFunctionName(codeHashStr)
srcFile = os.path.join(cacheConfig['objectCache'], codeHashStr + ".cpp")
if cacheConfig['readFromSharedLibrary']:
return cdll.LoadLibrary(cacheConfig['sharedLibrary'])[ast.functionName]
else:
if getCompilerConfig()['os'].lower() == 'windows':
libFile = os.path.join(cacheConfig['objectCache'], codeHashStr + ".dll")
if not os.path.exists(libFile):
compileWindows(ast, codeHashStr, srcFile, libFile)
else:
libFile = os.path.join(cacheConfig['objectCache'], codeHashStr + ".so")
if not os.path.exists(libFile):
compileLinux(ast, codeHashStr, srcFile, libFile)
return cdll.LoadLibrary(libFile)[ast.functionName]
def buildCTypeArgumentList(parameterSpecification, argumentDict):
argumentDict = {symbolNameToVariableName(k): v for k, v in argumentDict.items()}
ctArguments = []
arrayShapes = set()
indexArrShapes = set()
for arg in parameterSpecification:
if arg.isFieldArgument:
try:
fieldArr = argumentDict[arg.fieldName]
except KeyError:
raise KeyError("Missing field parameter for kernel call " + arg.fieldName)
symbolicField = arg.field
if arg.isFieldPtrArgument:
ctArguments.append(fieldArr.ctypes.data_as(toCtypes(arg.dtype)))
if symbolicField.hasFixedShape:
symbolicFieldShape = tuple(int(i) for i in symbolicField.shape)
if isinstance(symbolicField.dtype, StructType):
symbolicFieldShape = symbolicFieldShape[:-1]
if symbolicFieldShape != fieldArr.shape:
raise ValueError("Passed array '%s' has shape %s which does not match expected shape %s" %
(arg.fieldName, str(fieldArr.shape), str(symbolicField.shape)))
if symbolicField.hasFixedShape:
symbolicFieldStrides = tuple(int(i) * fieldArr.itemsize for i in symbolicField.strides)
if isinstance(symbolicField.dtype, StructType):
symbolicFieldStrides = symbolicFieldStrides[:-1]
if symbolicFieldStrides != fieldArr.strides:
raise ValueError("Passed array '%s' has strides %s which does not match expected strides %s" %
(arg.fieldName, str(fieldArr.strides), str(symbolicFieldStrides)))
if symbolicField.isIndexField:
indexArrShapes.add(fieldArr.shape[:symbolicField.spatialDimensions])
else:
arrayShapes.add(fieldArr.shape[:symbolicField.spatialDimensions])
elif arg.isFieldShapeArgument:
dataType = toCtypes(getBaseType(arg.dtype))
ctArguments.append(fieldArr.ctypes.shape_as(dataType))
elif arg.isFieldStrideArgument:
dataType = toCtypes(getBaseType(arg.dtype))
strides = fieldArr.ctypes.strides_as(dataType)
for i in range(len(fieldArr.shape)):
assert strides[i] % fieldArr.itemsize == 0
strides[i] //= fieldArr.itemsize
ctArguments.append(strides)
else:
assert False
else:
try:
param = argumentDict[arg.name]
except KeyError:
raise KeyError("Missing parameter for kernel call " + arg.name)
expectedType = toCtypes(arg.dtype)
ctArguments.append(expectedType(param))
if len(arrayShapes) > 1:
raise ValueError("All passed arrays have to have the same size " + str(arrayShapes))
if len(indexArrShapes) > 1:
raise ValueError("All passed index arrays have to have the same size " + str(arrayShapes))
return ctArguments
def makePythonFunctionIncompleteParams(kernelFunctionNode, argumentDict, func):
parameters = kernelFunctionNode.parameters
cache = {}
cacheValues = []
def wrapper(**kwargs):
key = hash(tuple((k, id(v)) for k, v in kwargs.items()))
try:
args = cache[key]
func(*args)
except KeyError:
fullArguments = argumentDict.copy()
fullArguments.update(kwargs)
args = buildCTypeArgumentList(parameters, fullArguments)
cache[key] = args
cacheValues.append(kwargs) # keep objects alive such that ids remain unique
func(*args)
return wrapper
import sympy as sp
from functools import partial
from collections import defaultdict
from pystencils.astnodes import SympyAssignment, Block, LoopOverCoordinate, KernelFunction
from pystencils.transformations import resolveFieldAccesses, makeLoopOverDomain, \
typeAllEquations, getOptimalLoopOrdering, parseBasePointerInfo, moveConstantsBeforeLoop, splitInnerLoop, \
substituteArrayAccessesWithConstants
from pystencils.data_types import TypedSymbol, BasicType, StructType, createType
from pystencils.field import Field
import pystencils.astnodes as ast
from pystencils.cpu.cpujit import makePythonFunction
def createKernel(listOfEquations, functionName="kernel", typeForSymbol='double', splitGroups=(),
iterationSlice=None, ghostLayers=None):
"""
Creates an abstract syntax tree for a kernel function, by taking a list of update rules.
Loops are created according to the field accesses in the equations.
:param listOfEquations: list of sympy equations, containing accesses to :class:`pystencils.field.Field`.
Defining the update rules of the kernel
:param functionName: name of the generated function - only important if generated code is written out
:param typeForSymbol: a map from symbol name to a C type specifier. If not specified all symbols are assumed to
be of type 'double' except symbols which occur on the left hand side of equations where the
right hand side is a sympy Boolean which are assumed to be 'bool' .
:param splitGroups: Specification on how to split up inner loop into multiple loops. For details see
transformation :func:`pystencils.transformation.splitInnerLoop`
:param iterationSlice: if not None, iteration is done only over this slice of the field
:param ghostLayers: a sequence of pairs for each coordinate with lower and upper nr of ghost layers
if None, the number of ghost layers is determined automatically and assumed to be equal for a
all dimensions
:return: :class:`pystencils.ast.KernelFunction` node
"""
def typeSymbol(term):
if isinstance(term, Field.Access) or isinstance(term, TypedSymbol):
return term
elif isinstance(term, sp.Symbol):
if isinstance(typeForSymbol, str):
return TypedSymbol(term.name, createType(typeForSymbol))
else:
return TypedSymbol(term.name, typeForSymbol[term.name])
else:
raise ValueError("Term has to be field access or symbol")
fieldsRead, fieldsWritten, assignments = typeAllEquations(listOfEquations, typeForSymbol)
allFields = fieldsRead.union(fieldsWritten)
readOnlyFields = set([f.name for f in fieldsRead - fieldsWritten])
body = ast.Block(assignments)
loopOrder = getOptimalLoopOrdering(allFields)
code = makeLoopOverDomain(body, functionName, iterationSlice=iterationSlice,
ghostLayers=ghostLayers, loopOrder=loopOrder)
code.target = 'cpu'
if splitGroups:
typedSplitGroups = [[typeSymbol(s) for s in splitGroup] for splitGroup in splitGroups]
splitInnerLoop(code, typedSplitGroups)
basePointerInfo = [['spatialInner0'], ['spatialInner1']]
basePointerInfos = {field.name: parseBasePointerInfo(basePointerInfo, loopOrder, field) for field in allFields}
resolveFieldAccesses(code, readOnlyFields, fieldToBasePointerInfo=basePointerInfos)
substituteArrayAccessesWithConstants(code)
moveConstantsBeforeLoop(code)
code.compile = partial(makePythonFunction, code)
return code
def createIndexedKernel(listOfEquations, indexFields, functionName="kernel", typeForSymbol=None,
coordinateNames=('x', 'y', 'z')):
"""
Similar to :func:`createKernel`, but here not all cells of a field are updated but only cells with
coordinates which are stored in an index field. This traversal method can e.g. be used for boundary handling.
The coordinates are stored in a separated indexField, which is a one dimensional array with struct data type.
This struct has to contain fields named 'x', 'y' and for 3D fields ('z'). These names are configurable with the
'coordinateNames' parameter. The struct can have also other fields that can be read and written in the kernel, for
example boundary parameters.
:param listOfEquations: list of update equations or AST nodes
:param indexFields: list of index fields, i.e. 1D fields with struct data type
:param typeForSymbol: see documentation of :func:`createKernel`
:param functionName: see documentation of :func:`createKernel`
:param coordinateNames: name of the coordinate fields in the struct data type
:return: abstract syntax tree
"""
fieldsRead, fieldsWritten, assignments = typeAllEquations(listOfEquations, typeForSymbol)
allFields = fieldsRead.union(fieldsWritten)
for indexField in indexFields:
indexField.isIndexField = True
assert indexField.spatialDimensions == 1, "Index fields have to be 1D"
nonIndexFields = [f for f in allFields if f not in indexFields]
spatialCoordinates = {f.spatialDimensions for f in nonIndexFields}
assert len(spatialCoordinates) == 1, "Non-index fields do not have the same number of spatial coordinates"
spatialCoordinates = list(spatialCoordinates)[0]
def getCoordinateSymbolAssignment(name):
for indexField in indexFields:
assert isinstance(indexField.dtype, StructType), "Index fields have to have a struct datatype"
dataType = indexField.dtype
if dataType.hasElement(name):
rhs = indexField[0](name)
lhs = TypedSymbol(name, BasicType(dataType.getElementType(name)))
return SympyAssignment(lhs, rhs)
raise ValueError("Index %s not found in any of the passed index fields" % (name,))
coordinateSymbolAssignments = [getCoordinateSymbolAssignment(n) for n in coordinateNames[:spatialCoordinates]]
coordinateTypedSymbols = [eq.lhs for eq in coordinateSymbolAssignments]
assignments = coordinateSymbolAssignments + assignments
# make 1D loop over index fields
loopBody = Block([])
loopNode = LoopOverCoordinate(loopBody, coordinateToLoopOver=0, start=0, stop=indexFields[0].shape[0])
for assignment in assignments:
loopBody.append(assignment)
functionBody = Block([loopNode])
ast = KernelFunction(functionBody, "cpu", functionName=functionName)
fixedCoordinateMapping = {f.name: coordinateTypedSymbols for f in nonIndexFields}
resolveFieldAccesses(ast, set(['indexField']), fieldToFixedCoordinates=fixedCoordinateMapping)
substituteArrayAccessesWithConstants(ast)
moveConstantsBeforeLoop(ast)
ast.compile = partial(makePythonFunction, ast)
return ast
def addOpenMP(astNode, schedule="static", numThreads=True):
"""
Parallelizes the outer loop with OpenMP
:param astNode: abstract syntax tree created e.g. by :func:`createKernel`
:param schedule: OpenMP scheduling policy e.g. 'static' or 'dynamic'
:param numThreads: explicitly specify number of threads
"""
if not numThreads:
return
assert type(astNode) is ast.KernelFunction
body = astNode.body
threadsClause = "" if numThreads and isinstance(numThreads,bool) else " num_threads(%s)" % (numThreads,)
wrapperBlock = ast.PragmaBlock('#pragma omp parallel' + threadsClause, body.takeChildNodes())
body.append(wrapperBlock)
outerLoops = [l for l in body.atoms(ast.LoopOverCoordinate) if l.isOutermostLoop]
assert outerLoops, "No outer loop found"
assert len(outerLoops) <= 1, "More than one outer loop found. Which one should be parallelized?"
loopToParallelize = outerLoops[0]
try:
loopRange = int(loopToParallelize.stop - loopToParallelize.start)
except TypeError:
loopRange = None
if numThreads is None:
import multiprocessing
numThreads = multiprocessing.cpu_count()
if loopRange is not None and loopRange < numThreads:
containedLoops = [l for l in loopToParallelize.body.args if isinstance(l, LoopOverCoordinate)]
if len(containedLoops) == 1:
containedLoop = containedLoops[0]
try:
containedLoopRange = int(containedLoop.stop - containedLoop.start)
if containedLoopRange > loopRange:
loopToParallelize = containedLoop
except TypeError:
pass
loopToParallelize.prefixLines.append("#pragma omp for schedule(%s)" % (schedule,))
import ctypes
import sympy as sp
import numpy as np
try:
import llvmlite.ir as ir
except ImportError as e:
ir = None
_ir_importerror = e
from sympy.core.cache import cacheit
from pystencils.cache import memorycache
from pystencils.utils import allEqual
# to work in conditions of sp.Piecewise castFunc has to be of type Relational as well
class castFunc(sp.Function, sp.Rel):
@property
def canonical(self):
if hasattr(self.args[0], 'canonical'):
return self.args[0].canonical
else:
raise NotImplementedError()
@property
def is_commutative(self):
return self.args[0].is_commutative
class pointerArithmeticFunc(sp.Function, sp.Rel):
@property
def canonical(self):
if hasattr(self.args[0], 'canonical'):
return self.args[0].canonical
else:
raise NotImplementedError()
class TypedSymbol(sp.Symbol):
def __new__(cls, *args, **kwds):
obj = TypedSymbol.__xnew_cached_(cls, *args, **kwds)
return obj
def __new_stage2__(cls, name, dtype):
obj = super(TypedSymbol, cls).__xnew__(cls, name)
try:
obj._dtype = createType(dtype)
except TypeError:
# on error keep the string
obj._dtype = dtype
return obj
__xnew__ = staticmethod(__new_stage2__)
__xnew_cached_ = staticmethod(cacheit(__new_stage2__))
@property
def dtype(self):
return self._dtype
def _hashable_content(self):
superClassContents = list(super(TypedSymbol, self)._hashable_content())
return tuple(superClassContents + [hash(self._dtype)])
def __getnewargs__(self):
return self.name, self.dtype
def createType(specification):
"""
Create a subclass of Type according to a string or an object of subclass Type
:param specification: Type object, or a string
:return: Type object, or a new Type object parsed from the string
"""
if isinstance(specification, Type):
return specification
else:
npDataType = np.dtype(specification)
if npDataType.fields is None:
return BasicType(npDataType, const=False)
else:
return StructType(npDataType, const=False)
@memorycache(maxsize=64)
def createCompositeTypeFromString(specification):
"""
Creates a new Type object from a c-like string specification
:param specification: Specification string
:return: Type object
"""
specification = specification.lower().split()
parts = []
current = []
for s in specification:
if s == '*':
parts.append(current)
current = [s]
else:
current.append(s)
if len(current) > 0:
parts.append(current)
# Parse native part
basePart = parts.pop(0)
const = False
if 'const' in basePart:
const = True
basePart.remove('const')
assert len(basePart) == 1
if basePart[0][-1] == "*":
basePart[0] = basePart[0][:-1]
parts.append('*')
currentType = BasicType(np.dtype(basePart[0]), const)
# Parse pointer parts
for part in parts:
restrict = False
const = False
if 'restrict' in part:
restrict = True
part.remove('restrict')
if 'const' in part:
const = True
part.remove("const")
assert len(part) == 1 and part[0] == '*'
currentType = PointerType(currentType, const, restrict)
return currentType
def getBaseType(type):
while type.baseType is not None:
type = type.baseType
return type
def toCtypes(dataType):
"""
Transforms a given Type into ctypes
:param dataType: Subclass of Type
:return: ctypes type object
"""
if isinstance(dataType, PointerType):
return ctypes.POINTER(toCtypes(dataType.baseType))
elif isinstance(dataType, StructType):
return ctypes.POINTER(ctypes.c_uint8)
else:
return toCtypes.map[dataType.numpyDtype]
toCtypes.map = {
np.dtype(np.int8): ctypes.c_int8,
np.dtype(np.int16): ctypes.c_int16,
np.dtype(np.int32): ctypes.c_int32,
np.dtype(np.int64): ctypes.c_int64,
np.dtype(np.uint8): ctypes.c_uint8,
np.dtype(np.uint16): ctypes.c_uint16,
np.dtype(np.uint32): ctypes.c_uint32,
np.dtype(np.uint64): ctypes.c_uint64,
np.dtype(np.float32): ctypes.c_float,
np.dtype(np.float64): ctypes.c_double,
}
def ctypes_from_llvm(data_type):
if not ir:
raise _ir_importerror
if isinstance(data_type, ir.PointerType):
ctype = ctypes_from_llvm(data_type.pointee)
if ctype is None:
return ctypes.c_void_p
else:
return ctypes.POINTER(ctype)
elif isinstance(data_type, ir.IntType):
if data_type.width == 8:
return ctypes.c_int8
elif data_type.width == 16:
return ctypes.c_int16
elif data_type.width == 32:
return ctypes.c_int32
elif data_type.width == 64:
return ctypes.c_int64
else:
raise ValueError("Int width %d is not supported" % data_type.width)
elif isinstance(data_type, ir.FloatType):
return ctypes.c_float
elif isinstance(data_type, ir.DoubleType):
return ctypes.c_double
elif isinstance(data_type, ir.VoidType):
return None # Void type is not supported by ctypes
else:
raise NotImplementedError('Data type %s of %s is not supported yet' % (type(data_type), data_type))
def to_llvm_type(data_type):
"""
Transforms a given type into ctypes
:param data_type: Subclass of Type
:return: llvmlite type object
"""
if not ir:
raise _ir_importerror
if isinstance(data_type, PointerType):
return to_llvm_type(data_type.baseType).as_pointer()
else:
return to_llvm_type.map[data_type.numpyDtype]
if ir:
to_llvm_type.map = {
np.dtype(np.int8): ir.IntType(8),
np.dtype(np.int16): ir.IntType(16),
np.dtype(np.int32): ir.IntType(32),
np.dtype(np.int64): ir.IntType(64),
np.dtype(np.uint8): ir.IntType(8),
np.dtype(np.uint16): ir.IntType(16),
np.dtype(np.uint32): ir.IntType(32),
np.dtype(np.uint64): ir.IntType(64),
np.dtype(np.float32): ir.FloatType(),
np.dtype(np.float64): ir.DoubleType(),
}
def peelOffType(dtype, typeToPeelOff):
while type(dtype) is typeToPeelOff:
dtype = dtype.baseType
return dtype
def collateTypes(types):
"""
Takes a sequence of types and returns their "common type" e.g. (float, double, float) -> double
Uses the collation rules from numpy.
"""
# Pointer arithmetic case i.e. pointer + integer is allowed
if any(type(t) is PointerType for t in types):
pointerType = None
for t in types:
if type(t) is PointerType:
if pointerType is not None:
raise ValueError("Cannot collate the combination of two pointer types")
pointerType = t
elif type(t) is BasicType:
if not (t.is_int() or t.is_uint()):
raise ValueError("Invalid pointer arithmetic")
else:
raise ValueError("Invalid pointer arithmetic")
return pointerType
# peel of vector types, if at least one vector type occurred the result will also be the vector type
vectorType = [t for t in types if type(t) is VectorType]
if not allEqual(t.width for t in vectorType):
raise ValueError("Collation failed because of vector types with different width")
types = [peelOffType(t, VectorType) for t in types]
# now we should have a list of basic types - struct types are not yet supported
assert all(type(t) is BasicType for t in types)
# use numpy collation -> create type from numpy type -> and, put vector type around if necessary
resultNumpyType = np.result_type(*(t.numpyDtype for t in types))
result = BasicType(resultNumpyType)
if vectorType:
result = VectorType(result, vectorType[0].width)
return result
@memorycache(maxsize=2048)
def getTypeOfExpression(expr):
from pystencils.astnodes import ResolvedFieldAccess
expr = sp.sympify(expr)
if isinstance(expr, sp.Integer):
return createType("int")
elif isinstance(expr, sp.Rational) or isinstance(expr, sp.Float):
return createType("double")
elif isinstance(expr, ResolvedFieldAccess):
return expr.field.dtype
elif isinstance(expr, TypedSymbol):
return expr.dtype
elif isinstance(expr, sp.Symbol):
raise ValueError("All symbols inside this expression have to be typed!")
elif hasattr(expr, 'func') and expr.func == castFunc:
return expr.args[1]
elif hasattr(expr, 'func') and expr.func == sp.Piecewise:
collatedResultType = collateTypes(tuple(getTypeOfExpression(a[0]) for a in expr.args))
collatedConditionType = collateTypes(tuple(getTypeOfExpression(a[1]) for a in expr.args))
if type(collatedConditionType) is VectorType and type(collatedResultType) is not VectorType:
collatedResultType = VectorType(collatedResultType, width=collatedConditionType.width)
return collatedResultType
elif isinstance(expr, sp.Indexed):
typedSymbol = expr.base.label
return typedSymbol.dtype.baseType
elif isinstance(expr, sp.boolalg.Boolean) or isinstance(expr, sp.boolalg.BooleanFunction):
# if any arg is of vector type return a vector boolean, else return a normal scalar boolean
result = createType("bool")
vecArgs = [getTypeOfExpression(a) for a in expr.args if isinstance(getTypeOfExpression(a), VectorType)]
if vecArgs:
result = VectorType(result, width=vecArgs[0].width)
return result
elif isinstance(expr, sp.Expr):
types = tuple(getTypeOfExpression(a) for a in expr.args)
return collateTypes(types)
raise NotImplementedError("Could not determine type for", expr, type(expr))
class Type(sp.Basic):
def __new__(cls, *args, **kwargs):
return sp.Basic.__new__(cls)
def __lt__(self, other): # deprecated
# Needed for sorting the types inside an expression
if isinstance(self, BasicType):
if isinstance(other, BasicType):
return self.numpyDtype > other.numpyDtype # TODO const
elif isinstance(other, PointerType):
return False
else: # isinstance(other, StructType):
raise NotImplementedError("Struct type comparison is not yet implemented")
elif isinstance(self, PointerType):
if isinstance(other, BasicType):
return True
elif isinstance(other, PointerType):
return self.baseType > other.baseType # TODO const, restrict
else: # isinstance(other, StructType):
raise NotImplementedError("Struct type comparison is not yet implemented")
elif isinstance(self, StructType):
raise NotImplementedError("Struct type comparison is not yet implemented")
else:
raise NotImplementedError
def _sympystr(self, *args, **kwargs):
return str(self)
def _sympystr(self, *args, **kwargs):
return str(self)
class BasicType(Type):
@staticmethod
def numpyNameToC(name):
if name == 'float64':
return 'double'
elif name == 'float32':
return 'float'
elif name.startswith('int'):
width = int(name[len("int"):])
return "int%d_t" % (width,)
elif name.startswith('uint'):
width = int(name[len("uint"):])
return "uint%d_t" % (width,)
elif name == 'bool':
return 'bool'
else:
raise NotImplemented("Can map numpy to C name for %s" % (name,))
def __init__(self, dtype, const=False):
self.const = const
if isinstance(dtype, Type):
self._dtype = dtype.numpyDtype
else:
self._dtype = np.dtype(dtype)
assert self._dtype.fields is None, "Tried to initialize NativeType with a structured type"
assert self._dtype.hasobject is False
assert self._dtype.subdtype is None
def __getnewargs__(self):
return self.numpyDtype, self.const
@property
def baseType(self):
return None
@property
def numpyDtype(self):
return self._dtype
@property
def itemSize(self):
return 1
def is_int(self):
return self.numpyDtype in np.sctypes['int']
def is_float(self):
return self.numpyDtype in np.sctypes['float']
def is_uint(self):
return self.numpyDtype in np.sctypes['uint']
def is_comlex(self):
return self.numpyDtype in np.sctypes['complex']
def is_other(self):
return self.numpyDtype in np.sctypes['others']
@property
def baseName(self):
return BasicType.numpyNameToC(str(self._dtype))
def __str__(self):
result = BasicType.numpyNameToC(str(self._dtype))
if self.const:
result += " const"
return result
def __repr__(self):
return str(self)
def __eq__(self, other):
if not isinstance(other, BasicType):
return False
else:
return (self.numpyDtype, self.const) == (other.numpyDtype, other.const)
def __hash__(self):
return hash(str(self))
class VectorType(Type):
instructionSet = None
def __init__(self, baseType, width=4):
self._baseType = baseType
self.width = width
@property
def baseType(self):
return self._baseType
@property
def itemSize(self):
return self.width * self.baseType.itemSize
def __eq__(self, other):
if not isinstance(other, VectorType):
return False
else:
return (self.baseType, self.width) == (other.baseType, other.width)
def __str__(self):
if self.instructionSet is None:
return "%s[%d]" % (self.baseType, self.width)
else:
if self.baseType == createType("int64"):
return self.instructionSet['int']
elif self.baseType == createType("float64"):
return self.instructionSet['double']
elif self.baseType == createType("float32"):
return self.instructionSet['float']
elif self.baseType == createType("bool"):
return self.instructionSet['bool']
else:
raise NotImplementedError()
def __hash__(self):
return hash((self.baseType, self.width))
class PointerType(Type):
def __init__(self, baseType, const=False, restrict=True):
self._baseType = baseType
self.const = const
self.restrict = restrict
def __getnewargs__(self):
return self.baseType, self.const, self.restrict
@property
def alias(self):
return not self.restrict
@property
def baseType(self):
return self._baseType
@property
def itemSize(self):
return self.baseType.itemSize
def __eq__(self, other):
if not isinstance(other, PointerType):
return False
else:
return (self.baseType, self.const, self.restrict) == (other.baseType, other.const, other.restrict)
def __str__(self):
return "%s *%s%s" % (self.baseType, " RESTRICT " if self.restrict else "", " const " if self.const else "")
def __repr__(self):
return str(self)
def __hash__(self):
return hash((self._baseType, self.const, self.restrict))
class StructType(object):
def __init__(self, numpyType, const=False):
self.const = const
self._dtype = np.dtype(numpyType)
def __getnewargs__(self):
return self.numpyDtype, self.const
@property
def baseType(self):
return None
@property
def numpyDtype(self):
return self._dtype
@property
def itemSize(self):
return self.numpyDtype.itemsize
def getElementOffset(self, elementName):
return self.numpyDtype.fields[elementName][1]
def getElementType(self, elementName):
npElementType = self.numpyDtype.fields[elementName][0]
return BasicType(npElementType, self.const)
def hasElement(self, elementName):
return elementName in self.numpyDtype.fields
def __eq__(self, other):
if not isinstance(other, StructType):
return False
else:
return (self.numpyDtype, self.const) == (other.numpyDtype, other.const)
def __str__(self):
# structs are handled byte-wise
result = "uint8_t"
if self.const:
result += " const"
return result
def __repr__(self):
return str(self)
def __hash__(self):
return hash((self.numpyDtype, self.const))
# TODO this should not work at all!!!
def __gt__(self, other):
if self.ptr and not other.ptr:
return True
if self.dtype > other.dtype:
return True
def get_type_from_sympy(node):
"""
Creates a Type object from a Sympy object
:param node: Sympy object
:return: Type object
"""
# Rational, NumberSymbol?
# Zero, One, NegativeOne )= Integer
# Half )= Rational
# NAN, Infinity, Negative Inifinity,
# Exp1, Imaginary Unit, Pi, EulerGamma, Catalan, Golden Ratio
# Pow, Mul, Add, Mod, Relational
if not isinstance(node, sp.Number):
raise TypeError(node, 'is not a sp.Number')
if isinstance(node, sp.Float) or isinstance(node, sp.RealNumber):
return createType('double'), float(node)
elif isinstance(node, sp.Integer):
return createType('int'), int(node)
elif isinstance(node, sp.Rational):
# TODO is it always float?
return createType('double'), float(node.p/node.q)
else:
raise TypeError(node, ' is not a supported type (yet)!')
import numpy as np
from abc import ABC, abstractmethod, abstractproperty
from collections import defaultdict
from contextlib import contextmanager
from lbmpy.stencils import getStencil
from pystencils import Field, makeSlice
from pystencils.parallel.blockiteration import BlockIterationInfo
from pystencils.slicing import normalizeSlice, removeGhostLayers
from pystencils.utils import DotDict
try:
import pycuda.gpuarray as gpuarray
except ImportError:
gpuarray = None
class DataHandling(ABC):
"""
Manages the storage of arrays and maps them to a symbolic field.
Two versions are available: a simple, pure Python implementation for single node
simulations :py:class:SerialDataHandling and a distributed version using waLBerla in :py:class:ParallelDataHandling
Keep in mind that the data can be distributed, so use the 'access' method whenever possible and avoid the
'gather' function that has collects (parts of the) distributed data on a single process.
"""
def __init__(self):
self._preAccessFunctions = defaultdict(list)
self._postAccessFunctions = defaultdict(list)
# ---------------------------- Adding and accessing data -----------------------------------------------------------
@property
@abstractmethod
def dim(self):
"""Dimension of the domain, either 2 or 3"""
@abstractmethod
def addArray(self, name, fSize=1, dtype=np.float64, latexName=None, ghostLayers=None, layout=None, cpu=True, gpu=False):
"""
Adds a (possibly distributed) array to the handling that can be accessed using the given name.
For each array a symbolic field is available via the 'fields' dictionary
:param name: unique name that is used to access the field later
:param fSize: shape of the dim+1 coordinate. DataHandling supports zero or one index dimensions, i.e. scalar
fields and vector fields. This parameter gives the shape of the index dimensions. The default
value of 1 means no index dimension
:param dtype: data type of the array as numpy data type
:param latexName: optional, name of the symbolic field, if not given 'name' is used
:param ghostLayers: number of ghost layers - if not specified a default value specified in the constructor
is used
:param layout: memory layout of array, either structure of arrays 'SoA' or array of structures 'AoS'.
this is only important if fSize > 1
:param cpu: allocate field on the CPU
:param gpu: allocate field on the GPU
"""
@abstractmethod
def hasData(self, name):
"""
Returns true if a field or custom data element with this name was added
"""
@abstractmethod
def addArrayLike(self, name, nameOfTemplateField, latexName=None, cpu=True, gpu=False):
"""
Adds an array with the same parameters (number of ghost layers, fSize, dtype) as existing array
:param name: name of new array
:param nameOfTemplateField: name of array that is used as template
:param latexName: see 'add' method
:param cpu: see 'add' method
:param gpu: see 'add' method
"""
@abstractmethod
def addCustomData(self, name, cpuCreationFunction,
gpuCreationFunction=None, cpuToGpuTransferFunc=None, gpuToCpuTransferFunc=None):
"""
Adds custom (non-array) data to domain
:param name: name to access data
:param cpuCreationFunction: function returning a new instance of the data that should be stored
:param gpuCreationFunction: optional, function returning a new instance, stored on GPU
:param cpuToGpuTransferFunc: function that transfers cpu to gpu version, getting two parameters (gpuInstance, cpuInstance)
:param gpuToCpuTransferFunc: function that transfers gpu to cpu version, getting two parameters (gpuInstance, cpuInstance)
:return:
"""
@property
@abstractmethod
def fields(self):
"""Dictionary mapping data name to symbolic pystencils field - use this to create pystencils kernels"""
@abstractmethod
def accessArray(self, name, sliceObj=None, innerGhostLayers=None, outerGhostLayers=0):
"""
Generator yielding locally stored sub-arrays together with information about their place in the global domain
:param name: name of data to access
:param sliceObj: optional rectangular sub-region to access
:param innerGhostLayers: how many inner (not at domain border) ghost layers to include
:param outerGhostLayers: how many ghost layers at the domain border to include
Yields a numpy array with local part of data and a BlockIterationInfo object containing geometric information
"""
@abstractmethod
def accessCustomData(self, name):
"""
Similar to accessArray, however for custom data no slicing and ghost layer info is necessary/available
"""
@abstractmethod
def gatherArray(self, name, sliceObj=None, allGather=False):
"""
Gathers part of the domain on a local process. Whenever possible use 'access' instead, since this method copies
the distributed data to a single process which is inefficient and may exhaust the available memory
:param name: name of the array to gather
:param sliceObj: slice expression of the rectangular sub-part that should be gathered
:param allGather: if False only the root process receives the result, if True all processes
:return: generator expression yielding the gathered field, the gathered field does not include any ghost layers
"""
def registerPreAccessFunction(self, name, function):
self._preAccessFunctions[name].append(function)
def registerPostAccessFunction(self, name, function):
self._postAccessFunctions[name].append(function)
@contextmanager
def accessWrapper(self, name):
for func in self._preAccessFunctions[name]:
func()
yield
for func in self._postAccessFunctions[name]:
func()
# ------------------------------- CPU/GPU transfer -----------------------------------------------------------------
@abstractmethod
def toCpu(self, name):
"""Copies GPU data of array with specified name to CPU.
Works only if 'cpu=True' and 'gpu=True' has been used in 'add' method"""
pass
@abstractmethod
def toGpu(self, name):
"""Copies GPU data of array with specified name to GPU.
Works only if 'cpu=True' and 'gpu=True' has been used in 'add' method"""
pass
@abstractmethod
def allToCpu(self, name):
"""Copies data from GPU to CPU for all arrays that have a CPU and a GPU representation"""
pass
@abstractmethod
def allToGpu(self, name):
"""Copies data from CPU to GPU for all arrays that have a CPU and a GPU representation"""
pass
# ------------------------------- Communication --------------------------------------------------------------------
def synchronizationFunctionCPU(self, names, stencil=None, **kwargs):
"""
Synchronizes ghost layers for distributed arrays - for serial scenario this has to be called
for correct periodicity handling
:param names: what data to synchronize: name of array or sequence of names
:param stencil: stencil as string defining which neighbors are synchronized e.g. 'D2Q9', 'D3Q19'
if None, a full synchronization (i.e. D2Q9 or D3Q27) is done
:param kwargs: implementation specific, optional optimization parameters for communication
:return: function object to run the communication
"""
def synchronizationFunctionGPU(self, names, stencil=None, **kwargs):
"""
Synchronization of GPU fields, for documentation see CPU version above
"""
class SerialDataHandling(DataHandling):
class _PassThroughContextManager:
def __init__(self, arr):
self.arr = arr
def __enter__(self, *args, **kwargs):
return self.arr
def __init__(self, domainSize, defaultGhostLayers=1, defaultLayout='SoA', periodicity=False):
"""
Creates a data handling for single node simulations
:param domainSize: size of the spatial domain as tuple
:param defaultGhostLayers: nr of ghost layers used if not specified in add() method
:param defaultLayout: layout used if no layout is given to add() method
"""
super(SerialDataHandling, self).__init__()
self._domainSize = tuple(domainSize)
self.defaultGhostLayers = defaultGhostLayers
self.defaultLayout = defaultLayout
self._fields = DotDict()
self.cpuArrays = DotDict()
self.gpuArrays = DotDict()
self.customDataCpu = DotDict()
self.customDataGpu = DotDict()
self._customDataTransferFunctions = {}
if periodicity is None or periodicity is False:
periodicity = [False] * self.dim
if periodicity is True:
periodicity = [True] * self.dim
self._periodicity = periodicity
self._fieldInformation = {}
@property
def dim(self):
return len(self._domainSize)
@property
def fields(self):
return self._fields
def addArray(self, name, fSize=1, dtype=np.float64, latexName=None, ghostLayers=None, layout=None, cpu=True, gpu=False):
if ghostLayers is None:
ghostLayers = self.defaultGhostLayers
if layout is None:
layout = self.defaultLayout
if latexName is None:
latexName = name
assert layout in ('SoA', 'AoS')
kwargs = {
'shape': tuple(s + 2 * ghostLayers for s in self._domainSize),
'dtype': dtype,
'order': 'C' if layout == 'AoS' else 'F',
}
self._fieldInformation[name] = {
'ghostLayers': ghostLayers,
'fSize': fSize,
'layout': layout,
'dtype': dtype,
}
if fSize > 1:
kwargs['shape'] = kwargs['shape'] + (fSize,)
indexDimensions = 1
else:
indexDimensions = 0
if cpu:
if name in self.cpuArrays:
raise ValueError("CPU Field with this name already exists")
self.cpuArrays[name] = np.empty(**kwargs)
if gpu:
if name in self.gpuArrays:
raise ValueError("GPU Field with this name already exists")
self.gpuArrays[name] = gpuarray.empty(**kwargs)
assert all(f.name != latexName for f in self.fields.values()), "Symbolic field with this name already exists"
self.fields[name] = Field.createFixedSize(latexName, shape=kwargs['shape'], indexDimensions=indexDimensions,
dtype=kwargs['dtype'], layout=kwargs['order'])
def addCustomData(self, name, cpuCreationFunction,
gpuCreationFunction=None, cpuToGpuTransferFunc=None, gpuToCpuTransferFunc=None):
assert name not in self.cpuArrays
assert name not in self.customDataCpu
self.customDataCpu[name] = cpuCreationFunction()
if gpuCreationFunction:
self.customDataGpu[name] = gpuCreationFunction()
if cpuToGpuTransferFunc is None or gpuToCpuTransferFunc is None:
raise ValueError("For GPU data, both transfer functions have to be specified")
self._customDataTransferFunctions[name] = (cpuToGpuTransferFunc, gpuToCpuTransferFunc)
def hasData(self, name):
return name in self.fields
def addArrayLike(self, name, nameOfTemplateField, latexName=None, cpu=True, gpu=False):
self.addArray(name, latexName=latexName, cpu=cpu, gpu=gpu, **self._fieldInformation[nameOfTemplateField])
def accessArray(self, name, sliceObj=None, outerGhostLayers='all', **kwargs):
if outerGhostLayers == 'all':
outerGhostLayers = self._fieldInformation[name]['ghostLayers']
if sliceObj is None:
sliceObj = [slice(None, None)] * self.dim
with self.accessWrapper(name):
arr = self.cpuArrays[name]
glToRemove = self._fieldInformation[name]['ghostLayers'] - outerGhostLayers
assert glToRemove >= 0
arr = removeGhostLayers(arr, indexDimensions=self.fields[name].indexDimensions, ghostLayers=glToRemove)
sliceObj = normalizeSlice(sliceObj, arr.shape[:self.dim])
yield arr[sliceObj], BlockIterationInfo(None, tuple(s.start for s in sliceObj), sliceObj)
def accessCustomData(self, name):
yield self.customDataCpu[name], ((0,0,0)[:self.dim], self._domainSize)
def gatherArray(self, name, sliceObj=None, **kwargs):
with self.accessWrapper(name):
gls = self._fieldInformation[name]['ghostLayers']
arr = self.cpuArrays[name]
arr = removeGhostLayers(arr, indexDimensions=self.fields[name].indexDimensions, ghostLayers=gls)
if sliceObj is not None:
arr = arr[sliceObj]
yield arr
def swap(self, name1, name2, gpu=False):
if not gpu:
self.cpuArrays[name1], self.cpuArrays[name2] = self.cpuArrays[name2], self.cpuArrays[name1]
else:
self.gpuArrays[name1], self.gpuArrays[name2] = self.gpuArrays[name2], self.gpuArrays[name1]
def allToCpu(self):
for name in (self.cpuArrays.keys() & self.gpuArrays.keys()) | self._customDataTransferFunctions.keys():
self.toCpu(name)
def allToGpu(self):
for name in (self.cpuArrays.keys() & self.gpuArrays.keys()) | self._customDataTransferFunctions.keys():
self.toGpu(name)
def toCpu(self, name):
if name in self._customDataTransferFunctions:
transferFunc = self._customDataTransferFunctions[name][1]
transferFunc(self.customDataGpu[name], self.customDataCpu[name])
else:
self.gpuArrays[name].get(self.cpuArrays[name])
def toGpu(self, name):
if name in self._customDataTransferFunctions:
transferFunc = self._customDataTransferFunctions[name][0]
transferFunc(self.customDataGpu[name], self.customDataCpu[name])
else:
self.gpuArrays[name].set(self.cpuArrays[name])
def synchronizationFunctionCPU(self, names, stencilName=None, **kwargs):
return self._synchronizationFunctor(names, stencilName, 'cpu')
def synchronizationFunctionGPU(self, names, stencilName=None, **kwargs):
return self._synchronizationFunctor(names, stencilName, 'gpu')
def _synchronizationFunctor(self, names, stencil, target):
if stencil is None:
stencil = 'D3Q27' if self.dim == 3 else 'D2Q9'
assert stencil in ("D2Q9", 'D3Q27'), "Serial scenario support only D2Q9 or D3Q27 for periodicity sync"
assert target in ('cpu', 'gpu')
if not hasattr(names, '__len__') or type(names) is str:
names = [names]
filteredStencil = []
for direction in getStencil(stencil):
useDirection = True
if direction == (0, 0) or direction == (0, 0, 0):
useDirection = False
for component, periodicity in zip(direction, self._periodicity):
if not periodicity and component != 0:
useDirection = False
if useDirection:
filteredStencil.append(direction)
resultFunctors = []
for name in names:
gls = self._fieldInformation[name]['ghostLayers']
if len(filteredStencil) > 0:
if target == 'cpu':
from pystencils.slicing import getPeriodicBoundaryFunctor
resultFunctors.append(getPeriodicBoundaryFunctor(filteredStencil, ghostLayers=gls))
else:
from pystencils.gpucuda.periodicity import getPeriodicBoundaryFunctor
resultFunctors.append(getPeriodicBoundaryFunctor(filteredStencil, self._domainSize,
indexDimensions=self.fields[name].indexDimensions,
indexDimShape=self._fieldInformation[name]['fSize'],
dtype=self.fields[name].dtype.numpyDtype,
ghostLayers=gls))
if target == 'cpu':
def resultFunctor():
for func in resultFunctors:
func(pdfs=self.cpuArrays[name])
else:
def resultFunctor():
for func in resultFunctors:
func(pdfs=self.gpuArrays[name])
return resultFunctor
def toDot(expr, graphStyle={}):
"""Show a sympy or pystencils AST as dot graph"""
from pystencils.astnodes import Node
import graphviz
if isinstance(expr, Node):
from pystencils.backends.dot import dotprint
return graphviz.Source(dotprint(expr, short=True, graph_attr=graphStyle))
else:
from sympy.printing.dot import dotprint
return graphviz.Source(dotprint(expr, graph_attr=graphStyle))
def highlightCpp(code):
"""Highlight the given C/C++ source code with Pygments"""
from IPython.display import HTML, display
from pygments import highlight
from pygments.formatters import HtmlFormatter
from pygments.lexers import CppLexer
display(HTML("""
<style>
{pygments_css}
</style>
""".format(pygments_css=HtmlFormatter().get_style_defs('.highlight'))))
return HTML(highlight(code, CppLexer(), HtmlFormatter()))
def showCode(ast):
from pystencils.cpu import generateC
class CodeDisplay:
def __init__(self, astInput):
self.ast = astInput
def _repr_html_(self):
return highlightCpp(generateC(self.ast)).__html__()
def __str__(self):
return generateC(self.ast)
def __repr__(self):
return generateC(self.ast)
return CodeDisplay(ast)
# ----------------- Embedding of animations as videos in IPython notebooks ---------------------------------------------
# ------- Version 1: Animation is embedded as an HTML5 Video tag ---------------------------------------
VIDEO_TAG = """<video controls width="100%">
<source src="data:video/x-m4v;base64,{0}" type="video/mp4">
Your browser does not support the video tag.
</video>"""
def __anim_to_html(anim, fps):
from tempfile import NamedTemporaryFile
import base64
if not hasattr(anim, '_encoded_video'):
with NamedTemporaryFile(suffix='.mp4') as f:
anim.save(f.name, fps=fps, extra_args=['-vcodec', 'libx264', '-pix_fmt',
'yuv420p', '-profile:v', 'baseline', '-level', '3.0'])
video = open(f.name, "rb").read()
anim._encoded_video = base64.b64encode(video).decode('ascii')
return VIDEO_TAG.format(anim._encoded_video)
def disp_as_video(anim, fps=30, show=True, **kwargs):
import matplotlib.pyplot as plt
from IPython.display import HTML
try:
plt.close(anim._fig)
res = __anim_to_html(anim, fps)
if show:
return HTML(res)
else:
return HTML("")
except KeyboardInterrupt:
pass
# ------- Version 2: Animation is shown in extra matplotlib window ----------------------------------
def disp_extra_window(animation, *args,**kwargs):
import matplotlib.pyplot as plt
fig = plt.gcf()
try:
fig.canvas.manager.window.raise_()
except Exception:
pass
plt.show()
# ------- Version 3: Animation is shown in images that are updated directly in website --------------
def disp_image_update(animation, iterations=10000, *args, **kwargs):
from IPython import display
import matplotlib.pyplot as plt
try:
fig = plt.gcf()
animation._init_draw()
for i in range(iterations):
display.display(fig)
animation._step()
display.clear_output(wait=True)
except KeyboardInterrupt:
pass
# Dispatcher
animation_display_mode = 'imageupdate'
display_animation_func = None
def disp(*args, **kwargs):
if not display_animation_func:
raise Exception("Call set_display_mode first")
return display_animation_func(*args, **kwargs)
def set_display_mode(mode):
from IPython import get_ipython
ipython = get_ipython()
if ipython is None:
return
global animation_display_mode
global display_animation_func
animation_display_mode = mode
if animation_display_mode == 'video':
ipython.magic("matplotlib inline")
display_animation_func = disp_as_video
elif animation_display_mode == 'window':
ipython.magic("matplotlib qt")
display_animation_func = disp_extra_window
elif animation_display_mode == 'imageupdate':
ipython.magic("matplotlib inline")
display_animation_func = disp_image_update
else:
raise Exception("Unknown mode. Available modes 'imageupdate', 'video' and 'window' ")
set_display_mode('video')
# --------------------- Convenience functions --------------------------------------------------------------------------
def makeSurfacePlotAnimation(runFunction, frames=90, interval=30):
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation
import matplotlib.pyplot as plt
from matplotlib import cm
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
X, Y, data = runFunction(1)
ax.plot_surface(X, Y, data, rstride=2, cstride=2, color='b', cmap=cm.coolwarm,)
ax.set_zlim(-1.0, 1.0)
def updatefig(*args):
X, Y, data = runFunction(1)
ax.clear()
plot = ax.plot_surface(X, Y, data, rstride=2, cstride=2, color='b', cmap=cm.coolwarm,)
ax.set_zlim(-1.0, 1.0)
return plot,
return animation.FuncAnimation(fig, updatefig, interval=interval, frames=frames, blit=False)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
import datetime
import sphinx_rtd_theme
import os
import re
import sys
sys.path.insert(0, os.path.abspath('.'))
import pystencils
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.intersphinx',
'sphinx.ext.mathjax',
'sphinx.ext.napoleon',
'nbsphinx',
'sphinxcontrib.bibtex',
'sphinx_autodoc_typehints',
]
add_module_names = False
templates_path = ['_templates']
source_suffix = '.rst'
master_doc = 'index'
copyright = f'{datetime.datetime.now().year}, Martin Bauer, Markus Holzer, Frederik Hennig'
author = 'Martin Bauer, Markus Holzer, Frederik Hennig'
# The short X.Y version (including .devXXXX, rcX, b1 suffixes if present)
version = re.sub(r'(\d+\.\d+)\.\d+(.*)', r'\1\2', pystencils.__version__)
version = re.sub(r'(\.dev\d+).*?$', r'\1', version)
# The full version, including alpha/beta/rc tags.
release = pystencils.__version__
language = 'en'
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '**.ipynb_checkpoints']
default_role = 'any'
pygments_style = 'sphinx'
todo_include_todos = False
# Options for HTML output
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
html_theme = 'sphinx_rtd_theme'
htmlhelp_basename = 'pystencilsdoc'
html_sidebars = {'**': ['globaltoc.html', 'relations.html', 'sourcelink.html', 'searchbox.html']}
# NbSphinx configuration
nbsphinx_execute = 'never'
nbsphinx_codecell_lexer = 'python3'
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'python': ('https://docs.python.org/3.8', None),
'numpy': ('https://docs.scipy.org/doc/numpy/', None),
'matplotlib': ('https://matplotlib.org/', None),
'sympy': ('https://docs.sympy.org/latest/', None),
}
autodoc_member_order = 'bysource'
bibtex_bibfiles = ['sphinx/pystencils.bib']
project = 'pystencils'
html_logo = 'img/logo.png'
This source diff could not be displayed because it is too large. You can view the blob instead.
doc/img/github_repo_card.png

78.4 KiB

doc/img/logo.png

9.88 KiB

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="53.913792mm"
height="53.913792mm"
viewBox="0 0 191.03312 191.03312"
id="svg2"
version="1.1"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
sodipodi:docname="logo.svg"
inkscape:export-filename="/local/bauer/code/lbmpy/pystencils/doc/img/logo.png"
inkscape:export-xdpi="350"
inkscape:export-ydpi="350">
<defs
id="defs4">
<inkscape:path-effect
effect="spiro"
id="path-effect4188"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect4188-5"
is_visible="true" />
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4596">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4598" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4600" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4602" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4604" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4606" />
</filter>
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4608">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4610" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4612" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4614" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4616" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4618" />
</filter>
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4620">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4622" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4624" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4626" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4628" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4630" />
</filter>
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4632">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4634" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4636" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4638" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4640" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4642" />
</filter>
<inkscape:path-effect
effect="spiro"
id="path-effect4188-7"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect4188-5-6"
is_visible="true" />
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4596-6">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4598-6" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4600-9" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4602-1" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4604-4" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4606-3" />
</filter>
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4620-1">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4622-1" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4624-4" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4626-8" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4628-5" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4630-7" />
</filter>
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4632-1">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4634-9" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4636-8" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4638-7" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4640-6" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4642-5" />
</filter>
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4608-0">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4610-2" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4612-5" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4614-7" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4616-6" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4618-9" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="-48.443059"
inkscape:cy="134.59857"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1447"
inkscape:window-height="1154"
inkscape:window-x="2586"
inkscape:window-y="191"
inkscape:window-maximized="0"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0">
<inkscape:grid
type="xygrid"
id="grid4176"
originx="-375.0827"
originy="-543.01469" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-375.08269,-318.31438)">
<rect
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#d2d2d2;stroke-width:1.80409861;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect1396-1"
width="189.22902"
height="189.22902"
x="375.98474"
y="319.21643"
ry="10.417198"
inkscape:export-xdpi="70.669998"
inkscape:export-ydpi="70.669998" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.49999952px;line-height:125%;font-family:'Latin Modern Mono Light';-inkscape-font-specification:'Latin Modern Mono Light, ';letter-spacing:0px;word-spacing:0px;fill:#252525;fill-opacity:1;stroke:none;stroke-width:0.93749994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="382.84055"
y="485.91989"
id="text1392-1"
inkscape:export-xdpi="70.669998"
inkscape:export-ydpi="70.669998"><tspan
sodipodi:role="line"
id="tspan1390-1"
x="382.84055"
y="485.91989"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:33.75000381px;font-family:'Latin Modern Mono Light';-inkscape-font-specification:'Latin Modern Mono Light, Bold';fill:#252525;fill-opacity:1;stroke-width:0.93749994px">pystencils</tspan></text>
<g
id="g9986"
transform="matrix(1.7743145,0,0,1.7743145,311.73549,345.04841)"
inkscape:export-xdpi="70.669998"
inkscape:export-ydpi="70.669998">
<path
inkscape:connector-curvature="0"
inkscape:original-d="M 60.891002,27.333516 H 118.64865"
inkscape:path-effect="#path-effect4188-7"
id="path4186-6"
d="M 60.891002,27.333516 H 118.64865"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.78799796;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.70388345" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
inkscape:original-d="M 89.922623,-0.47572315 C 31.237244,132.88729 89.846228,36.88339 89.846228,56.13594"
inkscape:path-effect="#path-effect4188-5-6"
id="path4186-3-9"
d="M 89.922623,-0.47572315 89.846228,56.13594"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.78799796;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.70388345" />
<circle
transform="matrix(0.21391721,0,0,0.21391721,27.733834,-23.442344)"
r="34.345188"
cy="108.02044"
cx="291.42902"
id="path4136-76"
style="opacity:1;fill:#e69f00;fill-opacity:1;stroke:none;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4596-6)" />
<circle
transform="matrix(0.21391721,0,0,0.21391721,27.733834,-23.442344)"
r="34.345188"
cy="365.43817"
cx="290.41885"
id="path4136-6-0"
style="opacity:1;fill:#0072b2;fill-opacity:1;stroke:none;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4620-1)" />
<circle
transform="matrix(0.21391721,0,0,0.21391721,27.733834,-23.442344)"
r="34.345188"
cy="236.72931"
cx="422.24377"
id="path4136-3-9"
style="opacity:1;fill:#999999;fill-opacity:1;stroke:none;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4632-1)" />
<circle
transform="matrix(0.21391721,0,0,0.21391721,27.733834,-23.442344)"
r="34.345188"
cy="236.72931"
cx="155.56349"
id="path4136-7-0"
style="opacity:1;fill:#009e73;fill-opacity:1;stroke:none;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4608-0)" />
</g>
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="379.82614mm"
height="189.91307mm"
viewBox="0 0 1345.8407 672.92033"
id="svg2"
version="1.1"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
sodipodi:docname="logo_large.svg"
inkscape:export-filename="/home/martin/code/pycodegen/pystencils/doc/img/github_repo_card.png"
inkscape:export-xdpi="85.599998"
inkscape:export-ydpi="85.599998">
<defs
id="defs4">
<inkscape:path-effect
effect="spiro"
id="path-effect4188"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect4188-5"
is_visible="true" />
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4596">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4598" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4600" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4602" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4604" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4606" />
</filter>
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4608">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4610" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4612" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4614" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4616" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4618" />
</filter>
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4620">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4622" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4624" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4626" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4628" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4630" />
</filter>
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4632">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4634" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4636" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4638" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4640" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4642" />
</filter>
<inkscape:path-effect
effect="spiro"
id="path-effect4188-7"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect4188-5-6"
is_visible="true" />
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4596-6">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4598-6" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4600-9" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4602-1" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4604-4" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4606-3" />
</filter>
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4620-1">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4622-1" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4624-4" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4626-8" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4628-5" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4630-7" />
</filter>
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4632-1">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4634-9" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4636-8" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4638-7" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4640-6" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4642-5" />
</filter>
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4608-0">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4610-2" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4612-5" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4614-7" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4616-6" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4618-9" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.70000001"
inkscape:cx="545.01294"
inkscape:cy="35.725386"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="3840"
inkscape:window-height="2061"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0">
<inkscape:grid
type="xygrid"
id="grid4176"
originx="267.20477"
originy="315.17846" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(267.20477,-694.6203)">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:34.78659058px;line-height:125%;font-family:'Latin Modern Mono Light';-inkscape-font-specification:'Latin Modern Mono Light, ';letter-spacing:0px;word-spacing:0px;fill:#252525;fill-opacity:1;stroke:none;stroke-width:4.34832382px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="159.99139"
y="964.43109"
id="text1392-1"
inkscape:export-xdpi="70.669998"
inkscape:export-ydpi="70.669998"><tspan
sodipodi:role="line"
id="tspan1390-1"
x="159.99139"
y="964.43109"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:156.53968811px;font-family:'Latin Modern Mono Light';-inkscape-font-specification:'Latin Modern Mono Light, Bold';fill:#252525;fill-opacity:1;stroke-width:4.34832382px">pystencils</tspan></text>
<g
id="g9986"
transform="matrix(4.1201463,0,0,4.1201463,-399.75066,866.02979)"
inkscape:export-xdpi="70.669998"
inkscape:export-ydpi="70.669998">
<path
inkscape:connector-curvature="0"
inkscape:original-d="M 60.891002,27.333516 H 118.64865"
inkscape:path-effect="#path-effect4188-7"
id="path4186-6"
d="M 60.891002,27.333516 H 118.64865"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.78799796;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.70388345" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
inkscape:original-d="M 89.922623,-0.47572315 C 31.237244,132.88729 89.846228,36.88339 89.846228,56.13594"
inkscape:path-effect="#path-effect4188-5-6"
id="path4186-3-9"
d="M 89.922623,-0.47572315 89.846228,56.13594"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.78799796;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.70388345" />
<circle
transform="matrix(0.21391721,0,0,0.21391721,27.733834,-23.442344)"
r="34.345188"
cy="108.02044"
cx="291.42902"
id="path4136-76"
style="opacity:1;fill:#e69f00;fill-opacity:1;stroke:none;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4596-6)" />
<circle
transform="matrix(0.21391721,0,0,0.21391721,27.733834,-23.442344)"
r="34.345188"
cy="365.43817"
cx="290.41885"
id="path4136-6-0"
style="opacity:1;fill:#0072b2;fill-opacity:1;stroke:none;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4620-1)" />
<circle
transform="matrix(0.21391721,0,0,0.21391721,27.733834,-23.442344)"
r="34.345188"
cy="236.72931"
cx="422.24377"
id="path4136-3-9"
style="opacity:1;fill:#999999;fill-opacity:1;stroke:none;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4632-1)" />
<circle
transform="matrix(0.21391721,0,0,0.21391721,27.733834,-23.442344)"
r="34.345188"
cy="236.72931"
cx="155.56349"
id="path4136-7-0"
style="opacity:1;fill:#009e73;fill-opacity:1;stroke:none;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4608-0)" />
</g>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.7668047px;line-height:125%;font-family:'Latin Modern Mono Light';-inkscape-font-specification:'Latin Modern Mono Light, ';letter-spacing:0px;word-spacing:0px;fill:#252525;fill-opacity:0.70629368;stroke:none;stroke-width:1.09585059px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="229.96391"
y="1071.713"
id="text1392-1-3"
inkscape:export-xdpi="70.669998"
inkscape:export-ydpi="70.669998"><tspan
sodipodi:role="line"
id="tspan1390-1-6"
x="229.96391"
y="1071.713"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:62.0406723px;line-height:105.99999428%;font-family:'Latin Modern Mono Light';-inkscape-font-specification:'Latin Modern Mono Light, Bold';fill:#252525;fill-opacity:0.70629368;stroke-width:1.09585059px">speed up stencil </tspan><tspan
sodipodi:role="line"
x="229.96391"
y="1137.4761"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:62.0406723px;line-height:105.99999428%;font-family:'Latin Modern Mono Light';-inkscape-font-specification:'Latin Modern Mono Light, Bold';fill:#252525;fill-opacity:0.70629368;stroke-width:1.09585059px"
id="tspan109">computations on</tspan><tspan
sodipodi:role="line"
x="229.96391"
y="1203.2393"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:62.0406723px;line-height:105.99999428%;font-family:'Latin Modern Mono Light';-inkscape-font-specification:'Latin Modern Mono Light, Bold';fill:#252525;fill-opacity:0.70629368;stroke-width:1.09585059px"
id="tspan107">numpy arrays</tspan></text>
</g>
</svg>
doc/img/logo_no_text.png

5.42 KiB

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="127.52666mm"
height="154.66043mm"
viewBox="0 0 451.86614 548.0094"
id="svg5381"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="arch_pystencils.svg">
<defs
id="defs5383">
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker4320"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
id="path4322"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="marker4274"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
inkscape:connector-curvature="0"
id="path4276"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker4549-8-0-1"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
id="path4551-4-3-0"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker4549-8-0"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
id="path4551-4-3"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker4549-8"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
id="path4551-4"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="296.09126"
inkscape:cy="379.58263"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="10"
fit-margin-left="10"
fit-margin-right="10"
fit-margin-bottom="10"
inkscape:window-width="2560"
inkscape:window-height="1403"
inkscape:window-x="4480"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata5386">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(48.790215,-76.703997)">
<rect
y="207.86151"
x="-12.857142"
height="300.71426"
width="380"
id="rect3338-2"
style="opacity:0.403;fill:#52a5ff;fill-opacity:0.65625;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<text
sodipodi:linespacing="125%"
id="text4140-7"
y="246.44052"
x="89.340813"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:27.5px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold'"
y="246.44052"
x="89.340813"
id="tspan4142-0"
sodipodi:role="line">pystencils</tspan></text>
<text
sodipodi:linespacing="125%"
id="text5052"
y="392.14828"
x="132.17844"
style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="392.14828"
x="132.17844"
id="tspan5054"
sodipodi:role="line">Backends</tspan></text>
<text
inkscape:transform-center-y="22.223356"
inkscape:transform-center-x="-30.809653"
sodipodi:linespacing="125%"
id="text5052-7"
y="277.12802"
x="15.323049"
style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="277.12802"
x="15.323049"
id="tspan5054-5"
sodipodi:role="line">Transformations</tspan></text>
<text
inkscape:transform-center-y="22.223356"
inkscape:transform-center-x="-30.809653"
sodipodi:linespacing="125%"
id="text5052-7-9"
y="276.52139"
x="190.22662"
style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="276.52139"
x="190.22662"
id="tspan5054-5-2"
sodipodi:role="line">Abstract Syntax Tree</tspan></text>
<g
transform="translate(-152.85714,-230.5007)"
id="g5211">
<rect
style="opacity:0.95800003;fill:#528cff;fill-opacity:1;stroke:#000000;stroke-width:0.81148541;stroke-opacity:1"
id="rect5100"
width="56.803982"
height="28.401972"
x="208.96922"
y="638.3288"
ry="11.536892"
rx="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:12.17228222px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="218.23126"
y="657.38635"
id="text5102"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5104"
x="218.23126"
y="657.38635">C(++)</tspan></text>
</g>
<g
transform="translate(-152.85714,-230.5007)"
id="g5221">
<rect
style="opacity:0.95800003;fill:#528cff;fill-opacity:1;stroke:#000000;stroke-width:0.81148541;stroke-opacity:1"
id="rect5100-2"
width="56.803982"
height="28.401972"
x="377.63678"
y="638.73236"
ry="11.536892"
rx="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:12.17228222px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="390.89883"
y="657.78992"
id="text5102-8"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5104-9"
x="390.89883"
y="657.78992">LLVM</tspan></text>
</g>
<g
transform="translate(-146.85714,-230.5007)"
id="g5226">
<rect
style="opacity:0.95800003;fill:#4cd9fc;fill-opacity:1;stroke:#000000;stroke-width:0.81148541;stroke-opacity:1"
id="rect5100-7"
width="87.969879"
height="26.406517"
x="159.02757"
y="698.0166"
ry="11.536892"
rx="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="169.97716"
y="715.43323"
id="text5142"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5144"
x="169.97716"
y="715.43323">Python JIT</tspan></text>
</g>
<g
transform="translate(-146.85714,-230.5007)"
id="g5236">
<rect
style="opacity:0.95800003;fill:#4cd9fc;fill-opacity:1;stroke:#000000;stroke-width:0.81148541;stroke-opacity:1"
id="rect5100-7-3-2"
width="87.969879"
height="26.406517"
x="390.64432"
y="697.91504"
ry="11.536892"
rx="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="406.13959"
y="708.26062"
id="text5142-6-9"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="406.13959"
y="708.26062"
id="tspan5188"
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.75px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Italic'">C/C++ </tspan><tspan
sodipodi:role="line"
x="406.13959"
y="719.19812"
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.75px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Italic'"
id="tspan4368">output</tspan></text>
</g>
<g
transform="translate(-153.39138,-230.5007)"
id="g5216">
<rect
style="opacity:0.95800003;fill:#528cff;fill-opacity:1;stroke:#000000;stroke-width:0.81148541;stroke-opacity:1"
id="rect5100-2-1"
width="56.803982"
height="28.401972"
x="293.83725"
y="639.13593"
ry="11.536892"
rx="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:12.17228222px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="303.0993"
y="658.19348"
id="text5102-8-9"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5104-9-4"
x="303.0993"
y="658.19348">CUDA</tspan></text>
</g>
<g
transform="matrix(0.69960031,0,0,0.69960031,-114.02169,-104.98602)"
id="g4242">
<rect
style="opacity:0.95800003;fill:#c2b600;fill-opacity:1;stroke:#000000;stroke-width:0.81148541;stroke-opacity:1"
id="rect5100-8"
width="101.08154"
height="28.134911"
x="168.91846"
y="564.22729"
ry="11.536892"
rx="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:12.17228222px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="178.1805"
y="583.28485"
id="text5102-4"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5104-5"
x="178.1805"
y="583.28485">Array access</tspan></text>
</g>
<g
transform="matrix(0.69960031,0,0,0.69960031,-39.021686,-129.98602)"
id="g4247">
<rect
style="opacity:0.95800003;fill:#c2b600;fill-opacity:1;stroke:#000000;stroke-width:0.81148541;stroke-opacity:1"
id="rect5100-8-0"
width="101.08154"
height="28.134911"
x="170.2814"
y="599.48108"
ry="11.536892"
rx="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:12.17228222px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="177.54344"
y="618.53864"
id="text5102-4-3"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5104-5-6"
x="177.54344"
y="618.53864">Loop Splitting</tspan></text>
</g>
<g
transform="matrix(0.69960031,0,0,0.69960031,-196.87883,-96.77172)"
id="g4252">
<rect
style="opacity:0.95800003;fill:#c2b600;fill-opacity:1;stroke:#000000;stroke-width:0.81148541;stroke-opacity:1"
id="rect5100-8-0-3"
width="101.08154"
height="28.134911"
x="288.13855"
y="589.48108"
ry="11.536892"
rx="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:12.17228222px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="336.39984"
y="601.75293"
id="text5102-4-3-6"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5104-5-6-7"
x="336.39984"
y="601.75293"
style="font-size:10px;text-align:center;text-anchor:middle">Move Constants</tspan><tspan
sodipodi:role="line"
x="336.39984"
y="614.25293"
id="tspan4240"
style="font-size:10px;text-align:center;text-anchor:middle">before loop</tspan></text>
</g>
<g
transform="matrix(0.69960031,0,0,0.69960031,-38.970926,-103.97587)"
id="g4247-3">
<rect
style="opacity:0.95800003;fill:#c2b600;fill-opacity:1;stroke:#000000;stroke-width:0.81148541;stroke-opacity:1"
id="rect5100-8-0-6"
width="101.08154"
height="28.134911"
x="170.2814"
y="599.48108"
ry="11.536892"
rx="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:12.17228222px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="194.69612"
y="618.53864"
id="text5102-4-3-7"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5104-5-6-5"
x="194.69612"
y="618.53864">Blocking</tspan></text>
</g>
<g
transform="translate(-150.71428,-266.13054)"
id="g4281">
<rect
style="opacity:0.95800003;fill:#58ff93;fill-opacity:1;stroke:#000000;stroke-width:0.4340325;stroke-opacity:1"
id="rect5100-8-0-62"
width="42.102448"
height="16.517235"
x="392.89755"
y="555.84497"
ry="6.1706414"
rx="0" />
<g
id="g4277">
<text
sodipodi:linespacing="125%"
id="text5102-4-3-9"
y="566.74445"
x="403.47351"
style="font-style:normal;font-weight:normal;font-size:8.51573277px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="566.74445"
x="403.47351"
id="tspan5104-5-6-1"
sodipodi:role="line">Loop</tspan></text>
</g>
</g>
<g
transform="translate(-200.71428,-266.13054)"
id="g4281-2">
<rect
style="opacity:0.95800003;fill:#58ff93;fill-opacity:1;stroke:#000000;stroke-width:0.4340325;stroke-opacity:1"
id="rect5100-8-0-62-7"
width="42.102448"
height="16.517235"
x="392.89755"
y="555.84497"
ry="6.1706414"
rx="0" />
<g
transform="translate(-4,0)"
id="g4277-0">
<text
sodipodi:linespacing="125%"
id="text5102-4-3-9-9"
y="566.74445"
x="403.47351"
style="font-style:normal;font-weight:normal;font-size:8.51573277px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="566.74445"
x="403.47351"
id="tspan5104-5-6-1-3"
sodipodi:role="line">Kernel</tspan></text>
</g>
</g>
<g
transform="translate(-200.35714,-238.98768)"
id="g4281-1">
<rect
style="opacity:0.95800003;fill:#58ff93;fill-opacity:1;stroke:#000000;stroke-width:0.4340325;stroke-opacity:1"
id="rect5100-8-0-62-8"
width="42.102448"
height="16.517235"
x="392.89755"
y="555.84497"
ry="6.1706414"
rx="0" />
<g
transform="translate(-4,0)"
id="g4277-7">
<text
sodipodi:linespacing="125%"
id="text5102-4-3-9-92"
y="566.74445"
x="403.47351"
style="font-style:normal;font-weight:normal;font-size:8.51573277px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="566.74445"
x="403.47351"
id="tspan5104-5-6-1-0"
sodipodi:role="line">Assign</tspan></text>
</g>
</g>
<g
transform="translate(-99.910712,-266.13054)"
id="g4281-1-2">
<rect
style="opacity:0.95800003;fill:#58ff93;fill-opacity:1;stroke:#000000;stroke-width:0.4340325;stroke-opacity:1"
id="rect5100-8-0-62-8-3"
width="42.102448"
height="16.517235"
x="392.89755"
y="555.84497"
ry="6.1706414"
rx="0" />
<g
transform="translate(-1.4125983,0)"
id="g4277-7-7">
<text
sodipodi:linespacing="125%"
id="text5102-4-3-9-92-5"
y="566.74445"
x="407.47351"
style="font-style:normal;font-weight:normal;font-size:8.51573277px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="566.74445"
x="407.47351"
id="tspan5104-5-6-1-0-9"
sodipodi:role="line">Add</tspan></text>
</g>
</g>
<g
transform="translate(-109.73213,-238.09483)"
id="g4281-1-2-2">
<g
transform="translate(12.678571,1.0714286)"
id="g4413">
<rect
rx="0"
ry="6.1706414"
y="554.59497"
x="390.04041"
height="16.517235"
width="42.102448"
id="rect5100-8-0-62-8-3-2"
style="opacity:0.95800003;fill:#58ff93;fill-opacity:1;stroke:#000000;stroke-width:0.4340325;stroke-opacity:1" />
<g
id="g4277-7-7-8"
transform="translate(-4,0)">
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:8.51573277px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="407.47351"
y="566.74445"
id="text5102-4-3-9-92-5-9"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5104-5-6-1-0-9-7"
x="407.47351"
y="566.74445">Mul</tspan></text>
</g>
</g>
</g>
<rect
rx="0"
ry="6.1706414"
y="317.03586"
x="242.68098"
height="16.517235"
width="42.102448"
id="rect5100-8-0-62-8-3-2-1"
style="opacity:0.95800003;fill:#58ff93;fill-opacity:1;stroke:#000000;stroke-width:0.4340325;stroke-opacity:1" />
<g
id="g4277-7-7-8-2"
transform="translate(-156.36991,-238.42268)">
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:8.51573277px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="420.12903"
y="566.74445"
id="text5102-4-3-9-92-5-9-9"
sodipodi:linespacing="125%"><tspan
style="font-size:8.12500095px;text-align:center;text-anchor:middle"
sodipodi:role="line"
id="tspan5104-5-6-1-0-9-7-3"
x="420.12903"
y="566.74445">Condition</tspan></text>
</g>
<text
transform="matrix(-0.00884296,0.9999609,-0.9999609,-0.00884296,0,0)"
sodipodi:linespacing="125%"
id="text4449-1"
y="-78.824646"
x="338.3754"
style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="-78.824646"
x="338.3754"
id="tspan4451-9"
sodipodi:role="line">...</tspan></text>
<text
transform="matrix(-0.00884296,0.9999609,-0.9999609,-0.00884296,0,0)"
sodipodi:linespacing="125%"
id="text4449-4"
y="-273.88837"
x="336.65042"
style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="-273.88837"
x="336.65042"
id="tspan4451-7"
sodipodi:role="line">...</tspan></text>
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path4175-5"
d="m 167.69728,153.37762 1e-5,53.57142"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4549-8-0-1)" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path4175-5-6"
d="m 67.285707,509.45149 1e-5,53.57142"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker4274)" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path4175-5-6-6"
d="M 292.99999,509.16577 293,562.73719"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker4320)" />
<text
sodipodi:linespacing="125%"
id="text4542"
y="125.43295"
x="169.46426"
style="font-style:normal;font-weight:normal;font-size:20px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="font-size:17.5px;text-align:center;text-anchor:middle"
y="125.43295"
x="169.46426"
id="tspan4544"
sodipodi:role="line"><tspan
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Italic'"
id="tspan4254">sympy</tspan> Equations containing</tspan><tspan
id="tspan4564"
style="font-size:17.5px;text-align:center;text-anchor:middle"
y="147.30795"
x="169.46426"
sodipodi:role="line">fields (neighbor accesses)</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4542-3"
y="585.6402"
x="20.557117"
style="font-style:normal;font-weight:normal;font-size:20px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
id="tspan4570"
style="font-size:17.5px"
y="585.6402"
x="20.557117"
sodipodi:role="line">Python Function</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4542-3-0"
y="585.24951"
x="239.9693"
style="font-style:normal;font-weight:normal;font-size:20px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
id="tspan4570-6"
style="font-size:17.5px"
y="585.24951"
x="239.9693"
sodipodi:role="line">C/C++ Code</tspan></text>
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="46.566666mm"
height="46.566666mm"
viewBox="0 0 165 164.99999"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:export-filename="/home/rzlin/im50ibaq/stencil2.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
sodipodi:docname="pystencils_stencil_four_points_with_arrows.svg">
<defs
id="defs4">
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="marker10934"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path10936"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:0.66666667"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="marker10780"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path10782"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:0.66666667"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="marker10770"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path10772"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:0.66666667"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker10604"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutL">
<path
transform="scale(0.8,0.8)"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:1pt;stroke-opacity:0.66666667"
d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
id="path10606"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker10462"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutL">
<path
transform="scale(0.8,0.8)"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:1pt;stroke-opacity:0.66666667"
d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
id="path10464"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker10452"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutL">
<path
transform="scale(0.8,0.8)"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:1pt;stroke-opacity:0.66666667"
d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
id="path10454"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker10174"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutL">
<path
transform="scale(0.8,0.8)"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:1pt;stroke-opacity:0.66666667"
d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
id="path10176"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker10050"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutL">
<path
transform="scale(0.8,0.8)"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:1pt;stroke-opacity:0.66666667"
d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
id="path10052"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker10040"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutL">
<path
transform="scale(0.8,0.8)"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:1pt;stroke-opacity:0.66666667"
d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
id="path10042"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9800"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lend"
inkscape:collect="always">
<path
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:0.66666667"
id="path9802"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9694"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lend">
<path
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:0.66666667"
id="path9696"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9684"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lend">
<path
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:0.66666667"
id="path9686"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9478"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lend">
<path
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:0.66666667"
id="path9480"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9390"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lend">
<path
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:0.66666667"
id="path9392"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker9308"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lend">
<path
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:0.66666667"
id="path9310"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="marker9074"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9076"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:0.66666667"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="marker9064"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9066"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:0.66666667"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="marker8994"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8996"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:0.66666667"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8816"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lend">
<path
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:0.66666667"
id="path8818"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8748"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lend">
<path
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:0.66666667"
id="path8750"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8640"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lstart">
<path
transform="matrix(0.8,0,0,0.8,10,0)"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:1pt;stroke-opacity:0.66666667"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
id="path8642"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8600"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lstart">
<path
transform="matrix(0.8,0,0,0.8,10,0)"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:1pt;stroke-opacity:0.66666667"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
id="path8602"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8566"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lstart">
<path
transform="matrix(0.8,0,0,0.8,10,0)"
style="fill:#aa0a00;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:1pt;stroke-opacity:0.66666667"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
id="path8568"
inkscape:connector-curvature="0" />
</marker>
<inkscape:path-effect
effect="construct_grid"
id="path-effect4531"
is_visible="true"
nr_x="5"
nr_y="5" />
<inkscape:path-effect
effect="construct_grid"
id="path-effect4511"
is_visible="true"
nr_x="5"
nr_y="5" />
<marker
inkscape:stockid="DotL"
orient="auto"
refY="0"
refX="0"
id="DotL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4221"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
transform="matrix(0.8,0,0,0.8,5.92,0.8)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4160"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
transform="matrix(0.8,0,0,0.8,10,0)"
inkscape:connector-curvature="0" />
</marker>
<linearGradient
id="linearGradient4146"
osb:paint="solid">
<stop
style="stop-color:#0000ff;stop-opacity:1;"
offset="0"
id="stop4148" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4"
inkscape:cx="76.245019"
inkscape:cy="-167.05185"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:window-width="2560"
inkscape:window-height="1371"
inkscape:window-x="1920"
inkscape:window-y="0"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0">
<inkscape:grid
type="xygrid"
id="grid3342"
originx="-49.99998"
originy="-804.99994" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-49.999981,-82.36222)">
<path
style="fill:#a70000;fill-opacity:0;stroke:#000000;stroke-width:0.36029893;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:"
d="m 214.81983,82.542339 -164.6397,0 m 164.6397,32.927941 -164.6397,0 m 164.6397,32.92794 -164.6397,0 m 164.6397,32.92794 -164.6397,0 m 164.6397,32.92794 -164.6397,0 m 164.6397,32.92794 -164.6397,0 m 164.6397,-164.639701 0,164.639701 m -32.92794,-164.639701 0,164.639701 m -32.92794,-164.639701 0,164.639701 m -32.92794,-164.639701 0,164.639701 M 83.10807,82.542339 l 0,164.639701 M 50.18013,82.542339 l 0,164.639701"
id="rect4513"
inkscape:path-effect="#path-effect4531"
inkscape:original-d="m 181.89189,82.542339 32.92794,0 0,32.927941 -32.92794,0 z"
inkscape:connector-curvature="0" />
<g
id="g11964"
transform="matrix(0.27499997,0,0,0.27499997,69.249999,59.71259)"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<g
id="g8533">
<circle
style="fill:#0f00aa;fill-opacity:0.66666667;stroke:#000000;stroke-width:1.37272894;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path8465"
cx="230"
cy="262.36221"
r="19.813635" />
<circle
style="fill:#aa0a00;fill-opacity:0.66666667;stroke:#000000;stroke-width:1.37272894;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path8465-6"
cx="230"
cy="142.36221"
r="19.813635" />
<circle
style="fill:#aa0a00;fill-opacity:0.66666667;stroke:#000000;stroke-width:1.37272894;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path8465-5"
cx="110"
cy="262.36221"
r="19.813635" />
<circle
style="fill:#aa0a00;fill-opacity:0.66666667;stroke:#000000;stroke-width:1.37272894;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path8465-7-3"
cx="349.99997"
cy="262.36221"
r="19.813635" />
<circle
style="fill:#aa0a00;fill-opacity:0.66666667;stroke:#000000;stroke-width:1.37272894;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path8465-7-2"
cx="230"
cy="382.36221"
r="19.813635" />
</g>
<path
inkscape:connector-curvature="0"
inkscape:connector-type="polyline"
id="path8546"
d="m 130,262.3622 80,0"
style="fill:none;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:3.0999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.66666667;marker-end:url(#marker10934)" />
<path
inkscape:connector-curvature="0"
inkscape:connector-type="polyline"
id="path8548"
d="m 230,362.3622 0,-80"
style="fill:none;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:3.0999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.66666667;marker-end:url(#marker9800)" />
<path
inkscape:connector-curvature="0"
inkscape:connector-type="polyline"
id="path8550"
d="m 330,262.3622 -80,0"
style="fill:none;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:3.0999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.66666667;marker-end:url(#marker10770)" />
<path
inkscape:connector-curvature="0"
inkscape:connector-type="polyline"
id="path8552"
d="m 230,162.3622 0,80"
style="fill:none;fill-opacity:0.66666667;fill-rule:evenodd;stroke:#aa0a00;stroke-width:3.0999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.66666667;marker-end:url(#marker10780)" />
</g>
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128.62013mm"
height="127.02013mm"
viewBox="0 0 128.62013 127.02013"
version="1.1"
id="svg8"
sodipodi:docname="staggeredgrid.svg"
inkscape:version="0.91 r13725"
inkscape:export-filename="/home/rzlin/spmabau2/PaperAndDoc/diss/img/staggeredgrid.png"
inkscape:export-xdpi="751.59003"
inkscape:export-ydpi="751.59003">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8"
inkscape:cx="109.09973"
inkscape:cy="179.8226"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="2560"
inkscape:window-height="1371"
inkscape:window-x="1920"
inkscape:window-y="0"
inkscape:window-maximized="1"
fit-margin-top="0.2"
fit-margin-left="1"
fit-margin-right="1"
fit-margin-bottom="0.2">
<inkscape:grid
type="xygrid"
id="grid4485"
originx="-16.991665"
originy="-148.39503" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-16.991667,-21.584832)">
<g
id="g4832"
transform="matrix(0.8,0,0,0.8,3.6776666,9.6848334)"
inkscape:label="Grid"
inkscape:groupmode="layer">
<g
id="g4800"
inkscape:groupmode="layer"
inkscape:label="InnerPart">
<path
style="fill:none;stroke:#000000;stroke-width:1.23914683px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 51.813899,46.542736 92.936021,0"
id="path4487"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1.23914683px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 51.813904,77.521413 92.936016,0"
id="path4487-3"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1.23914683px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 51.813904,108.50008 92.936016,0"
id="path4487-3-6"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1.23914683px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 51.813904,139.47875 92.936016,0"
id="path4487-3-6-7"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1.23914683px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 51.813904,46.542736 0,92.936014"
id="path4487-3-5"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1.23914683px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 82.792576,46.542736 0,92.936014"
id="path4487-3-5-3"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1.23914683px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 113.77125,46.542736 0,92.936014"
id="path4487-3-5-3-5"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1.23914683px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 144.74992,46.542736 0,92.936014"
id="path4487-3-5-3-6"
inkscape:connector-curvature="0" />
</g>
<g
id="g4790"
inkscape:label="GhostLayers"
inkscape:groupmode="layer">
<path
style="fill:none;stroke:#000000;stroke-width:0.87813562;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.58823529"
d="m 20.83523,170.45743 154.89336,0"
id="path4585"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.87813562;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.58823529"
d="m 20.83523,15.564066 154.89336,0"
id="path4585-2"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.87813562;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.58823529"
d="m 175.72859,15.564066 0,154.893364"
id="path4585-2-9"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.87813562;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.58823529"
d="m 20.83523,15.564066 0,154.893364"
id="path4585-2-9-1"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.87813562;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.58823529"
d="m 51.813904,139.47875 0,30.97868"
id="path4585-2-9-1-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.87813562;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.58823529"
d="m 51.813904,15.564062 0,30.978674"
id="path4585-2-9-1-2-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.87813562;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.58823529"
d="m 144.74992,15.564066 0,30.978675"
id="path4585-2-9-1-2-0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.87813562;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.58823529"
d="m 144.74992,139.47875 0,30.97868"
id="path4585-2-9-1-2-9"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.87813562;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.58823529"
d="m 113.77125,139.47875 0,30.97868"
id="path4585-2-9-1-2-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.87813562;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.58823529"
d="m 82.792576,139.47875 0,30.97868"
id="path4585-2-9-1-2-6"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.87813562;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.58823529"
d="m 82.792576,15.564062 0,30.978674"
id="path4585-2-9-1-2-06"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.87813562;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.58823529"
d="m 113.77125,15.564062 0,30.978674"
id="path4585-2-9-1-2-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.87813562;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.58823529"
d="m 175.72859,46.542736 -30.97867,0"
id="path4585-2-9-1-2-2-6"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.87813562;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.58823529"
d="m 175.72859,77.521413 -30.97867,0"
id="path4585-2-9-1-2-2-6-8"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.87813562;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.58823529"
d="m 175.72859,108.50008 -30.97867,0"
id="path4585-2-9-1-2-2-6-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.87813562;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.58823529"
d="m 175.72859,139.47875 -30.97867,0"
id="path4585-2-9-1-2-2-6-9"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.87813562;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.58823529"
d="m 51.813904,139.47875 -30.978674,0"
id="path4585-2-9-1-2-2-6-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.87813562;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.58823529"
d="m 51.813904,108.50008 -30.978674,0"
id="path4585-2-9-1-2-2-6-0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.87813562;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.58823529"
d="m 51.813904,77.521413 -30.978674,0"
id="path4585-2-9-1-2-2-6-23"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.87813562;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.58823529"
d="m 51.813904,46.542736 -30.978674,0"
id="path4585-2-9-1-2-2-6-75"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc"
inkscape:label="path4585-2-9-1-2-2-6-75" />
</g>
</g>
<g
id="g5504"
inkscape:label="StaggeredX"
transform="matrix(4.6833899,0,0,4.6833899,-66.27032,-80.242034)">
<g
inkscape:label="StaggeredX-Inner"
id="g5065">
<path
style="fill:none;stroke:#ff0000;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 23.283333,40.354167 1.058334,0"
id="path4834"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 23.283333,35.0625 1.058334,0"
id="path4834-9"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 23.283333,29.770833 1.058334,0"
id="path4834-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 28.574999,40.354167 1.058334,0"
id="path4834-28"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 28.574999,35.0625 1.058334,0"
id="path4834-9-9"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 28.574999,29.770833 1.058334,0"
id="path4834-2-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 33.866666,40.354167 1.058334,0"
id="path4834-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 33.866666,35.0625 1.058334,0"
id="path4834-9-6"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 33.866666,29.770833 1.058334,0"
id="path4834-2-1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
</g>
<g
inkscape:label="StaggeredX-GhostLayers"
id="g5035">
<path
style="fill:none;stroke:#ff0000;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 39.158333,40.354167 1.058334,0"
id="path4834-29"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 39.158333,35.0625 1.058334,0"
id="path4834-9-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 39.158333,29.770833 1.058334,0"
id="path4834-2-19"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 17.991667,40.354167 1.058334,0"
id="path4834-29-4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 17.991667,35.0625 1.058334,0"
id="path4834-9-3-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 17.991667,29.770833 1.058334,0"
id="path4834-2-19-8"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 17.991666,24.479167 1.058334,0"
id="path4834-29-4-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 23.283334,24.479167 1.058333,0"
id="path4834-29-4-0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 28.574999,24.479167 1.058334,0"
id="path4834-29-4-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 33.866666,24.479167 1.058334,0"
id="path4834-29-4-6"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 39.158333,24.479167 1.058334,0"
id="path4834-29-4-1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 17.991666,45.645833 1.058334,0"
id="path4834-29-4-5-0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 23.283334,45.645833 1.058333,0"
id="path4834-29-4-0-6"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 28.574999,45.645833 1.058334,0"
id="path4834-29-4-3-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 33.866666,45.645833 1.058334,0"
id="path4834-29-4-6-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 39.158333,45.645833 1.058334,0"
id="path4834-29-4-1-0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
</g>
</g>
<g
id="g5475"
inkscape:label="StaggeredY"
transform="matrix(4.6833899,0,0,4.6833899,-66.27032,-80.242034)">
<g
transform="matrix(0,1,-1,0,44.852085,12.572917)"
inkscape:label="StaggeredY-GhostLayers"
id="g5035-6">
<path
style="fill:none;stroke:#0081ff;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 35.189582,18.393752 1.058334,0"
id="path4834-29-1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 35.189582,13.102085 1.058334,0"
id="path4834-9-3-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 35.189582,7.8104186 1.058334,0"
id="path4834-2-19-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 14.022916,18.393752 1.058334,0"
id="path4834-29-4-4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 14.022916,13.102085 1.058334,0"
id="path4834-9-3-7-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 14.022916,7.8104186 1.058334,0"
id="path4834-2-19-8-6"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 14.022915,2.5187526 1.058334,0"
id="path4834-29-4-5-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 19.314583,2.5187526 1.058333,0"
id="path4834-29-4-0-69"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 24.606248,2.5187526 1.058334,0"
id="path4834-29-4-3-37"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 29.897915,2.5187526 1.058334,0"
id="path4834-29-4-6-4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 35.189582,2.5187526 1.058334,0"
id="path4834-29-4-1-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 14.022915,23.685418 1.058334,0"
id="path4834-29-4-5-0-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 19.314583,23.685418 1.058333,0"
id="path4834-29-4-0-6-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 24.606248,23.685418 1.058334,0"
id="path4834-29-4-3-3-4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 29.897915,23.685418 1.058334,0"
id="path4834-29-4-6-2-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.15000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.47058824"
d="m 35.189582,23.685418 1.058334,0"
id="path4834-29-4-1-0-4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
</g>
<g
transform="matrix(0,1,-1,0,43.529167,8.604167)"
inkscape:label="StaggeredY-Inner"
id="g5065-4">
<path
style="fill:none;stroke:#0081ff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 23.283333,17.070834 1.058334,0"
id="path4834-30"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 23.283333,11.779167 1.058334,0"
id="path4834-9-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 23.283333,6.4874997 1.058334,0"
id="path4834-2-8"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 28.574999,17.070834 1.058334,0"
id="path4834-28-6"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 28.574999,11.779167 1.058334,0"
id="path4834-9-9-8"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 28.574999,6.4874997 1.058334,0"
id="path4834-2-7-8"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 33.866666,17.070834 1.058334,0"
id="path4834-3-4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 33.866666,11.779167 1.058334,0"
id="path4834-9-6-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0081ff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 33.866666,6.4874997 1.058334,0"
id="path4834-2-1-1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
</g>
</g>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:19.82634926px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="53.159824"
y="110.05041"
id="text4360"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4362"
x="53.159824"
y="110.05041"
style="font-size:4.13048983px">(1,1)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:19.82634926px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="40.352985"
y="106.97871"
id="text4360-7"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4362-5"
x="40.352985"
y="106.97871"
style="font-size:4.13048983px;fill:#fa0000;fill-opacity:1">(1,1)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:19.82634926px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="65.253937"
y="106.74267"
id="text4360-7-3"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4362-5-5"
x="65.253937"
y="106.74267"
style="font-size:4.13048983px;fill:#fa0000;fill-opacity:1">(2,1)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:19.82634926px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="52.744442"
y="92.935028"
id="text4360-7-3-6"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4362-5-5-2"
x="52.744442"
y="92.935028"
style="font-size:4.13048983px;fill:#1543ff;fill-opacity:1">(1,2)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:19.82634926px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="52.98048"
y="127.67839"
id="text4360-7-3-6-9"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4362-5-5-2-1"
x="52.98048"
y="127.67839"
style="font-size:4.13048983px;fill:#1543ff;fill-opacity:1">(1,1)</tspan></text>
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="61.653625mm"
height="35.390694mm"
viewBox="0 0 218.45773 125.4001"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="walberla_blocks.svg">
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="4"
inkscape:cx="142.40869"
inkscape:cy="26.799911"
inkscape:document-units="px"
inkscape:current-layer="svg2"
showgrid="false"
inkscape:window-width="2560"
inkscape:window-height="1371"
inkscape:window-x="4480"
inkscape:window-y="0"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0">
<inkscape:grid
id="grid4136"
type="xygrid"
originx="48.362094"
originy="-864.69997" />
</sodipodi:namedview>
<defs
id="defs4">
<inkscape:path-effect
effect="spiro"
id="path-effect8294"
is_visible="true" />
</defs>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1"
transform="translate(48.362095,-62.262187)" />
<rect
style="opacity:1;fill:#94e2ff;fill-opacity:1;stroke:#000000;stroke-width:0.2;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect8324"
width="10"
height="10"
x="34.781345"
y="1.0154506"
inkscape:tile-cx="15"
inkscape:tile-cy="67.362183"
inkscape:tile-w="10.00001"
inkscape:tile-h="10.00001"
inkscape:tile-x0="9.999995"
inkscape:tile-y0="62.362178" />
<rect
style="opacity:1;fill:#c7c7c7;fill-opacity:1;stroke:#000000;stroke-width:0.30000001;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect8324-2"
width="10"
height="10"
x="34.711391"
y="15.813687"
inkscape:tile-cx="15"
inkscape:tile-cy="67.362183"
inkscape:tile-w="10.00001"
inkscape:tile-h="10.00001"
inkscape:tile-x0="9.999995"
inkscape:tile-y0="62.362178" />
<g
id="g8547"
transform="translate(103.18126,-62.262187)">
<use
style="fill:#ffabab;fill-opacity:1"
height="100%"
width="100%"
transform="translate(-24.781347,61.346736)"
id="use8326"
xlink:href="#rect8324"
inkscape:tiled-clone-of="#rect8324"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8328"
transform="translate(-24.781347,71.346746)"
xlink:href="#rect8324"
inkscape:tiled-clone-of="#rect8324"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8330"
transform="translate(-24.781347,81.346756)"
xlink:href="#rect8324"
inkscape:tiled-clone-of="#rect8324"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8332"
transform="translate(-24.781347,91.346766)"
xlink:href="#rect8324"
inkscape:tiled-clone-of="#rect8324"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8334"
transform="translate(-24.781347,101.34678)"
xlink:href="#rect8324"
inkscape:tiled-clone-of="#rect8324"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8336"
transform="translate(-24.781347,111.34679)"
xlink:href="#rect8324"
inkscape:tiled-clone-of="#rect8324"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8338"
transform="translate(-14.781337,61.346736)"
xlink:href="#rect8324"
inkscape:tiled-clone-of="#rect8324"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8348"
transform="translate(-14.781337,111.34679)"
xlink:href="#rect8324"
inkscape:tiled-clone-of="#rect8324"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8350"
transform="translate(-4.7813269,61.346736)"
xlink:href="#rect8324"
inkscape:tiled-clone-of="#rect8324"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8360"
transform="translate(-4.7813269,111.34679)"
xlink:href="#rect8324"
inkscape:tiled-clone-of="#rect8324"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8362"
transform="translate(5.2186831,61.346736)"
xlink:href="#rect8324"
inkscape:tiled-clone-of="#rect8324"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8372"
transform="translate(5.2186831,111.34679)"
xlink:href="#rect8324"
inkscape:tiled-clone-of="#rect8324"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8374"
transform="translate(15.218693,61.346736)"
xlink:href="#rect8324"
inkscape:tiled-clone-of="#rect8324"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8376"
transform="translate(15.218693,71.346746)"
xlink:href="#rect8324"
inkscape:tiled-clone-of="#rect8324"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8378"
transform="translate(15.218693,81.346756)"
xlink:href="#rect8324"
inkscape:tiled-clone-of="#rect8324"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8380"
transform="translate(15.218693,91.346766)"
xlink:href="#rect8324"
inkscape:tiled-clone-of="#rect8324"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8382"
transform="translate(15.218693,101.34678)"
xlink:href="#rect8324"
inkscape:tiled-clone-of="#rect8324"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8384"
transform="translate(15.218693,111.34679)"
xlink:href="#rect8324"
inkscape:tiled-clone-of="#rect8324"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(-14.711388,56.548511)"
id="use8409"
xlink:href="#rect8324-2"
inkscape:tiled-clone-of="#rect8324-2"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8411"
transform="translate(-14.711388,66.548522)"
xlink:href="#rect8324-2"
inkscape:tiled-clone-of="#rect8324-2"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8413"
transform="translate(-14.711388,76.548532)"
xlink:href="#rect8324-2"
inkscape:tiled-clone-of="#rect8324-2"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8415"
transform="translate(-14.711388,86.548542)"
xlink:href="#rect8324-2"
inkscape:tiled-clone-of="#rect8324-2"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8417"
transform="translate(-4.7113779,56.548512)"
xlink:href="#rect8324-2"
inkscape:tiled-clone-of="#rect8324-2"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8419"
transform="translate(-4.7113779,66.548522)"
xlink:href="#rect8324-2"
inkscape:tiled-clone-of="#rect8324-2"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8421"
transform="translate(-4.7113779,76.548532)"
xlink:href="#rect8324-2"
inkscape:tiled-clone-of="#rect8324-2"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8423"
transform="translate(-4.7113779,86.548542)"
xlink:href="#rect8324-2"
inkscape:tiled-clone-of="#rect8324-2"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8425"
transform="translate(5.2886321,56.548512)"
xlink:href="#rect8324-2"
inkscape:tiled-clone-of="#rect8324-2"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8427"
transform="translate(5.2886321,66.548522)"
xlink:href="#rect8324-2"
inkscape:tiled-clone-of="#rect8324-2"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8429"
transform="translate(5.2886321,76.548532)"
xlink:href="#rect8324-2"
inkscape:tiled-clone-of="#rect8324-2"
y="0"
x="0" />
<use
height="100%"
width="100%"
id="use8431"
transform="translate(5.2886321,86.548542)"
xlink:href="#rect8324-2"
inkscape:tiled-clone-of="#rect8324-2"
y="0"
x="0" />
</g>
<g
id="g8515"
transform="translate(-16.289736,2.5590552)">
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8433"
xlink:href="#use8326"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8435"
xlink:href="#use8328"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8437"
xlink:href="#use8330"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8439"
xlink:href="#use8332"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8441"
xlink:href="#use8334"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8443"
xlink:href="#use8336"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8445"
xlink:href="#use8338"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8447"
xlink:href="#use8348"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8449"
xlink:href="#use8350"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8451"
xlink:href="#use8360"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8453"
xlink:href="#use8362"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8455"
xlink:href="#use8372"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8457"
xlink:href="#use8374"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8459"
xlink:href="#use8376"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8461"
xlink:href="#use8378"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8463"
xlink:href="#use8380"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8465"
xlink:href="#use8382"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8467"
xlink:href="#use8384"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8469"
xlink:href="#use8409"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8471"
xlink:href="#use8411"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8473"
xlink:href="#use8413"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8475"
xlink:href="#use8415"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8477"
xlink:href="#use8417"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8479"
xlink:href="#use8419"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8481"
xlink:href="#use8421"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8483"
xlink:href="#use8423"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8485"
xlink:href="#use8425"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8487"
xlink:href="#use8427"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8489"
xlink:href="#use8429"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8491"
xlink:href="#use8431"
y="0"
x="0" />
</g>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:7.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-0.28076172"
y="6.4571352"
id="text8493"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan8495"
x="-0.28076172"
y="6.4571352"
style="font-size:5px">Ghost Layer</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:7.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="14.469238"
y="22.653563"
id="text8493-7"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan8495-0"
x="14.469238"
y="22.653563"
style="font-size:5px">Inner</tspan></text>
<g
transform="translate(-16.289736,-62.640994)"
id="g8579">
<use
x="0"
y="0"
xlink:href="#use8326"
id="use8581"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8328"
id="use8583"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8330"
id="use8585"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8332"
id="use8587"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8334"
id="use8589"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8336"
id="use8591"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8338"
id="use8593"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8348"
id="use8595"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8350"
id="use8597"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8360"
id="use8599"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8362"
id="use8601"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8372"
id="use8603"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8374"
id="use8605"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8376"
id="use8607"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8378"
id="use8609"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8380"
id="use8611"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8382"
id="use8613"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8384"
id="use8615"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8409"
id="use8617"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8411"
id="use8619"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8413"
id="use8621"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8415"
id="use8623"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8417"
id="use8625"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8419"
id="use8627"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8421"
id="use8629"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8423"
id="use8631"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8425"
id="use8633"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8427"
id="use8635"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8429"
id="use8637"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use8431"
id="use8639"
transform="translate(64.270956,0.37880721)"
width="100%"
height="100%" />
</g>
<g
id="g8641"
transform="translate(38.910304,2.5590552)">
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8643"
xlink:href="#use8326"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8645"
xlink:href="#use8328"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8647"
xlink:href="#use8330"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8649"
xlink:href="#use8332"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8651"
xlink:href="#use8334"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8653"
xlink:href="#use8336"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8655"
xlink:href="#use8338"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8657"
xlink:href="#use8348"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8659"
xlink:href="#use8350"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8661"
xlink:href="#use8360"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8663"
xlink:href="#use8362"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8665"
xlink:href="#use8372"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8667"
xlink:href="#use8374"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8669"
xlink:href="#use8376"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8671"
xlink:href="#use8378"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8673"
xlink:href="#use8380"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8675"
xlink:href="#use8382"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8677"
xlink:href="#use8384"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8679"
xlink:href="#use8409"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8681"
xlink:href="#use8411"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8683"
xlink:href="#use8413"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8685"
xlink:href="#use8415"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8687"
xlink:href="#use8417"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8689"
xlink:href="#use8419"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8691"
xlink:href="#use8421"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8693"
xlink:href="#use8423"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8695"
xlink:href="#use8425"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8697"
xlink:href="#use8427"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8699"
xlink:href="#use8429"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="translate(64.270956,0.37880721)"
id="use8701"
xlink:href="#use8431"
y="0"
x="0" />
</g>
<use
x="0"
y="0"
xlink:href="#g8547"
id="use8808"
transform="translate(55.176426,1.5980072e-7)"
width="100%"
height="100%" />
</svg>