diff --git a/tests/test_rectilinear_grid.ref b/tests/test_rectilinear_grid.ref index 966e98b..3ba014f 100644 --- a/tests/test_rectilinear_grid.ref +++ b/tests/test_rectilinear_grid.ref @@ -1,19 +1,19 @@ - - MAAAAA==AAAAAAAAAACamZmZmZnJP5qZmZmZmdk/NDMzMzMz4z+amZmZmZnpPwAAAAAAAPA/ - KAAAAA==AAAAAAAAAAAAAAAAAADQPwAAAAAAAOA/AAAAAAAA6D8AAAAAAADwPw== - GAAAAA==AAAAAAAAAAAAAAAAAADgPwAAAAAAAPA/ - 0AIAAA==AAAAAAAAAACamZmZmZnJP5qZmZmZmdk/NDMzMzMz4z+amZmZmZnpPwAAAAAAAPA/AAAAAAAA0D+aZeZ6cH3UPwNyaj1RMN4/zczMzMzM5D/9we6sJdLqPwftr2YPfvA/AAAAAAAA4D9driDqhjvhP5pl5npwfeQ/7imlEij+6D8Dcmo9UTDuP6j0l5t34/E/AAAAAAAA6D8phlyzs9boPzMzMzMzM+s/Z5hZuCi87j+Sk0FanYvxPwAAAAAAAPQ/AAAAAAAA8D9fJqjlHVHwP12uIOqGO/E/tU8pPreo8j+aZeZ6cH30P807f2aeoPY/AAAAAAAA4D9driDqhjvhP5pl5npwfeQ/7imlEij+6D8Dcmo9UTDuP6j0l5t34/E/qPSXm3fj4T8AjUgDu//iP6Ak5qoR/+U/GHingvA96j/YI++yEjvvP4UeFbmOVPI/zTt/Zp6g5j84jqSx3YPnP0bzvVY2/+k/h/PrwfKs7T9I5O7MVBXxPy4hCRSOmPM/81lhRCvY7D9AUn/fv4vtP/YZ0yOTju8/DhOHeTtT8T+WlY67fEjzP/PZqKRoivU/qPSXm3fj8T8GBUdmKSzyPwCNSAO7//I/o2LOyT1N9D+gJOaqEf/1PwAAAAAAAPg/AAAAAAAA8D9fJqjlHVHwP12uIOqGO/E/tU8pPreo8j+aZeZ6cH30P807f2aeoPY/B+2vZg9+8D/NzMzMzMzwP5aVNxzQsPE/0Oci9j0V8z+DwEe+dOD0P/DQYqFu+vY/qPSXm3fj8T8GBUdmKSzyPwCNSAO7//I/o2LOyT1N9D+gJOaqEf/1PwAAAAAAAPg/AAAAAAAA9D/MidExH0H0P7kyVpXB//Q/ymwnJkcv9j83mjz8zL73PwD/n5nMnPk/zTt/Zp6g9j9xaVcXQtr2PziOpLHdg/c/40tJBGWU+D9G871WNv/5P6pMWOh6tvs/ 0AIAAA==AAAAAAAAAACamZmZmZnJP5qZmZmZmdk/NDMzMzMz4z+amZmZmZnpPwAAAAAAAPA/AAAAAAAA0D+aZeZ6cH3UPwNyaj1RMN4/zczMzMzM5D/9we6sJdLqPwftr2YPfvA/AAAAAAAA4D9driDqhjvhP5pl5npwfeQ/7imlEij+6D8Dcmo9UTDuP6j0l5t34/E/AAAAAAAA6D8phlyzs9boPzMzMzMzM+s/Z5hZuCi87j+Sk0FanYvxPwAAAAAAAPQ/AAAAAAAA8D9fJqjlHVHwP12uIOqGO/E/tU8pPreo8j+aZeZ6cH30P807f2aeoPY/AAAAAAAA4D9driDqhjvhP5pl5npwfeQ/7imlEij+6D8Dcmo9UTDuP6j0l5t34/E/qPSXm3fj4T8AjUgDu//iP6Ak5qoR/+U/GHingvA96j/YI++yEjvvP4UeFbmOVPI/zTt/Zp6g5j84jqSx3YPnP0bzvVY2/+k/h/PrwfKs7T9I5O7MVBXxPy4hCRSOmPM/81lhRCvY7D9AUn/fv4vtP/YZ0yOTju8/DhOHeTtT8T+WlY67fEjzP/PZqKRoivU/qPSXm3fj8T8GBUdmKSzyPwCNSAO7//I/o2LOyT1N9D+gJOaqEf/1PwAAAAAAAPg/AAAAAAAA8D9fJqjlHVHwP12uIOqGO/E/tU8pPreo8j+aZeZ6cH30P807f2aeoPY/B+2vZg9+8D/NzMzMzMzwP5aVNxzQsPE/0Oci9j0V8z+DwEe+dOD0P/DQYqFu+vY/qPSXm3fj8T8GBUdmKSzyPwCNSAO7//I/o2LOyT1N9D+gJOaqEf/1PwAAAAAAAPg/AAAAAAAA9D/MidExH0H0P7kyVpXB//Q/ymwnJkcv9j83mjz8zL73PwD/n5nMnPk/zTt/Zp6g9j9xaVcXQtr2PziOpLHdg/c/40tJBGWU+D9G871WNv/5P6pMWOh6tvs/ UBkAAA==AAAAAAAAAAAAAAAAAADwPwAAAAAAAAAAAAAAAAAA8D8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwPwAAAAAAAPA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8D8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + + MAAAAA==AAAAAAAAAACamZmZmZnJP5qZmZmZmdk/NDMzMzMz4z+amZmZmZnpPwAAAAAAAPA/ + KAAAAA==AAAAAAAAAAAAAAAAAADQPwAAAAAAAOA/AAAAAAAA6D8AAAAAAADwPw== + GAAAAA==AAAAAAAAAAAAAAAAAADgPwAAAAAAAPA/ + _ \ No newline at end of file diff --git a/tests/test_structured_grid.py b/tests/test_structured_grid.py new file mode 100644 index 0000000..be9fe53 --- /dev/null +++ b/tests/test_structured_grid.py @@ -0,0 +1,28 @@ +from uvw import StructuredGrid, DataArray +import numpy as np + +def test_structured_grid(): + N = 5 + + r = np.linspace(0, 1, N) + theta = np.linspace(0, 2*np.pi, 5*N) + + theta, r = np.meshgrid(theta, r, indexing='ij') + + x = r*np.cos(theta) + y = r*np.sin(theta) + + points = np.vstack([x.ravel(), y.ravel()]).T + + out_name = 'test_structured_grid.vts' + grid = StructuredGrid(out_name, points, (N, 5*N)) + + data = np.exp(-4*r**2) + + grid.addPointData(DataArray(data, reversed(range(2)), 'data')) + grid.write() + + output = open(out_name, 'r') + reference = open('test_structured_grid.ref', 'r') + + assert output.read() == reference.read() diff --git a/tests/test_structured_grid.ref b/tests/test_structured_grid.ref new file mode 100644 index 0000000..2d2ffc4 --- /dev/null +++ b/tests/test_structured_grid.ref @@ -0,0 +1,15 @@ + + + + + + 6AMAAA==AAAAAAAA8D8Lgqye7+voPzjvLDZWi9c/91eEjnH7uj/0PCG4VcGSPwAAAAAAAPA/C4Ksnu/r6D847yw2VovXP/dXhI5x+7o/9DwhuFXBkj8AAAAAAADwPwuCrJ7v6+g/OO8sNlaL1z/3V4SOcfu6P/Q8IbhVwZI/AAAAAAAA8D8Lgqye7+voPzjvLDZWi9c/91eEjnH7uj/0PCG4VcGSPwAAAAAAAPA/C4Ksnu/r6D847yw2VovXP/dXhI5x+7o/9DwhuFXBkj8AAAAAAADwPwuCrJ7v6+g/OO8sNlaL1z/3V4SOcfu6P/Q8IbhVwZI/AAAAAAAA8D8Lgqye7+voPzjvLDZWi9c/91eEjnH7uj/0PCG4VcGSPwAAAAAAAPA/C4Ksnu/r6D847yw2VovXP/dXhI5x+7o/9DwhuFXBkj8AAAAAAADwPwuCrJ7v6+g/OO8sNlaL1z/3V4SOcfu6P/Q8IbhVwZI/AAAAAAAA8D8Lgqye7+voPzjvLDZWi9c/91eEjnH7uj/0PCG4VcGSPwAAAAAAAPA/C4Ksnu/r6D847yw2VovXP/dXhI5x+7o/9DwhuFXBkj8AAAAAAADwPwuCrJ7v6+g/OO8sNlaL1z/3V4SOcfu6P/Q8IbhVwZI/AAAAAAAA8D8Lgqye7+voPzjvLDZWi9c/91eEjnH7uj/0PCG4VcGSPwAAAAAAAPA/C4Ksnu/r6D847yw2VovXP/dXhI5x+7o/9DwhuFXBkj8AAAAAAADwPwuCrJ7v6+g/OO8sNlaL1z/3V4SOcfu6P/Q8IbhVwZI/AAAAAAAA8D8Lgqye7+voPzjvLDZWi9c/91eEjnH7uj/0PCG4VcGSPwAAAAAAAPA/C4Ksnu/r6D847yw2VovXP/dXhI5x+7o/9DwhuFXBkj8AAAAAAADwPwuCrJ7v6+g/OO8sNlaL1z/3V4SOcfu6P/Q8IbhVwZI/AAAAAAAA8D8Lgqye7+voPzjvLDZWi9c/91eEjnH7uj/0PCG4VcGSPwAAAAAAAPA/C4Ksnu/r6D847yw2VovXP/dXhI5x+7o/9DwhuFXBkj8AAAAAAADwPwuCrJ7v6+g/OO8sNlaL1z/3V4SOcfu6P/Q8IbhVwZI/AAAAAAAA8D8Lgqye7+voPzjvLDZWi9c/91eEjnH7uj/0PCG4VcGSPwAAAAAAAPA/C4Ksnu/r6D847yw2VovXP/dXhI5x+7o/9DwhuFXBkj8AAAAAAADwPwuCrJ7v6+g/OO8sNlaL1z/3V4SOcfu6P/Q8IbhVwZI/AAAAAAAA8D8Lgqye7+voPzjvLDZWi9c/91eEjnH7uj/0PCG4VcGSPw== + + + + uAsAAA==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 + + + + _ + \ No newline at end of file diff --git a/uvw/__init__.py b/uvw/__init__.py index ce55293..5fc1545 100644 --- a/uvw/__init__.py +++ b/uvw/__init__.py @@ -1,2 +1,2 @@ -from .vtk_files import VTKFile, RectilinearGrid, ImageData +from .vtk_files import VTKFile, RectilinearGrid, ImageData, StructuredGrid from .data_array import DataArray diff --git a/uvw/vtk_files.py b/uvw/vtk_files.py index a6f0cc9..29b7d3e 100644 --- a/uvw/vtk_files.py +++ b/uvw/vtk_files.py @@ -1,99 +1,129 @@ from . import writer from . import data_array import functools import numpy as np + class VTKFile: """Generic VTK file""" def __init__(self, filename, filetype, rank=None): self.filename = filename self.rank = rank self.writer = writer.Writer(filetype) + # Center piece + self.piece = self.writer.registerPiece() + + # Registering data elements + self.point_data = self.piece.register('PointData') + self.cell_data = self.piece.register('CellData') + def addPointData(self, data_array): self.point_data.registerDataArray(data_array) def addCellData(self, data_array): self.cell_data.registerDataArray(data_array) def write(self): self.writer.registerAppend() self.writer.write(self.filename) class ImageData(VTKFile): """VTK Image data (coordinates are given by a range and constant spacing)""" def __init__(self, filename, ranges, points, rank=None): - VTKFile.__init__(self, filename, 'ImageData', rank) + VTKFile.__init__(self, filename, self.__class__.__name__, rank) # Computing spacings spacings = [(x[1] - x[0]) / (n - 1) for x, n in zip(ranges, points)] # Filling in missing coordinates for _ in range(len(points), 3): points.append(1) # Setting extents, spacings and origin extent = functools.reduce(lambda x, y: x + "0 {} ".format(y-1), points, "") spacings = functools.reduce(lambda x, y: x + "{} ".format(y), spacings, "") origins = functools.reduce(lambda x, y: x + "{} ".format(y[0]), ranges, "") self.writer.setDataNodeAttributes({ 'WholeExtent': extent, 'Spacing': spacings, 'Origin': origins }) - self.piece = self.writer.registerPiece({ + self.piece.setAttributes({ "Extent": extent }) - # Registering data elements - self.point_data = self.piece.register('PointData') - self.cell_data = self.piece.register('CellData') - class RectilinearGrid(VTKFile): """VTK Rectilinear grid (coordinates are given by 3 seperate ranges)""" def __init__(self, filename, coordinates, rank=None): - VTKFile.__init__(self, filename, 'RectilinearGrid', rank) + VTKFile.__init__(self, filename, self.__class__.__name__, rank) # Checking that we actually have a list or tuple if type(coordinates).__name__ == 'ndarray': coordinates = [coordinates] self.coordinates = list(coordinates) # Filling in missing coordinates for _ in range(len(self.coordinates), 3): self.coordinates.append(np.array([0.])) # Setting data extent extent = [] for coord in self.coordinates: if coord.ndim != 1: raise Exception('Coordinate array should have only one dimension') extent.append(coord.size-1) extent = functools.reduce(lambda x, y: x + "0 {} ".format(y), extent, "") self.writer.setDataNodeAttributes({ "WholeExtent": extent }) - self.piece = self.writer.registerPiece({ + self.piece.setAttributes({ "Extent": extent }) # Registering coordinates coordinate_component = self.piece.register('Coordinates') for coord, prefix in zip(self.coordinates, ('x', 'y', 'z')): array = data_array.DataArray(coord, [0], prefix + '_coordinates') coordinate_component.registerDataArray(array) - # Registering data elements - self.point_data = self.piece.register('PointData') - self.cell_data = self.piece.register('CellData') + +class StructuredGrid(VTKFile): + """VTK Structured grid (coordinates given by a single array of points)""" + def __init__(self, filename, points, shape, rank=None): + VTKFile.__init__(self, filename, self.__class__.__name__, rank) + + if points.ndim != 2: + raise 'Points should be a 2D array' + + # Completing the missing coordinates + points_3d = np.zeros((points.shape[0], 3)) + for i in range(points.shape[1]): + points_3d[:, i] = points[:, i] + + extent = [n - 1 for n in shape] + for i in range(len(extent), 3): + extent.append(0) + + extent = functools.reduce(lambda x, y: x + "0 {} ".format(y), extent, "") + self.writer.setDataNodeAttributes({ + "WholeExtent": extent + }) + + self.piece.setAttributes({ + "Extent": extent + }) + + points_component = self.piece.register('Points') + points_component.registerDataArray(data_array.DataArray(points_3d, [0], 'points')) diff --git a/uvw/writer.py b/uvw/writer.py index 5608269..471c0cb 100644 --- a/uvw/writer.py +++ b/uvw/writer.py @@ -1,105 +1,107 @@ import xml.dom import xml.dom.minidom as dom import functools import base64 import numpy as np def setAttributes(node, attributes): """Set attributes of a node""" for item in attributes.items(): node.setAttribute(*item) def encodeArray(array): # Mandatory number of bytes encoded as uint32 nbytes = array.nbytes bytes = base64.b64encode(np.array([nbytes], dtype=np.uint32)) bytes += base64.b64encode(array) return bytes class Component: """Generic component class capable of registering sub-components""" def __init__(self, name, parent_node, writer): self.writer = writer self.document = writer.document self.node = self.document.createElement(name) parent_node.appendChild(self.node) + def setAttributes(self, attributes): + setAttributes(self.node, attributes) def register(self, name, attributes=dict()): """Register a sub-component""" sub_component = Component(name, self.node, self.writer) setAttributes(sub_component.node, attributes) return sub_component def registerDataArray(self, data_array, vtk_format='binary'): """Register a DataArray object""" array_component = Component('DataArray', self.node, self.writer) attributes = data_array.attributes attributes['format'] = vtk_format if vtk_format == 'append': raise 'Feature does not work' attributes['offset'] = str(self.writer.offset) array = data_array.flat_data self.writer.offset += array.nbytes self.writer.offset += self.writer.size_indicator_bytes self.writer.append_data_arrays.append(data_array) elif vtk_format == 'ascii': data_as_str = functools.reduce(lambda x, y: x + str(y) + ' ', data_array.flat_data, "") array_component.node.appendChild(self.document.createTextNode(data_as_str)) elif vtk_format == 'binary': array_component.node.appendChild( self.document.createTextNode( encodeArray(data_array.flat_data).decode('ascii'))) setAttributes(array_component.node, attributes) class Writer: """Generic XML handler for VTK files""" def __init__(self, vtk_format, vtk_version='0.1', byte_order='LittleEndian'): self.document = dom.getDOMImplementation().createDocument(None, 'VTKFile', None) self.root = self.document.documentElement self.root.setAttribute('type', vtk_format) self.root.setAttribute('version', vtk_version) self.root.setAttribute('byte_order', byte_order) self.data_node = self.document.createElement(vtk_format) self.root.appendChild(self.data_node) self.offset = 0 # Global offset self.size_indicator_bytes = np.dtype(np.uint32).itemsize self.append_data_arrays = [] def setDataNodeAttributes(self, attributes): """Set attributes for the entire dataset""" setAttributes(self.data_node, attributes) - def registerPiece(self, attributes): + def registerPiece(self, attributes={}): """Register a piece element""" piece = Component('Piece', self.data_node, self) setAttributes(piece.node, attributes) return piece def registerAppend(self): append_node = Component('AppendedData', self.root, self) setAttributes(append_node.node, {'format': 'base64'}) self.root.appendChild(append_node.node) data_str = b"_" for data_array in self.append_data_arrays: data_str += encodeArray(data_array.flat_data) text = self.document.createTextNode(data_str.decode('ascii')) append_node.node.appendChild(text) def write(self, filename): with open(filename, 'w') as file: self.document.writexml(file, indent="\n ", addindent=" ") def __str__(self): """Print XML to string""" return self.document.toprettyxml()