Source code for xopto.mcbase.mcpf.gk2

# -*- 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 .pfbase import PfBase, cltypes, McObject
from . import Gk
import xopto.pf


[docs]class Gk2(PfBase):
[docs] @staticmethod def cl_type(mc: McObject) -> cltypes.Structure: ''' Returns an OpenCL structure that can be passed to the Monte carlo simulator. Parameters ---------- mc: McObject A Monte Carlo simulator instance. Returns ------- struct: cltypes.Structure A structure type that represents the scattering phase function in the Monte Carlo kernel. Structure fields ---------------- gk_1: mc_pf_gk_t Parameters of the first Gegenbauer kernel scattering phase function. gk_2: mc_pf_gk_t Parameters of the second Gegenbauer kernel scattering phase function. b: mc_fp_t Relative contribution of the second Gegenbauer kernel scattering phase function. ''' T = mc.types T_GK = Gk.cl_type(mc) class ClGk2(cltypes.Structure): _fields_ = [ ('gk_1', T_GK), ('gk_2', T_GK), ('b', T.mc_fp_t), ] return ClGk2
[docs] @staticmethod def cl_declaration(mc: McObject) -> str: ''' OpenCL declarations of the scattering phase function. ''' return '\n'.join(( 'struct MC_STRUCT_ATTRIBUTES mc_pf_gk_t {' ' mc_fp_t g;', ' mc_fp_t a;', ' mc_fp_t inv_a;', ' mc_fp_t a1;', ' mc_fp_t a2;', '};', '', 'struct MC_STRUCT_ATTRIBUTES McPf{', ' struct mc_pf_gk_t gk_1;', ' struct mc_pf_gk_t gk_2;', ' mc_fp_t b;', '};' ))
[docs] @staticmethod def cl_implementation(mc: McObject) -> str: ''' OpenCL implementation of the scattering phase function. ''' return '\n'.join(( 'void dbg_print_pf(const McPf *pf) {', ' dbg_print("Gk2 scattering phase function:");', ' dbg_print(INDENT "The first Gk term:");', ' dbg_print_float(INDENT INDENT "gk_1.g:", pf->gk_1.g_1);', ' dbg_print_float(INDENT INDENT "gk_1.a:", pf->gk_1.a_1);', ' dbg_print_float(INDENT INDENT "gk_1.inv_a:", pf->gk_1.inv_a_1);', ' dbg_print_float(INDENT INDENT "gk_1.a1:", pf->gk_1.a1_1);', ' dbg_print_float(INDENT INDENT "gk_1.a2:", pf->gk_1.a2_1);', '', ' dbg_print(INDENT "The second Gk term:");', ' dbg_print_float(INDENT INDENT "gk_2.g:", pf->gk_2.g_1);', ' dbg_print_float(INDENT INDENT "gk_2.a:", pf->gk_2.a_1);', ' dbg_print_float(INDENT INDENT "gk_2.inv_a:", pf->gk_2.inv_a_1);', ' dbg_print_float(INDENT INDENT "gk_2.a1:", pf->gk_2.a1_1);', ' dbg_print_float(INDENT INDENT "gk_2.a2:", pf->gk_2.a2_1);', '', ' dbg_print(INDENT "Relative contribution of the second Gk term:");', ' dbg_print_float(INDENT INDENT "b:", pf->b);', '};', '', 'inline mc_fp_t mcsim_sample_pf(McSim *mcsim, mc_fp_t *azimuth){', ' mc_fp_t tmp, cos_theta;', ' mc_fp_t b = mcsim_current_pf(mcsim)->b;', '', ' mc_fp_t g;', ' mc_fp_t a;', ' mc_fp_t inv_a;', ' mc_fp_t a1;', ' mc_fp_t a2;', '', ' *azimuth = FP_2PI*mcsim_random(mcsim);', '', ' if (mcsim_random(mcsim) >= b) {', ' g = mcsim_current_pf(mcsim)->gk_1.g;', ' a = mcsim_current_pf(mcsim)->gk_1.a;', ' inv_a = mcsim_current_pf(mcsim)->gk_1.inv_a;', ' a1 = mcsim_current_pf(mcsim)->gk_1.a1;', ' a2 = mcsim_current_pf(mcsim)->gk_1.a2;', ' } else {', ' g = mcsim_current_pf(mcsim)->gk_2.g;', ' a = mcsim_current_pf(mcsim)->gk_2.a;', ' inv_a = mcsim_current_pf(mcsim)->gk_2.inv_a;', ' a1 = mcsim_current_pf(mcsim)->gk_2.a1;', ' a2 = mcsim_current_pf(mcsim)->gk_2.a2;', ' };', '', ' if (g == FP_0) {', ' cos_theta = FP_1 - FP_2*mcsim_random(mcsim);', ' } else if(a == FP_0) {', ' cos_theta = a1 + mc_pow(', ' mc_fdiv(FP_1 - g, FP_1 + g),', ' FP_2*mcsim_random(mcsim)', ' )*a2;', ' } else {', ' tmp = a1*mcsim_random(mcsim) + a2;', ' tmp = FP_1 + g*g - mc_pow(tmp, -inv_a);', ' cos_theta = mc_fdiv(tmp, FP_2*g);', ' };', '', ' return mc_fclip(cos_theta, -FP_1, FP_1);', '};' ))
def __init__(self, g1: float, a1: float, g2: float, a2: float, b: float): ''' Gegenbauer kernel scattering phase function constructor. Parameters ---------- g1: float Parameter of the first Gegenbauer kernel scattering scattering phase function. :math:`0 <= g <= 1` a1: float Parameter of the first Gegenbauer kernel scattering phase function. :math:`a > - 1/2` A value of 0.5 produces the Henyey-Greenstein scattering phase function. g2: float Parameter of the second Gegenbauer kernel scattering scattering phase function. :math:`-1 <= g < 0` a2: float Parameter of the second Gegenbauer kernel scattering phase function. :math:`a > - 1/2` A value of 0.5 produces the Henyey-Greenstein scattering phase function. b: float A value between 0 and 1 that determines the relative contribution of the second Gegenbauer kernel scattering scattering phase function. ''' super().__init__() self._gk1 = Gk(g1, a1) self._gk2 = Gk(g2, a2) self._b = 0.0 self._set_b(b) def _get_g1(self) -> float: return self._gk1.g def _set_g1(self, g: float): self._gk1.g = min(max(float(g), 0.0), 1.0) g1 = property(_get_g1, _set_g1, None, 'Parameter g (anisotropy factor when a=0.5) ' 'of the first GK term.') def _get_a1(self) -> float: return self._gk1.a def _set_a1(self, a: float): self._gk1.a = max(float(a), -0.5) a1 = property(_get_a1, _set_a1, None, 'Parameter alpha of the first GK term.') def _get_g2(self) -> float: return self._gk2.g def _set_g2(self, g: float): self._gk2.g = min(max(float(g), -1.0), 0.0) g2 = property(_get_g2, _set_g2, None, 'Parameter g (anisotropy factor when a=0.5) ' 'of the second GK term.') def _get_a2(self) -> float: return self._gk2.a def _set_a2(self, a: float): self._gk2.a = max(float(a), -0.5) a2 = property(_get_a2, _set_a2, None, 'Parameter alpha of the second GK term.') def _get_b(self) -> float: return self._b def _set_b(self, b: float): self._b = min(max(float(b), 0.0), 1.0) b = property(_get_b, _set_b, None, 'Relative contribution of the second GK term.')
[docs] def pf(self) -> xopto.pf.Gk2: ''' Returns a new instance of the related utility scattering phase function class that can be used to compute Legendre moments and other scattering phase function quantifiers. Returns ------- pf: xopto.pf.Gk2 Instance of the related utility scattering phase function. ''' return xopto.pf.Gk2(self._gk1.g, self._gk1.a, self._gk2.g, self._gk2.a, self.b)
[docs] def cl_pack(self, mc: McObject, target: cltypes.Structure = None) \ -> cltypes.Structure: ''' Fills the an OpenCL Structure (target) with the data required by the Monte Carlo simulator. See the :py:meth:`~Gk2.cl_type` method for a detailed list of fields. Parameters ---------- mc: McObject Simulator instance. target: cltypes.Structure Target OpenCL structure for packing. Returns ------- target: cltypes.Structure Target structure received as an input argument or a new instance of ClGk if the input argument target is None. ''' if target is None: target_type = self.fetch_cl_type(mc) target = target_type() self._gk1.cl_pack(mc, target.gk_1) self._gk2.cl_pack(mc, target.gk_2) target.b = self._b return target
[docs] def todict(self) -> dict: ''' Export object to a dict. ''' return {'g1': self._gk1.g, 'a1': self._gk1.a, 'g2': self._gk2.g, 'a2': self._gk2.a, 'b': self._b, 'type': self.__class__.__name__}
def __str__(self): return 'Gk2(g1={}, a1={}, g2={}, a2={}, b={})'.format( self._gk1.g, self._gk1.a, self._gk2.g, self._gk2.a, self._b)