Source code for xopto.mcml.mcsource.rectangular

# -*- coding: utf-8 -*-
################################ Begin license #################################
# Copyright (C) Laboratory of Imaging technologies,
#               Faculty of Electrical Engineering,
#               University of Ljubljana.
#
# This file is part of PyXOpto.
#
# PyXOpto is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# PyXOpto is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with PyXOpto. If not, see <https://www.gnu.org/licenses/>.
################################# End license ##################################

from typing import Tuple

import numpy as np

from xopto.mcml.mcsource.base import Source
from xopto.mcml import mcobject, mctypes, cltypes, mcoptions
from xopto.mcml.mcutil import boundary, geometry
from xopto.mcml.mcutil.lut import CollectionLut

[docs]class UniformRectangular(Source):
[docs] @staticmethod def cl_type(mc: mcobject.McObject) -> cltypes.Structure: T = mc.types class ClUniformRectangular(cltypes.Structure): ''' Structure that is passed to the Monte carlo simulator kernel. Fields ------ position: mc_point3f_t Source position (center of the source), size: mc_point2f_t Source size along the x and y axis. n: mc_fp_t Refractive index of the source. cos_critical: mc_fp_t Cosine of the total internal reflection angle for the source -> sample boundary transition. cos_min: mc_fp_t Cosine of the maximum emission angle in air. layer_index: mc_size_t Layer index in which the source is located. ''' _fields_ = [ ('position', T.mc_point3f_t), ('size', T.mc_point2f_t), ('n', T.mc_fp_t), ('cos_critical', T.mc_fp_t), ('cos_min', T.mc_fp_t), ('layer_index', T.mc_size_t), ] return ClUniformRectangular
[docs] @staticmethod def cl_declaration(mc: mcobject.McObject) -> str: ''' Structure that defines the source in the Monte Carlo simulator. ''' return '\n'.join(( 'struct MC_STRUCT_ATTRIBUTES McSource{', ' mc_point3f_t position;', ' mc_point2f_t size;', ' mc_fp_t n;', ' mc_fp_t cos_critical;', ' mc_fp_t cos_min;', ' mc_size_t layer_index;', '};' ))
[docs] @staticmethod def cl_implementation(mc: mcobject.McObject) -> str: ''' Implementation of the source in the Monte Carlo simulator. ''' return '\n'.join(( 'void dbg_print_source(__mc_source_mem const McSource *src){', ' dbg_print("UniformRectangular source:");', ' dbg_print_point3(INDENT "position:", &src->position);', ' dbg_print_point2f(INDENT "size:", &src->size);', ' dbg_print_float(INDENT "n:", src->n);', ' dbg_print_float(INDENT "cos_critical:", src->cos_critical);', ' dbg_print_float(INDENT "cos_min:", src->cos_min);', ' dbg_print_size_t(INDENT "layer_index:", src->layer_index);', '};', '', 'inline void mcsim_launch(McSim *mcsim){', '', ' mc_fp_t sin_fi, cos_fi, sin_theta, cos_theta;', ' mc_fp_t r;', ' __mc_source_mem const struct McSource *source = mcsim_source(mcsim);', '', ' mcsim_set_position_coordinates(', ' mcsim,', ' source->position.x + (mcsim_random(mcsim) - FP_0p5)*source->size.x,', ' source->position.y + (mcsim_random(mcsim) - FP_0p5)*source->size.y,', ' source->position.z', ' );', '', ' mc_sincos(mcsim_random(mcsim)*FP_2PI, &sin_fi, &cos_fi);', ' /* compute propagation direction in air, n_medium = 1 */', ' cos_theta = FP_1 - mcsim_random(mcsim)*(FP_1 - source->cos_min);', ' sin_theta = mc_sqrt(FP_1 - cos_theta*cos_theta);', ' /* adjust the emission angle for the refractive index of the medium */ ', ' sin_theta = mc_fdiv(sin_theta, ', ' mc_layer_n(mcsim_layer(mcsim, source->layer_index)));', ' cos_theta = mc_sqrt(FP_1 - sin_theta*sin_theta);' ' mcsim_set_direction_coordinates(', ' mcsim,', ' cos_fi*sin_theta,', ' sin_fi*sin_theta,', ' cos_theta', ' );', '', ' r = reflectance_cos2(', ' source->n, ', ' mc_layer_n(mcsim_layer(mcsim, source->layer_index)),', ' cos_theta', ' );', ' mcsim_set_weight(mcsim, FP_1 - r);', '', ' #if MC_USE_SPECULAR_DETECTOR', ' mc_point3f_t dir_in = {mcsim_direction_x(mcsim), ', ' mcsim_direction_y(mcsim), -mcsim_direction_z(mcsim)};', ' mc_point3f_t dir;', ' mc_point3f_t normal = {FP_0, FP_0, -FP_1};', ' refract(&dir_in, &normal, mc_layer_n(mcsim_layer(mcsim, 1)),', ' source->n, &dir);', ' mcsim_specular_detector_deposit(', ' mcsim, mcsim_position(mcsim), &dir, source->reflectance);', ' #endif', '', ' mcsim_set_current_layer_index(mcsim, source->layer_index);', '};', ))
def __init__(self, width: float, height: float, n: float, na: float, position: Tuple[float, float, float] = (0.0, 0.0, 0.0)): ''' A rectangular optical photon packet source with emission characteristics defined by the numerical aperture The propagation direction is internally adjusted according to the refractive index of the medium surrounding the source: sin(theta_lut) = n_medium*sin(theta_medium). The reflectance at the source-medium boundary is subtracted from the initial weight of the photon packet. Parameters ---------- width: float Source width (x) in (m). height: float Source height (y) in (m). n: float Refractive index of the source. na: float Numerical aperture of the source in air (emission is cut off at the NA). position: (float, float, float) Center of the source beam/rectangle as an array-like object of size 3 (px, py, pz). ''' Source.__init__(self) self._na = float(na) self._width = float(width) self._height = float(height) self._n = max(1.0, float(n)) self._position = np.zeros((3,)) self._set_position(position)
[docs] def update(self, other: 'UniformRectangular', dict): ''' Update this source configuration from the other source. The other source must be of the same type as this source or a dict with appropriate fields. Parameters ---------- other: UniformRectangular or dict This source is updated with the configuration of the other source. ''' if isinstance(other, UniformRectangular): self._na = other.na self.width = other.width self.height = other.height self.n = other.n self.position = other.position elif isinstance(other, dict): self.na = other.grt('na', self._na) self.width = other.get('width', self._width) self.height = other.get('height', self._height) self.n = other.get('n', self._n) self.position = other.get('position', self._position)
def _get_position(self) -> Tuple[float, float, float]: return self._position def _set_position(self, position: Tuple[float, float, float]): self._position[:] = position position = property(_get_position, _set_position, None, 'Source position.') def _get_width(self) -> float: return self._width def _set_width(self, width: float): self._width = float(width) width = property(_get_width, _set_width, None, 'Source width (m).') def _get_height(self) -> float: return self._height def _set_height(self, height: float): self._height = float(height) height = property(_get_height, _set_height, None, 'Source height (m).') def _get_n(self) -> float: return self._n def _set_n(self, n: float): self._n = max(1.0, float(n)) n = property(_get_n, _set_n, None, 'Source refractive index.') def _get_na(self) -> float: return self._na def _set_na(self, na: float): self._na = max(0.0, float(na)) na = property(_get_na, _set_na, None, 'Source numerical aperture (NA).')
[docs] def cl_pack(self, mc: mcobject.McObject, target: cltypes.Structure = None) \ -> Tuple[cltypes.Structure, None, None]: ''' Fills the structure (target) with the data required by the Monte Carlo simulator kernel. See the :py:meth:`RectangularLut.cl_type` method for a detailed list of fields. Parameters ---------- mc: mcobject.McObject Monte Carlo simulator instance. target: cltypes.Structure Structure that is filled with the source data. Returns ------- target: cltypes.Structure Filled ctypes structure received as an input argument or a new instance if the input argument target is None. topgeometry: None This source does not use advanced geometry at the top sample surface. bottomgeometry: None This source does not use advanced geometry at the bottom sample surface. ''' if target is None: target_type = self.cl_type(mc) target = target_type() if self._position[2] <= 0.0: position = (self._position[0], self._position[1], 0.0) layer_index = 1 else: position = self._position layer_index = mc.layer_index(self._position[2]) target.position.fromarray(position) target.size.fromarray([self._width, self._height]) target.n = self._n target.cos_critical = boundary.cos_critical( self._n, mc.layers[layer_index].n) target.cos_min = (1 - (self._na)**2)**0.5 target.layer_index = layer_index return target, None, None
[docs] def todict(self) -> dict: ''' Export object to a dict. ''' return {'width': self._width, 'height': self._height, 'n': self._n, 'na': self._na, 'position': self._position.tolist(), 'type': self.__class__.__name__}
def __str__(self): return 'UniformRectangular(width={}, height={}, n={}, na={},'\ 'position=({}, {}, {}))'.format( self._lut, self._width, self._height, self._n, self._na, *self._position)
[docs]class LambertianRectangular(UniformRectangular):
[docs] @staticmethod def cl_type(mc: mcobject.McObject) -> cltypes.Structure: T = mc.types class ClLambertianRectangular(cltypes.Structure): ''' Structure that is passed to the Monte carlo simulator kernel. Fields ------ position: mc_point3f_t Source position (center of the source), size: mc_point2f_t Source size along the x and y axis. n: mc_fp_t Refractive index of the source. cos_critical: mc_fp_t Cosine of the total internal reflection angle for the source -> sample boundary transition. na: mc_fp_t Numerical aperture of the source in air. layer_index: mc_size_t Layer index in which the source is located. ''' _fields_ = [ ('position', T.mc_point3f_t), ('size', T.mc_point2f_t), ('n', T.mc_fp_t), ('cos_critical', T.mc_fp_t), ('na', T.mc_fp_t), ('layer_index', T.mc_size_t), ] return ClLambertianRectangular
[docs] @staticmethod def cl_declaration(mc: mcobject.McObject) -> str: ''' Structure that defines the source in the Monte Carlo simulator. ''' return '\n'.join(( 'struct MC_STRUCT_ATTRIBUTES McSource{', ' mc_point3f_t position;', ' mc_point2f_t size;', ' mc_fp_t n;', ' mc_fp_t cos_critical;', ' mc_fp_t na;', ' mc_size_t layer_index;', '};' ))
[docs] @staticmethod def cl_implementation(mc: mcobject.McObject) -> str: ''' Implementation of the source in the Monte Carlo simulator. ''' return '\n'.join(( 'void dbg_print_source(__mc_source_mem const McSource *src){', ' dbg_print("LambertianRectangular source:");', ' dbg_print_point3(INDENT "position:", &src->position);', ' dbg_print_point2f(INDENT "size:", &src->size);', ' dbg_print_float(INDENT "n:", src->n);', ' dbg_print_float(INDENT "cos_critical:", src->cos_critical);', ' dbg_print_float(INDENT "na:", src->na);', ' dbg_print_size_t(INDENT "layer_index:", src->layer_index);', '};', '', 'inline void mcsim_launch(McSim *mcsim){', '', ' mc_fp_t sin_fi, cos_fi, sin_theta, cos_theta;', ' mc_fp_t r;', ' __mc_source_mem const struct McSource *source = mcsim_source(mcsim);', '', ' mcsim_set_position_coordinates(', ' mcsim,', ' source->position.x + (mcsim_random(mcsim) - FP_0p5)*source->size.x,', ' source->position.y + (mcsim_random(mcsim) - FP_0p5)*source->size.y,', ' source->position.z', ' );', '', ' mc_sincos(mcsim_random(mcsim)*FP_2PI, &sin_fi, &cos_fi);', ' /* compute propagation direction in air, n_medium = 1 */', ' sin_theta = mc_sqrt(mcsim_random(mcsim))*source->na;', ' /* Adjust the propagation direction to refractive index of the medium */', ' sin_theta = mc_fdiv(sin_theta, ', ' mc_layer_n(mcsim_layer(mcsim, source->layer_index)));', ' cos_theta = mc_sqrt(FP_1 - sin_theta*sin_theta);', '', ' mcsim_set_direction_coordinates(', ' mcsim,', ' cos_fi*sin_theta,', ' sin_fi*sin_theta,', ' cos_theta', ' );', '', ' r = reflectance_cos2(', ' source->n, ', ' mc_layer_n(mcsim_layer(mcsim, source->layer_index)),', ' cos_theta', ' );', ' mcsim_set_weight(mcsim, FP_1 - r);', '', ' #if MC_USE_SPECULAR_DETECTOR', ' mc_point3f_t dir_in = {mcsim_direction_x(mcsim), ', ' mcsim_direction_y(mcsim), -mcsim_direction_z(mcsim)};', ' mc_point3f_t dir;', ' mc_point3f_t normal = {FP_0, FP_0, -FP_1};', ' refract(&dir_in, &normal, mc_layer_n(mcsim_layer(mcsim, 1)),', ' source->n, &dir);', ' mcsim_specular_detector_deposit(', ' mcsim, mcsim_position(mcsim), &dir, source->reflectance);', ' #endif', '', ' mcsim_set_current_layer_index(mcsim, source->layer_index);', '};', ))
def __init__(self, width: float, height: float, n: float, na: float, position: Tuple[float, float, float] = (0.0, 0.0, 0.0)): ''' A rectangular optical photon packet source with a Lambertian emission characteristics defined by the numerical aperture. The propagation direction is internally adjusted according to the refractive index of the medium surrounding the source: sin(theta_lut) = n_medium*sin(theta_medium). The reflectance at the source-medium boundary is subtracted from the initial weight of the photon packet. Parameters ---------- width: float Source width (x) in (m). height: float Source height (y) in (m). n: float Refractive index of the source. na: float Numerical aperture of the source in air (emission is cut off at the NA). position: (float, float, float) Center of the source beam/rectangle as an array-like object of size 3 (px, py, pz). ''' Source.__init__(self) self._na = float(na) self._width = float(width) self._height = float(height) self._n = max(1.0, float(n)) self._position = np.zeros((3,)) self._set_position(position)
[docs] def cl_pack(self, mc: mcobject.McObject, target: cltypes.Structure = None) \ -> Tuple[cltypes.Structure, None, None]: ''' Fills the structure (target) with the data required by the Monte Carlo simulator kernel. See the :py:meth:`RectangularLut.cl_type` method for a detailed list of fields. Parameters ---------- mc: mcobject.McObject Monte Carlo simulator instance. target: cltypes.Structure Structure that is filled with the source data. Returns ------- target: cltypes.Structure Filled ctypes structure received as an input argument or a new instance if the input argument target is None. topgeometry: None This source does not use advanced geometry at the top sample surface. bottomgeometry: None This source does not use advanced geometry at the bottom sample surface. ''' if target is None: target_type = self.cl_type(mc) target = target_type() if self._position[2] <= 0.0: position = (self._position[0], self._position[1], 0.0) layer_index = 1 else: position = self._position layer_index = mc.layer_index(self._position[2]) target.position.fromarray(position) target.size.fromarray([self._width, self._height]) target.n = self._n target.cos_critical = boundary.cos_critical( self._n, mc.layers[layer_index].n) target.na = self._na target.layer_index = layer_index return target, None, None
def __str__(self): return 'LambertianRectangular(width={}, height={}, n={}, na={},'\ 'position=({}, {}, {}))'.format( self._width, self._height, self._n, self._na, *self._position)
[docs]class UniformRectangularLut(Source):
[docs] @staticmethod def cl_type(mc: mcobject.McObject) -> cltypes.Structure: T = mc.types class ClUniformRectangularLut(cltypes.Structure): ''' Structure that is passed to the Monte carlo simulator kernel. Fields ------ position: mc_point3f_t Source position (center of the source), size: mc_point2f_t Source size along the x and y axis. n: mc_fp_t Refractive index of the source. cos_critical: mc_fp_t Cosine of the total internal reflection angle for the source -> sample boundary transition. lut: cltypes.Structure Linear lookup table structure. layer_index: mc_size_t Layer index in which the source is located. ''' _fields_ = [ ('position', T.mc_point3f_t), ('size', T.mc_point2f_t), ('n', T.mc_fp_t), ('cos_critical', T.mc_fp_t), ('lut', CollectionLut.cl_type(mc)), ('layer_index', T.mc_size_t), ] return ClUniformRectangularLut
[docs] @staticmethod def cl_declaration(mc: mcobject.McObject) -> str: ''' Structure that defines the source in the Monte Carlo simulator. ''' return '\n'.join(( 'struct MC_STRUCT_ATTRIBUTES McSource{', ' mc_point3f_t position;', ' mc_point2f_t size;', ' mc_fp_t n;', ' mc_fp_t cos_critical;', ' mc_fp_lut_t lut;', ' mc_size_t layer_index;', '};' ))
[docs] @staticmethod def cl_implementation(mc: mcobject.McObject) -> str: ''' Implementation of the source in the Monte Carlo simulator. ''' return '\n'.join(( 'void dbg_print_source(__mc_source_mem const McSource *src){', ' dbg_print("UniformRectangularLut source:");', ' dbg_print_point3f(INDENT "position:", &src->position);', ' dbg_print_point2f(INDENT "size:", &src->size);', ' dbg_print_float(INDENT "n:", src->n);', ' dbg_print_fp_lut(INDENT "lut: ", &src->lut);', ' dbg_print_float(INDENT "cos_critical:", src->cos_critical);', ' dbg_print_size_t(INDENT "layer_index:", src->layer_index);', '};', '', 'inline void mcsim_launch(McSim *mcsim){', ' mc_fp_t sin_fi, cos_fi, sin_theta, cos_theta;', ' mc_fp_t r;', ' __mc_source_mem const struct McSource *source = mcsim_source(mcsim);', ' mcsim_set_position_coordinates(', ' mcsim,', ' source->position.x + (mcsim_random(mcsim) - FP_0p5)*source->size.x,', ' source->position.y + (mcsim_random(mcsim) - FP_0p5)*source->size.y,', ' source->position.z', ' );', '', ' mc_sincos(mcsim_random(mcsim)*FP_2PI, &sin_fi, &cos_fi);', ' /* compute propagation direction in air, n_medium = 1 */', ' cos_theta = FP_0;', ' fp_linear_lut_rel_sample(', ' mcsim_fp_lut_array(mcsim), &source->lut, ', ' mcsim_random(mcsim), &cos_theta);', '', ' /* Compute sine of the propagation direction and adjust ', ' * for the refractive index of the surrounding medium. */ ', ' sin_theta = mc_fdiv(mc_sqrt(FP_1 - cos_theta*cos_theta), ', ' mc_layer_n(mcsim_layer(mcsim, source->layer_index)));', ' cos_theta = mc_sqrt(FP_1 - sin_theta*sin_theta);' ' mcsim_set_direction_coordinates(', ' mcsim,', ' cos_fi*sin_theta,', ' sin_fi*sin_theta,', ' cos_theta', ' );', '', ' r = reflectance_cos2(', ' source->n, ', ' mcsim_layer(mcsim, source->layer_index)->n,', ' cos_theta', ' );', ' mcsim_set_weight(mcsim, FP_1 - r);', '', ' #if MC_USE_SPECULAR_DETECTOR', ' mc_point3f_t dir_in = {mcsim_direction_x(mcsim), ', ' mcsim_direction_y(mcsim), -mcsim_direction_z(mcsim)};', ' mc_point3f_t dir;', ' mc_point3f_t normal = {FP_0, FP_0, -FP_1};', ' refract(&dir_in, &normal, mc_layer_n(mcsim_layer(mcsim, 1)),', ' source->n, &dir);', ' mcsim_specular_detector_deposit(', ' mcsim, mcsim_position(mcsim), &dir, source->reflectance);', ' #endif', '', ' mcsim_set_current_layer_index(mcsim, source->layer_index);', '};', ))
[docs] @staticmethod def cl_options(mc: mcobject.McObject) -> mcoptions.RawOptions: return [('MC_USE_FP_LUT', True)]
def __init__(self, lut: CollectionLut, width: float, height: float, n: float, position: Tuple[float, float, float] = (0.0, 0.0, 0.0)): ''' A rectangular optical photon packet source with emission characteristics defined by a lookup table. The lookup table is sampled using a uniform random variable and linear interpolation. The obtained value represents cosine of the propagation direction with respect to the source normal. The propagation direction cosines defined in the lookup table should be valid for a surrounding medium with a refractive index 1 (air). The propagation direction is internally adjusted according to the refractive index of the medium surrounding the source: sin(theta_lut) = n_medium*sin(theta_medium). The reflectance at the source-medium boundary is subtracted from the initial weight of the photon packet. Parameters ---------- lut: CollectionLut Lookup table of the angular sensitivity. width: float Source width (x) in (m). height: float Source height (y) in (m). n: float Refractive index of the source. position: (float, float, float) Center of the source beam/rectangle as an array-like object of size 3 (px, py, pz). ''' Source.__init__(self) self._lut = lut self._width = float(width) self._height = float(height) self._n = max(1.0, float(n)) self._position = np.zeros((3,)) self._set_position(position)
[docs] def update(self, other: 'UniformRectangularLut' or dict): ''' Update this source configuration from the other source. The other source must be of the same type as this source or a dict with appropriate fields. Parameters ---------- other: UniformRectangularLut or dict This source is updated with the configuration of the other source. ''' if isinstance(other, UniformRectangularLut): self._lut = np.asarray(other.lut, dtype=np.float64) self._offset = 0 self.width = other.width self.height = other.height self.n = other.n self.position = other.position elif isinstance(other, dict): new_lut = other.get('lut') if new_lut is not None: self._lut = np.asarray(new_lut, dtype=np.float64) self._offset = 0 self.width = other.get('width', self._width) self.height = other.get('height', self._height) self.n = other.get('n', self._n) self.position = other.get('position', self._position)
def _get_position(self) -> Tuple[float, float, float]: return self._position def _set_position(self, position: Tuple[float, float, float]): self._position[:] = position position = property(_get_position, _set_position, None, 'Source position.') def _get_width(self) -> float: return self._width def _set_width(self, width: float): self._width = float(width) width = property(_get_width, _set_width, None, 'Source width (m).') def _get_height(self) -> float: return self._height def _set_height(self, height: float): self._height = float(height) height = property(_get_height, _set_height, None, 'Source height (m).') def _get_lut(self) -> CollectionLut: return self._lut.data lut = property(_get_lut, None, None, 'Lookup table of angular sensitivity.') def _get_n(self) -> float: return self._n def _set_n(self, n: float): self._n = max(1.0, float(n)) n = property(_get_n, _set_n, None, 'Source refractive index.')
[docs] def cl_pack(self, mc: mcobject.McObject, target: cltypes.Structure = None) \ -> Tuple[cltypes.Structure, None, None]: ''' Fills the structure (target) with the data required by the Monte Carlo simulator kernel. See the :py:meth:`UniformRectangularLut.cl_type` method for a detailed list of fields. Parameters ---------- mc: mcobject.McObject Monte Carlo simulator instance. target: cltypes.Structure Structure that is filled with the source data. Returns ------- target: cltypes.Structure Filled ctypes structure received as an input argument or a new instance if the input argument target is None. topgeometry: None This source does not use advanced geometry at the top sample surface. bottomgeometry: None This source does not use advanced geometry at the bottom sample surface. ''' if target is None: target_type = self.cl_type(mc) target = target_type() if self._position[2] <= 0.0: position = (self._position[0], self._position[1], 0.0) layer_index = 1 else: position = self._position layer_index = mc.layer_index(self._position[2]) self._lut.cl_pack(mc, target.lut) target.position.fromarray(position) target.size.fromarray([self._width, self._height]) target.n = self._n target.cos_critical = boundary.cos_critical( self._n, mc.layers[layer_index].n) target.layer_index = layer_index return target, None, None
[docs] def todict(self) -> dict: ''' Save the source configuration data to a dictionary. Use the :meth:`UniformRectangularLut.fromdict` method to create a new source instance from the returned data. Returns ------- data: dict Source configuration as a dictionary. ''' return { 'type':'UniformRectangularLut', 'lut':self._lut.todict(), 'width':self._width, 'height':self._height, 'n':self._n, 'position':self._position.tolist() }
[docs] @staticmethod def fromdict(data) -> 'UniformRectangularLut': ''' Create a source instance from a dictionary. Parameters ---------- data: dict Dictionary created by the :py:meth:`Radial.todict` method. ''' source_type = data.pop('type') if source_type != 'UniformRectangularLut': raise TypeError( 'Expected "UniformRectangularLut" type bot got "{}"!'.format( source_type)) lut = CollectionLut.fromdict(data.pop('lut')) return UniformRectangularLut(lut, **data)
def __str__(self): return 'UniformRectangularLut(lut={}, width={}, height={}, n={}, '\ 'position=({}, {}, {}))'.format( self._lut, self._width, self._height, self._n, *self._position) def __repr__(self): return '{} #{}'.format(self, id(self))