# Copyright 2014 Diamond Light Source Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
.. module:: data_additions
:platform: Unix
:synopsis: A module containing add_on classes, which have instances \
encapsulated within the Data class.
.. moduleauthor:: Nicola Wadeson <scientificsoftware@diamond.ac.uk>
"""
import savu.data.data_structures.data_notes as notes
from savu.core.utils import docstring_parameter
[docs]class Padding(object):
""" A class that organises padding of the data. An instance of Padding can
be associated with a Data object in a plugin that inherits from BaseFilter,
inside :meth:`savu.plugins.base_filter.BaseFilter.set_filter_padding`
"""
def __init__(self, pData):
self._pData = pData
self.mtp = pData._get_max_frames_process()
self.padding_dirs = {}
self.pad_dict = None
self.dims = None
self.pattern_name = list(pData.get_pattern().keys())[0]
self.pattern = pData.get_pattern()[self.pattern_name]
self.dims = self.__set_dims()
self.mode = 'edge'
def __set_dims(self):
dims = []
core_dir = self.pattern['core_dims']
slice_dir = self.pattern['slice_dims']
for dim in range(len(core_dir + slice_dir)):
self.padding_dirs[dim] = {'before': 0, 'after': 0}
return dims
[docs] def pad_mode(self, mode):
self.mode = mode
[docs] def pad_frame_edges(self, padding):
""" Pad all the edges of a frame of data with the same pad amount
(i.e pad in the core dimensions).
:param int padding: The pad amount
"""
core_dirs = self.pattern['core_dims']
for core in core_dirs:
self._pad_direction(str(core) + '.' + str(padding))
[docs] def pad_multi_frames(self, padding):
""" Add extra frames before and after the current frame of data (i.e
pad in the fastest changing slice dimension).
:param int padding: The pad amount
"""
sdir = self.pattern['slice_dims'][0]
self._pad_direction(str(sdir) + '.' + str(padding))
[docs] @docstring_parameter(notes._padding.__doc__)
def pad_directions(self, pad_list):
""" Pad multiple, individually specified, dimensions.
:param list(dict) pad_list: A list of strings of the form 'dim.pad',\
'dim.after.pad' or 'dim.before.pad'
{0}
"""
for entry in pad_list:
self._pad_direction(entry)
@docstring_parameter(notes._padding.__doc__)
def _pad_direction(self, pad_str):
""" Pad the data in a specified dimension.
:param str pad_str: A string of the form 'dim.pad', 'dim.after.pad'\
or 'dim.before.pad'
{0}
"""
pad_vals = pad_str.split('.')
pplace = None
pad_place = ['before', 'after']
if len(pad_vals) == 3:
pdir, pplace, pval = pad_vals
remove = list(set(pad_place).difference(set([pplace])))[0]
pad_place.remove(remove)
else:
pdir, pval = pad_vals
pdir = int(pdir)
allowed_dims = \
self.pattern['core_dims'] + (self.pattern['slice_dims'][0],)
if pdir not in allowed_dims:
raise Exception('Only core and first slice dimensions, %s, can be '
'padded. I cannot pad data dim %s in this plugin.'
% (allowed_dims, str(pdir)))
else:
for p in pad_place:
self.padding_dirs[pdir][p] += int(pval)
def _get_padding_directions(self):
""" Get padding directions.
:returns: padding dictionary
:rtype: dict
"""
for key in list(self.padding_dirs.keys()):
if sum(self.padding_dirs[key].values()) == 0:
del self.padding_dirs[key]
return self.padding_dirs
def _get_plugin_padding_directions(self):
""" Get padding directions.
:returns: padding dictionary
:rtype: dict
"""
for key in list(self.padding_dirs.keys()):
if sum(self.padding_dirs[key].values()) == 0:
del self.padding_dirs[key]
return self.padding_dirs
[docs]class DataMapping(object):
""" A class providing helper functions to multi-modal loaders.
"""
def __init__(self):
self._is_tomo = None
self._is_map = None
self._motors = None
self._motor_type = None
self._axes = None
[docs] def set_motors(self, motors):
self.motors = motors
[docs] def get_motors(self):
return self.motors
[docs] def set_motor_type(self, motor_type):
self.motor_type = motor_type
[docs] def get_motor_type(self):
return self.motor_type
[docs] def set_axes(self, axes):
self.axes = axes
[docs] def get_axes(self):
return self.axes
[docs] def check_is_map(self, proj_dir):
pattern = []
if self._is_map:
ovs = []
for i in self.get_shape():
if i != proj_dir[0]:
if i != proj_dir[1]:
ovs.append(i)
pattern = \
{"PROJECTION", {'core_dims': proj_dir, 'slice_dims': ovs}}
return pattern
[docs] def check_is_tomo(self, proj_dir, rotation):
pattern = []
if self._is_tomo:
ovs = []
for i in self.get_shape():
if i != rotation:
if i != proj_dir[1]:
ovs.append(i)
pattern = {"SINOGRAM", {'core_dims': (rotation, proj_dir[-1]),
'slice_dims': ovs}}
return pattern