diff --git a/datahandling.py b/datahandling.py index dd6917be52a2abaa3fb25162bd3b354fb6a22dab..27e16abfdc6110a571b4fbc786576f21c0d9d9e0 100644 --- a/datahandling.py +++ b/datahandling.py @@ -4,7 +4,6 @@ from abc import ABC, abstractmethod, abstractproperty from collections import defaultdict from contextlib import contextmanager -from lbmpy.boundaries.periodicityhandling import PeriodicityHandling from lbmpy.stencils import getStencil from pystencils import Field, makeSlice from pystencils.parallel.blockiteration import BlockIterationInfo @@ -16,62 +15,6 @@ try: except ImportError: gpuarray = None - -class WalberlaFlagInterface: - def __init__(self, flagField): - self.flagField = flagField - - def registerFlag(self, flagName): - return self.flagField.registerFlag(flagName) - - def flag(self, flagName): - return self.flagField.flag(flagName) - - def flagName(self, flag): - return self.flagField.flagName(flag) - - @property - def flags(self): - return self.flagField.flags - - -class PythonFlagInterface: - def __init__(self): - self.nameToFlag = {} - self.flagToName = {} - self.nextFreeBit = 0 - - def registerFlag(self, flagName): - assert flagName not in self.nameToFlag - flag = 1 << self.nextFreeBit - self.nextFreeBit += 1 - self.flagToName[flag] = flagName - self.nameToFlag[flagName] = flag - return flag - - def flag(self, flagName): - return self.nameToFlag[flagName] - - def flagName(self, flag): - return self.flagToName[flag] - - @property - def flags(self): - return tuple(self.nameToFlag.keys()) - - -class FlagArray(np.ndarray): - def __new__(cls, inputArray, flagInterface): - obj = np.asarray(inputArray).view(cls) - obj.flagInterface = flagInterface - assert inputArray.dtype.kind in ('u', 'i'), "FlagArrays can only be created from integer arrays" - return obj - - def __array_finalize__(self, obj): - if obj is None: return - self.flagInterface = getattr(obj, 'flagInterface', None) - - class DataHandling(ABC): """ Manages the storage of arrays and maps them to a symbolic field. @@ -113,6 +56,12 @@ class DataHandling(ABC): :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 addLike(self, name, nameOfTemplateField, latexName=None, cpu=True, gpu=False): """ @@ -124,13 +73,6 @@ class DataHandling(ABC): :param gpu: see 'add' method """ - def addFlagArray(self, name, dtype=np.int32, latexName=None, ghostLayers=None): - """ - Adds a flag array (of integer type) where each bit is interpreted as a boolean - Flag arrays additionally store a mapping of name to bit nr, which is accessible as arr.flagInterface. - For parameter documentation see 'add()' function. - """ - @property @abstractmethod def fields(self): @@ -297,13 +239,10 @@ class SerialDataHandling(DataHandling): self.fields[name] = Field.createFixedSize(latexName, shape=kwargs['shape'], indexDimensions=indexDimensions, dtype=kwargs['dtype'], layout=kwargs['order']) - def addFlagArray(self, name, dtype=np.int32, latexName=None, ghostLayers=None): - self.add(name, 1, dtype, latexName, ghostLayers, layout='AoS', cpu=True, gpu=False) - self.cpuArrays[name] = FlagArray(self.cpuArrays[name], PythonFlagInterface()) + def hasData(self, name): + return name in self.fields def addLike(self, name, nameOfTemplateField, latexName=None, cpu=True, gpu=False): - if hasattr(self.fields[nameOfTemplateField], 'flagInterface'): - raise ValueError("addLike() does not work for flag arrays") self.add(name,latexName=latexName, cpu=cpu, gpu=gpu, **self._fieldInformation[nameOfTemplateField]) def access(self, name, sliceObj=None, outerGhostLayers='all', **kwargs): diff --git a/field.py b/field.py index c53ba6b57895940d9334f24348cb3edd5b7415fc..d545d15c8eb4852365a2a9ce88197f4dc26e0182 100644 --- a/field.py +++ b/field.py @@ -465,7 +465,7 @@ def layoutStringToTuple(layoutStr, dim): elif layoutStr == 'zyxf' or layoutStr == 'aos': assert dim <= 4 return tuple(reversed(range(dim - 1))) + (dim-1,) - elif layoutStr == 'f' or layoutStr == 'reverseNumpy': + elif layoutStr == 'f' or layoutStr == 'reversenumpy': return tuple(reversed(range(dim))) elif layoutStr == 'c' or layoutStr == 'numpy': return tuple(range(dim)) diff --git a/parallel/datahandling.py b/parallel/datahandling.py index 778d4ce782364e9d9269f057bb4a02f1f1006213..b6a8f2c2b75d6d510bba1ab5fc076fe881ff3cfc 100644 --- a/parallel/datahandling.py +++ b/parallel/datahandling.py @@ -1,6 +1,6 @@ import numpy as np from pystencils import Field, makeSlice -from pystencils.datahandling import DataHandling, FlagArray, WalberlaFlagInterface +from pystencils.datahandling import DataHandling from pystencils.parallel.blockiteration import slicedBlockIteration from pystencils.utils import DotDict import waLBerla as wlb @@ -42,14 +42,51 @@ class ParallelDataHandling(DataHandling): return self._fields def add(self, name, fSize=1, dtype=np.float64, latexName=None, ghostLayers=None, layout=None, cpu=True, gpu=False): - return self._add(name, fSize, dtype, latexName, ghostLayers, layout, cpu, gpu, flagField=False) + if ghostLayers is None: + ghostLayers = self.defaultGhostLayers + if layout is None: + layout = self.defaultLayout + if latexName is None: + latexName = name + if len(self.blocks) == 0: + raise ValueError("Data handling expects that each process has at least one block") + if hasattr(dtype, 'type'): + dtype = dtype.type + if name in self.blocks[0] or self.GPU_DATA_PREFIX + name in self.blocks[0]: + raise ValueError("Data with this name has already been added") - def addLike(self, name, nameOfTemplateField, latexName=None, cpu=True, gpu=False): - assert not self._fieldInformation[nameOfTemplateField]['flagField'] - self._add(name,latexName=latexName, cpu=cpu, gpu=gpu, **self._fieldInformation[nameOfTemplateField]) + self._fieldInformation[name] = {'ghostLayers': ghostLayers, + 'fSize': fSize, + 'layout': layout, + 'dtype': dtype} - def addFlagArray(self, name, dtype=np.int32, latexName=None, ghostLayers=None): - return self._add(name, dtype=dtype, latexName=latexName, ghostLayers=ghostLayers, flagField=True) + layoutMap = {'fzyx': wlb.field.Layout.fzyx, 'zyxf': wlb.field.Layout.zyxf, + 'SoA': wlb.field.Layout.fzyx, 'AoS': wlb.field.Layout.zyxf} + + if cpu: + wlb.field.addToStorage(self.blocks, name, dtype, fSize=fSize, layout=layoutMap[layout], + ghostLayers=ghostLayers) + if gpu: + wlb.cuda.addGpuFieldToStorage(self.blocks, self.GPU_DATA_PREFIX+name, dtype, fSize=fSize, + usePitchedMem=False, ghostLayers=ghostLayers, layout=layoutMap[layout]) + + if cpu and gpu: + self._cpuGpuPairs.append((name, self.GPU_DATA_PREFIX + name)) + + blockBB = self.blocks.getBlockCellBB(self.blocks[0]) + shape = tuple(s + 2 * ghostLayers for s in blockBB.size) + indexDimensions = 1 if fSize > 1 else 0 + if indexDimensions == 1: + shape += (fSize, ) + + 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, indexDimensions, dtype, layout) + + def hasData(self, name): + return name in self._fields + + def addLike(self, name, nameOfTemplateField, latexName=None, cpu=True, gpu=False): + self.add(name,latexName=latexName, cpu=cpu, gpu=gpu, **self._fieldInformation[nameOfTemplateField]) def swap(self, name1, name2, gpu=False): if gpu: @@ -68,8 +105,6 @@ class ParallelDataHandling(DataHandling): for iterInfo in slicedBlockIteration(self.blocks, sliceObj, innerGhostLayers, outerGhostLayers): arr = wlb.field.toArray(iterInfo.block[name], withGhostLayers=innerGhostLayers)[iterInfo.localSlice] - if fieldInfo['flagField']: - arr = FlagArray(arr, WalberlaFlagInterface(iterInfo.block[name])) if self.fields[name].indexDimensions == 0: arr = arr[..., 0] if self.dim == 2: @@ -107,55 +142,6 @@ class ParallelDataHandling(DataHandling): def synchronizationFunctionGPU(self, names, stencil=None, buffered=True, **kwargs): return self._synchronizationFunction(names, stencil, buffered, 'gpu') - def _add(self, name, fSize=1, dtype=np.float64, latexName=None, ghostLayers=None, layout=None, - cpu=True, gpu=False, flagField=False): - if ghostLayers is None: - ghostLayers = self.defaultGhostLayers - if layout is None: - layout = self.defaultLayout - if latexName is None: - latexName = name - if len(self.blocks) == 0: - raise ValueError("Data handling expects that each process has at least one block") - if hasattr(dtype, 'type'): - dtype = dtype.type - if name in self.blocks[0] or self.GPU_DATA_PREFIX + name in self.blocks[0]: - raise ValueError("Data with this name has already been added") - - self._fieldInformation[name] = {'ghostLayers': ghostLayers, - 'fSize': fSize, - 'layout': layout, - 'dtype': dtype, - 'flagField': flagField} - - layoutMap = {'fzyx': wlb.field.Layout.fzyx, 'zyxf': wlb.field.Layout.zyxf, - 'SoA': wlb.field.Layout.fzyx, 'AoS': wlb.field.Layout.zyxf} - - if flagField: - assert not gpu - assert np.dtype(dtype).kind in ('u', 'i'), "FlagArrays can only be created from integer arrays" - nrOfBits = np.dtype(dtype).itemsize * 8 - wlb.field.addFlagFieldToStorage(self.blocks, name, nrOfBits, ghostLayers) - else: - if cpu: - wlb.field.addToStorage(self.blocks, name, dtype, fSize=fSize, layout=layoutMap[layout], - ghostLayers=ghostLayers) - if gpu: - wlb.cuda.addGpuFieldToStorage(self.blocks, self.GPU_DATA_PREFIX+name, dtype, fSize=fSize, - usePitchedMem=False, ghostLayers=ghostLayers, layout=layoutMap[layout]) - - if cpu and gpu: - self._cpuGpuPairs.append((name, self.GPU_DATA_PREFIX + name)) - - blockBB = self.blocks.getBlockCellBB(self.blocks[0]) - shape = tuple(s + 2 * ghostLayers for s in blockBB.size) - indexDimensions = 1 if fSize > 1 else 0 - if indexDimensions == 1: - shape += (fSize, ) - - 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, indexDimensions, dtype, layout) - def _synchronizationFunction(self, names, stencil, buffered, target): if stencil is None: stencil = 'D3Q27' if self.dim == 3 else 'D2Q9'