Source code for pisa.stages.osc.osc_params

# author: T. Ehrhardt
# date:   2018
"""
OscParams: Characterize neutrino oscillation parameters
           (mixing angles, Dirac-type CP-violating phase, mass splittings)

changed by Elisa Lohfink (ellohfin; elohfink@icecube.wisc.edu)
to include NSI changes made by Thomas Ehrhardt on his branch:
original version can be found in thehrh/pisa nsi_reparameterisation branch
"""

from __future__ import division

import numpy as np

from pisa import FTYPE

__all__ = ['OscParams']


[docs] class OscParams(object): """ Holds neutrino oscillation parameters, i.e., mixing angles, squared-mass differences, and a Dirac-type CPV phase. The neutrino mixing (PMNS) matrix constructed from these parameters is given in the standard 3x3 parameterization. Also holds the generalised matter potential matrix (divided by the matter potential a), i.e. diag(1, 0, 0) for the standard case. Parameters ---------- dm21, dm31, dm41 : float Mass splittings (delta M^2_{21,31,41}) expected to be given in [eV^2] sin12, sin13, sin23 : float 1-2, 1-3 and 2-3 mixing angles, interpreted as sin(theta_{ij}) deltacp : float Value of CPV phase in [rad] Attributes ---------- dm21, dm31, dm41 : float Cf. parameters sin12, sin13, sin23, sin14 : float Cf. parameters theta12, theta13, theta23, theta14 : float Mixing angles (corresponding to sinXY) deltacp : float Cf. parameters mix_matrix : 3d float array of shape (3, 3, 2) Neutrino mixing (PMNS) matrix in standard parameterization. The third dimension holds the real and imaginary parts of each matrix element. mix_matrix_complex : 3d complex array mix_matrix_reparam : 3d float array of shape (3, 3, 2) Reparameterized neutrino mixing matrix, such that CPT invariance of vacuum propagation implemented by 3 simultaneous osc. param. transformations. mix_matrix_reparam_complex : 3d complex array dm_matrix : 2d float array of shape (3, 3) Antisymmetric matrix of squared-mass differences in vacuum """ def __init__(self): self._sin12 = 0. self._sin13 = 0. self._sin23 = 0. self._sin14 = 0. self._deltacp = 0. self.dm21 = 0. self.dm31 = 0. self.dm41 = 0. self.gamma21 = 0. # TODO Add full 3x3 matrix option, TODO update docs, TODO getters/setters to enforce values ranges? self.gamma31 = 0. self.gamma32 = 0. # --- theta12 --- @property def sin12(self): """Sine of 1-2 mixing angle""" return self._sin12 @sin12.setter def sin12(self, value): assert (abs(value) <= 1) self._sin12 = value @property def theta12(self): return np.arcsin(self.sin12) @theta12.setter def theta12(self, value): self.sin12 = np.sin(value) # --- theta13 --- @property def sin13(self): """Sine of 1-3 mixing angle""" return self._sin13 @sin13.setter def sin13(self, value): assert (abs(value) <= 1) self._sin13 = value @property def theta13(self): return np.arcsin(self.sin13) @theta13.setter def theta13(self, value): self.sin13 = np.sin(value) # --- theta23 --- @property def sin23(self): """Sine of 2-3 mixing angle""" return self._sin23 @sin23.setter def sin23(self, value): assert (abs(value) <= 1) self._sin23 = value @property def theta23(self): return np.arcsin(self.sin23) @theta23.setter def theta23(self, value): self.sin23 = np.sin(value) # --- theta14 --- @property def sin14(self): """Sine of 1-4 mixing angle""" return self._sin14 @sin14.setter def sin14(self, value): assert (abs(value) <= 1) self._sin14 = value @property def theta14(self): return np.arcsin(self.sin14) @theta14.setter def theta14(self, value): self.sin14 = np.sin(value) # --- deltaCP --- @property def deltacp(self): """CPV phase""" return self._deltacp @deltacp.setter def deltacp(self, value): assert value >= 0. and value <= 2*np.pi self._deltacp = value @property def mix_matrix(self): """Neutrino mixing matrix in its 'standard' form""" mix = np.zeros((3, 3, 2), dtype=FTYPE) sd = np.sin(self.deltacp) cd = np.cos(self.deltacp) c12 = np.sqrt(1. - self.sin12**2) c23 = np.sqrt(1. - self.sin23**2) c13 = np.sqrt(1. - self.sin13**2) mix[0, 0, 0] = c12 * c13 mix[0, 0, 1] = 0. mix[0, 1, 0] = self.sin12 * c13 mix[0, 1, 1] = 0. mix[0, 2, 0] = self.sin13 * cd mix[0, 2, 1] = - self.sin13 * sd mix[1, 0, 0] = - self.sin12 * c23 - c12 * self.sin23 * self.sin13 * cd mix[1, 0, 1] = - c12 * self.sin23 * self.sin13 * sd mix[1, 1, 0] = c12 * c23 - self.sin12 * self.sin23 * self.sin13 * cd mix[1, 1, 1] = - self.sin12 * self.sin23 * self.sin13 * sd mix[1, 2, 0] = self.sin23 * c13 mix[1, 2, 1] = 0. mix[2, 0, 0] = self.sin12 * self.sin23 - c12 * c23 * self.sin13 * cd mix[2, 0, 1] = - c12 * c23 * self.sin13 * sd mix[2, 1, 0] = - c12 * self.sin23 - self.sin12 * c23 * self.sin13 * cd mix[2, 1, 1] = - self.sin12 * c23 * self.sin13 * sd mix[2, 2, 0] = c23 * c13 mix[2, 2, 1] = 0. return mix @property def mix_matrix_complex(self): """Mixing matrix as complex 2-d array""" mix = self.mix_matrix return mix[:, :, 0] + mix[:, :, 1] * 1.j @property def mix_matrix_reparam(self): """ Neutrino mixing matrix reparameterised in a way such that the CPT trafo Hvac -> -Hvac* is exactly implemented by the simultaneous transformations * deltamsq31 -> -deltamsq32 * theta12 -> pi/2 - theta12 * deltacp -> pi - deltacp which hence leave vacuum propagation invariant. This representation follows from the standard form U as diag(exp(i*deltacp), 0, 0) * U * diag(exp(-i*deltacp), 0, 0). """ mix = np.zeros((3, 3, 2), dtype=FTYPE) sd = np.sin(self.deltacp) cd = np.cos(self.deltacp) c12 = np.sqrt(1. - self.sin12**2) c23 = np.sqrt(1. - self.sin23**2) c13 = np.sqrt(1. - self.sin13**2) mix[0, 0, 0] = c12 * c13 mix[0, 0, 1] = 0. mix[0, 1, 0] = self.sin12 * c13 * cd mix[0, 1, 1] = self.sin12 * c13 * sd mix[0, 2, 0] = self.sin13 mix[0, 2, 1] = 0. mix[1, 0, 0] = - self.sin12 * c23 * cd - c12 * self.sin23 * self.sin13 mix[1, 0, 1] = self.sin12 * c23 * sd mix[1, 1, 0] = c12 * c23 - self.sin12 * self.sin23 * self.sin13 * cd mix[1, 1, 1] = - self.sin12 * self.sin23 * self.sin13 * sd mix[1, 2, 0] = self.sin23 * c13 mix[1, 2, 1] = 0. mix[2, 0, 0] = self.sin12 * self.sin23 * cd - c12 * c23 * self.sin13 mix[2, 0, 1] = - self.sin12 * self.sin23 * sd mix[2, 1, 0] = - c12 * self.sin23 - self.sin12 * c23 * self.sin13 * cd mix[2, 1, 1] = - self.sin12 * c23 * self.sin13 * sd mix[2, 2, 0] = c23 * c13 mix[2, 2, 1] = 0. return mix @property def mix_matrix_reparam_complex(self): """Reparameterised mixing matrix as complex 2-d array""" mix_reparam = self.mix_matrix_reparam return mix_reparam[:, :, 0] + mix_reparam[:, :, 1] * 1.j @property def dm_matrix(self): """Neutrino mass splitting matrix in vacuum""" dmVacVac = np.zeros((3, 3), dtype=FTYPE) mVac = np.zeros(3, dtype=FTYPE) delta = 5.e-9 mVac[0] = 0. mVac[1] = self.dm21 mVac[2] = self.dm31 # Break any degeneracies if mVac[1] == 0.: mVac[0] -= delta if mVac[2] == 0.: mVac[2] += delta dmVacVac[0, 0] = 0. dmVacVac[1, 1] = 0. dmVacVac[2, 2] = 0. dmVacVac[0, 1] = mVac[0] - mVac[1] dmVacVac[1, 0] = - dmVacVac[0, 1] dmVacVac[0, 2] = mVac[0] - mVac[2] dmVacVac[2, 0] = - dmVacVac[0, 2] dmVacVac[1, 2] = mVac[1] - mVac[2] dmVacVac[2, 1] = - dmVacVac[1, 2] return dmVacVac
def test_osc_params(): """ # TODO: implement me! """ pass if __name__=='__main__': from pisa import TARGET from pisa.utils.log import set_verbosity, logging assert TARGET == 'cpu', "Cannot test functions on GPU, set PISA_TARGET to 'cpu'" set_verbosity(1) test_osc_params()