Source code for xopto.mccyl.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.mccyl import mcoptions
from xopto.mccyl import mcobject
from xopto.mccyl import cltypes

OUTER = 'outer'
''' Identifier of the outer sample surface. '''

INTERNAL = 'internal'
''' Identifier of the internal 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 = OUTER or INTERNAL): ''' Complex surface layout at the specified sample surface. Parameters ---------- location: OUTER or INTERNAL Location of the sample surface to which the layout applies. ''' super().__init__() if location not in (OUTER, INTERNAL, NONE): raise ValueError( 'Surface layout location must be "{}", "{}" or "{}"!'.format( NONE, OUTER, INTERNAL) ) self._location = location def _get_location(self) -> str: return self._location def _set_location(self, location: OUTER or INTERNAL): if location not in (NONE, OUTER, INTERNAL): raise ValueError( 'Surface layout location must be "{}", "{}" or "{}"!'.format( NONE, OUTER, INTERNAL) ) 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 SurfaceLayoutOuter(SurfaceLayoutBase): ''' Base class of the outer sample surface layout. ''' def __init__(self, *args, **kwargs): ''' Create a layout for the outer sample surface. ''' super().__init__(OUTER)
[docs]class SurfaceLayoutInternal(SurfaceLayoutBase): ''' Base class of the internal sample surfaces layout. ''' def __init__(self, *args, **kwargs): ''' Create a layout for the internal sample surfaces. ''' super().__init__(INTERNAL)
[docs]class SurfaceLayoutAny(SurfaceLayoutBase): ''' Base class of surface layouts that can be used for both the outer or internal sample surfaces. ''' def __init__(self, location: str = NONE): ''' Create a layout for the outer or internal sample surfaces. 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 outer or internal 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_surface_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. ''' data_ = dict(data) 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: - outer: SurfaceLayoutOuter Layout of the outer sample surface (z = 0). - internal: SurfaceLayoutInternal Layout of the internal sample surfaces (z = 0). ''' class ClSurfaceLayouts(cltypes.Structure): _fields_ = [ ('outer', self.outer.fetch_cl_type(mc)), ('internal', self.internal.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 outer and / or internal 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_OUTER_SURFACE_LAYOUT for the outer surface and MC_USE_INTERNAL_SURFACE_LAYOUT for the internal surface. ''' out = [] use_layouts = False if type(self.outer) != SurfaceLayoutDefault: out.append(('MC_USE_OUTER_SURFACE_LAYOUT', True)) out.extend(self._outer.fetch_cl_options(mc)) use_layouts = True if type(self.internal) != SurfaceLayoutDefault: out.append(('MC_USE_INTERNAL_SURFACE_LAYOUT', True)) out.extend(self._internal.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._outer.fetch_cl_declaration(mc), 'typedef struct McOuterSurfaceLayout McOuterSurfaceLayout;', '', self._internal.fetch_cl_declaration(mc), 'typedef struct McInternalSurfaceLayout McInternalSurfaceLayout;', '', 'struct MC_STRUCT_ATTRIBUTES McSurfaceLayouts{', ' McOuterSurfaceLayout outer;', ' McInternalSurfaceLayout internal;', '};', 'typedef struct McSurfaceLayouts McSurfaceLayouts;', '', '#define mcsim_outer_surface_layout(psim) (&mcsim_surface_layouts(psim)->outer)', '#define mcsim_internal_surface_layout(psim) (&mcsim_surface_layouts(psim)->internal)', ))
[docs] def cl_implementation(self, mc: mcobject.McObject) -> str: ''' Implementation of surface layouts. ''' return '\n'.join(( self._outer.fetch_cl_implementation(mc), '', self._internal.fetch_cl_implementation(mc), '', 'void dbg_print_surface_layouts(__mc_surface_mem const McSurfaceLayouts *layouts){', ' dbg_print("McSurfaceLayouts");', ' dbg_print_outer_surface_layout(&layouts->outer);', ' dbg_print_internal_surface_layout(&layouts->internal);', '};', ))
def __init__(self, outer: SurfaceLayoutOuter or SurfaceLayoutAny = None, internal: SurfaceLayoutInternal or SurfaceLayoutAny = None): ''' Container of the outer and internal sample surface layouts. Parameters ---------- outer: SurfaceLayoutOuter or SurfaceLayoutAny Layout of the outer sample surface. internal: SurfaceLayoutInternal or SurfaceLayoutAny Layout at the internal sample surfaces. ''' if isinstance(outer, SurfaceLayouts): sg = outer outer = sg.outer internal = sg.internal if outer is None: outer = SurfaceLayoutDefault() elif not isinstance(outer, (SurfaceLayoutOuter, SurfaceLayoutAny)): raise TypeError('Layout of the outer sample surface must be an ' 'instance of SurfaceLayoutOuter or ' 'SurfaceLayoutAny!') if internal is None: internal = SurfaceLayoutDefault() elif not isinstance(internal, (SurfaceLayoutInternal, SurfaceLayoutAny)): raise TypeError('Layout of the internal sample surfaces must be an ' 'instance of SurfaceLayoutInternal or ' 'SurfaceLayoutAny!') outer.location = OUTER internal.location = INTERNAL self._outer = outer self._internal = internal def _get_outer(self) -> mcobject.McObject: return self._outer outer = property(_get_outer, None, None, 'Outer sample surface layout.') def _get_internal(self) -> mcobject.McObject: return self._internal internal = property(_get_internal, None, None, 'Layouts of the internal sample surfaces.')
[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.outer.cl_pack(mc, target.outer) self.internal.cl_pack(mc, target.internal) return target
[docs] def types(self) -> tuple: ''' Returns a tuple of surface layout types assigned to this instance. ''' return type(self._outer), type(self._internal)
[docs] def todict(self) -> dict: ''' Export object to dict. ''' return { 'type': self.__class__.__name__, 'outer': self._outer.todict(), 'internal': self._internal.todict() }
def __str__(self): return 'SurfaceLayouts(outer={}, internal={})'.format( self._outer, self._internal) def __repr__(self): return '{} #{}'.format(self.__str__(), id(self))