Source code for xopto.mcml.mcrun.mcrun

# -*- 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.mcbase.mcrun import RunMinWeightBase, RunMinPacketsBase
from xopto.mcml import mc


class _RunMinWeightDetector(RunMinWeightBase):
    def __init__(self, location: str, min_weight: float, batch_size: int,
                 selection: slice or int):
        '''
        Base class for running MC simulations until the desired weight
        is collected by the selected detector.

        Parameters
        ----------
        location: str
            Detector location ("top", "bottom" or "specular")
        min_weight: float
            Minimum weight that needs to be collected by the detector.
        batch_size: int
            Number of packets to launch in a single simulation.
        selection: slice or int
            A slice / region or index of the detector that is used to compute
            the collected weight. If None (default), the entire detector
            contributes to the total weight.
        '''
        self._location = location
        super().__init__(min_weight, batch_size, selection)

    def process_batch(self, result: mc.MC_RESULT_TYPE) \
            -> Tuple[float, int, mc.MC_RESULT_TYPE]:
        '''
        Process one MC simulation.

        Note
        ----
        Do not call this method directly. The method is called by
        :py:meth:`run`.

        Parameters
        ----------
        result: mc.MC_RESULT_TYPE
            A tuple as returned by the :py:meth:`mcml.mc.Mc.run` method.
    
        Returns
        -------
        total_weight: float
            Total weight collected by the selected detector.
        n: int
            The number of packets collected by the detector or None.
        result: mc.MC_RESULT_TYPE
            Input simulation result ready for the next Monte Carlo simulation.
        '''
        detectors = result[2]
        if detectors is None or type(getattr(detectors, self._location)) == \
                mc.mcdetector.DetectorDefault:
            raise RuntimeError(
                'This MC simulator instance does not use the configured'
                ' ("{}") detector!'.format(self._location))

        detector = getattr(detectors, self._location)

        raw_data = detector.raw
        if self.selection is not None:
            raw_data = raw_data[self.selection]
        total_weight = np.sum(raw_data)

        return total_weight, None, result

    def _get_location(self) -> str:
        return self._location
    location = property(_get_location, None, None,
                        'Detector location.')


[docs]class RunMinWeightTop(_RunMinWeightDetector): def __init__(self, min_weight: float, batch_size: int, selection: slice or int = None): ''' Object for running MC simulations until the desired weight is collected by the top detector. Parameters ---------- min_weight: float Minimum weight that needs to be collected by the detector. batch_size: int Number of packets to launch in a single simulation. selection: slice or int A slice / region or index of the detector that is used to compute the collected weight. If None (default), the entire detector contributes to the total weight. ''' super().__init__('top', min_weight, batch_size, selection)
[docs]class RunMinWeightBottom(_RunMinWeightDetector): def __init__(self, min_weight: float, batch_size: int, selection: slice or int = None): ''' Object for running MC simulations until the desired weight is collected by the bottom detector. Parameters ---------- min_weight: float Minimum weight that needs to be collected by the detector. batch_size: int Number of packets to launch in a single simulation. selection: slice or int A slice / region or index of the detector that is used to compute the collected weight. If None (default), the entire detector contributes to the total weight. ''' super().__init__('bottom', min_weight, batch_size, selection)
[docs]class RunMinWeightSpecular(_RunMinWeightDetector): def __init__(self, min_weight: float, batch_size: int, selection: slice or int = None): ''' Object for running MC simulations until the desired weight is collected by the specular detector. Parameters ---------- min_weight: float Minimum weight that needs to be collected by the detector. batch_size: int Number of packets to launch in a single simulation. selection: slice or int A slice / region or index of the detector that is used to compute the collected weight. If None (default), the entire detector contributes to the total weight. ''' super().__init__('specular', min_weight, batch_size, selection)
[docs]class RunMinWeightTrace(RunMinWeightBase): def __init__(self, min_weight: float, batch_size: int): ''' Object for running MC simulations until the desired weight is collected by the trace, i.e. the sum of terminal weights of the traced packets. Parameters ---------- min_weight: float Minimum total terminal weight of the packets that needs to be collected by the trace. batch_size: int Number of packets to launch in a single simulation. ''' super().__init__(min_weight, batch_size, None)
[docs] def process_batch(self, result: mc.MC_RESULT_TYPE) \ -> Tuple[float, int, mc.MC_RESULT_TYPE]: ''' Process one MC simulation. Note ---- Do not call this method directly. The method is called by :py:meth:`run`. Parameters ---------- result: mc.MC_RESULT_TYPE A tuple as returned by the :py:meth:`mcml.mc.Mc.run` method. Returns ------- total_weight: float Total weight collected by the selected detector. n: int The number of packets collected by the detector or None. result: mc.MC_RESULT_TYPE Input simulation result ready for the next Monte Carlo simulation. ''' trace = result[0] if trace is None: raise RuntimeError('This MC simulator instance does not use trace!') total_weight = np.sum(trace.terminal['w']) num_packets = len(trace) return total_weight, num_packets, result
[docs]class RunMinPacketsTrace(RunMinPacketsBase): def __init__(self, min_packets: float, batch_size: int): ''' Object for running MC simulations until the desired number of packets is collected in the (filtered) trace. Parameters ---------- min_packets: float Minimum number of packet traces that needs to be collected. batch_size: int Number of packets to launch in a single simulation. ''' super().__init__(min_packets, batch_size, None)
[docs] def process_batch(self, result: mc.MC_RESULT_TYPE) \ -> Tuple[float, int, mc.MC_RESULT_TYPE]: ''' Process one MC simulation. Note ---- Do not call this method directly. The method is called by :py:meth:`run`. Parameters ---------- result: mc.MC_RESULT_TYPE A tuple as returned by the :py:meth:`mcml.mc.Mc.run` method. Returns ------- total_weight: float Total weight collected by the selected detector. n: int The number of packets collected by the detector or None. result: mc.MC_RESULT_TYPE Input simulation result ready for the next Monte Carlo simulation. ''' trace = result[0] if trace is None: raise RuntimeError('This MC simulator instance does not use trace!') total_weight = np.sum(trace.terminal['w']) num_packets = len(trace) return total_weight, num_packets, result