Source code for xopto.mcml.mcsurface.base

# -*- 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 xopto.mcml import mcoptions
from xopto.mcml import mcobject
from xopto.mcml import cltypes

TOP = 'top'
''' Identifier of the top sample surface. '''

BOTTOM = 'bottom'
''' Identifier of the bottom sample surface. '''

NONE = 'none'
''' Identifier used for a surface that is not yet assigned. '''

[docs]class SurfaceLayoutBase(mcobject.McObject): ''' Base class of all the sample surface layouts. ''' def __init__(self, location: str = TOP or BOTTOM): ''' Complex surface layout at the specified sample surface. Parameters ---------- location: TOP or BOTTOM Location of the sample surface to which the layout applies. ''' super().__init__() if location not in (TOP, BOTTOM, NONE): raise ValueError( 'Surface layout location must be "{}", "{}" or "{}"!'.format( NONE, TOP, BOTTOM) ) self._location = location def _get_location(self) -> str: return self._location def _set_location(self, location: TOP or BOTTOM): if location not in (NONE, TOP, BOTTOM): raise ValueError( 'Surface layout location must be "{}", "{}" or "{}"!'.format( NONE, TOP, BOTTOM) ) if location != self._location and self._location != NONE: raise RuntimeError('Surface layout cannot be changed!') self._location = str(location) location = property(_get_location, _set_location, None, 'Location of the surface layout.')
[docs]class SurfaceLayoutTop(SurfaceLayoutBase): ''' Base class of the top sample surface layout. ''' def __init__(self, *args, **kwargs): ''' Create a layout for the top sample surface. ''' super().__init__(TOP)
[docs]class SurfaceLayoutBottom(SurfaceLayoutBase): ''' Base class of the bottom sample surface layout. ''' def __init__(self, *args, **kwargs): ''' Create a layout for the bottom sample surface. ''' super().__init__(BOTTOM)
[docs]class SurfaceLayoutAny(SurfaceLayoutBase): ''' Base class of surface layouts that can be used for both the top or bottom sample surface. ''' def __init__(self, location: str = NONE): ''' Create a layout for the top or bottom sample surface. By default the location is not initialized. ''' super().__init__(location)
[docs] @classmethod def fromdict(cls, data:dict) -> 'SurfaceLayoutAny': ''' Create a new instance of a surface layout from a dict. The dict keys must match the parameter names defined by the constructor. ''' data_ = dict(data) T = data_.pop('type') if T != cls.__name__: raise TypeError( 'Cannot initialize an instance of "{:s}" from the data' 'of instance "{}"!'.format(cls.__name__, T)) return cls(**data_)
[docs]class SurfaceLayoutDefault(SurfaceLayoutAny): ''' Default / dummy layout for the top or bottom sample surface. '''
[docs] def cl_type(self, mc: mcobject.McObject) -> cltypes.Structure: ''' Structure that is passed to the Monte carlo simulator kernel. Parameters ---------- mc: McObject A Monte Carlo simulator instance. Returns ------- struct: cltypes.Structure A structure type that represents the surface layout in the Monte Carlo kernel. The returned structure type implements the following fields: - dummy: mc_int_t Dummy field of the dummy detector. ''' T = mc.types class ClSurfaceLayoutDefault(cltypes.Structure): _fields_ = [('dummy', T.mc_int_t)] return ClSurfaceLayoutDefault
[docs] @staticmethod def cl_options(mc: mcobject.McObject) -> str: ''' Raw OpenCL options of the default detector. ''' return ''
[docs] def cl_declaration(self, mc: mcobject.McObject) -> str: ''' Structure that defines the dummy reflector in the Monte Carlo simulator. ''' Loc = self.location.capitalize() return 'struct Mc{}SurfaceLayout{{mc_int_t dummy;}};'.format(Loc)
[docs] def cl_implementation(self, mc: mcobject.McObject) -> str: ''' OpenCL implementation of the default surface layout ''' loc = self.location Loc = loc.capitalize() return '\n'.join(( 'void dbg_print_{}_surface_layout('.format(loc), ' __mc_detector_mem const Mc{}SurfaceLayout *layout){{'.format(Loc), ' dbg_print("Mc{}SurfaceLayout - default layout:");'.format(Loc), '};', ))
[docs] def cl_pack(self, mc: mcobject.McObject, target: cltypes.Structure = None) \ -> cltypes.Structure: ''' Fills the structure (target) with the data required by the Monte Carlo simulator. See the :py:meth:`SurfaceLayoutDefault.cl_type` 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. ''' if target is None: target_type = self.cl_type(mc) target = target_type() target.dummy = 0 return target
[docs] def todict(self) -> dict: ''' Export object to dict. ''' return {'type': self.__class__.__name__}
[docs] @classmethod def fromdict(cls, data: dict) -> 'SurfaceLayoutDefault': ''' Create an instance of :py:class:`SurfaceLayoutDefault` from a dictionary. Parameters ---------- data: dict Dictionary created by the :py:meth:`SurfaceLayoutDefault.todict` method. ''' layout_type = data.pop('type') if layout_type != cls.__name__: raise TypeError( 'Expected a "{}" type bot got "{}"!'.format( cls.__name__, layout_type)) return cls(**data)
[docs]class SurfaceLayouts(mcobject.McObject):
[docs] def cl_type(self, mc: mcobject.McObject) -> cltypes.Structure: ''' Structure that is passed to the OpenCL simulator. Parameters ---------- mc: McObject A Monte Carlo simulator instance. Returns ------- struct: cltypes.Structure A structure type that represents surface layouts in the Monte Carlo kernel. The returned structure type implements the following fields: - top: SurfaceLayoutTop Layout of the top sample surface (z = 0). - bottom: SurfaceLayoutBottom Layout of the bottom sample surface (z = 0). ''' class ClSurfaceLayouts(cltypes.Structure): _fields_ = [ ('top', self.top.fetch_cl_type(mc)), ('bottom', self.bottom.fetch_cl_type(mc)) ] return ClSurfaceLayouts
[docs] def cl_options(self, mc: mcobject.McObject) -> mcoptions.RawOptions: ''' Returns the OpenCL options of the surface layout. If the top and / or bottom sample surface layouts are specified (not the dummy default :py:class:`SurfaceLayoutDefault`), the corresponding OpenCL options that activate the use of surface layouts are set, i.e. MC_USE_TOP_SURFACE_LAYOUT for the top surface and MC_USE_BOTTOM_SURFACE_LAYOUT for the bottom surface. ''' out = [] use_layouts = False if type(self.top) != SurfaceLayoutDefault: out.append(('MC_USE_TOP_SURFACE_LAYOUT', True)) out.extend(self._top.fetch_cl_options(mc)) use_layouts = True if type(self.bottom) != SurfaceLayoutDefault: out.append(('MC_USE_BOTTOM_SURFACE_LAYOUT', True)) out.extend(self._bottom.fetch_cl_options(mc)) use_layouts = True if use_layouts: out.append(('MC_USE_SURFACE_LAYOUTS', True)) return out
[docs] def cl_declaration(self, mc: mcobject.McObject) -> str: ''' Declarations of surface layouts in OpenCL. ''' return '\n'.join(( self._top.fetch_cl_declaration(mc), 'typedef struct McTopSurfaceLayout McTopSurfaceLayout;', '', self._bottom.fetch_cl_declaration(mc), 'typedef struct McBottomSurfaceLayout McBottomSurfaceLayout;', '', 'struct MC_STRUCT_ATTRIBUTES McSurfaceLayouts{', ' McTopSurfaceLayout top;', ' McBottomSurfaceLayout bottom;', '};', 'typedef struct McSurfaceLayouts McSurfaceLayouts;', '', '#define mcsim_top_surface_layout(psim) (&mcsim_surface_layouts(psim)->top)', '#define mcsim_bottom_surface_layout(psim) (&mcsim_surface_layouts(psim)->bottom)', ))
[docs] def cl_implementation(self, mc: mcobject.McObject) -> str: ''' Implementation of surface layouts. ''' return '\n'.join(( self._top.fetch_cl_implementation(mc), '', self._bottom.fetch_cl_implementation(mc), '', 'void dbg_print_surface_layouts(__mc_detector_mem const McSurfaceLayouts *layouts){', ' dbg_print("McSurfaceLayouts");', ' dbg_print_top_surface_layout(&layouts->top);', ' dbg_print_bottom_surface_layout(&layouts->bottom);', '};', ))
def __init__(self, top: SurfaceLayoutTop or SurfaceLayoutAny = None, bottom: SurfaceLayoutBottom or SurfaceLayoutAny = None): ''' Container of the top and bottom sample surface layouts. Parameters ---------- top: SurfaceLayoutTop or SurfaceLayoutAny Layout of the top sample surface. bottom: SurfaceLayoutBottom or SurfaceLayoutAny Layout at the bottom sample surface. ''' if isinstance(top, SurfaceLayouts): sg = top top = sg.top bottom = sg.bottom if top is None: top = SurfaceLayoutDefault() elif not isinstance(top, (SurfaceLayoutTop, SurfaceLayoutAny)): raise TypeError('Layout of the top sample surface must be an ' 'instance of SurfaceLayoutTop or ' 'SurfaceLayoutAny!') if bottom is None: bottom = SurfaceLayoutDefault() elif not isinstance(bottom, (SurfaceLayoutBottom, SurfaceLayoutAny)): raise TypeError('Layout of the bottom sample surface must be an ' 'instance of SurfaceLayoutBottom or ' 'SurfaceLayoutAny!') top.location = TOP bottom.location = BOTTOM self._top = top self._bottom = bottom def _get_top(self) -> mcobject.McObject: return self._top top = property(_get_top, None, None, 'Top sample surface layout.') def _get_bottom(self) -> mcobject.McObject: return self._bottom bottom = property(_get_bottom, None, None, 'Bottom sample surface layout.')
[docs] def cl_pack(self, mc: mcobject.McObject, target: cltypes.Structure = None) \ -> cltypes.Structure: ''' Fills the structure (target) with the data required by the Monte Carlo simulator. See the :py:meth:`SurfaceLayouts.cl_type` method for a detailed list of fields. Parameters ---------- mc: mcobject.McObject Monte Carlo simulator instance. target: cltypes.Structure Ctypes structure that is filled with the source data. Returns ------- target: cltypes.Structure Filled structure received as an input argument or a new instance if the input argument target is None. ''' if target is None: target_type = self.cl_type(mc) target = target_type() self.top.cl_pack(mc, target.top) self.bottom.cl_pack(mc, target.bottom) return target
[docs] def types(self) -> tuple: ''' Returns a tuple of surface layout types assigned to this instance. ''' return type(self._top), type(self._bottom)
[docs] def todict(self) -> dict: ''' Export object to dict. ''' return { 'type': self.__class__.__name__, 'top': self._top.todict(), 'bottom': self._bottom.todict() }
def __str__(self): return 'SurfaceLayouts(top={}, bottom={})'.format( self._top, self._bottom) def __repr__(self): return '{} #{}'.format(self.__str__(), id(self))