Index: trunk/src/particles/particles.nw =================================================================== --- trunk/src/particles/particles.nw (revision 8373) +++ trunk/src/particles/particles.nw (revision 8374) @@ -1,8369 +1,8371 @@ %% -*- ess-noweb-default-code-mode: f90-mode; noweb-default-code-mode: f90-mode; -*- % WHIZARD code as NOWEB source: particle objects %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \chapter{Particles} \includemodulegraph{particles} This chapter collects modules that implement particle objects, for use in event records. While within interactions, all correlations are manifest, a particle array is derived by selecting a particular quantum number set. This involves tracing over all other particles, as far as polarization is concerned. Thus, a particle has definite flavor, color, and a single-particle density matrix for polarization. \begin{description} \item[su\_algebra] We make use of $su(N)$ generators as the basis for representing polarization matrices. This module defines the basis and provides the necessary transformation routines. \item[bloch\_vectors] This defines polarization objects in Bloch representation. The object describes the spin density matrix of a particle, currently restricted to spin $0\ldots 2$. \item[polarizations] This extends the basic polarization object such that it supports properties of physical particles and appropriate constructors. \item[particles] Particle objects and particle lists, as the base of event records. \end{description} \clearpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{$su(N)$ Algebra} We need a specific choice of basis for a well-defined component representation. The matrix elements of $T^a$ are ordered as $m=\ell,\ell-1,\ldots -\ell$, i.e., from highest down to lowest weight, for both row and column. We list first the generators of the $su(2)$ subalgebras which leave $|m|$ invariant ($|m|\neq 0$): \begin{equation} T^{b+1,b+2,b+3} \equiv \sigma^{1,2,3} \end{equation} acting on the respective subspace $|m|=\ell,\ell-1,\ldots$ for $b=0,1,\ldots$. This defines generators $T^a$ for $a=1,\ldots 3N/2$ ($\ldots 3(N-1)/2$) for $N$ even (odd), respectively. The following generators successively extend this to $su(4)$, $su(6)$, \ldots until $su(N)$ by adding first the missing off-diagonal and then diagonal generators. The phase conventions are analogous. (It should be possible to code these conventions for generic spin, but in the current implementation we restrict ourselves to $s\leq 2$, i.e., $N\leq 5$.) <<[[su_algebra.f90]]>>= <> module su_algebra <> use physics_defs, only: SCALAR, SPINOR, VECTOR, VECTORSPINOR, TENSOR <> <> contains <> end module su_algebra @ %def su_algebra @ \subsection{$su(N)$ fundamental representation} The dimension of the basis for a given spin type. consecutively, starting at [[SCALAR=1]]. <>= public :: algebra_dimension <>= function algebra_dimension (s) result (n) integer :: n integer, intent(in) :: s n = fundamental_dimension (s) ** 2 - 1 end function algebra_dimension @ %def algebra_dimension @ The dimension of the fundamental (defining) representation that we use. This implementation assumes that the spin type is numerically equal to the fundamental dimension. <>= public :: fundamental_dimension <>= function fundamental_dimension (s) result (d) integer :: d integer, intent(in) :: s d = s end function fundamental_dimension @ %def fundamental_dimension @ \subsection{Mapping between helicity and matrix index} Return the helicity that corresponds to a particular entry in the polarization matrix representation. Helicities are counted downwards, in integers, and zero helicity is included (omitted) for odd (even) spin, respectively. <>= public :: helicity_value <>= function helicity_value (s, i) result (h) integer :: h integer, intent(in) :: s, i integer, dimension(1), parameter :: hh1 = [0] integer, dimension(2), parameter :: hh2 = [1, -1] integer, dimension(3), parameter :: hh3 = [1, 0, -1] integer, dimension(4), parameter :: hh4 = [2, 1, -1, -2] integer, dimension(5), parameter :: hh5 = [2, 1, 0, -1, -2] h = 0 select case (s) case (SCALAR) select case (i) case (1:1); h = hh1(i) end select case (SPINOR) select case (i) case (1:2); h = hh2(i) end select case (VECTOR) select case (i) case (1:3); h = hh3(i) end select case (VECTORSPINOR) select case (i) case (1:4); h = hh4(i) end select case (TENSOR) select case (i) case (1:5); h = hh5(i) end select end select end function helicity_value @ %def helicity_value @ Inverse: return the index that corresponds to a certain helicity value in the chosen representation. <>= public :: helicity_index <>= function helicity_index (s, h) result (i) integer, intent(in) :: s, h integer :: i integer, dimension(0:0), parameter :: hi1 = [1] integer, dimension(-1:1), parameter :: hi2 = [2, 0, 1] integer, dimension(-1:1), parameter :: hi3 = [3, 2, 1] integer, dimension(-2:2), parameter :: hi4 = [4, 3, 0, 2, 1] integer, dimension(-2:2), parameter :: hi5 = [5, 4, 3, 2, 1] select case (s) case (SCALAR) i = hi1(h) case (SPINOR) i = hi2(h) case (VECTOR) i = hi3(h) case (VECTORSPINOR) i = hi4(h) case (TENSOR) i = hi5(h) end select end function helicity_index @ %def helicity_index @ \subsection{Generator Basis: Cartan Generators} For each supported spin type, we return specific properties of the set of generators via inquiry functions. This is equivalent to using explicit representations of the generators. For easy access, the properties are hard-coded and selected via case expressions. Return true if the generator \#[[i]] is in the Cartan subalgebra, i.e., a diagonal matrix for spin type [[s]]. <>= public :: is_cartan_generator <>= elemental function is_cartan_generator (s, i) result (cartan) logical :: cartan integer, intent(in) :: s, i select case (s) case (SCALAR) case (SPINOR) select case (i) case (3); cartan = .true. case default cartan = .false. end select case (VECTOR) select case (i) case (3,8); cartan = .true. case default cartan = .false. end select case (VECTORSPINOR) select case (i) case (3,6,15); cartan = .true. case default cartan = .false. end select case (TENSOR) select case (i) case (3,6,15,24); cartan = .true. case default cartan = .false. end select case default cartan = .false. end select end function is_cartan_generator @ %def is_cartan_generator @ Return the index of Cartan generator \#[[k]] in the chosen representation. This has to conform to [[cartan]] above. <>= public :: cartan_index <>= elemental function cartan_index (s, k) result (ci) integer :: ci integer, intent(in) :: s, k integer, dimension(1), parameter :: ci2 = [3] integer, dimension(2), parameter :: ci3 = [3,8] integer, dimension(3), parameter :: ci4 = [3,6,15] integer, dimension(4), parameter :: ci5 = [3,6,15,24] select case (s) case (SPINOR) ci = ci2(k) case (VECTOR) ci = ci3(k) case (VECTORSPINOR) ci = ci4(k) case (TENSOR) ci = ci5(k) case default ci = 0 end select end function cartan_index @ %def cartan_index @ The element \#[[k]] of the result vector [[a]] is equal to the $(h,h)$ diagonal entry of the generator matrix $T^k$. That is, evaluating this for all allowed values of [[h]], we recover the set of Cartan generator matrices. <>= public :: cartan_element <>= function cartan_element (s, h) result (a) real(default), dimension(:), allocatable :: a integer, intent(in) :: s, h real(default), parameter :: sqrt2 = sqrt (2._default) real(default), parameter :: sqrt3 = sqrt (3._default) real(default), parameter :: sqrt10 = sqrt (10._default) allocate (a (algebra_dimension (s)), source = 0._default) select case (s) case (SCALAR) case (SPINOR) select case (h) case (1) a(3) = 1._default / 2 case (-1) a(3) = -1._default / 2 end select case (VECTOR) select case (h) case (1) a(3) = 1._default / 2 a(8) = 1._default / (2 * sqrt3) case (-1) a(3) = -1._default / 2 a(8) = 1._default / (2 * sqrt3) case (0) a(8) = -1._default / sqrt3 end select case (VECTORSPINOR) select case (h) case (2) a(3) = 1._default / 2 a(15) = 1._default / (2 * sqrt2) case (-2) a(3) = -1._default / 2 a(15) = 1._default / (2 * sqrt2) case (1) a(6) = 1._default / 2 a(15) = -1._default / (2 * sqrt2) case (-1) a(6) = -1._default / 2 a(15) = -1._default / (2 * sqrt2) end select case (TENSOR) select case (h) case (2) a(3) = 1._default / 2 a(15) = 1._default / (2 * sqrt2) a(24) = 1._default / (2 * sqrt10) case (-2) a(3) = -1._default / 2 a(15) = 1._default / (2 * sqrt2) a(24) = 1._default / (2 * sqrt10) case (1) a(6) = 1._default / 2 a(15) = -1._default / (2 * sqrt2) a(24) = 1._default / (2 * sqrt10) case (-1) a(6) = -1._default / 2 a(15) = -1._default / (2 * sqrt2) a(24) = 1._default / (2 * sqrt10) case (0) a(24) = -4._default / (2 * sqrt10) end select end select end function cartan_element @ %def cartan_element @ Given an array of diagonal matrix elements [[rd]] of a generator, compute the array [[a]] of basis coefficients. The array must be ordered as defined by [[helicity_value]], i.e., highest weight first. The calculation is organized such that the trace of the generator, i.e., the sum of [[rd]] values, drops out. The result array [[a]] has coefficients for all basis generators, but only Cartan generators can get a nonzero coefficient. <>= public :: cartan_coeff <>= function cartan_coeff (s, rd) result (a) real(default), dimension(:), allocatable :: a integer, intent(in) :: s real(default), dimension(:), intent(in) :: rd real(default), parameter :: sqrt2 = sqrt (2._default) real(default), parameter :: sqrt3 = sqrt (3._default) real(default), parameter :: sqrt10 = sqrt (10._default) integer :: n n = algebra_dimension (s) allocate (a (n), source = 0._default) select case (s) case (SPINOR) a(3) = rd(1) - rd(2) case (VECTOR) a(3) = rd(1) - rd(3) a(8) = (rd(1) - 2 * rd(2) + rd(3)) / sqrt3 case (VECTORSPINOR) a(3) = rd(1) - rd(4) a(6) = rd(2) - rd(3) a(15) = (rd(1) - rd(2) - rd(3) + rd(4)) / sqrt2 case (TENSOR) a(3) = rd(1) - rd(5) a(6) = rd(2) - rd(4) a(15) = (rd(1) - rd(2) - rd(4) + rd(5)) / sqrt2 a(24) = (rd(1) + rd(2) - 4 * rd(3) + rd(4) + rd(5)) / sqrt10 end select end function cartan_coeff @ %def cartan_coeff @ \subsection{Roots (Off-Diagonal Generators)} Return the appropriate generator index for a given off-diagonal helicity combination. We require $h_1>h_2$. We return the index of the appropriate real-valued generator if [[r]] is true, else the complex-valued one. This is separate from the [[cartan_coeff]] function above. The reason is that the off-diagonal generators have only a single nonzero matrix element, so there is a one-to-one correspondence of helicity and index. <>= public :: root_index <>= function root_index (s, h1, h2, r) result (ai) integer :: ai integer, intent(in) :: s, h1, h2 logical :: r ai = 0 select case (s) case (SCALAR) case (SPINOR) select case (h1) case (1) select case (h2) case (-1); ai = 1 end select end select case (VECTOR) select case (h1) case (1) select case (h2) case (-1); ai = 1 case (0); ai = 4 end select case (0) select case (h2) case (-1); ai = 6 end select end select case (VECTORSPINOR) select case (h1) case (2) select case (h2) case (-2); ai = 1 case (1); ai = 7 case (-1); ai = 11 end select case (1) select case (h2) case (-1); ai = 4 case (-2); ai = 13 end select case (-1) select case (h2) case (-2); ai = 9 end select end select case (TENSOR) select case (h1) case (2) select case (h2) case (-2); ai = 1 case (1); ai = 7 case (-1); ai = 11 case (0); ai = 16 end select case (1) select case (h2) case (-1); ai = 4 case (-2); ai = 13 case (0); ai = 20 end select case (-1) select case (h2) case (-2); ai = 9 end select case (0) select case (h2) case (-2); ai = 18 case (-1); ai = 22 end select end select end select if (ai /= 0 .and. .not. r) ai = ai + 1 end function root_index @ %def root_index @ Inverse: return the helicity values ($h_2>h_1$) for an off-diagonal generator. The flag [[r]] tells whether this is a real or diagonal generator. The others are Cartan generators. <>= public :: root_helicity <>= subroutine root_helicity (s, i, h1, h2, r) integer, intent(in) :: s, i integer, intent(out) :: h1, h2 logical, intent(out) :: r h1 = 0 h2 = 0 r = .false. select case (s) case (SCALAR) case (SPINOR) select case (i) case ( 1, 2); h1 = 1; h2 = -1; r = i == 1 end select case (VECTOR) select case (i) case ( 1, 2); h1 = 1; h2 = -1; r = i == 1 case ( 4, 5); h1 = 1; h2 = 0; r = i == 4 case ( 6, 7); h1 = 0; h2 = -1; r = i == 6 end select case (VECTORSPINOR) select case (i) case ( 1, 2); h1 = 2; h2 = -2; r = i == 1 case ( 4, 5); h1 = 1; h2 = -1; r = i == 4 case ( 7, 8); h1 = 2; h2 = 1; r = i == 7 case ( 9,10); h1 = -1; h2 = -2; r = i == 9 case (11,12); h1 = 2; h2 = -1; r = i ==11 case (13,14); h1 = 1; h2 = -2; r = i ==13 end select case (TENSOR) select case (i) case ( 1, 2); h1 = 2; h2 = -2; r = i == 1 case ( 4, 5); h1 = 1; h2 = -1; r = i == 4 case ( 7, 8); h1 = 2; h2 = 1; r = i == 7 case ( 9,10); h1 = -1; h2 = -2; r = i == 9 case (11,12); h1 = 2; h2 = -1; r = i ==11 case (13,14); h1 = 1; h2 = -2; r = i ==13 case (16,17); h1 = 2; h2 = 0; r = i ==16 case (18,19); h1 = 0; h2 = -2; r = i ==18 case (20,21); h1 = 1; h2 = 0; r = i ==20 case (22,23); h1 = 0; h2 = -1; r = i ==22 end select end select end subroutine root_helicity @ %def root_helicity @ \subsection{Unit tests} Test module, followed by the corresponding implementation module. <<[[su_algebra_ut.f90]]>>= <> module su_algebra_ut use unit_tests use su_algebra_uti <> <> contains <> end module su_algebra_ut @ %def su_algebra_ut @ <<[[su_algebra_uti.f90]]>>= <> module su_algebra_uti <> use physics_defs, only: SCALAR, SPINOR, VECTOR, VECTORSPINOR, TENSOR use su_algebra <> <> contains <> end module su_algebra_uti @ %def su_algebra_ut @ API: driver for the unit tests below. <>= public :: su_algebra_test <>= subroutine su_algebra_test (u, results) integer, intent(in) :: u type(test_results_t), intent(inout) :: results <> end subroutine su_algebra_test @ %def su_algebra_test @ \subsubsection{Generator Ordering} Show the position of Cartan generators in the sequence of basis generators. <>= call test (su_algebra_1, "su_algebra_1", & "generator ordering", & u, results) <>= public :: su_algebra_1 <>= subroutine su_algebra_1 (u) integer, intent(in) :: u write (u, "(A)") "* Test output: su_algebra_1" write (u, "(A)") "* Purpose: test su(N) algebra implementation" write (u, "(A)") write (u, "(A)") "* su(N) generators: & &list and mark Cartan subalgebra" write (u, "(A)") write (u, "(A)") "* s = 0" call cartan_check (SCALAR) write (u, "(A)") write (u, "(A)") "* s = 1/2" call cartan_check (SPINOR) write (u, "(A)") write (u, "(A)") "* s = 1" call cartan_check (VECTOR) write (u, "(A)") write (u, "(A)") "* s = 3/2" call cartan_check (VECTORSPINOR) write (u, "(A)") write (u, "(A)") "* s = 2" call cartan_check (TENSOR) write (u, "(A)") write (u, "(A)") "* Test output end: su_algebra_1" contains subroutine cartan_check (s) integer, intent(in) :: s integer :: i write (u, *) do i = 1, algebra_dimension (s) write (u, "(1x,L1)", advance="no") is_cartan_generator (s, i) end do write (u, *) end subroutine cartan_check end subroutine su_algebra_1 @ %def su_algebra_1 @ \subsubsection{Cartan Generator Basis} Show the explicit matrix representation for all Cartan generators and check their traces and Killing products. Also test helicity index mappings. <>= call test (su_algebra_2, "su_algebra_2", & "Cartan generator representation", & u, results) <>= public :: su_algebra_2 <>= subroutine su_algebra_2 (u) integer, intent(in) :: u write (u, "(A)") "* Test output: su_algebra_2" write (u, "(A)") "* Purpose: test su(N) algebra implementation" write (u, "(A)") write (u, "(A)") "* diagonal su(N) generators: & &show explicit representation" write (u, "(A)") "* and check trace and Killing form" write (u, "(A)") write (u, "(A)") "* s = 1/2" call cartan_show (SPINOR) write (u, "(A)") write (u, "(A)") "* s = 1" call cartan_show (VECTOR) write (u, "(A)") write (u, "(A)") "* s = 3/2" call cartan_show (VECTORSPINOR) write (u, "(A)") write (u, "(A)") "* s = 2" call cartan_show (TENSOR) write (u, "(A)") write (u, "(A)") "* Test output end: su_algebra_2" contains subroutine cartan_show (s) integer, intent(in) :: s real(default), dimension(:,:), allocatable :: rd integer, dimension(:), allocatable :: ci integer :: n, d, h, i, j, k, l n = algebra_dimension (s) d = fundamental_dimension (s) write (u, *) write (u, "(A2,5X)", advance="no") "h:" do i = 1, d j = helicity_index (s, helicity_value (s, i)) write (u, "(1x,I2,5X)", advance="no") helicity_value (s, j) end do write (u, "(8X)", advance="no") write (u, "(1X,A)") "tr" allocate (rd (n,d), source = 0._default) do i = 1, d h = helicity_value (s, i) rd(:,i) = cartan_element (s, h) end do allocate (ci (d-1), source = 0) do k = 1, d-1 ci(k) = cartan_index (s, k) end do write (u, *) do k = 1, d-1 write (u, "('T',I2,':',1X)", advance="no") ci(k) do i = 1, d write (u, 1, advance="no") rd(ci(k),i) end do write (u, "(8X)", advance="no") write (u, 1) sum (rd(ci(k),:)) end do write (u, *) write (u, "(6X)", advance="no") do k = 1, d-1 write (u, "(2X,'T',I2,3X)", advance="no") ci(k) end do write (u, *) do k = 1, d-1 write (u, "('T',I2,2X)", advance="no") ci(k) do l = 1, d-1 write (u, 1, advance="no") dot_product (rd(ci(k),:), rd(ci(l),:)) end do write (u, *) end do 1 format (1x,F7.4) end subroutine cartan_show end subroutine su_algebra_2 @ %def su_algebra_2 @ \subsubsection{Bloch Representation: Cartan Generators} Transform from Bloch vectors to matrix and back, considering Cartan generators only. <>= call test (su_algebra_3, "su_algebra_3", & "Cartan generator mapping", & u, results) <>= public :: su_algebra_3 <>= subroutine su_algebra_3 (u) integer, intent(in) :: u write (u, "(A)") "* Test output: su_algebra_3" write (u, "(A)") "* Purpose: test su(N) algebra implementation" write (u, "(A)") write (u, "(A)") "* diagonal su(N) generators: & &transform to matrix and back" write (u, "(A)") write (u, "(A)") "* s = 1/2" call cartan_expand (SPINOR) write (u, "(A)") write (u, "(A)") "* s = 1" call cartan_expand (VECTOR) write (u, "(A)") write (u, "(A)") "* s = 3/2" call cartan_expand (VECTORSPINOR) write (u, "(A)") write (u, "(A)") "* s = 2" call cartan_expand (TENSOR) write (u, "(A)") write (u, "(A)") "* Test output end: su_algebra_3" contains subroutine cartan_expand (s) integer, intent(in) :: s real(default), dimension(:,:), allocatable :: rd integer, dimension(:), allocatable :: ci real(default), dimension(:), allocatable :: a logical, dimension(:), allocatable :: mask integer :: n, d, h, i, k, l n = algebra_dimension (s) d = fundamental_dimension (s) allocate (rd (n,d), source = 0._default) do i = 1, d h = helicity_value (s, i) rd(:,i) = cartan_element (s, h) end do allocate (ci (d-1), source = 0) do k = 1, d-1 ci(k) = cartan_index (s, k) end do allocate (a (n)) write (u, *) do k = 1, d-1 a(:) = cartan_coeff (s, rd(ci(k),:)) write (u, "('T',I2,':',1X)", advance="no") ci(k) do i = 1, n if (is_cartan_generator (s, i)) then write (u, 1, advance="no") a(i) else if (a(i) /= 0) then ! this should not happen (nonzero non-Cartan entry) write (u, "(1X,':',I2,':',3X)", advance="no") i end if end do write (u, *) end do 1 format (1X,F7.4) end subroutine cartan_expand end subroutine su_algebra_3 @ %def su_algebra_3 @ \subsubsection{Bloch Representation: Roots} List the mapping between helicity transitions and (real) off-diagonal generators. <>= call test (su_algebra_4, "su_algebra_4", & "Root-helicity mapping", & u, results) <>= public :: su_algebra_4 <>= subroutine su_algebra_4 (u) integer, intent(in) :: u write (u, "(A)") "* Test output: su_algebra_4" write (u, "(A)") "* Purpose: test su(N) algebra implementation" write (u, "(A)") write (u, "(A)") "* off-diagonal su(N) generators: & &mapping from/to helicity pair" write (u, "(A)") write (u, "(A)") "* s = 1/2" call root_expand (SPINOR) write (u, "(A)") write (u, "(A)") "* s = 1" call root_expand (VECTOR) write (u, "(A)") write (u, "(A)") "* s = 3/2" call root_expand (VECTORSPINOR) write (u, "(A)") write (u, "(A)") "* s = 2" call root_expand (TENSOR) write (u, "(A)") write (u, "(A)") "* Test output end: su_algebra_4" contains subroutine root_expand (s) integer, intent(in) :: s integer :: n, d, i, j, h1, h2 logical :: r n = algebra_dimension (s) write (u, *) do i = 1, n if (is_cartan_generator (s, i)) cycle call root_helicity (s, i, h1, h2, r) j = root_index (s, h1, h2, r) write (u, "('T',I2,':')", advance="no") j write (u, "(2(1x,I2))", advance="no") h1, h2 if (r) then write (u, *) else write (u, "('*')") end if end do end subroutine root_expand end subroutine su_algebra_4 @ %def su_algebra_4 @ \clearpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Bloch Representation} Particle polarization is determined by a particular quantum state which has just helicity information. Physically, this is the spin density matrix $\rho$, where we do not restrict ourselves to pure states. We adopt the phase convention for a spin-1/2 particle that \begin{equation} \rho = \tfrac12(1 + \vec\alpha\cdot\vec\sigma) \end{equation} with the polarization axis $\vec\alpha$. For a particle with arbitrary spin $s$, and thus $N=2s+1$ spin states, we extend the above definition to generalized Bloch form \begin{equation} \rho = \frac1N\left(1 + \sqrt{2N(N-1)}\alpha^aT^a\right) \end{equation} where the $T^a$ ($a=1,\ldots N^2-1$) are a basis of $su(N)$ algebra generators. These $N\times N$ matrices are hermitean, traceless, and orthogonal via \begin{equation} \mathop{\rm Tr}T^aT^b = \frac12 \delta^{ab} \end{equation} In the spin-1/2 case, this reduces to the above (standard Bloch) representation since $T^a = \sigma^a/2$, $a=1,2,3$. For the spin-1 case, we could use $T^a = \lambda^a/2$ with the Gell-Mann matrices, \begin{equation} \rho = \frac13\left(1 + \sqrt{3}\alpha^a\lambda^a\right), \end{equation} The normalization is chosen that $|alpha|\leq 1$ for allowed density matrix, where $|\alpha|=1$ is a necessary, but not sufficient, condition for a pure state. We need a specific choice of basis for a well-defined component representation. The matrix elements of $T^a$ are ordered as $m=\ell,\ell-1,\ldots -\ell$, i.e., from highest down to lowest weight, for both row and column. We list first the generators of the $su(2)$ subalgebras which leave $|m|$ invariant ($|m|\neq 0$): \begin{equation} T^{b+1,b+2,b+3} \equiv \sigma^{1,2,3} \end{equation} acting on the respective subspace $|m|=\ell,\ell-1,\ldots$ for $b=0,1,\ldots$. This defines generators $T^a$ for $a=1,\ldots 3N/2$ ($\ldots 3(N-1)/2$) for $N$ even (odd), respectively. The following generators successively extend this to $su(4)$, $su(6)$, \ldots until $su(N)$ by adding first the missing off-diagonal and then diagonal generators. The phase conventions are analogous. (It should be possible to code these conventions for generic spin, but in the current implementation we restrict ourselves to $s\leq 2$, i.e., $N\leq 5$.) Particle polarization is determined by a particular quantum state which has just helicity information. Physically, this is the spin density matrix $\rho$, where we do not restrict ourselves to pure states. We adopt the phase convention for a spin-1/2 particle that \begin{equation} \rho = \tfrac12(1 + \vec\alpha\cdot\vec\sigma) \end{equation} with the polarization axis $\vec\alpha$. For a particle with arbitrary spin $s$, and thus $N=2s+1$ spin states, we extend the above definition to generalized Bloch form \begin{equation} \rho = \frac1N\left(1 + \sqrt{2N(N-1)}\alpha^aT^a\right) \end{equation} where the $T^a$ ($a=1,\ldots N^2-1$) are a basis of $su(N)$ algebra generators. These $N\times N$ matrices are hermitean, traceless, and orthogonal via \begin{equation} \mathop{\rm Tr}T^aT^b = \frac12 \delta^{ab} \end{equation} In the spin-1/2 case, this reduces to the above (standard Bloch) representation since $T^a = \sigma^a/2$, $a=1,2,3$. For the spin-1 case, we could use $T^a = \lambda^a/2$ with the Gell-Mann matrices, \begin{equation} \rho = \frac13\left(1 + \sqrt{3}\alpha^a\lambda^a\right), \end{equation} The normalization is chosen that $|alpha|\leq 1$ for allowed density matrix, where $|\alpha|=1$ is a necessary, but not sufficient, condition for a pure state. <<[[bloch_vectors.f90]]>>= <> module bloch_vectors <> use physics_defs, only: UNKNOWN, SCALAR, SPINOR, VECTOR, VECTORSPINOR, TENSOR use su_algebra <> <> <> contains <> end module bloch_vectors @ %def bloch_vectors @ \subsection{Preliminaries} The normalization factor $\sqrt{2N(N-1)}/N$ that enters the Bloch representation. <>= function bloch_factor (s) result (f) real(default) :: f integer, intent(in) :: s select case (s) case (SCALAR) f = 0 case (SPINOR) f = 1 case (VECTOR) f = 2 * sqrt (3._default) / 3 case (VECTORSPINOR) f = 2 * sqrt (6._default) / 4 case (TENSOR) f = 2 * sqrt (10._default) / 5 case default f = 0 end select end function bloch_factor @ %def bloch_factor @ \subsection{The basic polarization type} The basic polarization object holds just the entries of the Bloch vector as an allocatable array. Bloch is active whenever the coefficient array is allocated. For convenience, we store the spin type ($2s$) and the multiplicity ($N$) together with the coefficient array ($\alpha$). We have to allow for the massless case where $s$ is arbitrary $>0$ but $N=2$, and furthermore the chiral massless case where $N=1$. In the latter case, the array remains deallocated but the chirality is set to $\pm 1$. In the Bloch vector implementation, we do not distinguish between particle and antiparticle. If the distinction applies, it must be made by the caller when transforming between density matrix and Bloch vector. <>= public :: bloch_vector_t <>= type :: bloch_vector_t private integer :: spin_type = UNKNOWN real(default), dimension(:), allocatable :: a contains <> end type bloch_vector_t @ %def bloch_vector_t @ \subsection{Direct Access} This basic initializer just sets the spin type, leaving the Bloch vector unallocated. The object therefore does not support nonzero polarization. <>= procedure :: init_unpolarized => bloch_vector_init_unpolarized <>= subroutine bloch_vector_init_unpolarized (pol, spin_type) class(bloch_vector_t), intent(out) :: pol integer, intent(in) :: spin_type pol%spin_type = spin_type end subroutine bloch_vector_init_unpolarized @ %def bloch_vector_init_unpolarized @ The standard initializer allocates the Bloch vector and initializes with zeros, so we can define a polarization later. We make sure that this works only for the supported spin type. Initializing with [[UNKNOWN]] spin type resets the Bloch vector to undefined, i.e., unpolarized state. <>= generic :: init => bloch_vector_init procedure, private :: bloch_vector_init <>= subroutine bloch_vector_init (pol, spin_type) class(bloch_vector_t), intent(out) :: pol integer, intent(in) :: spin_type pol%spin_type = spin_type select case (spin_type) case (SCALAR,SPINOR,VECTOR,VECTORSPINOR,TENSOR) allocate (pol%a (algebra_dimension (spin_type)), source = 0._default) end select end subroutine bloch_vector_init @ %def bloch_vector_init @ Fill the Bloch vector from an array, no change of normalization. No initialization and no check, we assume that the shapes do match. <>= procedure :: from_array => bloch_vector_from_array <>= subroutine bloch_vector_from_array (pol, a) class(bloch_vector_t), intent(inout) :: pol real(default), dimension(:), allocatable, intent(in) :: a pol%a(:) = a end subroutine bloch_vector_from_array @ %def bloch_vector_from_array @ Transform to an array of reals, i.e., extract the Bloch vector as-is. <>= procedure :: to_array => bloch_vector_to_array <>= subroutine bloch_vector_to_array (pol, a) class(bloch_vector_t), intent(in) :: pol real(default), dimension(:), allocatable, intent(out) :: a if (pol%is_defined ()) allocate (a (size (pol%a)), source = pol%a) end subroutine bloch_vector_to_array @ %def bloch_vector_to_array @ \subsection{Raw I/O} <>= procedure :: write_raw => bloch_vector_write_raw procedure :: read_raw => bloch_vector_read_raw <>= subroutine bloch_vector_write_raw (pol, u) class(bloch_vector_t), intent(in) :: pol integer, intent(in) :: u write (u) pol%spin_type write (u) allocated (pol%a) if (allocated (pol%a)) then write (u) pol%a end if end subroutine bloch_vector_write_raw subroutine bloch_vector_read_raw (pol, u, iostat) class(bloch_vector_t), intent(out) :: pol integer, intent(in) :: u integer, intent(out) :: iostat integer :: s logical :: polarized read (u, iostat=iostat) s read (u, iostat=iostat) polarized if (iostat /= 0) return if (polarized) then call pol%init (s) read (u, iostat=iostat) pol%a else call pol%init_unpolarized (s) end if end subroutine bloch_vector_read_raw @ %def bloch_vector_write_raw @ %def bloch_vector_read_raw @ \subsection{Properties} Re-export algebra functions that depend on the spin type. These functions do not depend on the Bloch vector being allocated. <>= procedure :: get_n_states procedure :: get_length procedure :: hel_index => bv_helicity_index procedure :: hel_value => bv_helicity_value procedure :: bloch_factor => bv_factor <>= function get_n_states (pol) result (n) class(bloch_vector_t), intent(in) :: pol integer :: n n = fundamental_dimension (pol%spin_type) end function get_n_states function get_length (pol) result (n) class(bloch_vector_t), intent(in) :: pol integer :: n n = algebra_dimension (pol%spin_type) end function get_length function bv_helicity_index (pol, h) result (i) class(bloch_vector_t), intent(in) :: pol integer, intent(in) :: h integer :: i i = helicity_index (pol%spin_type, h) end function bv_helicity_index function bv_helicity_value (pol, i) result (h) class(bloch_vector_t), intent(in) :: pol integer, intent(in) :: i integer :: h h = helicity_value (pol%spin_type, i) end function bv_helicity_value function bv_factor (pol) result (f) class(bloch_vector_t), intent(in) :: pol real(default) :: f f = bloch_factor (pol%spin_type) end function bv_factor @ %def get_n_states @ %def helicity_index @ %def helicity_value @ If the Bloch vector object is defined, the spin type is anything else but [[UNKNOWN]]. This allows us the provide the representation-specific functions above. <>= procedure :: is_defined => bloch_vector_is_defined <>= function bloch_vector_is_defined (pol) result (flag) class(bloch_vector_t), intent(in) :: pol logical :: flag flag = pol%spin_type /= UNKNOWN end function bloch_vector_is_defined @ %def bloch_vector_is_defined @ If the Bloch vector object is (technically) polarized, it is defined, and the vector coefficient array has been allocated. However, the vector value may be zero. <>= procedure :: is_polarized => bloch_vector_is_polarized <>= function bloch_vector_is_polarized (pol) result (flag) class(bloch_vector_t), intent(in) :: pol logical :: flag flag = allocated (pol%a) end function bloch_vector_is_polarized @ %def bloch_vector_is_polarized @ Return true if the polarization is diagonal, i.e., all entries in the density matrix are on the diagonal. This is equivalent to requiring that only Cartan generator coefficients are nonzero in the Bloch vector. <>= procedure :: is_diagonal => bloch_vector_is_diagonal <>= function bloch_vector_is_diagonal (pol) result (diagonal) class(bloch_vector_t), intent(in) :: pol logical :: diagonal integer :: s, i s = pol%spin_type diagonal = .true. if (pol%is_polarized ()) then do i = 1, size (pol%a) if (is_cartan_generator (s, i)) cycle if (pol%a(i) /= 0) then diagonal = .false. return end if end do end if end function bloch_vector_is_diagonal @ %def bloch_vector_is_diagonal @ Return the Euclidean norm of the Bloch vector. This is equal to the Killing form value of the corresponding algebra generator. We assume that the polarization object has been initialized. For a pure state, the norm is unity. All other allowed states have a norm less than unity. (For $s\geq 1$, this is a necessary but not sufficient condition.) <>= procedure :: get_norm => bloch_vector_get_norm <>= function bloch_vector_get_norm (pol) result (norm) class(bloch_vector_t), intent(in) :: pol real(default) :: norm select case (pol%spin_type) case (SPINOR,VECTOR,VECTORSPINOR,TENSOR) norm = sqrt (dot_product (pol%a, pol%a)) case default norm = 1 end select end function bloch_vector_get_norm @ %def bloch_vector_get_norm @ \subsection{Diagonal density matrix} This initializer takes a diagonal density matrix, represented by a real-valued array. We assume that the trace is unity, and that the array has the correct shape for the given [[spin_type]]. The [[bloch_factor]] renormalization is necessary such that a pure state maps to a Bloch vector with unit norm. <>= generic :: init => bloch_vector_init_diagonal procedure, private :: bloch_vector_init_diagonal <>= subroutine bloch_vector_init_diagonal (pol, spin_type, rd) class(bloch_vector_t), intent(out) :: pol integer, intent(in) :: spin_type real(default), dimension(:), intent(in) :: rd call pol%init (spin_type) call pol%set (rd) end subroutine bloch_vector_init_diagonal @ %def bloch_vector_init_diagonal @ Set a Bloch vector, given a diagonal density matrix as a real array. The Bloch vector must be initialized with correct characteristics. <>= generic :: set => bloch_vector_set_diagonal procedure, private :: bloch_vector_set_diagonal <>= subroutine bloch_vector_set_diagonal (pol, rd) class(bloch_vector_t), intent(inout) :: pol real(default), dimension(:), intent(in) :: rd integer :: s s = pol%spin_type select case (s) case (SCALAR,SPINOR,VECTOR,VECTORSPINOR,TENSOR) pol%a(:) = cartan_coeff (s, rd) / bloch_factor (s) end select end subroutine bloch_vector_set_diagonal @ %def bloch_vector_set_diagonal @ @ \subsection{Massless density matrix} This is a specific variant which initializes an equipartition for the maximum helicity, corresponding to an unpolarized massless particle. <>= procedure :: init_max_weight => bloch_vector_init_max_weight <>= subroutine bloch_vector_init_max_weight (pol, spin_type) class(bloch_vector_t), intent(out) :: pol integer, intent(in) :: spin_type call pol%init (spin_type) select case (spin_type) case (VECTOR) call pol%set ([0.5_default, 0._default, 0.5_default]) case (VECTORSPINOR) call pol%set ([0.5_default, 0._default, 0._default, 0.5_default]) case (TENSOR) call pol%set ([0.5_default, 0._default, 0._default, 0._default, 0.5_default]) end select end subroutine bloch_vector_init_max_weight @ %def bloch_vector_init_max_weight @ Initialize the maximum-weight submatrix with a three-component Bloch vector. This is not as trivial as it seems because we need the above initialization for the generalized Bloch in order to remove the lower weights from the density matrix. <>= procedure :: init_vector => bloch_vector_init_vector procedure :: to_vector => bloch_vector_to_vector <>= subroutine bloch_vector_init_vector (pol, s, a) class(bloch_vector_t), intent(out) :: pol integer, intent(in) :: s real(default), dimension(3), intent(in) :: a call pol%init_max_weight (s) select case (s) case (SPINOR, VECTOR, VECTORSPINOR, TENSOR) pol%a(1:3) = a / bloch_factor (s) end select end subroutine bloch_vector_init_vector subroutine bloch_vector_to_vector (pol, a) class(bloch_vector_t), intent(in) :: pol real(default), dimension(3), intent(out) :: a integer :: s s = pol%spin_type select case (s) case (SPINOR, VECTOR, VECTORSPINOR, TENSOR) a = pol%a(1:3) * bloch_factor (s) case default a = 0 end select end subroutine bloch_vector_to_vector @ %def bloch_vector_init_vector @ %def bloch_vector_to_vector @ \subsection{Arbitrary density matrix} Initialize the Bloch vector from a density matrix. We assume that the density is valid. In particular, the shape should match, the matrix should be hermitian, and the trace should be unity. We first fill the diagonal, then add the off-diagonal parts. <>= generic :: init => bloch_vector_init_matrix procedure, private :: bloch_vector_init_matrix <>= subroutine bloch_vector_init_matrix (pol, spin_type, r) class(bloch_vector_t), intent(out) :: pol integer, intent(in) :: spin_type complex(default), dimension(:,:), intent(in) :: r select case (spin_type) case (SCALAR,SPINOR,VECTOR,VECTORSPINOR,TENSOR) call pol%init (spin_type) call pol%set (r) case default call pol%init (UNKNOWN) end select end subroutine bloch_vector_init_matrix @ %def bloch_vector_init_matrix @ Set a Bloch vector, given an arbitrary density matrix as a real array. The Bloch vector must be initialized with correct characteristics. <>= generic :: set => bloch_vector_set_matrix procedure, private :: bloch_vector_set_matrix <>= subroutine bloch_vector_set_matrix (pol, r) class(bloch_vector_t), intent(inout) :: pol complex(default), dimension(:,:), intent(in) :: r real(default), dimension(:), allocatable :: rd integer :: s, d, i, j, h1, h2, ir, ii s = pol%spin_type select case (s) case (SCALAR,SPINOR,VECTOR,VECTORSPINOR,TENSOR) d = fundamental_dimension (s) allocate (rd (d)) do i = 1, d rd(i) = r(i,i) end do call pol%set (rd) do i = 1, d h1 = helicity_value (s, i) do j = i+1, d h2 = helicity_value (s, j) ir = root_index (s, h1, h2, .true.) ii = root_index (s, h1, h2, .false.) pol%a(ir) = real (r(j,i) + r(i,j)) / bloch_factor (s) pol%a(ii) = aimag (r(j,i) - r(i,j)) / bloch_factor (s) end do end do end select end subroutine bloch_vector_set_matrix @ %def bloch_vector_set_matrix @ Allocate and fill the density matrix [[r]] (with the index ordering as defined in [[su_algebra]]) that corresponds to a given Bloch vector. If the optional [[only_max_weight]] is set, the resulting matrix has entries only for $\pm h_\text{max}$, as appropriate for a massless particle (for spin $\geq 1$). Note that we always add the unit matrix, as this is part of the Bloch-vector definition. <>= procedure :: to_matrix => bloch_vector_to_matrix <>= subroutine bloch_vector_to_matrix (pol, r, only_max_weight) class(bloch_vector_t), intent(in) :: pol complex(default), dimension(:,:), intent(out), allocatable :: r logical, intent(in), optional :: only_max_weight integer :: d, s, h0, ng, ai, h, h1, h2, i, j logical :: is_real, only_max complex(default) :: val if (.not. pol%is_polarized ()) return s = pol%spin_type only_max = .false. select case (s) case (VECTOR, VECTORSPINOR, TENSOR) if (present (only_max_weight)) only_max = only_max_weight end select if (only_max) then ng = 2 h0 = helicity_value (s, 1) else ng = algebra_dimension (s) h0 = 0 end if d = fundamental_dimension (s) allocate (r (d, d), source = (0._default, 0._default)) do i = 1, d h = helicity_value (s, i) if (abs (h) < h0) cycle r(i,i) = 1._default / d & + dot_product (cartan_element (s, h), pol%a) * bloch_factor (s) end do do ai = 1, ng if (is_cartan_generator (s, ai)) cycle call root_helicity (s, ai, h1, h2, is_real) i = helicity_index (s, h1) j = helicity_index (s, h2) if (is_real) then val = cmplx (pol%a(ai) / 2 * bloch_factor (s), 0._default, & kind=default) r(i,j) = r(i,j) + val r(j,i) = r(j,i) + val else val = cmplx (0._default, pol%a(ai) / 2 * bloch_factor (s), & kind=default) r(i,j) = r(i,j) - val r(j,i) = r(j,i) + val end if end do end subroutine bloch_vector_to_matrix @ %def bloch_vector_to_matrix @ \subsection{Unit tests} Test module, followed by the corresponding implementation module. <<[[bloch_vectors_ut.f90]]>>= <> module bloch_vectors_ut use unit_tests use bloch_vectors_uti <> <> contains <> end module bloch_vectors_ut @ %def bloch_vectors_ut @ <<[[bloch_vectors_uti.f90]]>>= <> module bloch_vectors_uti <> use physics_defs, only: UNKNOWN, SCALAR, SPINOR, VECTOR, VECTORSPINOR, TENSOR use su_algebra, only: algebra_dimension, fundamental_dimension, helicity_value use bloch_vectors <> <> contains <> end module bloch_vectors_uti @ %def bloch_vectors_ut @ API: driver for the unit tests below. <>= public :: bloch_vectors_test <>= subroutine bloch_vectors_test (u, results) integer, intent(in) :: u type(test_results_t), intent(inout) :: results <> end subroutine bloch_vectors_test @ %def bloch_vectors_test @ \subsubsection{Initialization} Initialize the Bloch vector for any spin type. First as unpolarized (no array), then as polarized but with zero polarization. <>= call test (bloch_vectors_1, "bloch_vectors_1", & "initialization", & u, results) <>= public :: bloch_vectors_1 <>= subroutine bloch_vectors_1 (u) integer, intent(in) :: u write (u, "(A)") "* Test output: bloch_vectors_1" write (u, "(A)") "* Purpose: test Bloch-vector & &polarization implementation" write (u, "(A)") write (u, "(A)") "* Initialization (unpolarized)" write (u, "(A)") write (u, "(A)") "* unknown" call bloch_init (UNKNOWN) write (u, "(A)") write (u, "(A)") "* s = 0" call bloch_init (SCALAR) write (u, "(A)") write (u, "(A)") "* s = 1/2" call bloch_init (SPINOR) write (u, "(A)") write (u, "(A)") "* s = 1" call bloch_init (VECTOR) write (u, "(A)") write (u, "(A)") "* s = 3/2" call bloch_init (VECTORSPINOR) write (u, "(A)") write (u, "(A)") "* s = 2" call bloch_init (TENSOR) write (u, "(A)") write (u, "(A)") "* Test output end: bloch_vectors_1" contains subroutine bloch_init (s) integer, intent(in) :: s type(bloch_vector_t) :: pol real(default), dimension(:), allocatable :: a integer :: i write (u, *) write (u, "(1X,L1,L1)", advance="no") & pol%is_defined (), pol%is_polarized () call pol%init_unpolarized (s) write (u, "(1X,L1,L1)", advance="no") & pol%is_defined (), pol%is_polarized () call pol%init (s) write (u, "(1X,L1,L1)", advance="no") & pol%is_defined (), pol%is_polarized () write (u, *) call pol%to_array (a) if (allocated (a)) then write (u, "(*(F7.4))") a a(:) = [(real (mod (i, 10), kind=default), i = 1, size (a))] call pol%from_array (a) call pol%to_array (a) write (u, "(*(F7.4))") a else write (u, *) write (u, *) end if end subroutine bloch_init end subroutine bloch_vectors_1 @ %def bloch_vectors_1 @ \subsubsection{Pure state (diagonal)} Initialize the Bloch vector with a pure state of definite helicity and check the normalization. <>= call test (bloch_vectors_2, "bloch_vectors_2", & "pure state (diagonal)", & u, results) <>= public :: bloch_vectors_2 <>= subroutine bloch_vectors_2 (u) integer, intent(in) :: u write (u, "(A)") "* Test output: bloch_vectors_2" write (u, "(A)") "* Purpose: test Bloch-vector & &polarization implementation" write (u, "(A)") write (u, "(A)") "* Initialization (polarized, diagonal): & &display vector and norm" write (u, "(A)") "* transform back" write (u, "(A)") write (u, "(A)") "* s = 0" call bloch_diagonal (SCALAR) write (u, "(A)") write (u, "(A)") "* s = 1/2" call bloch_diagonal (SPINOR) write (u, "(A)") write (u, "(A)") "* s = 1" call bloch_diagonal (VECTOR) write (u, "(A)") write (u, "(A)") "* s = 3/2" call bloch_diagonal (VECTORSPINOR) write (u, "(A)") write (u, "(A)") "* s = 2" call bloch_diagonal (TENSOR) write (u, "(A)") write (u, "(A)") "* Test output end: bloch_vectors_2" contains subroutine bloch_diagonal (s) integer, intent(in) :: s type(bloch_vector_t) :: pol real(default), dimension(:), allocatable :: a real(default), dimension(:), allocatable :: rd complex(default), dimension(:,:), allocatable :: r integer :: i, j, d real(default) :: rj real, parameter :: tolerance = 1.E-14_default d = fundamental_dimension (s) do i = 1, d allocate (rd (d), source = 0._default) rd(i) = 1 call pol%init (s, rd) call pol%to_array (a) write (u, *) write (u, "(A,1X,I2)") "h:", helicity_value (s, i) write (u, 1, advance="no") a write (u, "(1X,L1)") pol%is_diagonal () write (u, 1) pol%get_norm () call pol%to_matrix (r) do j = 1, d rj = real (r(j,j)) if (abs (rj) < tolerance) rj = 0 write (u, 1, advance="no") rj end do write (u, "(1X,L1)") matrix_is_diagonal (r) deallocate (a, rd, r) end do 1 format (99(1X,F7.4,:)) end subroutine bloch_diagonal function matrix_is_diagonal (r) result (diagonal) complex(default), dimension(:,:), intent(in) :: r logical :: diagonal integer :: i, j diagonal = .true. do j = 1, size (r, 2) do i = 1, size (r, 1) if (i == j) cycle if (r(i,j) /= 0) then diagonal = .false. return end if end do end do end function matrix_is_diagonal end subroutine bloch_vectors_2 @ %def bloch_vectors_2 @ \subsubsection{Pure state (arbitrary)} Initialize the Bloch vector with an arbitrarily chosen pure state, check the normalization, and transform back to the density matrix. <>= call test (bloch_vectors_3, "bloch_vectors_3", & "pure state (arbitrary)", & u, results) <>= public :: bloch_vectors_3 <>= subroutine bloch_vectors_3 (u) integer, intent(in) :: u write (u, "(A)") "* Test output: bloch_vectors_3" write (u, "(A)") "* Purpose: test Bloch-vector & &polarization implementation" write (u, "(A)") write (u, "(A)") "* Initialization (pure polarized, arbitrary):" write (u, "(A)") "* input matrix, transform, display norm, transform back" write (u, "(A)") write (u, "(A)") "* s = 0" call bloch_arbitrary (SCALAR) write (u, "(A)") write (u, "(A)") "* s = 1/2" call bloch_arbitrary (SPINOR) write (u, "(A)") write (u, "(A)") "* s = 1" call bloch_arbitrary (VECTOR) write (u, "(A)") write (u, "(A)") "* s = 3/2" call bloch_arbitrary (VECTORSPINOR) write (u, "(A)") write (u, "(A)") "* s = 2" call bloch_arbitrary (TENSOR) write (u, "(A)") write (u, "(A)") "* Test output end: bloch_vectors_3" contains subroutine bloch_arbitrary (s) integer, intent(in) :: s type(bloch_vector_t) :: pol complex(default), dimension(:,:), allocatable :: r integer :: d d = fundamental_dimension (s) write (u, *) call init_matrix (d, r) call write_matrix (d, r) call pol%init (s, r) write (u, *) write (u, 2) pol%get_norm (), pol%is_diagonal () write (u, *) call pol%to_matrix (r) call write_matrix (d, r) 2 format (1X,F7.4,1X,L1) end subroutine bloch_arbitrary subroutine init_matrix (d, r) integer, intent(in) :: d complex(default), dimension(:,:), allocatable, intent(out) :: r complex(default), dimension(:), allocatable :: a real(default) :: norm integer :: i, j allocate (a (d)) norm = 0 do i = 1, d a(i) = cmplx (2*i-1, 2*i, kind=default) norm = norm + conjg (a(i)) * a(i) end do a = a / sqrt (norm) allocate (r (d,d)) do i = 1, d do j = 1, d r(i,j) = conjg (a(i)) * a(j) end do end do end subroutine init_matrix subroutine write_matrix (d, r) integer, intent(in) :: d complex(default), dimension(:,:), intent(in) :: r integer :: i, j do i = 1, d do j = 1, d write (u, 1, advance="no") r(i,j) end do write (u, *) end do 1 format (99(1X,'(',F7.4,',',F7.4,')',:)) end subroutine write_matrix end subroutine bloch_vectors_3 @ %def bloch_vectors_3 @ \subsubsection{Raw I/O} Check correct input/output in raw format. <>= call test (bloch_vectors_4, "bloch_vectors_4", & "raw I/O", & u, results) <>= public :: bloch_vectors_4 <>= subroutine bloch_vectors_4 (u) integer, intent(in) :: u write (u, "(A)") "* Test output: bloch_vectors_4" write (u, "(A)") "* Purpose: test Bloch-vector & &polarization implementation" write (u, "(A)") write (u, "(A)") "* Raw I/O" write (u, "(A)") write (u, "(A)") "* s = 0" call bloch_io (SCALAR) write (u, "(A)") write (u, "(A)") "* s = 1/2" call bloch_io (SPINOR) write (u, "(A)") write (u, "(A)") "* s = 1" call bloch_io (VECTOR) write (u, "(A)") write (u, "(A)") "* s = 3/2" call bloch_io (VECTORSPINOR) write (u, "(A)") write (u, "(A)") "* s = 2" call bloch_io (TENSOR) write (u, "(A)") write (u, "(A)") "* Test output end: bloch_vectors_4" contains subroutine bloch_io (s) integer, intent(in) :: s type(bloch_vector_t) :: pol real(default), dimension(:), allocatable :: a integer :: n, i, utmp, iostat n = algebra_dimension (s) allocate (a (n)) a(:) = [(real (mod (i, 10), kind=default), i = 1, size (a))] write (u, *) write (u, "(*(F7.4))") a call pol%init (s) call pol%from_array (a) open (newunit = utmp, status = "scratch", action = "readwrite", & form = "unformatted") call pol%write_raw (utmp) rewind (utmp) call pol%read_raw (utmp, iostat=iostat) close (utmp) call pol%to_array (a) write (u, "(*(F7.4))") a end subroutine bloch_io end subroutine bloch_vectors_4 @ %def bloch_vectors_4 @ \subsubsection{Convenience Methods} Check some further TBP that are called by the [[polarizations]] module. <>= call test (bloch_vectors_5, "bloch_vectors_5", & "massless state (unpolarized)", & u, results) <>= public :: bloch_vectors_5 <>= subroutine bloch_vectors_5 (u) integer, intent(in) :: u write (u, "(A)") "* Test output: bloch_vectors_5" write (u, "(A)") "* Purpose: test Bloch-vector & &polarization implementation" write (u, "(A)") write (u, "(A)") "* Massless states: equipartition" write (u, "(A)") write (u, "(A)") "* s = 0" call bloch_massless_unpol (SCALAR) write (u, "(A)") write (u, "(A)") "* s = 1/2" call bloch_massless_unpol (SPINOR) write (u, "(A)") write (u, "(A)") "* s = 1" call bloch_massless_unpol (VECTOR) write (u, "(A)") write (u, "(A)") "* s = 3/2" call bloch_massless_unpol (VECTORSPINOR) write (u, "(A)") write (u, "(A)") "* s = 2" call bloch_massless_unpol (TENSOR) write (u, "(A)") write (u, "(A)") "* Test output end: bloch_vectors_5" contains subroutine bloch_massless_unpol (s) integer, intent(in) :: s type(bloch_vector_t) :: pol complex(default), dimension(:,:), allocatable :: r real(default), dimension(:), allocatable :: a integer :: d d = fundamental_dimension (s) call pol%init_max_weight (s) call pol%to_matrix (r, only_max_weight = .false.) write (u, *) where (abs (r) < 1.e-14_default) r = 0 call write_matrix (d, r) call pol%to_matrix (r, only_max_weight = .true.) write (u, *) call write_matrix (d, r) end subroutine bloch_massless_unpol subroutine write_matrix (d, r) integer, intent(in) :: d complex(default), dimension(:,:), intent(in) :: r integer :: i, j do i = 1, d do j = 1, d write (u, 1, advance="no") r(i,j) end do write (u, *) end do 1 format (99(1X,'(',F7.4,',',F7.4,')',:)) end subroutine write_matrix end subroutine bloch_vectors_5 @ %def bloch_vectors_5 @ \subsubsection{Massless state (arbitrary)} Initialize the Bloch vector with an arbitrarily chosen pure state which consists only of highest-weight components. Transform back to the density matrix. <>= call test (bloch_vectors_6, "bloch_vectors_6", & "massless state (arbitrary)", & u, results) <>= public :: bloch_vectors_6 <>= subroutine bloch_vectors_6 (u) integer, intent(in) :: u write (u, "(A)") "* Test output: bloch_vectors_6" write (u, "(A)") "* Purpose: test Bloch-vector & &polarization implementation" write (u, "(A)") write (u, "(A)") "* Initialization (pure polarized massless, arbitrary):" write (u, "(A)") "* input matrix, transform, display norm, transform back" write (u, "(A)") write (u, "(A)") "* s = 0" call bloch_massless (SCALAR) write (u, "(A)") write (u, "(A)") "* s = 1/2" call bloch_massless (SPINOR) write (u, "(A)") write (u, "(A)") "* s = 1" call bloch_massless (VECTOR) write (u, "(A)") write (u, "(A)") "* s = 3/2" call bloch_massless (VECTORSPINOR) write (u, "(A)") write (u, "(A)") "* s = 2" call bloch_massless (TENSOR) write (u, "(A)") write (u, "(A)") "* Test output end: bloch_vectors_6" contains subroutine bloch_massless (s) integer, intent(in) :: s type(bloch_vector_t) :: pol complex(default), dimension(:,:), allocatable :: r integer :: d d = fundamental_dimension (s) write (u, *) call init_matrix (d, r) call write_matrix (d, r) call pol%init (s, r) write (u, *) write (u, 2) pol%get_norm (), pol%is_diagonal () write (u, *) call pol%to_matrix (r, only_max_weight = .true.) call write_matrix (d, r) 2 format (1X,F7.4,1X,L1) end subroutine bloch_massless subroutine init_matrix (d, r) integer, intent(in) :: d complex(default), dimension(:,:), allocatable, intent(out) :: r complex(default), dimension(:), allocatable :: a real(default) :: norm integer :: i, j allocate (a (d), source = (0._default, 0._default)) norm = 0 do i = 1, d, max (d-1, 1) a(i) = cmplx (2*i-1, 2*i, kind=default) norm = norm + conjg (a(i)) * a(i) end do a = a / sqrt (norm) allocate (r (d,d), source = (0._default, 0._default)) do i = 1, d, max (d-1, 1) do j = 1, d, max (d-1, 1) r(i,j) = conjg (a(i)) * a(j) end do end do end subroutine init_matrix subroutine write_matrix (d, r) integer, intent(in) :: d complex(default), dimension(:,:), intent(in) :: r integer :: i, j do i = 1, d do j = 1, d write (u, 1, advance="no") r(i,j) end do write (u, *) end do 1 format (99(1X,'(',F7.4,',',F7.4,')',:)) end subroutine write_matrix end subroutine bloch_vectors_6 @ %def bloch_vectors_6 @ \subsubsection{Massless state (Bloch vector)} Initialize the (generalized) Bloch vector with an ordinary three-component Bloch vector that applies to the highest-weight part only. <>= call test (bloch_vectors_7, "bloch_vectors_7", & "massless state (vector)", & u, results) <>= public :: bloch_vectors_7 <>= subroutine bloch_vectors_7 (u) integer, intent(in) :: u write (u, "(A)") "* Test output: bloch_vectors_7" write (u, "(A)") "* Purpose: test Bloch-vector & &polarization implementation" write (u, "(A)") write (u, "(A)") "* Initialization & &(pure polarized massless, arbitrary Bloch vector):" write (u, "(A)") "* input vector, transform, display norm, & &transform back" write (u, "(A)") write (u, "(A)") "* s = 0" call bloch_massless_vector (SCALAR) write (u, "(A)") write (u, "(A)") "* s = 1/2" call bloch_massless_vector (SPINOR) write (u, "(A)") write (u, "(A)") "* s = 1" call bloch_massless_vector (VECTOR) write (u, "(A)") write (u, "(A)") "* s = 3/2" call bloch_massless_vector (VECTORSPINOR) write (u, "(A)") write (u, "(A)") "* s = 2" call bloch_massless_vector (TENSOR) write (u, "(A)") write (u, "(A)") "* Test output end: bloch_vectors_7" contains subroutine bloch_massless_vector (s) integer, intent(in) :: s type(bloch_vector_t) :: pol real(default), dimension(3) :: a complex(default), dimension(:,:), allocatable :: r write (u, *) a = [1._default, 2._default, 4._default] a = a / sqrt (sum (a ** 2)) write (u, 2) a call pol%init_vector (s, a) write (u, 2) pol%get_norm () call pol%to_vector (a) write (u, 2) a call pol%to_matrix (r, only_max_weight = .false.) write (u, *) where (abs (r) < 1.e-14_default) r = 0 call write_matrix (r) call pol%to_matrix (r, only_max_weight = .true.) write (u, *) call write_matrix (r) 2 format (99(1X,F7.4,:)) end subroutine bloch_massless_vector subroutine write_matrix (r) complex(default), dimension(:,:), intent(in) :: r integer :: i, j do i = 1, size (r, 1) do j = 1, size (r, 2) write (u, 1, advance="no") r(i,j) end do write (u, *) end do 1 format (99(1X,'(',F7.4,',',F7.4,')',:)) end subroutine write_matrix end subroutine bloch_vectors_7 @ %def bloch_vectors_7 @ \clearpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Polarization} Using generalized Bloch vectors and the $su(N)$ algebra (see above) for the internal representation, we can define various modes of polarization. For spin-1/2, and analogously for massless spin-$s$ particles, we introduce \begin{enumerate} \item Trivial polarization: $\vec\alpha=0$. [This is unpolarized, but distinct from the particular undefined polarization matrix which has the same meaning.] \item Circular polarization: $\vec\alpha$ points in $\pm z$ direction. \item Transversal polarization: $\vec\alpha$ points orthogonal to the $z$ direction, with a phase $\phi$ that is $0$ for the $x$ axis, and $\pi/2=90^\circ$ for the $y$ axis. For antiparticles, the phase switches sign, corresponding to complex conjugation. \item Axis polarization, where we explicitly give $\vec\alpha$. \end{enumerate} For higher spin, we retain this definition, but apply it to the two components with maximum and minimum weight. In effect, we concentrate on the first three entries in the $\alpha^a$ array. For massless particles, this is sufficient. For massive particles, we then add the possibilities: \begin{enumerate}\setcounter{enumi}{4} \item Longitudinal polarization: Only the 0-component is set. This is possible only for bosons. \item Diagonal polarization: Explicitly specify all components in the helicity basis. The $su(N)$ representation consists of diagonal generators only, the Cartan subalgebra. \end{enumerate} Obviously, this does not exhaust the possible density matrices for higher spin, but it should cover practical applications. <<[[polarizations.f90]]>>= <> module polarizations <> use io_units use format_defs, only: FMT_19 use diagnostics use physics_defs, only: SCALAR, SPINOR, VECTOR, VECTORSPINOR, TENSOR use flavors use helicities use quantum_numbers use state_matrices use bloch_vectors <> <> <> <> contains <> end module polarizations @ %def polarizations @ \subsection{The polarization type} Polarization is active whenever the coefficient array is allocated. For convenience, we store the spin type ($2s$) and the multiplicity ($N$) together with the coefficient array ($\alpha$). We have to allow for the massless case where $s$ is arbitrary $>0$ but $N=2$, and furthermore the chiral massless case where $N=1$. In the latter case, the array remains deallocated but the chirality is set to $\pm 1$. There is a convention that an antiparticle transforms according to the complex conjugate representation. We apply this only when transforming from/to polarization defined by a three-vector. For antiparticles, the two-component flips sign in that case. When transforming from/to a state matrix or [[pmatrix]] representation, we do not apply this sign flip. <>= public :: polarization_t <>= type :: polarization_t private integer :: spin_type = SCALAR integer :: multiplicity = 1 integer :: chirality = 0 logical :: anti = .false. type(bloch_vector_t) :: bv contains <> end type polarization_t @ %def polarization_t @ \subsection{Basic initializer and finalizer} We need the particle flavor for determining the allowed helicity values. The Bloch vector is left undefined, so this initializer (in two versions) creates an unpolarized particle. Exception: a chiral particle is always polarized with definite helicity, it doesn't need a Bloch vector. This is private. <>= generic, private :: init => polarization_init, polarization_init_flv procedure, private :: polarization_init procedure, private :: polarization_init_flv <>= subroutine polarization_init (pol, spin_type, multiplicity, & anti, left_handed, right_handed) class(polarization_t), intent(out) :: pol integer, intent(in) :: spin_type integer, intent(in) :: multiplicity logical, intent(in) :: anti logical, intent(in) :: left_handed logical, intent(in) :: right_handed pol%spin_type = spin_type pol%multiplicity = multiplicity pol%anti = anti select case (pol%multiplicity) case (1) if (left_handed) then pol%chirality = -1 else if (right_handed) then pol%chirality = 1 end if end select select case (pol%chirality) case (0) call pol%bv%init_unpolarized (spin_type) end select end subroutine polarization_init subroutine polarization_init_flv (pol, flv) class(polarization_t), intent(out) :: pol type(flavor_t), intent(in) :: flv call pol%init ( & spin_type = flv%get_spin_type (), & multiplicity = flv%get_multiplicity (), & anti = flv%is_antiparticle (), & left_handed = flv%is_left_handed (), & right_handed = flv%is_right_handed ()) end subroutine polarization_init_flv @ %def polarization_init polarization_init_flv @ Generic polarization: as before, but create a polarized particle (Bloch vector defined) with initial polarization zero. <>= generic :: init_generic => & polarization_init_generic, & polarization_init_generic_flv procedure, private :: polarization_init_generic procedure, private :: polarization_init_generic_flv <>= subroutine polarization_init_generic (pol, spin_type, multiplicity, & anti, left_handed, right_handed) class(polarization_t), intent(out) :: pol integer, intent(in) :: spin_type integer, intent(in) :: multiplicity logical, intent(in) :: anti logical, intent(in) :: left_handed logical, intent(in) :: right_handed call pol%init (spin_type, multiplicity, & anti, left_handed, right_handed) select case (pol%chirality) case (0) if (pol%multiplicity == pol%bv%get_n_states ()) then call pol%bv%init (spin_type) else call pol%bv%init_max_weight (spin_type) end if end select end subroutine polarization_init_generic subroutine polarization_init_generic_flv (pol, flv) class(polarization_t), intent(out) :: pol type(flavor_t), intent(in) :: flv call pol%init_generic ( & spin_type = flv%get_spin_type (), & multiplicity = flv%get_multiplicity (), & anti = flv%is_antiparticle (), & left_handed = flv%is_left_handed (), & right_handed = flv%is_right_handed ()) end subroutine polarization_init_generic_flv @ %def polarization_init_generic @ A finalizer is no longer necessary. \subsection{I/O} The default setting produces a tabular output of the polarization vector entries. Optionally, we can create a state matrix and write its contents, emulating the obsolete original implementation. If [[all_states]] is true (default), we generate all helity combinations regardless of the matrix-element value. Otherwise, skip helicities with zero entry, or absolute value less than [[tolerance]], if also given. <>= procedure :: write => polarization_write <>= subroutine polarization_write (pol, unit, state_matrix, all_states, tolerance) class(polarization_t), intent(in) :: pol integer, intent(in), optional :: unit logical, intent(in), optional :: state_matrix, all_states real(default), intent(in), optional :: tolerance logical :: state_m type(state_matrix_t) :: state real(default), dimension(:), allocatable :: a integer :: u, i u = given_output_unit (unit); if (u < 0) return state_m = .false.; if (present (state_matrix)) state_m = state_matrix if (pol%anti) then write (u, "(1x,A,I1,A,I1,A,L1,A)") & "Polarization: [spin_type = ", pol%spin_type, & ", mult = ", pol%multiplicity, ", anti = ", pol%anti, "]" else write (u, "(1x,A,I1,A,I1,A)") & "Polarization: [spin_type = ", pol%spin_type, & ", mult = ", pol%multiplicity, "]" end if if (state_m) then call pol%to_state (state, all_states, tolerance) call state%write (unit=unit) call state%final () else if (pol%chirality == 1) then write (u, "(1x,A)") "chirality = +" else if (pol%chirality == -1) then write (u, "(1x,A)") "chirality = -" else if (pol%bv%is_polarized ()) then call pol%bv%to_array (a) do i = 1, size (a) write (u, "(1x,I2,':',1x,F10.7)") i, a(i) end do else write (u, "(1x,A)") "[unpolarized]" end if end subroutine polarization_write @ %def polarization_write @ Binary I/O. <>= procedure :: write_raw => polarization_write_raw procedure :: read_raw => polarization_read_raw <>= subroutine polarization_write_raw (pol, u) class(polarization_t), intent(in) :: pol integer, intent(in) :: u write (u) pol%spin_type write (u) pol%multiplicity write (u) pol%chirality write (u) pol%anti call pol%bv%write_raw (u) end subroutine polarization_write_raw subroutine polarization_read_raw (pol, u, iostat) class(polarization_t), intent(out) :: pol integer, intent(in) :: u integer, intent(out), optional :: iostat read (u, iostat=iostat) pol%spin_type read (u, iostat=iostat) pol%multiplicity read (u, iostat=iostat) pol%chirality read (u, iostat=iostat) pol%anti call pol%bv%read_raw (u, iostat) end subroutine polarization_read_raw @ %def polarization_read_raw @ \subsection{Accessing contents} Return true if the particle is technically polarized. The particle is either chiral, or its Bloch vector has been defined. The function returns true even if the Bloch vector is zero or the particle is scalar. <>= procedure :: is_polarized => polarization_is_polarized <>= function polarization_is_polarized (pol) result (polarized) class(polarization_t), intent(in) :: pol logical :: polarized polarized = pol%chirality /= 0 .or. pol%bv%is_polarized () end function polarization_is_polarized @ %def polarization_is_polarized @ Return true if the polarization is diagonal, i.e., all entries in the density matrix are diagonal. For an unpolarized particle, we also return [[.true.]] since the density matrix is proportional to the unit matrix. <>= procedure :: is_diagonal => polarization_is_diagonal <>= function polarization_is_diagonal (pol) result (diagonal) class(polarization_t), intent(in) :: pol logical :: diagonal select case (pol%chirality) case (0) diagonal = pol%bv%is_diagonal () case default diagonal = .true. end select end function polarization_is_diagonal @ %def polarization_is_diagonal @ \subsection{Mapping between polarization and state matrix} Create the polarization object that corresponds to a state matrix. The state matrix is not necessarily normalized. The result will be either unpolarized, or a generalized Bloch vector that we compute in terms of the appropriate spin generator basis. To this end, we first construct the complete density matrix, then set the Bloch vector with this input. For a naturally chiral particle (i.e., neutrino), we do not set the polarization vector, it is implied. Therefore, we cannot account for any sign flip and transform as-is. <>= procedure :: init_state_matrix => polarization_init_state_matrix <>= subroutine polarization_init_state_matrix (pol, state) class(polarization_t), intent(out) :: pol type(state_matrix_t), intent(in), target :: state type(state_iterator_t) :: it type(flavor_t) :: flv type(helicity_t) :: hel integer :: d, h1, h2, i, j complex(default), dimension(:,:), allocatable :: r complex(default) :: me real(default) :: trace call it%init (state) flv = it%get_flavor (1) hel = it%get_helicity (1) if (hel%is_defined ()) then call pol%init_generic (flv) select case (pol%chirality) case (0) trace = 0 d = pol%bv%get_n_states () allocate (r (d, d), source = (0._default, 0._default)) do while (it%is_valid ()) hel = it%get_helicity (1) call hel%get_indices (h1, h2) i = pol%bv%hel_index (h1) j = pol%bv%hel_index (h2) me = it%get_matrix_element () r(i,j) = me if (i == j) trace = trace + real (me) call it%advance () end do if (trace /= 0) call pol%bv%set (r / trace) end select else call pol%init (flv) end if end subroutine polarization_init_state_matrix @ %def polarization_init_state_matrix @ Create the state matrix that corresponds to a given polarization. We make use of the polarization iterator as defined below, which should iterate according to the canonical helicity ordering. <>= procedure :: to_state => polarization_to_state_matrix <>= subroutine polarization_to_state_matrix (pol, state, all_states, tolerance) class(polarization_t), intent(in), target :: pol type(state_matrix_t), intent(out) :: state logical, intent(in), optional :: all_states real(default), intent(in), optional :: tolerance type(polarization_iterator_t) :: it type(quantum_numbers_t), dimension(1) :: qn complex(default) :: value call it%init (pol, all_states, tolerance) call state%init (store_values = .true.) do while (it%is_valid ()) value = it%get_value () qn(1) = it%get_quantum_numbers () call state%add_state (qn, value = value) call it%advance () end do call state%freeze () end subroutine polarization_to_state_matrix @ %def polarization_to_state_matrix @ \subsection{Specific initializers} Unpolarized particle, no nontrivial entries in the density matrix. This is the default initialization mode. <>= procedure :: init_unpolarized => polarization_init_unpolarized <>= subroutine polarization_init_unpolarized (pol, flv) class(polarization_t), intent(out) :: pol type(flavor_t), intent(in) :: flv call pol%init (flv) end subroutine polarization_init_unpolarized @ %def polarization_init_unpolarized @ The following three modes are useful mainly for spin-1/2 particle and massless particles of any nonzero spin. Only the highest-weight components are filled. Circular polarization: The density matrix of the two highest-weight states is \begin{equation*} \rho(f) = \frac{1-|f|}{2}\mathbf{1} + |f| \times \begin{cases} \begin{pmatrix} 1 & 0 \\ 0 & 0 \end{pmatrix}, & f > 0; \\[6pt] \begin{pmatrix} 0 & 0 \\ 0 & 1 \end{pmatrix}, & f < 0, \end{cases} \end{equation*} In the generalized Bloch representation, this is an entry for the $T^3$ generator only, regardless of the spin representation. A chiral particle is not affected. <>= procedure :: init_circular => polarization_init_circular <>= subroutine polarization_init_circular (pol, flv, f) class(polarization_t), intent(out) :: pol type(flavor_t), intent(in) :: flv real(default), intent(in) :: f call pol%init (flv) select case (pol%chirality) case (0) call pol%bv%init_vector (pol%spin_type, & [0._default, 0._default, f]) end select end subroutine polarization_init_circular @ %def polarization_init_circular @ Transversal polarization is analogous to circular, but we get a density matrix \begin{equation*} \rho(f,\phi) = \frac{1-|f|}{2}\mathbf{1} + \frac{|f|}{2} \begin{pmatrix} 1 & e^{-i\phi} \\ e^{i\phi} & 1 \end{pmatrix}. \end{equation*} for the highest-weight subspace. The lower weights are unaffected. The phase is $\phi=0$ for the $x$-axis, $\phi=90^\circ$ for the $y$ axis as polarization vector. For an antiparticle, the phase switches sign, and for $f<0$, the off-diagonal elements switch sign. A chiral particle is not affected. <>= procedure :: init_transversal => polarization_init_transversal <>= subroutine polarization_init_transversal (pol, flv, phi, f) class(polarization_t), intent(out) :: pol type(flavor_t), intent(in) :: flv real(default), intent(in) :: phi, f call pol%init (flv) select case (pol%chirality) case (0) if (pol%anti) then call pol%bv%init_vector (pol%spin_type, & [f * cos (phi), f * sin (phi), 0._default]) else call pol%bv%init_vector (pol%spin_type, & [f * cos (phi),-f * sin (phi), 0._default]) end if end select end subroutine polarization_init_transversal @ %def polarization_init_transversal @ For axis polarization, we again set only the entries with maximum weight, which for spin $1/2$ means \begin{equation*} \rho(f,\phi) = \frac{1}{2} \begin{pmatrix} 1 + \alpha_3 & \alpha_1 - i\alpha_2 \\ \alpha_1 + i\alpha_2 & 1 - \alpha_3 \end{pmatrix}. \end{equation*} For an antiparticle, the imaginary part proportional to $\alpha_2$ switches sign (complex conjugate). A chiral particle is not affected. In the generalized Bloch representation, this translates into coefficients for $T^{1,2,3}$, all others stay zero. <>= procedure :: init_axis => polarization_init_axis <>= subroutine polarization_init_axis (pol, flv, alpha) class(polarization_t), intent(out) :: pol type(flavor_t), intent(in) :: flv real(default), dimension(3), intent(in) :: alpha call pol%init (flv) select case (pol%chirality) case (0) if (pol%anti) then call pol%bv%init_vector (pol%spin_type, & [alpha(1), alpha(2), alpha(3)]) else call pol%bv%init_vector (pol%spin_type, & [alpha(1),-alpha(2), alpha(3)]) end if end select end subroutine polarization_init_axis @ %def polarization_init_axis @ This version specifies the polarization axis in terms of $r$ (polarization degree) and $\theta,\phi$ (polar and azimuthal angles). If one of the angles is a nonzero multiple of $\pi$, roundoff errors typically will result in tiny contributions to unwanted components. Therefore, include a catch for small numbers. <>= procedure :: init_angles => polarization_init_angles <>= subroutine polarization_init_angles (pol, flv, r, theta, phi) class(polarization_t), intent(out) :: pol type(flavor_t), intent(in) :: flv real(default), intent(in) :: r, theta, phi real(default), dimension(3) :: alpha real(default), parameter :: eps = 10 * epsilon (1._default) alpha(1) = r * sin (theta) * cos (phi) alpha(2) = r * sin (theta) * sin (phi) alpha(3) = r * cos (theta) where (abs (alpha) < eps) alpha = 0 call pol%init_axis (flv, alpha) end subroutine polarization_init_angles @ %def polarization_init_angles @ Longitudinal polarization is defined only for massive bosons. Only the zero component is filled. Otherwise, unpolarized. In the generalized Bloch representation, the zero component corresponds to a linear combination of all diagonal (Cartan) generators. <>= procedure :: init_longitudinal => polarization_init_longitudinal <>= subroutine polarization_init_longitudinal (pol, flv, f) class(polarization_t), intent(out) :: pol type(flavor_t), intent(in) :: flv real(default), intent(in) :: f real(default), dimension(:), allocatable :: rd integer :: s, d s = flv%get_spin_type () select case (s) case (VECTOR, TENSOR) call pol%init_generic (flv) if (pol%bv%is_polarized ()) then d = pol%bv%get_n_states () allocate (rd (d), source = 0._default) rd(pol%bv%hel_index (0)) = f call pol%bv%set (rd) end if case default call pol%init_unpolarized (flv) end select end subroutine polarization_init_longitudinal @ %def polarization_init_longitudinal @ This is diagonal polarization: we specify all components explicitly. [[rd]] is the array of diagonal elements of the density matrix. We assume that the length of [[rd]] is equal to the particle multiplicity. <>= procedure :: init_diagonal => polarization_init_diagonal <>= subroutine polarization_init_diagonal (pol, flv, rd) class(polarization_t), intent(out) :: pol type(flavor_t), intent(in) :: flv real(default), dimension(:), intent(in) :: rd real(default) :: trace call pol%init_generic (flv) if (pol%bv%is_polarized ()) then trace = sum (rd) if (trace /= 0) call pol%bv%set (rd / trace) end if end subroutine polarization_init_diagonal @ %def polarization_init_diagonal @ \subsection{Operations} Combine polarization states by computing the outer product of the state matrices. <>= public :: combine_polarization_states <>= subroutine combine_polarization_states (pol, state) type(polarization_t), dimension(:), intent(in), target :: pol type(state_matrix_t), intent(out) :: state type(state_matrix_t), dimension(size(pol)), target :: pol_state integer :: i do i = 1, size (pol) call pol(i)%to_state (pol_state(i)) end do call outer_multiply (pol_state, state) do i = 1, size (pol) call pol_state(i)%final () end do end subroutine combine_polarization_states @ %def combine_polarization_states @ Transform a polarization density matrix into a polarization vector. This is possible without information loss only for spin-1/2 and for massless particles. To get a unique answer in all cases, we consider only the components with highest weight. Obviously, this loses the longitudinal component of a massive vector, for instance. The norm of the returned axis is the polarization fraction for the highest-weight subspace. For a scalar particle, we return a zero vector. The same result applies if the highest-weight component vanishes. This is the inverse operation of [[polarization_init_axis]] above, where the polarization fraction is set to unity. For an antiparticle, the [[alpha(2)]] coefficient flips sign. <>= procedure :: get_axis => polarization_get_axis <>= function polarization_get_axis (pol) result (alpha) class(polarization_t), intent(in), target :: pol real(default), dimension(3) :: alpha select case (pol%chirality) case (0) call pol%bv%to_vector (alpha) if (.not. pol%anti) alpha(2) = - alpha(2) case (-1) alpha = [0._default, 0._default, -1._default] case (1) alpha = [0._default, 0._default, 1._default] end select end function polarization_get_axis @ %def polarization_get_axis @ This function returns polarization degree and polar and azimuthal angles ($\theta,\phi$) of the polarization axis. The same restrictions apply as above. Since we call the [[get_axis]] method, the phase flips sign for an antiparticle. <>= procedure :: to_angles => polarization_to_angles <>= subroutine polarization_to_angles (pol, r, theta, phi) class(polarization_t), intent(in) :: pol real(default), intent(out) :: r, theta, phi real(default), dimension(3) :: alpha real(default) :: norm, r12 alpha = pol%get_axis () norm = sum (alpha**2) r = sqrt (norm) if (norm > 0) then r12 = sqrt (alpha(1)**2 + alpha(2)**2) theta = atan2 (r12, alpha(3)) if (any (alpha(1:2) /= 0)) then phi = atan2 (alpha(2), alpha(1)) else phi = 0 end if else theta = 0 phi = 0 end if end subroutine polarization_to_angles @ %def polarization_to_angles @ \subsection{Polarization Iterator} The iterator acts like a state matrix iterator, i.e., it points to one helicity combination at a time and can return the corresponding helicity object and matrix-element value. Since the polarization is stored as a Bloch vector, we recover the whole density matrix explicitly upon initialization, store it inside the iterator object, and then just return its elements one at a time. For an unpolarized particle, the iterator returns a single state with undefined helicity. The value is the value of any diagonal density matrix element, $1/n$ where $n$ is the multiplicity. <>= public :: polarization_iterator_t <>= type :: polarization_iterator_t private type(polarization_t), pointer :: pol => null () logical :: polarized = .false. integer :: h1 = 0 integer :: h2 = 0 integer :: i = 0 integer :: j = 0 complex(default), dimension(:,:), allocatable :: r complex(default) :: value = 1._default real(default) :: tolerance = -1._default logical :: valid = .false. contains <> end type polarization_iterator_t @ %def polarization_iterator_t @ Output for debugging purposes only, therefore no format for real/complex. <>= procedure :: write => polarization_iterator_write <>= subroutine polarization_iterator_write (it, unit) class(polarization_iterator_t), intent(in) :: it integer, intent(in), optional :: unit integer :: u, i u = given_output_unit (unit) write (u, "(1X,A)") "Polarization iterator:" write (u, "(3X,A,L1)") "assigned = ", associated (it%pol) write (u, "(3X,A,L1)") "valid = ", it%valid if (it%valid) then write (u, "(3X,A,2(1X,I2))") "i, j = ", it%i, it%j write (u, "(3X,A,2(1X,I2))") "h1, h2 = ", it%h1, it%h2 write (u, "(3X,A)", advance="no") "value = " write (u, *) it%value if (allocated (it%r)) then do i = 1, size (it%r, 2) write (u, *) it%r(i,:) end do end if end if end subroutine polarization_iterator_write @ %def polarization_iterator_write @ Initialize, i.e., (virtually) point to the first helicity state supported by the polarization object. If the density matrix is nontrivial, we calculate it here. Following the older state-matrix conventions, the iterator sequence starts at the lowest helicity value. In the current internal representation, this corresponds to the highest index value. If the current matrix-element value is zero, advance the iterator. Advancing will stop at a nonzero value or if the iterator becomes invalid. If [[tolerance]] is given, any state matrix entry less or equal will be treated as zero, causing the iterator to skip an entry. By default, the value is negative, so no entry is skipped. <>= procedure :: init => polarization_iterator_init <>= subroutine polarization_iterator_init (it, pol, all_states, tolerance) class(polarization_iterator_t), intent(out) :: it type(polarization_t), intent(in), target :: pol logical, intent(in), optional :: all_states real(default), intent(in), optional :: tolerance integer :: d logical :: only_max_weight it%pol => pol if (present (all_states)) then if (.not. all_states) then if (present (tolerance)) then it%tolerance = tolerance else it%tolerance = 0 end if end if end if select case (pol%chirality) case (0) d = pol%bv%get_n_states () only_max_weight = pol%multiplicity < d it%polarized = pol%bv%is_polarized () if (it%polarized) then it%i = d it%j = it%i it%h1 = pol%bv%hel_value (it%i) it%h2 = it%h1 call pol%bv%to_matrix (it%r, only_max_weight) it%value = it%r(it%i, it%j) else it%value = 1._default / d end if it%valid = .true. case (1,-1) it%polarized = .true. select case (pol%spin_type) case (SPINOR) it%h1 = pol%chirality case (VECTORSPINOR) it%h1 = 2 * pol%chirality end select it%h2 = it%h1 it%valid = .true. end select if (it%valid .and. abs (it%value) <= it%tolerance) call it%advance () end subroutine polarization_iterator_init @ %def polarization_iterator_init @ Advance to the next valid helicity state. Repeat if the returned value is zero. For an unpolarized object, we iterate through the diagonal helicity states with a constant value. <>= procedure :: advance => polarization_iterator_advance <>= recursive subroutine polarization_iterator_advance (it) class(polarization_iterator_t), intent(inout) :: it if (it%valid) then select case (it%pol%chirality) case (0) if (it%polarized) then if (it%j > 1) then it%j = it%j - 1 it%h2 = it%pol%bv%hel_value (it%j) it%value = it%r(it%i, it%j) else if (it%i > 1) then it%j = it%pol%bv%get_n_states () it%h2 = it%pol%bv%hel_value (it%j) it%i = it%i - 1 it%h1 = it%pol%bv%hel_value (it%i) it%value = it%r(it%i, it%j) else it%valid = .false. end if else it%valid = .false. end if case default it%valid = .false. end select if (it%valid .and. abs (it%value) <= it%tolerance) call it%advance () end if end subroutine polarization_iterator_advance @ %def polarization_iterator_advance @ This is true as long as the iterator points to a valid helicity state. <>= procedure :: is_valid => polarization_iterator_is_valid <>= function polarization_iterator_is_valid (it) result (is_valid) logical :: is_valid class(polarization_iterator_t), intent(in) :: it is_valid = it%valid end function polarization_iterator_is_valid @ %def polarization_iterator_is_valid @ Return the matrix element value for the helicity that we are currently pointing at. <>= procedure :: get_value => polarization_iterator_get_value <>= function polarization_iterator_get_value (it) result (value) complex(default) :: value class(polarization_iterator_t), intent(in) :: it if (it%valid) then value = it%value else value = 0 end if end function polarization_iterator_get_value @ %def polarization_iterator_get_value @ Return a quantum number object for the helicity that we are currently pointing at. This is a single quantum number object, not an array. Note that the [[init]] method of the helicity object has the order reversed. <>= procedure :: get_quantum_numbers => polarization_iterator_get_quantum_numbers <>= function polarization_iterator_get_quantum_numbers (it) result (qn) class(polarization_iterator_t), intent(in) :: it type(helicity_t) :: hel type(quantum_numbers_t) :: qn if (it%polarized) then call hel%init (it%h2, it%h1) end if call qn%init (hel) end function polarization_iterator_get_quantum_numbers @ %def polarization_iterator_get_quantum_numbers @ \subsection{Sparse Matrix} We introduce a simple implementation of a sparse matrix that can represent polarization (or similar concepts) for transfer to I/O within the program. It consists of an integer array that represents the index values, and a complex array that represents the nonvanishing entries. The number of nonvanishing entries must be known for initialization, but the entries are filled one at a time. Here is a base type without the special properties of a spin-density matrix. <>= public :: smatrix_t <>= type :: smatrix_t private integer :: dim = 0 integer :: n_entry = 0 integer, dimension(:,:), allocatable :: index complex(default), dimension(:), allocatable :: value contains <> end type smatrix_t @ %def smatrix_t @ Output. <>= procedure :: write => smatrix_write <>= subroutine smatrix_write (object, unit, indent) class(smatrix_t), intent(in) :: object integer, intent(in), optional :: unit, indent integer :: u, i, ind u = given_output_unit (unit) ind = 0; if (present (indent)) ind = indent if (allocated (object%value)) then if (size (object%value) > 0) then do i = 1, object%n_entry write (u, "(1x,A,'@(')", advance="no") repeat (" ", ind) write (u, "(SP,9999(I2.1,':',1x))", advance="no") & object%index(:,i) write (u, "('('," // FMT_19 // ",','," // FMT_19 // & ",'))')") object%value(i) end do else write (u, "(1x,A)", advance="no") repeat (" ", ind) write (u, "(A)") "[empty matrix]" end if else write (u, "(1x,A)", advance="no") repeat (" ", ind) write (u, "(A)") "[undefined matrix]" end if end subroutine smatrix_write @ %def smatrix_write @ Initialization: allocate arrays to the correct size. We specify both the dimension of the matrix (if different from two, this is rather a generic tensor) and the number of nonvanishing entries. <>= procedure :: init => smatrix_init <>= subroutine smatrix_init (smatrix, dim, n_entry) class(smatrix_t), intent(out) :: smatrix integer, intent(in) :: dim integer, intent(in) :: n_entry smatrix%dim = dim smatrix%n_entry = n_entry allocate (smatrix%index (dim, n_entry)) allocate (smatrix%value (n_entry)) end subroutine smatrix_init @ %def smatrix_init @ Fill: one entry at a time. <>= procedure :: set_entry => smatrix_set_entry <>= subroutine smatrix_set_entry (smatrix, i, index, value) class(smatrix_t), intent(inout) :: smatrix integer, intent(in) :: i integer, dimension(:), intent(in) :: index complex(default), intent(in) :: value smatrix%index(:,i) = index smatrix%value(i) = value end subroutine smatrix_set_entry @ %def smatrix_set_entry @ <>= procedure :: exists => smatrix_exists <>= elemental function smatrix_exists (smatrix) result (exist) logical :: exist class(smatrix_t), intent(in) :: smatrix exist = .not. all (smatrix%value == 0) end function smatrix_exists @ %def smatrix_exists @ \subsection{Polarization Matrix} As an extension of the more generic [[smatrix]] type, we implement a proper spin-density matrix. After the matrix has been filled, we can fix spin type and multiplicity for a particle, check the matrix for consistency, and normalize it if necessary. This implementation does not have an antiparticle flag, just like the state matrix object. We therefore cannot account for sign flips when using this object. TODO: The [[pure]] flag is for informational purposes only, and it only represents a necessary condition if spin is greater than $1/2$. We may either check purity for all spins or drop this. <>= public :: pmatrix_t <>= type, extends (smatrix_t) :: pmatrix_t private integer :: spin_type = 0 integer :: multiplicity = 0 logical :: massive = .true. integer :: chirality = 0 real(default) :: degree = 1 logical :: pure = .false. contains <> end type pmatrix_t @ %def pmatrix_t @ Output, including extra data. (The [[indent]] argument is ignored.) <>= procedure :: write => pmatrix_write <>= subroutine pmatrix_write (object, unit, indent) class(pmatrix_t), intent(in) :: object integer, intent(in), optional :: unit, indent integer :: u u = given_output_unit (unit) write (u, "(1x,A)") "Polarization: spin density matrix" write (u, "(3x,A,I0)") "spin type = ", object%spin_type write (u, "(3x,A,I0)") "multiplicity = ", object%multiplicity write (u, "(3x,A,L1)") "massive = ", object%massive write (u, "(3x,A,I0)") "chirality = ", object%chirality write (u, "(3x,A,F10.7)") "pol.degree =", object%degree write (u, "(3x,A,L1)") "pure state = ", object%pure call object%smatrix_t%write (u, 1) end subroutine pmatrix_write @ %def pmatrix_write @ This assignment is trivial, but must be coded explicitly. <>= generic :: assignment(=) => pmatrix_assign_from_smatrix procedure, private :: pmatrix_assign_from_smatrix <>= subroutine pmatrix_assign_from_smatrix (pmatrix, smatrix) class(pmatrix_t), intent(out) :: pmatrix type(smatrix_t), intent(in) :: smatrix pmatrix%smatrix_t = smatrix end subroutine pmatrix_assign_from_smatrix @ %def pmatrix_assign_from_smatrix @ Declare spin, multiplicity, and polarization degree. Check whether all entries fit, and whether this is a valid matrix. The required properties are: \begin{enumerate} \item all entries apply to the given spin and mass type \item the diagonal is real \item only the upper of corresponding off-diagonal elements is specified, i.e., the row index is less than the column index \item the trace is nonnegative and equal to the polarization degree (the remainder, proportional to the unit matrix, is understood to be present) \item the trace of the matrix square is positive and less or equal to the trace of the matrix itself, which is the polarization degree. \item If the trace of the matrix square and the trace of the matrix are unity, we may have a pure state. (For spin up to $1/2$, this is actually sufficient.) \end{enumerate} <>= procedure :: normalize => pmatrix_normalize <>= subroutine pmatrix_normalize (pmatrix, flv, degree, tolerance) class(pmatrix_t), intent(inout) :: pmatrix type(flavor_t), intent(in) :: flv real(default), intent(in), optional :: degree real(default), intent(in), optional :: tolerance integer :: i, hmax logical :: fermion, ok real(default) :: trace, trace_sq real(default) :: tol tol = 0; if (present (tolerance)) tol = tolerance pmatrix%spin_type = flv%get_spin_type () pmatrix%massive = flv%get_mass () /= 0 if (.not. pmatrix%massive) then if (flv%is_left_handed ()) then pmatrix%chirality = -1 else if (flv%is_right_handed ()) then pmatrix%chirality = +1 end if end if if (pmatrix%spin_type == SCALAR) then pmatrix%multiplicity = 1 else if (pmatrix%massive) then pmatrix%multiplicity = pmatrix%spin_type else if (pmatrix%chirality == 0) then pmatrix%multiplicity = 2 else pmatrix%multiplicity = 1 end if if (present (degree)) then if (degree < 0 .or. degree > 1) & call msg_error ("polarization degree must be between 0 and 1") pmatrix%degree = degree end if if (size (pmatrix%index, 1) /= 2) call error ("wrong array rank") fermion = mod (pmatrix%spin_type, 2) == 0 hmax = pmatrix%spin_type / 2 if (pmatrix%n_entry > 0) then if (fermion) then if (pmatrix%massive) then ok = all (pmatrix%index /= 0) & .and. all (abs (pmatrix%index) <= hmax) else if (pmatrix%chirality == -1) then ok = all (pmatrix%index == -hmax) else if (pmatrix%chirality == +1) then ok = all (pmatrix%index == +hmax) else ok = all (abs (pmatrix%index) == hmax) end if else if (pmatrix%massive) then ok = all (abs (pmatrix%index) <= hmax) else ok = all (abs (pmatrix%index) == hmax) end if end if if (.not. ok) call error ("illegal index value") else pmatrix%degree = 0 pmatrix%pure = pmatrix%multiplicity == 1 return end if trace = 0 do i = 1, pmatrix%n_entry associate (index => pmatrix%index(:,i), value => pmatrix%value(i)) if (index(1) == index(2)) then if (abs (aimag (value)) > tol) call error ("diagonal must be real") value = real (value, kind=default) trace = trace + value else if (any (pmatrix%index(1,:) == index(2) & .and. pmatrix%index(2,:) == index(1))) then call error ("redundant off-diagonal entry") else if (index(2) < index (1)) then index = index([2,1]) value = conjg (value) end if end associate end do if (abs (trace) <= tol) call error ("trace must not vanish") trace = real (trace, kind=default) pmatrix%value = pmatrix%value / trace * pmatrix%degree trace_sq = (1 - pmatrix%degree ** 2) / pmatrix%multiplicity do i = 1, pmatrix%n_entry associate (index => pmatrix%index(:,i), value => pmatrix%value(i)) if (index(1) == index(2)) then trace_sq = trace_sq + abs (value) ** 2 else trace_sq = trace_sq + 2 * abs (value) ** 2 end if end associate end do if (pmatrix%multiplicity == 1) then pmatrix%pure = .true. else if (abs (trace_sq - 1) <= tol) then pmatrix%pure = .true. else if (trace_sq - 1 > tol .or. trace_sq < -tol) then print *, "Trace of matrix square = ", trace_sq call error ("not permissible as density matrix") end if contains subroutine error (msg) character(*), intent(in) :: msg call pmatrix%write () call msg_fatal ("Spin density matrix: " // msg) end subroutine error end subroutine pmatrix_normalize @ %def pmatrix_normalize @ A polarized matrix is defined as one with a positive polarization degree, even if the actual matrix is trivial. <>= procedure :: is_polarized => pmatrix_is_polarized <>= elemental function pmatrix_is_polarized (pmatrix) result (flag) class(pmatrix_t), intent(in) :: pmatrix logical :: flag flag = pmatrix%degree > 0 end function pmatrix_is_polarized @ %def pmatrix_is_polarized @ Check if there are only diagonal entries. <>= procedure :: is_diagonal => pmatrix_is_diagonal <>= elemental function pmatrix_is_diagonal (pmatrix) result (flag) class(pmatrix_t), intent(in) :: pmatrix logical :: flag flag = all (pmatrix%index(1,:) == pmatrix%index(2,:)) end function pmatrix_is_diagonal @ %def pmatrix_is_diagonal @ Check if there are only diagonal entries. <>= procedure :: get_simple_pol => pmatrix_get_simple_pol <>= elemental function pmatrix_get_simple_pol (pmatrix) result (pol) class(pmatrix_t), intent(in) :: pmatrix real(default) :: pol if (pmatrix%is_polarized ()) then select case (size (pmatrix%value)) case (0) pol = 0 case (1) pol = pmatrix%index (1,1) * pmatrix%degree case (2) pol = 42 end select else pol = 0 end if end function pmatrix_get_simple_pol @ %def pmatrix_get_simple_pol @ \subsection{Data Transformation} Create a [[polarization_t]] object from the contents of a normalized [[pmatrix_t]] object. We scan the entries as present in [[pmatrix]] and transform them into a density matrix, if necessary. The density matrix then initializes the Bloch vector. This is analogous to [[polarization_init_state_matrix]]. There is a subtlety associated with massless particles. Since the [[pmatrix]] doesn't contain the full density matrix but just the nontrivial part, we have to initialize the polarization object with the massless equipartion, which contains nonzero entries for the Cartan generators. The [[set]] method therefore should not erase those initial contents. This is a constraint for the implementation of [[set]], as applied to the Bloch vector. As mentioned above, [[pmatrix_t]] does not support an antiparticle flag. <>= procedure :: init_pmatrix => polarization_init_pmatrix <>= subroutine polarization_init_pmatrix (pol, pmatrix) class(polarization_t), intent(out) :: pol type(pmatrix_t), intent(in) :: pmatrix integer :: d, i, j, k, h1, h2 complex(default), dimension(:,:), allocatable :: r call pol%init_generic ( & spin_type = pmatrix%spin_type, & multiplicity = pmatrix%multiplicity, & anti = .false., & !!! SUFFICIENT? left_handed = pmatrix%chirality < 0, & right_handed = pmatrix%chirality > 0) if (pol%bv%is_polarized ()) then d = pol%bv%get_n_states () allocate (r (d, d), source = (0._default, 0._default)) if (d == pmatrix%multiplicity) then do i = 1, d r(i,i) = (1 - pmatrix%degree) / d end do else if (d > pmatrix%multiplicity) then r(1,1) = (1 - pmatrix%degree) / 2 r(d,d) = r(1,1) end if do k = 1, size (pmatrix%value) h1 = pmatrix%index(1,k) h2 = pmatrix%index(2,k) i = pol%bv%hel_index (h1) j = pol%bv%hel_index (h2) r(i,j) = r(i,j) + pmatrix%value(k) r(j,i) = conjg (r(i,j)) end do call pol%bv%set (r) end if end subroutine polarization_init_pmatrix @ %def polarization_init_pmatrix @ \subsection{Unit tests} Test module, followed by the corresponding implementation module. <<[[polarizations_ut.f90]]>>= <> module polarizations_ut use unit_tests use polarizations_uti <> <> contains <> end module polarizations_ut @ %def polarizations_ut @ <<[[polarizations_uti.f90]]>>= <> module polarizations_uti <> use flavors use model_data use polarizations <> <> contains <> end module polarizations_uti @ %def polarizations_ut @ API: driver for the unit tests below. <>= public :: polarizations_test <>= subroutine polarizations_test (u, results) integer, intent(in) :: u type(test_results_t), intent(inout) :: results <> end subroutine polarizations_test @ %def polarizations_test @ \subsubsection{Polarization type} Checking the setup for polarization. <>= call test (polarization_1, "polarization_1", & "check polarization setup", & u, results) <>= public :: polarization_1 <>= subroutine polarization_1 (u) use os_interface integer, intent(in) :: u type(model_data_t), target :: model type(polarization_t) :: pol type(flavor_t) :: flv real(default), dimension(3) :: alpha real(default) :: r, theta, phi real(default), parameter :: tolerance = 1.E-14_default write (u, "(A)") "* Test output: polarization_1" write (u, "(A)") "* Purpose: test polarization setup" write (u, "(A)") write (u, "(A)") "* Reading model file" write (u, "(A)") call model%init_sm_test () write (u, "(A)") "* Unpolarized fermion" write (u, "(A)") call flv%init (1, model) call pol%init_unpolarized (flv) call pol%write (u, state_matrix = .true.) write (u, "(A,L1)") " diagonal =", pol%is_diagonal () write (u, "(A)") write (u, "(A)") "* Unpolarized fermion" write (u, "(A)") call pol%init_circular (flv, 0._default) call pol%write (u, state_matrix = .true., all_states = .false.) write (u, "(A)") write (u, "(A)") "* Transversally polarized fermion, phi=0" write (u, "(A)") call pol%init_transversal (flv, 0._default, 1._default) call pol%write (u, state_matrix = .true.) write (u, "(A,L1)") " diagonal =", pol%is_diagonal () write (u, "(A)") write (u, "(A)") "* Transversally polarized fermion, phi=0.9, frac=0.8" write (u, "(A)") call pol%init_transversal (flv, 0.9_default, 0.8_default) call pol%write (u, state_matrix = .true.) write (u, "(A,L1)") " diagonal =", pol%is_diagonal () write (u, "(A)") write (u, "(A)") "* All polarization directions of a fermion" write (u, "(A)") call pol%init_generic (flv) call pol%write (u, state_matrix = .true.) call flv%init (21, model) write (u, "(A)") write (u, "(A)") "* Circularly polarized gluon, frac=0.3" write (u, "(A)") call pol%init_circular (flv, 0.3_default) call pol%write (u, state_matrix = .true., & all_states = .false., tolerance = tolerance) call flv%init (23, model) write (u, "(A)") write (u, "(A)") "* Circularly polarized massive vector, frac=-0.7" write (u, "(A)") call pol%init_circular (flv, -0.7_default) call pol%write (u, state_matrix = .true., & all_states = .false., tolerance = tolerance) write (u, "(A)") write (u, "(A)") "* Circularly polarized massive vector" write (u, "(A)") call pol%init_circular (flv, 1._default) call pol%write (u, state_matrix = .true., & all_states = .false., tolerance = tolerance) write (u, "(A)") write (u, "(A)") "* Longitudinally polarized massive vector, frac=0.4" write (u, "(A)") call pol%init_longitudinal (flv, 0.4_default) call pol%write (u, state_matrix = .true., & all_states = .false., tolerance = tolerance) write (u, "(A)") write (u, "(A)") "* Longitudinally polarized massive vector" write (u, "(A)") call pol%init_longitudinal (flv, 1._default) call pol%write (u, state_matrix = .true., & all_states = .false., tolerance = tolerance) write (u, "(A)") write (u, "(A)") "* Diagonally polarized massive vector" write (u, "(A)") call pol%init_diagonal & (flv, [2._default, 1._default, 0._default]) call pol%write (u, state_matrix = .true., & all_states = .false., tolerance = tolerance) write (u, "(A)") write (u, "(A)") "* All polarization directions of a massive vector" write (u, "(A)") call pol%init_generic (flv) call pol%write (u, state_matrix = .true.) call flv%init (21, model) write (u, "(A)") write (u, "(A)") "* Axis polarization (0.2, 0.4, 0.6)" write (u, "(A)") alpha = [0.2_default, 0.4_default, 0.6_default] call pol%init_axis (flv, alpha) call pol%write (u, state_matrix = .true., & all_states = .false., tolerance = tolerance) write (u, "(A)") write (u, "(1X,A)") "Recovered axis:" alpha = pol%get_axis () write (u, "(3(1X,F10.7))") alpha write (u, "(A)") write (u, "(A)") "* Angle polarization (0.5, 0.6, -1)" r = 0.5_default theta = 0.6_default phi = -1._default call pol%init_angles (flv, r, theta, phi) write (u, "(A)") call pol%write (u, state_matrix = .true., & all_states = .false., tolerance = tolerance) write (u, "(A)") write (u, "(1X,A)") "Recovered parameters (r, theta, phi):" call pol%to_angles (r, theta, phi) write (u, "(3(1x,F10.7))") r, theta, phi call model%final () write (u, "(A)") write (u, "(A)") "* Test output end: polarization_1" end subroutine polarization_1 @ %def polarization_1 @ \subsubsection{Sparse-Matrix type} Use a sparse density matrix universally as the input for setting up polarization. <>= call test (polarization_2, "polarization_2", & "matrix polarization setup", & u, results) <>= public :: polarization_2 <>= subroutine polarization_2 (u) use os_interface integer, intent(in) :: u type(model_data_t), target :: model type(flavor_t) :: flv type(polarization_t) :: pol real(default), dimension(3) :: alpha type(pmatrix_t) :: pmatrix real(default), parameter :: tolerance = 1e-8_default write (u, "(A)") "* Test output: polarization_2" write (u, "(A)") "* Purpose: matrix polarization setup" write (u, "(A)") write (u, "(A)") "* Reading model file" write (u, "(A)") call model%init_sm_test () write (u, "(A)") "* Unpolarized fermion" write (u, "(A)") call flv%init (1, model) call pmatrix%init (2, 0) call pmatrix%normalize (flv, 0._default, tolerance) call pmatrix%write (u) write (u, *) write (u, "(1x,A,L1)") "polarized = ", pmatrix%is_polarized () write (u, "(1x,A,L1)") "diagonal = ", pmatrix%is_diagonal () write (u, *) call pol%init_pmatrix (pmatrix) call pol%write (u, state_matrix = .true., & all_states = .false., tolerance = tolerance) ! call pol%final () write (u, "(A)") write (u, "(A)") "* Transversally polarized fermion, phi=0" write (u, "(A)") call pmatrix%init (2, 3) call pmatrix%set_entry (1, [-1,-1], (1._default, 0._default)) call pmatrix%set_entry (2, [+1,+1], (1._default, 0._default)) call pmatrix%set_entry (3, [-1,+1], (1._default, 0._default)) call pmatrix%normalize (flv, 1._default, tolerance) call pmatrix%write (u) write (u, *) write (u, "(1x,A,L1)") "polarized = ", pmatrix%is_polarized () write (u, "(1x,A,L1)") "diagonal = ", pmatrix%is_diagonal () write (u, *) call pol%init_pmatrix (pmatrix) call pol%write (u, state_matrix = .true., & all_states = .false., tolerance = tolerance) ! call pol%final () write (u, "(A)") write (u, "(A)") "* Transversally polarized fermion, phi=0.9, frac=0.8" write (u, "(A)") call pmatrix%init (2, 3) call pmatrix%set_entry (1, [-1,-1], (1._default, 0._default)) call pmatrix%set_entry (2, [+1,+1], (1._default, 0._default)) call pmatrix%set_entry (3, [-1,+1], exp ((0._default, -0.9_default))) call pmatrix%normalize (flv, 0.8_default, tolerance) call pmatrix%write (u) write (u, *) call pol%init_pmatrix (pmatrix) call pol%write (u, state_matrix = .true.) ! call pol%final () write (u, "(A)") write (u, "(A)") "* Left-handed massive fermion, frac=1" write (u, "(A)") call flv%init (11, model) call pmatrix%init (2, 1) call pmatrix%set_entry (1, [-1,-1], (1._default, 0._default)) call pmatrix%normalize (flv, 1._default, tolerance) call pmatrix%write (u) write (u, *) write (u, "(1x,A,L1)") "polarized = ", pmatrix%is_polarized () write (u, "(1x,A,L1)") "diagonal = ", pmatrix%is_diagonal () write (u, *) call pol%init_pmatrix (pmatrix) call pol%write (u, state_matrix = .true., & all_states = .false., tolerance = tolerance) ! call pol%final () write (u, "(A)") write (u, "(A)") "* Left-handed massive fermion, frac=0.8" write (u, "(A)") call flv%init (11, model) call pmatrix%init (2, 1) call pmatrix%set_entry (1, [-1,-1], (1._default, 0._default)) call pmatrix%normalize (flv, 0.8_default, tolerance) call pmatrix%write (u) write (u, *) call pol%init_pmatrix (pmatrix) call pol%write (u, state_matrix = .true., & all_states = .false., tolerance = tolerance) ! call pol%final () write (u, "(A)") write (u, "(A)") "* Left-handed massless fermion" write (u, "(A)") call flv%init (12, model) call pmatrix%init (2, 0) call pmatrix%normalize (flv, 1._default, tolerance) call pmatrix%write (u) write (u, *) call pol%init_pmatrix (pmatrix) call pol%write (u, state_matrix = .true.) ! call pol%final () write (u, "(A)") write (u, "(A)") "* Right-handed massless fermion, frac=0.5" write (u, "(A)") call flv%init (-12, model) call pmatrix%init (2, 1) call pmatrix%set_entry (1, [1,1], (1._default, 0._default)) call pmatrix%normalize (flv, 0.5_default, tolerance) call pmatrix%write (u) write (u, *) call pol%init_pmatrix (pmatrix) call pol%write (u, state_matrix = .true.) ! call pol%final () write (u, "(A)") write (u, "(A)") "* Circularly polarized gluon, frac=0.3" write (u, "(A)") call flv%init (21, model) call pmatrix%init (2, 1) call pmatrix%set_entry (1, [1,1], (1._default, 0._default)) call pmatrix%normalize (flv, 0.3_default, tolerance) call pmatrix%write (u) write (u, *) call pol%init_pmatrix (pmatrix) call pol%write (u, state_matrix = .true., & all_states = .false., tolerance = tolerance) ! call pol%final () write (u, "(A)") write (u, "(A)") "* Circularly polarized massive vector, frac=0.7" write (u, "(A)") call flv%init (23, model) call pmatrix%init (2, 1) call pmatrix%set_entry (1, [1,1], (1._default, 0._default)) call pmatrix%normalize (flv, 0.7_default, tolerance) call pmatrix%write (u) write (u, *) call pol%init_pmatrix (pmatrix) call pol%write (u, state_matrix = .true., & all_states = .false., tolerance = tolerance) ! call pol%final () write (u, "(A)") write (u, "(A)") "* Circularly polarized massive vector" write (u, "(A)") call flv%init (23, model) call pmatrix%init (2, 1) call pmatrix%set_entry (1, [1,1], (1._default, 0._default)) call pmatrix%normalize (flv, 1._default, tolerance) call pmatrix%write (u) write (u, *) call pol%init_pmatrix (pmatrix) call pol%write (u, state_matrix = .true., & all_states = .false., tolerance = tolerance) ! call pol%final () write (u, "(A)") write (u, "(A)") "* Longitudinally polarized massive vector, frac=0.4" write (u, "(A)") call flv%init (23, model) call pmatrix%init (2, 1) call pmatrix%set_entry (1, [0,0], (1._default, 0._default)) call pmatrix%normalize (flv, 0.4_default, tolerance) call pmatrix%write (u) write (u, *) write (u, "(1x,A,L1)") "polarized = ", pmatrix%is_polarized () write (u, "(1x,A,L1)") "diagonal = ", pmatrix%is_diagonal () write (u, *) call pol%init_pmatrix (pmatrix) call pol%write (u, state_matrix = .true., & all_states = .false., tolerance = tolerance) ! call pol%final () write (u, "(A)") write (u, "(A)") "* Longitudinally polarized massive vector" write (u, "(A)") call flv%init (23, model) call pmatrix%init (2, 1) call pmatrix%set_entry (1, [0,0], (1._default, 0._default)) call pmatrix%normalize (flv, 1._default, tolerance) call pmatrix%write (u) write (u, *) write (u, "(1x,A,L1)") "polarized = ", pmatrix%is_polarized () write (u, "(1x,A,L1)") "diagonal = ", pmatrix%is_diagonal () write (u, *) call pol%init_pmatrix (pmatrix) call pol%write (u, state_matrix = .true., & all_states = .false., tolerance = tolerance) ! call pol%final () write (u, "(A)") write (u, "(A)") "* Axis polarization (0.2, 0.4, 0.6)" write (u, "(A)") call flv%init (11, model) alpha = [0.2_default, 0.4_default, 0.6_default] alpha = alpha / sqrt (sum (alpha**2)) call pmatrix%init (2, 3) call pmatrix%set_entry (1, [-1,-1], cmplx (1 - alpha(3), kind=default)) call pmatrix%set_entry (2, [1,-1], & cmplx (alpha(1),-alpha(2), kind=default)) call pmatrix%set_entry (3, [1,1], cmplx (1 + alpha(3), kind=default)) call pmatrix%normalize (flv, 1._default, tolerance) call pmatrix%write (u) write (u, *) call pol%init_pmatrix (pmatrix) call pol%write (u, state_matrix = .true.) ! call pol%final () call model%final () write (u, "(A)") write (u, "(A)") "* Test output end: polarization_2" end subroutine polarization_2 @ %def polarization_2 @ \clearpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Particles} This module defines the [[particle_t]] object type, and the methods and operations that deal with it. <<[[particles.f90]]>>= <> module particles <> <> <> use io_units use format_utils, only: write_compressed_integer_array, write_separator use format_utils, only: pac_fmt use format_defs, only: FMT_16, FMT_19 use numeric_utils use diagnostics use lorentz use model_data use flavors use colors use helicities use quantum_numbers use state_matrices use interactions use subevents use polarizations use pdg_arrays, only: is_quark, is_gluon <> <> <> <> <> contains <> end module particles @ %def particles @ \subsection{The particle type} \subsubsection{Particle status codes} The overall status codes (incoming/outgoing etc.) are inherited from the module [[subevents]]. Polarization status: <>= integer, parameter, public :: PRT_UNPOLARIZED = 0 integer, parameter, public :: PRT_DEFINITE_HELICITY = 1 integer, parameter, public :: PRT_GENERIC_POLARIZATION = 2 @ %def PRT_UNPOLARIZED PRT_DEFINITE_HELICITY PRT_GENERIC_POLARIZATION @ \subsubsection{Definition} The quantum numbers are flavor (from which invariant particle properties can be derived), color, and polarization. The particle may be unpolarized. In this case, [[hel]] and [[pol]] are unspecified. If it has a definite helicity, the [[hel]] component is defined. If it has a generic polarization, the [[pol]] component is defined. For each particle we store the four-momentum and the invariant mass squared, i.e., the squared norm of the four-momentum. There is also an optional list of parent and child particles, for bookkeeping in physical events. The [[vertex]] is an optional component that consists of a Lorentz 4-vector, denoting the position and time of the vertex (displaced vertex/time). [[lifetime]] is an optional component that accounts for the finite lifetime $\tau$ of a decaying particle. In case there is no magnetic field etc., the true decay vertex of a particle in the detector would be $\vec{v}^\prime = \vec{v} + \tau \times \vec{p}/p^0$, where $p^0$ and $\vec{p}$ are the energy and 3-momentum of the particle. <>= public :: particle_t <>= type :: particle_t !private integer :: status = PRT_UNDEFINED integer :: polarization = PRT_UNPOLARIZED type(flavor_t) :: flv type(color_t) :: col type(helicity_t) :: hel type(polarization_t) :: pol type(vector4_t) :: p = vector4_null real(default) :: p2 = 0 type(vector4_t), allocatable :: vertex real(default), allocatable :: lifetime integer, dimension(:), allocatable :: parent integer, dimension(:), allocatable :: child contains <> end type particle_t @ %def particle_t @ Copy a particle. (Deep copy) This excludes the parent-child relations. <>= generic :: init => init_particle procedure :: init_particle => particle_init_particle <>= subroutine particle_init_particle (prt_out, prt_in) class(particle_t), intent(out) :: prt_out type(particle_t), intent(in) :: prt_in prt_out%status = prt_in%status prt_out%polarization = prt_in%polarization prt_out%flv = prt_in%flv prt_out%col = prt_in%col prt_out%hel = prt_in%hel prt_out%pol = prt_in%pol prt_out%p = prt_in%p prt_out%p2 = prt_in%p2 if (allocated (prt_in%vertex)) & allocate (prt_out%vertex, source=prt_in%vertex) if (allocated (prt_in%lifetime)) & allocate (prt_out%lifetime, source=prt_in%lifetime) end subroutine particle_init_particle @ %def particle_init_particle @ Initialize a particle using external information. <>= generic :: init => init_external procedure :: init_external => particle_init_external <>= subroutine particle_init_external & (particle, status, pdg, model, col, anti_col, mom) class(particle_t), intent(out) :: particle integer, intent(in) :: status, pdg, col, anti_col class(model_data_t), pointer, intent(in) :: model type(vector4_t), intent(in) :: mom type(flavor_t) :: flavor type(color_t) :: color call flavor%init (pdg, model) call particle%set_flavor (flavor) call color%init_col_acl (col, anti_col) call particle%set_color (color) call particle%set_status (status) call particle%set_momentum (mom) end subroutine particle_init_external @ %def particle_init_external @ Initialize a particle using a single-particle state matrix which determines flavor, color, and polarization. The state matrix must have unique flavor and color. The factorization mode determines whether the particle is unpolarized, has definite helicity, or generic polarization. This mode is translated into the polarization status. <>= generic :: init => init_state procedure :: init_state => particle_init_state <>= subroutine particle_init_state (prt, state, status, mode) class(particle_t), intent(out) :: prt type(state_matrix_t), intent(in), target :: state integer, intent(in) :: status, mode type(state_iterator_t) :: it prt%status = status call it%init (state) prt%flv = it%get_flavor (1) if (prt%flv%is_radiated ()) prt%status = PRT_BEAM_REMNANT prt%col = it%get_color (1) select case (mode) case (FM_SELECT_HELICITY) prt%hel = it%get_helicity (1) if (prt%hel%is_defined ()) then prt%polarization = PRT_DEFINITE_HELICITY end if case (FM_FACTOR_HELICITY) call prt%pol%init_state_matrix (state) prt%polarization = PRT_GENERIC_POLARIZATION end select end subroutine particle_init_state @ %def particle_init_state @ Finalizer. <>= procedure :: final => particle_final <>= subroutine particle_final (prt) class(particle_t), intent(inout) :: prt if (allocated (prt%vertex)) deallocate (prt%vertex) if (allocated (prt%lifetime)) deallocate (prt%lifetime) end subroutine particle_final @ %def particle_final @ \subsubsection{I/O} <>= procedure :: write => particle_write <>= subroutine particle_write (prt, unit, testflag, compressed, polarization) class(particle_t), intent(in) :: prt integer, intent(in), optional :: unit logical, intent(in), optional :: testflag, compressed, polarization logical :: comp, pacified, pol integer :: u, h1, h2 real(default) :: pp2 character(len=7) :: fmt character(len=20) :: buffer comp = .false.; if (present (compressed)) comp = compressed pacified = .false.; if (present (testflag)) pacified = testflag pol = .true.; if (present (polarization)) pol = polarization call pac_fmt (fmt, FMT_19, FMT_16, testflag) u = given_output_unit (unit); if (u < 0) return pp2 = prt%p2 if (pacified) call pacify (pp2, tolerance = 1E-10_default) select case (prt%status) case (PRT_UNDEFINED); write (u, "(1x, A)", advance="no") "[-]" case (PRT_BEAM); write (u, "(1x, A)", advance="no") "[b]" case (PRT_INCOMING); write (u, "(1x, A)", advance="no") "[i]" case (PRT_OUTGOING); write (u, "(1x, A)", advance="no") "[o]" case (PRT_VIRTUAL); write (u, "(1x, A)", advance="no") "[v]" case (PRT_RESONANT); write (u, "(1x, A)", advance="no") "[r]" case (PRT_BEAM_REMNANT); write (u, "(1x, A)", advance="no") "[x]" end select write (u, "(1x)", advance="no") if (comp) then write (u, "(A7,1X)", advance="no") char (prt%flv%get_name ()) if (pol) then select case (prt%polarization) case (PRT_DEFINITE_HELICITY) ! Integer helicity, assumed diagonal call prt%hel%get_indices (h1, h2) write (u, "(I2,1X)", advance="no") h1 case (PRT_GENERIC_POLARIZATION) ! No space for full density matrix here write (u, "(A2,1X)", advance="no") "*" case default ! Blank entry if helicity is undefined write (u, "(A2,1X)", advance="no") " " end select end if write (u, "(2(I4,1X))", advance="no") & prt%col%get_col (), prt%col%get_acl () call write_compressed_integer_array (buffer, prt%parent) write (u, "(A,1X)", advance="no") buffer call write_compressed_integer_array (buffer, prt%child) write (u, "(A,1X)", advance="no") buffer call prt%p%write(u, testflag = testflag, compressed = comp) write (u, "(F12.3)") pp2 else call prt%flv%write (unit) if (prt%col%is_nonzero ()) then call color_write (prt%col, unit) end if if (pol) then select case (prt%polarization) case (PRT_DEFINITE_HELICITY) call prt%hel%write (unit) write (u, *) case (PRT_GENERIC_POLARIZATION) write (u, *) call prt%pol%write (unit, state_matrix = .true.) case default write (u, *) end select else write (u, *) end if call prt%p%write (unit, testflag = testflag) write (u, "(1x,A,1x," // fmt // ")") "T = ", pp2 if (allocated (prt%parent)) then if (size (prt%parent) /= 0) then write (u, "(1x,A,40(1x,I0))") "Parents: ", prt%parent end if end if if (allocated (prt%child)) then if (size (prt%child) /= 0) then write (u, "(1x,A,40(1x,I0))") "Children:", prt%child end if end if if (allocated (prt%vertex)) then write (u, "(1x,A,1x," // fmt // ")") "Vtx t = ", prt%vertex%p(0) write (u, "(1x,A,1x," // fmt // ")") "Vtx x = ", prt%vertex%p(1) write (u, "(1x,A,1x," // fmt // ")") "Vtx y = ", prt%vertex%p(2) write (u, "(1x,A,1x," // fmt // ")") "Vtx z = ", prt%vertex%p(3) end if if (allocated (prt%lifetime)) then write (u, "(1x,A,1x," // fmt // ")") "Lifetime = ", & prt%lifetime end if end if end subroutine particle_write @ %def particle_write @ Binary I/O: <>= procedure :: write_raw => particle_write_raw procedure :: read_raw => particle_read_raw <>= subroutine particle_write_raw (prt, u) class(particle_t), intent(in) :: prt integer, intent(in) :: u write (u) prt%status, prt%polarization call prt%flv%write_raw (u) call prt%col%write_raw (u) select case (prt%polarization) case (PRT_DEFINITE_HELICITY) call prt%hel%write_raw (u) case (PRT_GENERIC_POLARIZATION) call prt%pol%write_raw (u) end select call vector4_write_raw (prt%p, u) write (u) prt%p2 write (u) allocated (prt%parent) if (allocated (prt%parent)) then write (u) size (prt%parent) write (u) prt%parent end if write (u) allocated (prt%child) if (allocated (prt%child)) then write (u) size (prt%child) write (u) prt%child end if write (u) allocated (prt%vertex) if (allocated (prt%vertex)) then call vector4_write_raw (prt%vertex, u) end if write (u) allocated (prt%lifetime) if (allocated (prt%lifetime)) then write (u) prt%lifetime end if end subroutine particle_write_raw subroutine particle_read_raw (prt, u, iostat) class(particle_t), intent(out) :: prt integer, intent(in) :: u integer, intent(out) :: iostat logical :: allocated_parent, allocated_child logical :: allocated_vertex, allocated_lifetime integer :: size_parent, size_child read (u, iostat=iostat) prt%status, prt%polarization call prt%flv%read_raw (u, iostat=iostat) call prt%col%read_raw (u, iostat=iostat) select case (prt%polarization) case (PRT_DEFINITE_HELICITY) call prt%hel%read_raw (u, iostat=iostat) case (PRT_GENERIC_POLARIZATION) call prt%pol%read_raw (u, iostat=iostat) end select call vector4_read_raw (prt%p, u, iostat=iostat) read (u, iostat=iostat) prt%p2 read (u, iostat=iostat) allocated_parent if (allocated_parent) then read (u, iostat=iostat) size_parent allocate (prt%parent (size_parent)) read (u, iostat=iostat) prt%parent end if read (u, iostat=iostat) allocated_child if (allocated_child) then read (u, iostat=iostat) size_child allocate (prt%child (size_child)) read (u, iostat=iostat) prt%child end if read (u, iostat=iostat) allocated_vertex if (allocated_vertex) then allocate (prt%vertex) read (u, iostat=iostat) prt%vertex%p end if read (u, iostat=iostat) allocated_lifetime if (allocated_lifetime) then allocate (prt%lifetime) read (u, iostat=iostat) prt%lifetime end if end subroutine particle_read_raw @ %def particle_write_raw particle_read_raw @ \subsubsection{Setting contents} Reset the status code. Where applicable, set $p^2$ assuming that the particle is on-shell. <>= procedure :: reset_status => particle_reset_status <>= elemental subroutine particle_reset_status (prt, status) class(particle_t), intent(inout) :: prt integer, intent(in) :: status prt%status = status select case (status) case (PRT_BEAM, PRT_INCOMING, PRT_OUTGOING) prt%p2 = prt%flv%get_mass () ** 2 end select end subroutine particle_reset_status @ %def particle_reset_status @ The color can be given explicitly. <>= procedure :: set_color => particle_set_color <>= elemental subroutine particle_set_color (prt, col) class(particle_t), intent(inout) :: prt type(color_t), intent(in) :: col prt%col = col end subroutine particle_set_color @ %def particle_set_color @ The flavor can be given explicitly. <>= procedure :: set_flavor => particle_set_flavor <>= subroutine particle_set_flavor (prt, flv) class(particle_t), intent(inout) :: prt type(flavor_t), intent(in) :: flv prt%flv = flv end subroutine particle_set_flavor @ %def particle_set_flavor @ As can the helicity. <>= procedure :: set_helicity => particle_set_helicity <>= subroutine particle_set_helicity (prt, hel) class(particle_t), intent(inout) :: prt type(helicity_t), intent(in) :: hel prt%hel = hel end subroutine particle_set_helicity @ %def particle_set_helicity @ And the polarization. <>= procedure :: set_pol => particle_set_pol <>= subroutine particle_set_pol (prt, pol) class(particle_t), intent(inout) :: prt type(polarization_t), intent(in) :: pol prt%pol = pol end subroutine particle_set_pol @ %def particle_set_pol @ Manually set the model for the particle flavor. This is required, e.g., if the particle has been read from file. <>= procedure :: set_model => particle_set_model <>= subroutine particle_set_model (prt, model) class(particle_t), intent(inout) :: prt class(model_data_t), intent(in), target :: model call prt%flv%set_model (model) end subroutine particle_set_model @ %def particle_set_model @ The momentum is set independent of the quantum numbers. <>= procedure :: set_momentum => particle_set_momentum <>= elemental subroutine particle_set_momentum (prt, p, p2, on_shell) class(particle_t), intent(inout) :: prt type(vector4_t), intent(in) :: p real(default), intent(in), optional :: p2 logical, intent(in), optional :: on_shell prt%p = p if (present (on_shell)) then if (on_shell) then if (prt%flv%is_associated ()) then prt%p2 = prt%flv%get_mass () ** 2 return end if end if end if if (present (p2)) then prt%p2 = p2 else prt%p2 = p ** 2 end if end subroutine particle_set_momentum @ %def particle_set_momentum @ Set resonance information. This should be done after momentum assignment, because we need to know wheter the particle is spacelike or timelike. The resonance flag is defined only for virtual particles. <>= procedure :: set_resonance_flag => particle_set_resonance_flag <>= elemental subroutine particle_set_resonance_flag (prt, resonant) class(particle_t), intent(inout) :: prt logical, intent(in) :: resonant select case (prt%status) case (PRT_VIRTUAL) if (resonant) prt%status = PRT_RESONANT end select end subroutine particle_set_resonance_flag @ %def particle_set_resonance_flag @ Set children and parents information. <>= procedure :: set_children => particle_set_children procedure :: set_parents => particle_set_parents <>= subroutine particle_set_children (prt, idx) class(particle_t), intent(inout) :: prt integer, dimension(:), intent(in) :: idx if (allocated (prt%child)) deallocate (prt%child) allocate (prt%child (count (idx /= 0))) prt%child = pack (idx, idx /= 0) end subroutine particle_set_children subroutine particle_set_parents (prt, idx) class(particle_t), intent(inout) :: prt integer, dimension(:), intent(in) :: idx if (allocated (prt%parent)) deallocate (prt%parent) allocate (prt%parent (count (idx /= 0))) prt%parent = pack (idx, idx /= 0) end subroutine particle_set_parents @ %def particle_set_children particle_set_parents @ <>= procedure :: add_child => particle_add_child <>= subroutine particle_add_child (prt, new_child) class(particle_t), intent(inout) :: prt integer, intent(in) :: new_child integer, dimension(:), allocatable :: idx integer :: n, i n = prt%get_n_children() if (n == 0) then call prt%set_children ([new_child]) else do i = 1, n if (prt%child(i) == new_child) then return end if end do allocate (idx (1:n+1)) idx(1:n) = prt%get_children () idx(n+1) = new_child call prt%set_children (idx) end if end subroutine particle_add_child @ %def particle_add_child @ <>= procedure :: add_children => particle_add_children <>= subroutine particle_add_children (prt, new_child) class(particle_t), intent(inout) :: prt integer, dimension(:), intent(in) :: new_child integer, dimension(:), allocatable :: idx integer :: n n = prt%get_n_children() if (n == 0) then call prt%set_children (new_child) else allocate (idx (1:n+size(new_child))) idx(1:n) = prt%get_children () idx(n+1:n+size(new_child)) = new_child call prt%set_children (idx) end if end subroutine particle_add_children @ %def particle_add_children @ <>= procedure :: set_status => particle_set_status <>= elemental subroutine particle_set_status (prt, status) class(particle_t), intent(inout) :: prt integer, intent(in) :: status prt%status = status end subroutine particle_set_status @ %def particle_set_status @ <>= procedure :: set_polarization => particle_set_polarization <>= subroutine particle_set_polarization (prt, polarization) class(particle_t), intent(inout) :: prt integer, intent(in) :: polarization prt%polarization = polarization end subroutine particle_set_polarization @ %def particle_set_polarization @ <>= generic :: set_vertex => set_vertex_from_vector3, set_vertex_from_xyz, & set_vertex_from_vector4, set_vertex_from_xyzt procedure :: set_vertex_from_vector4 => particle_set_vertex_from_vector4 procedure :: set_vertex_from_vector3 => particle_set_vertex_from_vector3 procedure :: set_vertex_from_xyzt => particle_set_vertex_from_xyzt procedure :: set_vertex_from_xyz => particle_set_vertex_from_xyz <>= subroutine particle_set_vertex_from_vector4 (prt, vertex) class(particle_t), intent(inout) :: prt type(vector4_t), intent(in) :: vertex if (allocated (prt%vertex)) deallocate (prt%vertex) allocate (prt%vertex, source=vertex) end subroutine particle_set_vertex_from_vector4 subroutine particle_set_vertex_from_vector3 (prt, vertex) class(particle_t), intent(inout) :: prt type(vector3_t), intent(in) :: vertex type(vector4_t) :: vtx vtx = vector4_moving (0._default, vertex) if (allocated (prt%vertex)) deallocate (prt%vertex) allocate (prt%vertex, source=vtx) end subroutine particle_set_vertex_from_vector3 subroutine particle_set_vertex_from_xyzt (prt, vx, vy, vz, t) class(particle_t), intent(inout) :: prt real(default), intent(in) :: vx, vy, vz, t type(vector4_t) :: vertex if (allocated (prt%vertex)) deallocate (prt%vertex) vertex = vector4_moving (t, vector3_moving ([vx, vy, vz])) allocate (prt%vertex, source=vertex) end subroutine particle_set_vertex_from_xyzt subroutine particle_set_vertex_from_xyz (prt, vx, vy, vz) class(particle_t), intent(inout) :: prt real(default), intent(in) :: vx, vy, vz type(vector4_t) :: vertex if (allocated (prt%vertex)) deallocate (prt%vertex) vertex = vector4_moving (0._default, vector3_moving ([vx, vy, vz])) allocate (prt%vertex, source=vertex) end subroutine particle_set_vertex_from_xyz @ %def particle_set_vertex_from_vector3 @ %def particle_set_vertex_from_vector4 @ %def particle_set_vertex_from_xyz @ %def particle_set_vertex_from_xyzt @ Set the lifetime of a particle. <>= procedure :: set_lifetime => particle_set_lifetime <>= elemental subroutine particle_set_lifetime (prt, lifetime) class(particle_t), intent(inout) :: prt real(default), intent(in) :: lifetime if (allocated (prt%lifetime)) deallocate (prt%lifetime) allocate (prt%lifetime, source=lifetime) end subroutine particle_set_lifetime @ %def particle_set_lifetime @ \subsubsection{Accessing contents} The status code. <>= procedure :: get_status => particle_get_status <>= elemental function particle_get_status (prt) result (status) integer :: status class(particle_t), intent(in) :: prt status = prt%status end function particle_get_status @ %def particle_get_status @ Return true if the status is either [[INCOMING]], [[OUTGOING]] or [[RESONANT]]. [[BEAM]] is kept, if [[keep_beams]] is set true. <>= procedure :: is_real => particle_is_real <>= elemental function particle_is_real (prt, keep_beams) result (flag) logical :: flag, kb class(particle_t), intent(in) :: prt logical, intent(in), optional :: keep_beams kb = .false. if (present (keep_beams)) kb = keep_beams select case (prt%status) case (PRT_INCOMING, PRT_OUTGOING, PRT_RESONANT) flag = .true. case (PRT_BEAM) flag = kb case default flag = .false. end select end function particle_is_real @ %def particle_is_real @ <>= procedure :: is_colored => particle_is_colored <>= elemental function particle_is_colored (particle) result (flag) logical :: flag class(particle_t), intent(in) :: particle flag = particle%col%is_nonzero () end function particle_is_colored @ %def particle_is_colored @ $[90,100]$ hopefully catches all of them and not too many. <>= procedure :: is_hadronic_beam_remnant => particle_is_hadronic_beam_remnant <>= elemental function particle_is_hadronic_beam_remnant (particle) result (flag) class(particle_t), intent(in) :: particle logical :: flag integer :: pdg pdg = particle%flv%get_pdg () flag = particle%status == PRT_BEAM_REMNANT .and. & abs(pdg) >= 90 .and. abs(pdg) <= 100 end function particle_is_hadronic_beam_remnant @ %def particle_is_hadronic_beam_remnant @ <>= procedure :: is_beam_remnant => particle_is_beam_remnant <>= elemental function particle_is_beam_remnant (particle) result (flag) class(particle_t), intent(in) :: particle logical :: flag flag = particle%status == PRT_BEAM_REMNANT end function particle_is_beam_remnant @ %def particle_is_beam_remnant @ Polarization status. <>= procedure :: get_polarization_status => particle_get_polarization_status <>= elemental function particle_get_polarization_status (prt) result (status) integer :: status class(particle_t), intent(in) :: prt status = prt%polarization end function particle_get_polarization_status @ %def particle_get_polarization_status @ Return the PDG code from the flavor component directly. <>= procedure :: get_pdg => particle_get_pdg <>= elemental function particle_get_pdg (prt) result (pdg) integer :: pdg class(particle_t), intent(in) :: prt pdg = prt%flv%get_pdg () end function particle_get_pdg @ %def particle_get_pdg @ Return the color and anticolor quantum numbers. <>= procedure :: get_color => particle_get_color <>= pure function particle_get_color (prt) result (col) integer, dimension(2) :: col class(particle_t), intent(in) :: prt col(1) = prt%col%get_col () col(2) = prt%col%get_acl () end function particle_get_color @ %def particle_get_color @ Return a copy of the polarization density matrix. <>= procedure :: get_polarization => particle_get_polarization <>= function particle_get_polarization (prt) result (pol) class(particle_t), intent(in) :: prt type(polarization_t) :: pol pol = prt%pol end function particle_get_polarization @ %def particle_get_polarization @ Return the flavor, color and helicity. <>= procedure :: get_flv => particle_get_flv procedure :: get_col => particle_get_col procedure :: get_hel => particle_get_hel <>= function particle_get_flv (prt) result (flv) class(particle_t), intent(in) :: prt type(flavor_t) :: flv flv = prt%flv end function particle_get_flv function particle_get_col (prt) result (col) class(particle_t), intent(in) :: prt type(color_t) :: col col = prt%col end function particle_get_col function particle_get_hel (prt) result (hel) class(particle_t), intent(in) :: prt type(helicity_t) :: hel hel = prt%hel end function particle_get_hel @ %def particle_get_flv particle_get_col particle_get_hel @ Return the helicity (if defined and diagonal). <>= procedure :: get_helicity => particle_get_helicity <>= elemental function particle_get_helicity (prt) result (hel) integer :: hel integer, dimension(2) :: hel_arr class(particle_t), intent(in) :: prt hel = 0 if (prt%hel%is_defined () .and. prt%hel%is_diagonal ()) then hel_arr = prt%hel%to_pair () hel = hel_arr (1) end if end function particle_get_helicity @ %def particle_get_helicity @ Return the number of children/parents <>= procedure :: get_n_parents => particle_get_n_parents procedure :: get_n_children => particle_get_n_children <>= elemental function particle_get_n_parents (prt) result (n) integer :: n class(particle_t), intent(in) :: prt if (allocated (prt%parent)) then n = size (prt%parent) else n = 0 end if end function particle_get_n_parents elemental function particle_get_n_children (prt) result (n) integer :: n class(particle_t), intent(in) :: prt if (allocated (prt%child)) then n = size (prt%child) else n = 0 end if end function particle_get_n_children @ %def particle_get_n_parents particle_get_n_children @ Return the array of parents/children. <>= procedure :: get_parents => particle_get_parents procedure :: get_children => particle_get_children <>= function particle_get_parents (prt) result (parent) class(particle_t), intent(in) :: prt integer, dimension(:), allocatable :: parent if (allocated (prt%parent)) then allocate (parent (size (prt%parent))) parent = prt%parent else allocate (parent (0)) end if end function particle_get_parents function particle_get_children (prt) result (child) class(particle_t), intent(in) :: prt integer, dimension(:), allocatable :: child if (allocated (prt%child)) then allocate (child (size (prt%child))) child = prt%child else allocate (child (0)) end if end function particle_get_children @ %def particle_get_children @ <>= procedure :: has_children => particle_has_children <>= elemental function particle_has_children (prt) result (has_children) logical :: has_children class(particle_t), intent(in) :: prt has_children = .false. if (allocated (prt%child)) then has_children = size (prt%child) > 0 end if end function particle_has_children @ %def particle_has_children @ <>= procedure :: has_parents => particle_has_parents <>= elemental function particle_has_parents (prt) result (has_parents) logical :: has_parents class(particle_t), intent(in) :: prt has_parents = .false. if (allocated (prt%parent)) then has_parents = size (prt%parent) > 0 end if end function particle_has_parents @ %def particle_has_parents @ Return momentum and momentum squared. <>= procedure :: get_momentum => particle_get_momentum procedure :: get_p2 => particle_get_p2 <>= elemental function particle_get_momentum (prt) result (p) type(vector4_t) :: p class(particle_t), intent(in) :: prt p = prt%p end function particle_get_momentum elemental function particle_get_p2 (prt) result (p2) real(default) :: p2 class(particle_t), intent(in) :: prt p2 = prt%p2 end function particle_get_p2 @ %def particle_get_momentum particle_get_p2 @ Return the particle vertex, if allocated. <>= procedure :: get_vertex => particle_get_vertex <>= elemental function particle_get_vertex (prt) result (vtx) type(vector4_t) :: vtx class(particle_t), intent(in) :: prt if (allocated (prt%vertex)) then vtx = prt%vertex else vtx = vector4_null end if end function particle_get_vertex @ %def particle_get_vertex @ Return the lifetime of a particle. <>= procedure :: get_lifetime => particle_get_lifetime <>= elemental function particle_get_lifetime (prt) result (lifetime) real(default) :: lifetime class(particle_t), intent(in) :: prt if (allocated (prt%lifetime)) then lifetime = prt%lifetime else lifetime = 0 end if end function particle_get_lifetime @ %def particle_get_lifetime @ <>= procedure :: momentum_to_pythia6 => particle_momentum_to_pythia6 <>= pure function particle_momentum_to_pythia6 (prt) result (p) real(double), dimension(1:5) :: p class(particle_t), intent(in) :: prt p = prt%p%to_pythia6 (sqrt (prt%p2)) end function particle_momentum_to_pythia6 @ %def particle_momentum_to_pythia6 @ \subsection{Particle sets} A particle set is what is usually called an event: an array of particles. The individual particle entries carry momentum, quantum numbers, polarization, and optionally connections. There is (also optionally) a correlated state-density matrix that maintains spin correlations that are lost in the individual particle entries. <>= public :: particle_set_t <>= type :: particle_set_t ! private !!! integer :: n_beam = 0 integer :: n_in = 0 integer :: n_vir = 0 integer :: n_out = 0 integer :: n_tot = 0 integer :: factorization_mode = FM_IGNORE_HELICITY type(particle_t), dimension(:), allocatable :: prt type(state_matrix_t) :: correlated_state contains <> end type particle_set_t @ %def particle_set_t @ A particle set can be initialized from an interaction or from a HepMC event record. <>= generic :: init => init_interaction procedure :: init_interaction => particle_set_init_interaction @ When a particle set is initialized from a given interaction, we have to determine the branch within the original state matrix that fixes the particle quantum numbers. This is done with the appropriate probabilities, based on a random number [[x]]. The [[mode]] determines whether the individual particles become unpolarized, or take a definite (diagonal) helicity, or acquire single-particle polarization matrices. The flag [[keep_correlations]] tells whether the spin-correlation matrix is to be calculated and stored in addition to the particles. The flag [[keep_virtual]] tells whether virtual particles should be dropped. Note that if virtual particles are dropped, the spin-correlation matrix makes no sense, and parent-child relations are not set. For a correct disentangling of color and flavor (in the presence of helicity), we consider two interactions. [[int]] has no color information, and is used to select a flavor state. Consequently, we trace over helicities here. [[int_flows]] contains color-flow and potentially helicity information, but is useful only after the flavor combination has been chosen. So this interaction is used to select helicity and color, but restricted to the selected flavor combination. [[int]] and [[int_flows]] may be identical if there is only a single (or no) color flow. If there is just a single flavor combination, [[x(1)]] can be set to zero. The current algorithm of evaluator convolution requires that the beam particles are assumed outgoing (in the beam interaction) and become virtual in all derived interactions. In the particle set they should be re-identified as incoming. The optional integer [[n_incoming]] can be used to perform this correction. The flag [[is_valid]] is false if factorization of the state is not possible, in particular if the squared matrix element is zero. <>= subroutine particle_set_init_interaction & (particle_set, is_valid, int, int_flows, mode, x, & keep_correlations, keep_virtual, n_incoming, qn_select) class(particle_set_t), intent(out) :: particle_set logical, intent(out) :: is_valid type(interaction_t), intent(in), target :: int, int_flows integer, intent(in) :: mode real(default), dimension(2), intent(in) :: x logical, intent(in) :: keep_correlations, keep_virtual integer, intent(in), optional :: n_incoming type(quantum_numbers_t), dimension(:), intent(in), optional :: qn_select type(state_matrix_t), dimension(:), allocatable, target :: flavor_state type(state_matrix_t), dimension(:), allocatable, target :: single_state integer :: n_in, n_vir, n_out, n_tot type(quantum_numbers_t), dimension(:,:), allocatable :: qn logical :: ok integer :: i, j if (present (n_incoming)) then n_in = n_incoming n_vir = int%get_n_vir () - n_incoming else n_in = int%get_n_in () n_vir = int%get_n_vir () end if n_out = int%get_n_out () n_tot = int%get_n_tot () particle_set%n_in = n_in particle_set%n_out = n_out if (keep_virtual) then particle_set%n_vir = n_vir particle_set%n_tot = n_tot else particle_set%n_vir = 0 particle_set%n_tot = n_in + n_out end if particle_set%factorization_mode = mode allocate (qn (n_tot, 1)) if (.not. present (qn_select)) then call int%factorize & (FM_IGNORE_HELICITY, x(1), is_valid, flavor_state) do i = 1, n_tot qn(i,:) = flavor_state(i)%get_quantum_number (1) end do else do i = 1, n_tot qn(i,:) = qn_select(i) end do end if if (keep_correlations .and. keep_virtual) then call particle_set%correlated_state%final () call int_flows%factorize (mode, x(2), ok, & single_state, particle_set%correlated_state, qn(:,1)) else call int_flows%factorize (mode, x(2), ok, & single_state, qn_in=qn(:,1)) end if is_valid = is_valid .and. ok allocate (particle_set%prt (particle_set%n_tot)) j = 1 do i = 1, n_tot if (i <= n_in) then call particle_set%prt(j)%init (single_state(i), PRT_INCOMING, mode) call particle_set%prt(j)%set_momentum (int%get_momentum (i)) else if (i <= n_in + n_vir) then if (.not. keep_virtual) cycle call particle_set%prt(j)%init & (single_state(i), PRT_VIRTUAL, mode) call particle_set%prt(j)%set_momentum (int%get_momentum (i)) else call particle_set%prt(j)%init (single_state(i), PRT_OUTGOING, mode) call particle_set%prt(j)%set_momentum & (int%get_momentum (i), on_shell = .true.) end if if (keep_virtual) then call particle_set%prt(j)%set_children & (interaction_get_children (int, i)) call particle_set%prt(j)%set_parents & (interaction_get_parents (int, i)) end if j = j + 1 end do if (keep_virtual) then call particle_set_resonance_flag & (particle_set%prt, int%get_resonance_flags ()) end if if (allocated (flavor_state)) then do i = 1, size(flavor_state) call flavor_state(i)%final () end do end if do i = 1, size(single_state) call single_state(i)%final () end do end subroutine particle_set_init_interaction @ %def particle_set_init_interaction @ Duplicate generic binding, to make sure that assignment works as it should. <>= generic :: assignment(=) => init_particle_set generic :: init => init_particle_set procedure :: init_particle_set => particle_set_init_particle_set <>= subroutine particle_set_init_particle_set (pset_out, pset_in) class(particle_set_t), intent(out) :: pset_out type(particle_set_t), intent(in) :: pset_in integer :: i pset_out%n_beam = pset_in%n_beam pset_out%n_in = pset_in%n_in pset_out%n_vir = pset_in%n_vir pset_out%n_out = pset_in%n_out pset_out%n_tot = pset_in%n_tot pset_out%factorization_mode = pset_in%factorization_mode if (allocated (pset_in%prt)) then allocate (pset_out%prt (size (pset_in%prt))) do i = 1, size (pset_in%prt) pset_out%prt(i) = pset_in%prt(i) end do end if pset_out%correlated_state = pset_in%correlated_state end subroutine particle_set_init_particle_set @ %def particle_set_init_particle_set @ Manually set the model for the stored particles. <>= procedure :: set_model => particle_set_set_model <>= subroutine particle_set_set_model (particle_set, model) class(particle_set_t), intent(inout) :: particle_set class(model_data_t), intent(in), target :: model integer :: i do i = 1, particle_set%n_tot call particle_set%prt(i)%set_model (model) end do call particle_set%correlated_state%set_model (model) end subroutine particle_set_set_model @ %def particle_set_set_model @ Pointer components are hidden inside the particle polarization, and in the correlated state matrix. <>= procedure :: final => particle_set_final <>= subroutine particle_set_final (particle_set) class(particle_set_t), intent(inout) :: particle_set integer :: i if (allocated (particle_set%prt)) then do i = 1, size(particle_set%prt) call particle_set%prt(i)%final () end do deallocate (particle_set%prt) end if call particle_set%correlated_state%final () end subroutine particle_set_final @ %def particle_set_final @ \subsection{Manual build} Basic initialization. Just allocate with a given number of beam, incoming, virtual, and outgoing particles. <>= procedure :: basic_init => particle_set_basic_init <>= subroutine particle_set_basic_init (particle_set, n_beam, n_in, n_vir, n_out) class(particle_set_t), intent(out) :: particle_set integer, intent(in) :: n_beam, n_in, n_vir, n_out particle_set%n_beam = n_beam particle_set%n_in = n_in particle_set%n_vir = n_vir particle_set%n_out = n_out particle_set%n_tot = n_beam + n_in + n_vir + n_out allocate (particle_set%prt (particle_set%n_tot)) end subroutine particle_set_basic_init @ %def particle_set_basic_init @ Build a particle set from scratch. This is used for testing purposes. The ordering of particles in the result is beam-incoming-remnant-virtual-outgoing. Parent-child relations: \begin{itemize} \item Beams are parents of incoming and beam remnants. The assignment is alternating (first beam, second beam). \item Incoming are parents of virtual and outgoing, collectively. \end{itemize} More specific settings, such as resonance histories, cannot be set this way. Beam-remnant particles are counted as virtual, but have a different status code. We assume that the [[pdg]] array has the correct size. <>= procedure :: init_direct => particle_set_init_direct <>= subroutine particle_set_init_direct (particle_set, & n_beam, n_in, n_rem, n_vir, n_out, pdg, model) class(particle_set_t), intent(out) :: particle_set integer, intent(in) :: n_beam integer, intent(in) :: n_in integer, intent(in) :: n_rem integer, intent(in) :: n_vir integer, intent(in) :: n_out integer, dimension(:), intent(in) :: pdg class(model_data_t), intent(in), target :: model type(flavor_t), dimension(:), allocatable :: flv integer :: i, k, n call particle_set%basic_init (n_beam, n_in, n_rem+n_vir, n_out) n = 0 call particle_set%prt(n+1:n+n_beam)%reset_status (PRT_BEAM) do i = n+1, n+n_beam call particle_set%prt(i)%set_children & ([(k, k=i+n_beam, n+n_beam+n_in+n_rem, 2)]) end do n = n + n_beam call particle_set%prt(n+1:n+n_in)%reset_status (PRT_INCOMING) do i = n+1, n+n_in if (n_beam > 0) then call particle_set%prt(i)%set_parents & ([i-n_beam]) end if call particle_set%prt(i)%set_children & ([(k, k=n+n_in+n_rem+1, n+n_in+n_rem+n_vir+n_out)]) end do n = n + n_in call particle_set%prt(n+1:n+n_rem)%reset_status (PRT_BEAM_REMNANT) do i = n+1, n+n_rem if (n_beam > 0) then call particle_set%prt(i)%set_parents & ([i-n_in-n_beam]) end if end do n = n + n_rem call particle_set%prt(n+1:n+n_vir)%reset_status (PRT_VIRTUAL) do i = n+1, n+n_vir call particle_set%prt(i)%set_parents & ([(k, k=n-n_rem-n_in+1, n-n_rem)]) end do n = n + n_vir call particle_set%prt(n+1:n+n_out)%reset_status (PRT_OUTGOING) do i = n+1, n+n_out call particle_set%prt(i)%set_parents & ([(k, k=n-n_vir-n_rem-n_in+1, n-n_vir-n_rem)]) end do allocate (flv (particle_set%n_tot)) call flv%init (pdg, model) do k = n_beam+n_in+1, n_beam+n_in+n_rem call flv(k)%tag_radiated () end do do i = 1, particle_set%n_tot call particle_set%prt(i)%set_flavor (flv(i)) end do end subroutine particle_set_init_direct @ %def particle_set_init_direct @ Copy a particle set into a new, extended one. Use the mapping array to determine the new positions of particles. The new set contains [[n_new]] additional entries. Count the new, undefined particles as virtual. <>= procedure :: transfer => particle_set_transfer <>= subroutine particle_set_transfer (pset, source, n_new, map) class(particle_set_t), intent(out) :: pset class(particle_set_t), intent(in) :: source integer, intent(in) :: n_new integer, dimension(:), intent(in) :: map integer :: i call pset%basic_init & (source%n_beam, source%n_in, source%n_vir + n_new, source%n_out) do i = 1, source%n_tot call pset%prt(map(i))%reset_status (source%prt(i)%get_status ()) call pset%prt(map(i))%set_flavor (source%prt(i)%get_flv ()) call pset%prt(map(i))%set_color (source%prt(i)%get_col ()) call pset%prt(map(i))%set_parents (map (source%prt(i)%get_parents ())) call pset%prt(map(i))%set_children (map (source%prt(i)%get_children ())) end do end subroutine particle_set_transfer @ %def particle_set_transfer @ Insert a new particle as an intermediate into a previously empty position. Flavor and status are just set. Color is not set (but see below). The complicated part is reassigning parent-child relations. The inserted particle comes with an array [[child]] of its children which are supposed to be existing particles. We first scan all particles that come before the new insertion. Whenever a particle has children that coincide with the children of the new particle, those child entries are removed. (a) If the new particle has no parent entry yet, those child entries are replaced by the index of the new particle and simultaneously, the particle is registered as a parent of the new particle. (b) If the current particle already has a parent entry, those child entries are removed. When this is done, the new particle is registered as the (only) parent of its children. <>= procedure :: insert => particle_set_insert <>= subroutine particle_set_insert (pset, i, status, flv, child) class(particle_set_t), intent(inout) :: pset integer, intent(in) :: i integer, intent(in) :: status type(flavor_t), intent(in) :: flv integer, dimension(:), intent(in) :: child integer, dimension(:), allocatable :: p_child, parent integer :: j, k, c, n_parent logical :: no_match call pset%prt(i)%reset_status (status) call pset%prt(i)%set_flavor (flv) call pset%prt(i)%set_children (child) n_parent = pset%prt(i)%get_n_parents () do j = 1, i - 1 p_child = pset%prt(j)%get_children () no_match = .true. do k = 1, size (p_child) if (any (p_child(k) == child)) then if (n_parent == 0 .and. no_match) then if (.not. allocated (parent)) then parent = [j] else parent = [parent, j] end if p_child(k) = i else p_child(k) = 0 end if no_match = .false. end if end do if (.not. no_match) then p_child = pack (p_child, p_child /= 0) call pset%prt(j)%set_children (p_child) end if end do if (n_parent == 0) then call pset%prt(i)%set_parents (parent) end if do j = 1, size (child) c = child(j) call pset%prt(c)%set_parents ([i]) end do end subroutine particle_set_insert @ %def particle_set_insert @ This should be done after completing all insertions: recover color assignments for the inserted particles, working backwards from children to parents. A single call to the routine recovers the color and anticolor line indices for a single particle. <>= procedure :: recover_color => particle_set_recover_color <>= subroutine particle_set_recover_color (pset, i) class(particle_set_t), intent(inout) :: pset integer, intent(in) :: i type(color_t) :: col integer, dimension(:), allocatable :: child integer :: j child = pset%prt(i)%get_children () if (size (child) > 0) then col = pset%prt(child(1))%get_col () do j = 2, size (child) col = col .fuse. pset%prt(child(j))%get_col () end do call pset%prt(i)%set_color (col) end if end subroutine particle_set_recover_color @ %def particle_set_recover_color @ \subsection{Extract/modify contents} <>= generic :: get_color => get_color_all generic :: get_color => get_color_indices procedure :: get_color_all => particle_set_get_color_all procedure :: get_color_indices => particle_set_get_color_indices <>= function particle_set_get_color_all (particle_set) result (col) class(particle_set_t), intent(in) :: particle_set type(color_t), dimension(:), allocatable :: col allocate (col (size (particle_set%prt))) col = particle_set%prt%col end function particle_set_get_color_all @ %def particle_set_get_color_all @ <>= function particle_set_get_color_indices (particle_set, indices) result (col) type(color_t), dimension(:), allocatable :: col class(particle_set_t), intent(in) :: particle_set integer, intent(in), dimension(:), allocatable :: indices integer :: i allocate (col (size (indices))) do i = 1, size (indices) col(i) = particle_set%prt(indices(i))%col end do end function particle_set_get_color_indices @ %def particle_set_get_color_indices @ Set a single or all color components. This is a wrapper around the corresponding [[particle_t]] method, with the same options. We assume that the particle array is allocated. <>= generic :: set_color => set_color_single generic :: set_color => set_color_indices generic :: set_color => set_color_all procedure :: set_color_single => particle_set_set_color_single procedure :: set_color_indices => particle_set_set_color_indices procedure :: set_color_all => particle_set_set_color_all <>= subroutine particle_set_set_color_single (particle_set, i, col) class(particle_set_t), intent(inout) :: particle_set integer, intent(in) :: i type(color_t), intent(in) :: col call particle_set%prt(i)%set_color (col) end subroutine particle_set_set_color_single subroutine particle_set_set_color_indices (particle_set, indices, col) class(particle_set_t), intent(inout) :: particle_set integer, dimension(:), intent(in) :: indices type(color_t), dimension(:), intent(in) :: col integer :: i do i = 1, size (indices) call particle_set%prt(indices(i))%set_color (col(i)) end do end subroutine particle_set_set_color_indices subroutine particle_set_set_color_all (particle_set, col) class(particle_set_t), intent(inout) :: particle_set type(color_t), dimension(:), intent(in) :: col call particle_set%prt%set_color (col) end subroutine particle_set_set_color_all @ %def particle_set_set_color @ Assigning particles manually may result in color mismatches. This is checked here for all particles in the set. The color object is compared against the color type that belongs to the flavor object. The return value is an allocatable array which consists of the particles with invalid color assignments. If the array size is zero, all is fine. <>= procedure :: find_prt_invalid_color => particle_set_find_prt_invalid_color <>= subroutine particle_set_find_prt_invalid_color (particle_set, index, prt) class(particle_set_t), intent(in) :: particle_set integer, dimension(:), allocatable, intent(out) :: index type(particle_t), dimension(:), allocatable, intent(out), optional :: prt type(flavor_t) :: flv type(color_t) :: col logical, dimension(:), allocatable :: mask integer :: i, n, n_invalid n = size (particle_set%prt) allocate (mask (n)) do i = 1, n associate (prt => particle_set%prt(i)) flv = prt%get_flv () col = prt%get_col () mask(i) = flv%get_color_type () /= col%get_type () end associate end do index = pack ([(i, i = 1, n)], mask) if (present (prt)) prt = pack (particle_set%prt, mask) end subroutine particle_set_find_prt_invalid_color @ %def particle_set_find_prt_invalid_color @ <>= generic :: get_momenta => get_momenta_all generic :: get_momenta => get_momenta_indices procedure :: get_momenta_all => particle_set_get_momenta_all procedure :: get_momenta_indices => particle_set_get_momenta_indices <>= function particle_set_get_momenta_all (particle_set) result (p) class(particle_set_t), intent(in) :: particle_set type(vector4_t), dimension(:), allocatable :: p allocate (p (size (particle_set%prt))) p = particle_set%prt%p end function particle_set_get_momenta_all @ %def particle_set_get_momenta_all @ <>= function particle_set_get_momenta_indices (particle_set, indices) result (p) type(vector4_t), dimension(:), allocatable :: p class(particle_set_t), intent(in) :: particle_set integer, intent(in), dimension(:), allocatable :: indices integer :: i allocate (p (size (indices))) do i = 1, size (indices) p(i) = particle_set%prt(indices(i))%p end do end function particle_set_get_momenta_indices @ %def particle_set_get_momenta_indices @ Replace a single or all momenta. This is a wrapper around the corresponding [[particle_t]] method, with the same options. We assume that the particle array is allocated. <>= generic :: set_momentum => set_momentum_single generic :: set_momentum => set_momentum_indices generic :: set_momentum => set_momentum_all procedure :: set_momentum_single => particle_set_set_momentum_single procedure :: set_momentum_indices => particle_set_set_momentum_indices procedure :: set_momentum_all => particle_set_set_momentum_all <>= subroutine particle_set_set_momentum_single & (particle_set, i, p, p2, on_shell) class(particle_set_t), intent(inout) :: particle_set integer, intent(in) :: i type(vector4_t), intent(in) :: p real(default), intent(in), optional :: p2 logical, intent(in), optional :: on_shell call particle_set%prt(i)%set_momentum (p, p2, on_shell) end subroutine particle_set_set_momentum_single subroutine particle_set_set_momentum_indices & (particle_set, indices, p, p2, on_shell) class(particle_set_t), intent(inout) :: particle_set integer, dimension(:), intent(in) :: indices type(vector4_t), dimension(:), intent(in) :: p real(default), dimension(:), intent(in), optional :: p2 logical, intent(in), optional :: on_shell integer :: i if (present (p2)) then do i = 1, size (indices) call particle_set%prt(indices(i))%set_momentum (p(i), p2(i), on_shell) end do else do i = 1, size (indices) call particle_set%prt(indices(i))%set_momentum & (p(i), on_shell=on_shell) end do end if end subroutine particle_set_set_momentum_indices subroutine particle_set_set_momentum_all (particle_set, p, p2, on_shell) class(particle_set_t), intent(inout) :: particle_set type(vector4_t), dimension(:), intent(in) :: p real(default), dimension(:), intent(in), optional :: p2 logical, intent(in), optional :: on_shell call particle_set%prt%set_momentum (p, p2, on_shell) end subroutine particle_set_set_momentum_all @ %def particle_set_set_momentum @ Recover a momentum by recombining from children, assuming that this is possible. The reconstructed momentum is not projected on-shell. <>= procedure :: recover_momentum => particle_set_recover_momentum <>= subroutine particle_set_recover_momentum (particle_set, i) class(particle_set_t), intent(inout) :: particle_set integer, intent(in) :: i type(vector4_t), dimension(:), allocatable :: p integer, dimension(:), allocatable :: index index = particle_set%prt(i)%get_children () p = particle_set%get_momenta (index) call particle_set%set_momentum (i, sum (p)) end subroutine particle_set_recover_momentum @ %def particle_set_recover_momentum @ <>= procedure :: replace_incoming_momenta => particle_set_replace_incoming_momenta <>= subroutine particle_set_replace_incoming_momenta (particle_set, p) class(particle_set_t), intent(inout) :: particle_set type(vector4_t), intent(in), dimension(:) :: p integer :: i, j i = 1 do j = 1, particle_set%get_n_tot () if (particle_set%prt(j)%get_status () == PRT_INCOMING) then particle_set%prt(j)%p = p(i) i = i + 1 if (i > particle_set%n_in) exit end if end do end subroutine particle_set_replace_incoming_momenta @ %def particle_set_replace_incoming_momenta @ <>= procedure :: replace_outgoing_momenta => particle_set_replace_outgoing_momenta <>= subroutine particle_set_replace_outgoing_momenta (particle_set, p) class(particle_set_t), intent(inout) :: particle_set type(vector4_t), intent(in), dimension(:) :: p integer :: i, j i = particle_set%n_in + 1 do j = 1, particle_set%n_tot if (particle_set%prt(j)%get_status () == PRT_OUTGOING) then particle_set%prt(j)%p = p(i) i = i + 1 end if end do end subroutine particle_set_replace_outgoing_momenta @ %def particle_set_replace_outgoing_momenta @ <>= procedure :: get_outgoing_momenta => particle_set_get_outgoing_momenta <>= function particle_set_get_outgoing_momenta (particle_set) result (p) class(particle_set_t), intent(in) :: particle_set type(vector4_t), dimension(:), allocatable :: p integer :: i, k allocate (p (count (particle_set%prt%get_status () == PRT_OUTGOING))) k = 0 do i = 1, size (particle_set%prt) if (particle_set%prt(i)%get_status () == PRT_OUTGOING) then k = k + 1 p(k) = particle_set%prt(i)%get_momentum () end if end do end function particle_set_get_outgoing_momenta @ %def particle_set_get_outgoing_momenta @ <>= procedure :: parent_add_child => particle_set_parent_add_child <>= subroutine particle_set_parent_add_child (particle_set, parent, child) class(particle_set_t), intent(inout) :: particle_set integer, intent(in) :: parent, child call particle_set%prt(child)%set_parents ([parent]) call particle_set%prt(parent)%add_child (child) end subroutine particle_set_parent_add_child @ %def particle_set_parent_add_child @ Given the [[particle_set]] before radiation, the new momenta [[p_radiated]], the [[emitter]] and the [[flv_radiated]] as well as the [[model]] and a random number [[r_color]] for chosing a color, we update the [[particle_set]]. <>= procedure :: build_radiation => particle_set_build_radiation <>= subroutine particle_set_build_radiation (particle_set, p_radiated, & emitter, flv_radiated, model, r_color) class(particle_set_t), intent(inout) :: particle_set type(vector4_t), intent(in), dimension(:) :: p_radiated integer, intent(in) :: emitter integer, intent(in), dimension(:) :: flv_radiated class(model_data_t), intent(in), target :: model real(default), intent(in) :: r_color type(particle_set_t) :: new_particle_set type(particle_t) :: new_particle integer :: i integer :: pdg_index_emitter, pdg_index_radiation integer, dimension(:), allocatable :: parents, children type(flavor_t) :: new_flv logical, dimension(:), allocatable :: status_mask integer, dimension(:), allocatable :: & i_in1, i_beam1, i_remnant1, i_virt1, i_out1 integer, dimension(:), allocatable :: & i_in2, i_beam2, i_remnant2, i_virt2, i_out2 integer :: n_in1, n_beam1, n_remnant1, n_virt1, n_out1 integer :: n_in2, n_beam2, n_remnant2, n_virt2, n_out2 integer :: n, n_tot integer :: i_emitter n = particle_set%get_n_tot () allocate (status_mask (n)) do i = 1, n status_mask(i) = particle_set%prt(i)%get_status () == PRT_INCOMING end do n_in1 = count (status_mask) allocate (i_in1 (n_in1)) i_in1 = particle_set%get_indices (status_mask) do i = 1, n status_mask(i) = particle_set%prt(i)%get_status () == PRT_BEAM end do n_beam1 = count (status_mask) allocate (i_beam1 (n_beam1)) i_beam1 = particle_set%get_indices (status_mask) do i = 1, n status_mask(i) = particle_set%prt(i)%get_status () == PRT_BEAM_REMNANT end do n_remnant1 = count (status_mask) allocate (i_remnant1 (n_remnant1)) i_remnant1 = particle_set%get_indices (status_mask) do i = 1, n status_mask(i) = particle_set%prt(i)%get_status () == PRT_VIRTUAL end do n_virt1 = count (status_mask) allocate (i_virt1 (n_virt1)) i_virt1 = particle_set%get_indices (status_mask) do i = 1, n status_mask(i) = particle_set%prt(i)%get_status () == PRT_OUTGOING end do n_out1 = count (status_mask) allocate (i_out1 (n_out1)) i_out1 = particle_set%get_indices (status_mask) n_in2 = n_in1; n_beam2 = n_beam1; n_remnant2 = n_remnant1 n_virt2 = n_virt1 + n_out1 n_out2 = n_out1 + 1 n_tot = n_in2 + n_beam2 + n_remnant2 + n_virt2 + n_out2 allocate (i_in2 (n_in2), i_beam2 (n_beam2), i_remnant2 (n_remnant2)) i_in2 = i_in1; i_beam2 = i_beam1; i_remnant2 = i_remnant1 allocate (i_virt2 (n_virt2)) i_virt2(1 : n_virt1) = i_virt1 i_virt2(n_virt1 + 1 : n_virt2) = i_out1 allocate (i_out2 (n_out2)) i_out2(1 : n_out1) = i_out1(1 : n_out1) + n_out1 i_out2(n_out2) = n_tot new_particle_set%n_beam = n_beam2 new_particle_set%n_in = n_in2 new_particle_set%n_vir = n_virt2 new_particle_set%n_out = n_out2 new_particle_set%n_tot = n_tot new_particle_set%correlated_state = particle_set%correlated_state allocate (new_particle_set%prt (n_tot)) if (size (i_beam1) > 0) new_particle_set%prt(i_beam2) = particle_set%prt(i_beam1) if (size (i_remnant1) > 0) new_particle_set%prt(i_remnant2) = particle_set%prt(i_remnant1) do i = 1, n_virt1 new_particle_set%prt(i_virt2(i)) = particle_set%prt(i_virt1(i)) end do do i = n_virt1 + 1, n_virt2 new_particle_set%prt(i_virt2(i)) = particle_set%prt(i_out1(i - n_virt1)) call new_particle_set%prt(i_virt2(i))%reset_status (PRT_VIRTUAL) end do do i = 1, n_in2 new_particle_set%prt(i_in2(i)) = particle_set%prt(i_in1(i)) new_particle_set%prt(i_in2(i))%p = p_radiated (i) end do do i = 1, n_out2 - 1 new_particle_set%prt(i_out2(i)) = particle_set%prt(i_out1(i)) new_particle_set%prt(i_out2(i))%p = p_radiated(i + n_in2) call new_particle_set%prt(i_out2(i))%reset_status (PRT_OUTGOING) end do call new_particle%reset_status (PRT_OUTGOING) call new_particle%set_momentum (p_radiated (n_in2 + n_out2)) !!! Helicity and polarization handling is missing at this point !!! Also, no helicities or polarizations yet pdg_index_emitter = flv_radiated (emitter) pdg_index_radiation = flv_radiated (n_in2 + n_out2) call new_flv%init (pdg_index_radiation, model) i_emitter = emitter + n_virt2 + n_remnant2 + n_beam2 call reassign_colors (new_particle, new_particle_set%prt(i_emitter), & pdg_index_radiation, pdg_index_emitter, r_color) call new_particle%set_flavor (new_flv) new_particle_set%prt(n_tot) = new_particle allocate (children (n_out2)) children = i_out2 do i = n_in2 + n_beam2 + n_remnant2 + n_virt1 + 1, n_in2 + n_beam2 + n_remnant2 + n_virt2 call new_particle_set%prt(i)%set_children (children) end do !!! Set proper parents for outgoing particles allocate (parents (n_out1)) parents = i_out1 do i = n_in2 + n_beam2 + n_remnant2 + n_virt2 + 1, n_tot call new_particle_set%prt(i)%set_parents (parents) end do call particle_set%init (new_particle_set) contains <> subroutine reassign_colors (prt_radiated, prt_emitter, i_rad, i_em, r_col) type(particle_t), intent(inout) :: prt_radiated, prt_emitter integer, intent(in) :: i_rad, i_em real(default), intent(in) :: r_col type(color_t) :: col_rad, col_em if (is_quark (i_em) .and. is_gluon (i_rad)) then call reassign_colors_qg (prt_emitter, col_rad, col_em) else if (is_gluon (i_em) .and. is_gluon (i_rad)) then call reassign_colors_gg (prt_emitter, r_col, col_rad, col_em) else if (is_gluon (i_em) .and. is_quark (i_rad)) then call reassign_colors_qq (prt_emitter, i_em, col_rad, col_em) else call msg_fatal ("Invalid splitting") end if call prt_emitter%set_color (col_em) call prt_radiated%set_color (col_rad) end subroutine reassign_colors subroutine reassign_colors_qg (prt_emitter, col_rad, col_em) type(particle_t), intent(in) :: prt_emitter type(color_t), intent(out) :: col_rad, col_em integer, dimension(2) :: color_rad, color_em integer :: i1, i2 integer :: new_color_index logical :: is_anti_quark color_em = prt_emitter%get_color () i1 = 1; i2 = 2 is_anti_quark = color_em(2) /= 0 if (is_anti_quark) then i1 = 2; i2 = 1 end if new_color_index = color_em(i1)+1 color_rad(i1) = color_em(i1) color_rad(i2) = new_color_index color_em(i1) = new_color_index call col_em%init_col_acl (color_em(1), color_em(2)) call col_rad%init_col_acl (color_rad(1), color_rad(2)) end subroutine reassign_colors_qg subroutine reassign_colors_gg (prt_emitter, random, col_rad, col_em) !!! NOT TESTED YET type(particle_t), intent(in) :: prt_emitter real(default), intent(in) :: random type(color_t), intent(out) :: col_rad, col_em integer, dimension(2) :: color_rad, color_em integer :: i1, i2 integer :: new_color_index color_em = prt_emitter%get_color () new_color_index = maxval (abs (color_em)) i1 = 1; i2 = 2 if (random < 0.5) then i1 = 2; i2 = 1 end if color_rad(i1) = new_color_index color_rad(i2) = color_em(i2) color_em(i2) = new_color_index call col_em%init_col_acl (color_em(1), color_em(2)) call col_rad%init_col_acl (color_rad(1), color_rad(2)) end subroutine reassign_colors_gg subroutine reassign_colors_qq (prt_emitter, pdg_emitter, col_rad, col_em) !!! NOT TESTED YET type(particle_t), intent(in) :: prt_emitter integer, intent(in) :: pdg_emitter type(color_t), intent(out) :: col_rad, col_em integer, dimension(2) :: color_rad, color_em integer :: i1, i2 logical :: is_anti_quark color_em = prt_emitter%get_color () i1 = 1; i2 = 2 is_anti_quark = pdg_emitter < 0 if (is_anti_quark) then i1 = 2; i1 = 1 end if color_em(i2) = 0 color_rad(i1) = 0 color_rad(i2) = color_em(i1) call col_em%init_col_acl (color_em(1), color_em(2)) call col_rad%init_col_acl (color_rad(1), color_rad(2)) end subroutine reassign_colors_qq end subroutine particle_set_build_radiation @ %def particle_set_build_radiation @ Increments the color indices of all particles by their maximal value to distinguish them from the record-keeping Born particles in the LHE-output if the virtual entries are kept. <>= subroutine set_color_offset (particle_set) type(particle_set_t), intent(inout) :: particle_set integer, dimension(2) :: color integer :: i, i_color_max type(color_t) :: new_color i_color_max = 0 do i = 1, size (particle_set%prt) associate (prt => particle_set%prt(i)) if (prt%get_status () <= PRT_INCOMING) cycle color = prt%get_color () i_color_max = maxval([i_color_max, color(1), color(2)]) end associate end do do i = 1, size (particle_set%prt) associate (prt => particle_set%prt(i)) if (prt%get_status () /= PRT_OUTGOING) cycle color = prt%get_color () where (color /= 0) color = color + i_color_max call new_color%init_col_acl (color(1), color(2)) call prt%set_color (new_color) end associate end do end subroutine set_color_offset @ %def set_color_offset @ Output (default format) <>= procedure :: write => particle_set_write <>= subroutine particle_set_write & (particle_set, unit, testflag, summary, compressed) class(particle_set_t), intent(in) :: particle_set integer, intent(in), optional :: unit logical, intent(in), optional :: testflag, summary, compressed logical :: summ, comp, pol type(vector4_t) :: sum_vec integer :: u, i u = given_output_unit (unit); if (u < 0) return summ = .false.; if (present (summary)) summ = summary comp = .false.; if (present (compressed)) comp = compressed pol = particle_set%factorization_mode /= FM_IGNORE_HELICITY write (u, "(1x,A)") "Particle set:" call write_separator (u) if (comp) then if (pol) then write (u, & "((A4,1X),(A6,1X),(A7,1X),(A3),2(A4,1X),2(A20,1X),5(A12,1X))") & "Nr", "Status", "Flavor", "Hel", "Col", "ACol", & "Parents", "Children", & "P(0)", "P(1)", "P(2)", "P(3)", "P^2" else write (u, & "((A4,1X),(A6,1X),(A7,1X),2(A4,1X),2(A20,1X),5(A12,1X))") & "Nr", "Status", "Flavor", "Col", "ACol", & "Parents", "Children", & "P(0)", "P(1)", "P(2)", "P(3)", "P^2" end if end if if (particle_set%n_tot /= 0) then do i = 1, particle_set%n_tot if (comp) then write (u, "(I4,1X,2X)", advance="no") i else write (u, "(1x,A,1x,I0)", advance="no") "Particle", i end if call particle_set%prt(i)%write (u, testflag = testflag, & compressed = comp, polarization = pol) end do if (particle_set%correlated_state%is_defined ()) then call write_separator (u) write (u, *) "Correlated state density matrix:" call particle_set%correlated_state%write (u) end if if (summ) then call write_separator (u) write (u, "(A)", advance="no") & "Sum of incoming momenta: p(0:3) = " sum_vec = sum (particle_set%prt%p, & mask=particle_set%prt%get_status () == PRT_INCOMING) call pacify (sum_vec, tolerance = 1E-3_default) call sum_vec%write (u, compressed=.true.) write (u, *) write (u, "(A)", advance="no") & "Sum of beam remnant momenta: p(0:3) = " sum_vec = sum (particle_set%prt%p, & mask=particle_set%prt%get_status () == PRT_BEAM_REMNANT) call pacify (sum_vec, tolerance = 1E-3_default) call sum_vec%write (u, compressed=.true.) write (u, *) write (u, "(A)", advance="no") & "Sum of outgoing momenta: p(0:3) = " sum_vec = sum (particle_set%prt%p, & mask=particle_set%prt%get_status () == PRT_OUTGOING) call pacify (sum_vec, tolerance = 1E-3_default) call sum_vec%write (u, compressed=.true.) write (u, "(A)") "" end if else write (u, "(3x,A)") "[empty]" end if end subroutine particle_set_write @ %def particle_set_write @ \subsection{I/O formats} Here, we define input/output of particle sets in various formats. This is the right place since particle sets contain most of the event information. All write/read routines take as first argument the object, as second argument the I/O unit which in this case is a mandatory argument. Then follow further event data. \subsubsection{Internal binary format} This format is supposed to contain the complete information, so the particle data set can be fully reconstructed. The exception is the model part of the particle flavors; this is unassigned for the flavor values read from file. <>= procedure :: write_raw => particle_set_write_raw procedure :: read_raw => particle_set_read_raw <>= subroutine particle_set_write_raw (particle_set, u) class(particle_set_t), intent(in) :: particle_set integer, intent(in) :: u integer :: i write (u) & particle_set%n_beam, particle_set%n_in, & particle_set%n_vir, particle_set%n_out write (u) particle_set%factorization_mode write (u) particle_set%n_tot do i = 1, particle_set%n_tot call particle_set%prt(i)%write_raw (u) end do call particle_set%correlated_state%write_raw (u) end subroutine particle_set_write_raw subroutine particle_set_read_raw (particle_set, u, iostat) class(particle_set_t), intent(out) :: particle_set integer, intent(in) :: u integer, intent(out) :: iostat integer :: i read (u, iostat=iostat) & particle_set%n_beam, particle_set%n_in, & particle_set%n_vir, particle_set%n_out read (u, iostat=iostat) particle_set%factorization_mode read (u, iostat=iostat) particle_set%n_tot allocate (particle_set%prt (particle_set%n_tot)) do i = 1, size (particle_set%prt) call particle_set%prt(i)%read_raw (u, iostat=iostat) end do call particle_set%correlated_state%read_raw (u, iostat=iostat) end subroutine particle_set_read_raw @ %def particle_set_write_raw particle_set_read_raw @ \subsubsection{Get contents} Find parents/children of a particular particle recursively; the search terminates if a parent/child has status [[BEAM]], [[INCOMING]], [[OUTGOING]] or [[RESONANT]]. <>= procedure :: get_real_parents => particle_set_get_real_parents procedure :: get_real_children => particle_set_get_real_children <>= function particle_set_get_real_parents (pset, i, keep_beams) result (parent) integer, dimension(:), allocatable :: parent class(particle_set_t), intent(in) :: pset integer, intent(in) :: i logical, intent(in), optional :: keep_beams logical, dimension(:), allocatable :: is_real logical, dimension(:), allocatable :: is_parent, is_real_parent logical :: kb integer :: j, k kb = .false. if (present (keep_beams)) kb = keep_beams allocate (is_real (pset%n_tot)) is_real = pset%prt%is_real (kb) allocate (is_parent (pset%n_tot), is_real_parent (pset%n_tot)) is_real_parent = .false. is_parent = .false. is_parent(pset%prt(i)%get_parents()) = .true. do while (any (is_parent)) where (is_real .and. is_parent) is_real_parent = .true. is_parent = .false. end where mark_next_parent: do j = size (is_parent), 1, -1 if (is_parent(j)) then is_parent(pset%prt(j)%get_parents()) = .true. is_parent(j) = .false. exit mark_next_parent end if end do mark_next_parent end do allocate (parent (count (is_real_parent))) j = 0 do k = 1, size (is_parent) if (is_real_parent(k)) then j = j + 1 parent(j) = k end if end do end function particle_set_get_real_parents function particle_set_get_real_children (pset, i, keep_beams) result (child) integer, dimension(:), allocatable :: child class(particle_set_t), intent(in) :: pset integer, intent(in) :: i logical, dimension(:), allocatable :: is_real logical, dimension(:), allocatable :: is_child, is_real_child logical, intent(in), optional :: keep_beams integer :: j, k logical :: kb kb = .false. if (present (keep_beams)) kb = keep_beams allocate (is_real (pset%n_tot)) is_real = pset%prt%is_real (kb) is_real = pset%prt%is_real (kb) allocate (is_child (pset%n_tot), is_real_child (pset%n_tot)) is_real_child = .false. is_child = .false. is_child(pset%prt(i)%get_children()) = .true. do while (any (is_child)) where (is_real .and. is_child) is_real_child = .true. is_child = .false. end where mark_next_child: do j = 1, size (is_child) if (is_child(j)) then is_child(pset%prt(j)%get_children()) = .true. is_child(j) = .false. exit mark_next_child end if end do mark_next_child end do allocate (child (count (is_real_child))) j = 0 do k = 1, size (is_child) if (is_real_child(k)) then j = j + 1 child(j) = k end if end do end function particle_set_get_real_children @ %def particle_set_get_real_parents @ %def particle_set_get_real_children @ Get the [[n_tot]], [[n_in]], and [[n_out]] values out of the particle set. <>= procedure :: get_n_beam => particle_set_get_n_beam procedure :: get_n_in => particle_set_get_n_in procedure :: get_n_vir => particle_set_get_n_vir procedure :: get_n_out => particle_set_get_n_out procedure :: get_n_tot => particle_set_get_n_tot procedure :: get_n_remnants => particle_set_get_n_remnants <>= function particle_set_get_n_beam (pset) result (n_beam) class(particle_set_t), intent(in) :: pset integer :: n_beam n_beam = pset%n_beam end function particle_set_get_n_beam function particle_set_get_n_in (pset) result (n_in) class(particle_set_t), intent(in) :: pset integer :: n_in n_in = pset%n_in end function particle_set_get_n_in function particle_set_get_n_vir (pset) result (n_vir) class(particle_set_t), intent(in) :: pset integer :: n_vir n_vir = pset%n_vir end function particle_set_get_n_vir function particle_set_get_n_out (pset) result (n_out) class(particle_set_t), intent(in) :: pset integer :: n_out n_out = pset%n_out end function particle_set_get_n_out function particle_set_get_n_tot (pset) result (n_tot) class(particle_set_t), intent(in) :: pset integer :: n_tot n_tot = pset%n_tot end function particle_set_get_n_tot function particle_set_get_n_remnants (pset) result (n_remn) class(particle_set_t), intent(in) :: pset integer :: n_remn if (allocated (pset%prt)) then n_remn = count (pset%prt%get_status () == PRT_BEAM_REMNANT) else n_remn = 0 end if end function particle_set_get_n_remnants @ %def particle_set_get_n_beam @ %def particle_set_get_n_in @ %def particle_set_get_n_vir @ %def particle_set_get_n_out @ %def particle_set_get_n_tot @ %def particle_set_get_n_remnants @ Return a pointer to the particle corresponding to the number <>= procedure :: get_particle => particle_set_get_particle <>= function particle_set_get_particle (pset, index) result (particle) class(particle_set_t), intent(in) :: pset integer, intent(in) :: index type(particle_t) :: particle particle = pset%prt(index) end function particle_set_get_particle @ %def particle_set_get_particle @ <>= procedure :: get_indices => particle_set_get_indices <>= pure function particle_set_get_indices (pset, mask) result (finals) integer, dimension(:), allocatable :: finals class(particle_set_t), intent(in) :: pset logical, dimension(:), intent(in) :: mask integer, dimension(size(mask)) :: indices integer :: i allocate (finals (count (mask))) indices = [(i, i=1, pset%n_tot)] finals = pack (indices, mask) end function particle_set_get_indices @ %def particle_set_get_indices @ <>= procedure :: get_in_and_out_momenta => particle_set_get_in_and_out_momenta <>= function particle_set_get_in_and_out_momenta (pset) result (phs_point) type(phs_point_t) :: phs_point class(particle_set_t), intent(in) :: pset logical, dimension(:), allocatable :: mask integer, dimension(:), allocatable :: indices type(vector4_t), dimension(:), allocatable :: p allocate (mask (pset%get_n_tot ())) allocate (p (size (pset%prt))) mask = pset%prt%status == PRT_INCOMING .or. & pset%prt%status == PRT_OUTGOING allocate (indices (count (mask))) indices = pset%get_indices (mask) phs_point = pset%get_momenta (indices) end function particle_set_get_in_and_out_momenta @ %def particle_set_get_in_and_out_momenta @ \subsubsection{Tools} Build a new particles array without hadronic remnants but with [[n_extra]] additional spots. We also update the mother-daughter relations assuming the ordering [[b]], [[i]], [[r]], [[x]], [[o]]. <>= procedure :: without_hadronic_remnants => & particle_set_without_hadronic_remnants <>= subroutine particle_set_without_hadronic_remnants & (particle_set, particles, n_particles, n_extra) class(particle_set_t), intent(inout) :: particle_set type(particle_t), dimension(:), allocatable, intent(out) :: particles integer, intent(out) :: n_particles integer, intent(in) :: n_extra logical, dimension(:), allocatable :: no_hadronic_remnants, & no_hadronic_children integer, dimension(:), allocatable :: children, new_children integer :: i, j, k, first_remnant first_remnant = particle_set%n_tot do i = 1, particle_set%n_tot if (particle_set%prt(i)%is_hadronic_beam_remnant ()) then first_remnant = i exit end if end do n_particles = count (.not. particle_set%prt%is_hadronic_beam_remnant ()) allocate (no_hadronic_remnants (particle_set%n_tot)) no_hadronic_remnants = .not. particle_set%prt%is_hadronic_beam_remnant () allocate (particles (n_particles + n_extra)) k = 1 do i = 1, particle_set%n_tot if (no_hadronic_remnants(i)) then particles(k) = particle_set%prt(i) k = k + 1 end if end do if (n_particles /= particle_set%n_tot) then do i = 1, n_particles select case (particles(i)%get_status ()) case (PRT_BEAM) if (allocated (children)) deallocate (children) allocate (children (particles(i)%get_n_children ())) children = particles(i)%get_children () if (allocated (no_hadronic_children)) & deallocate (no_hadronic_children) allocate (no_hadronic_children (particles(i)%get_n_children ())) no_hadronic_children = .not. & particle_set%prt(children)%is_hadronic_beam_remnant () if (allocated (new_children)) deallocate (new_children) allocate (new_children (count (no_hadronic_children))) new_children = pack (children, no_hadronic_children) call particles(i)%set_children (new_children) case (PRT_INCOMING, PRT_RESONANT) <> case (PRT_OUTGOING, PRT_BEAM_REMNANT) case default end select end do end if end subroutine particle_set_without_hadronic_remnants @ %def particle_set_without_hadronic_remnants <>= if (allocated (children)) deallocate (children) allocate (children (particles(i)%get_n_children ())) children = particles(i)%get_children () do j = 1, size (children) if (children(j) > first_remnant) then children(j) = children (j) - & (particle_set%n_tot - n_particles) end if end do call particles(i)%set_children (children) @ Build a new particles array without remnants but with [[n_extra]] additional spots. We also update the mother-daughter relations assuming the ordering [[b]], [[i]], [[r]], [[x]], [[o]]. <>= procedure :: without_remnants => particle_set_without_remnants <>= subroutine particle_set_without_remnants & (particle_set, particles, n_particles, n_extra) class(particle_set_t), intent(inout) :: particle_set type(particle_t), dimension(:), allocatable, intent(out) :: particles integer, intent(in) :: n_extra integer, intent(out) :: n_particles logical, dimension(:), allocatable :: no_remnants, no_children integer, dimension(:), allocatable :: children, new_children integer :: i,j, k, first_remnant first_remnant = particle_set%n_tot do i = 1, particle_set%n_tot if (particle_set%prt(i)%is_beam_remnant ()) then first_remnant = i exit end if end do allocate (no_remnants (particle_set%n_tot)) no_remnants = .not. (particle_set%prt%is_beam_remnant ()) n_particles = count (no_remnants) allocate (particles (n_particles + n_extra)) k = 1 do i = 1, particle_set%n_tot if (no_remnants(i)) then particles(k) = particle_set%prt(i) k = k + 1 end if end do if (n_particles /= particle_set%n_tot) then do i = 1, n_particles select case (particles(i)%get_status ()) case (PRT_BEAM) if (allocated (children)) deallocate (children) allocate (children (particles(i)%get_n_children ())) children = particles(i)%get_children () if (allocated (no_children)) deallocate (no_children) allocate (no_children (particles(i)%get_n_children ())) no_children = .not. (particle_set%prt(children)%is_beam_remnant ()) if (allocated (new_children)) deallocate (new_children) allocate (new_children (count (no_children))) new_children = pack (children, no_children) call particles(i)%set_children (new_children) case (PRT_INCOMING, PRT_RESONANT) <> case (PRT_OUTGOING, PRT_BEAM_REMNANT) case default end select end do end if end subroutine particle_set_without_remnants @ %def particle_set_without_remnants @ <>= procedure :: find_particle => particle_set_find_particle <>= pure function particle_set_find_particle (particle_set, pdg, & momentum, abs_smallness, rel_smallness) result (idx) integer :: idx class(particle_set_t), intent(in) :: particle_set integer, intent(in) :: pdg type(vector4_t), intent(in) :: momentum real(default), intent(in), optional :: abs_smallness, rel_smallness integer :: i logical, dimension(0:3) :: equals idx = 0 do i = 1, size (particle_set%prt) if (particle_set%prt(i)%flv%get_pdg () == pdg) then equals = nearly_equal (particle_set%prt(i)%p%p, momentum%p, & abs_smallness, rel_smallness) if (all (equals)) then idx = i return end if end if end do end function particle_set_find_particle @ %def particle_set_find_particle <>= procedure :: reverse_find_particle => particle_set_reverse_find_particle <>= pure function particle_set_reverse_find_particle & (particle_set, pdg, momentum, abs_smallness, rel_smallness) result (idx) integer :: idx class(particle_set_t), intent(in) :: particle_set integer, intent(in) :: pdg type(vector4_t), intent(in) :: momentum real(default), intent(in), optional :: abs_smallness, rel_smallness integer :: i idx = 0 do i = size (particle_set%prt), 1, -1 if (particle_set%prt(i)%flv%get_pdg () == pdg) then if (all (nearly_equal (particle_set%prt(i)%p%p, momentum%p, & abs_smallness, rel_smallness))) then idx = i return end if end if end do end function particle_set_reverse_find_particle @ %def particle_set_reverse_find_particle @ This connects broken links of the form $\text{something} \to i \to \text{none or} j$ and $\text{none} \to j \to \text{something or none}$ where the particles $i$ and $j$ are \emph{identical}. It also works if $i \to j$, directly, and thus removes duplicates. We are removing $j$ and connect the possible daughters to $i$. <>= procedure :: remove_duplicates => particle_set_remove_duplicates <>= subroutine particle_set_remove_duplicates (particle_set, smallness) class(particle_set_t), intent(inout) :: particle_set real(default), intent(in) :: smallness integer :: n_removals integer, dimension(particle_set%n_tot) :: to_remove type(particle_t), dimension(:), allocatable :: particles type(vector4_t) :: p_i integer, dimension(:), allocatable :: map to_remove = 0 call find_duplicates () n_removals = count (to_remove > 0) if (n_removals > 0) then call strip_duplicates (particles) call particle_set%replace (particles) end if contains <> end subroutine particle_set_remove_duplicates @ %def particle_set_remove_duplicates @ This doesn't catch all cases. Missing are splittings of the type $i \to \text{something and} j$. <>= subroutine find_duplicates () integer :: pdg_i, child_i, i, j OUTER: do i = 1, particle_set%n_tot if (particle_set%prt(i)%status == PRT_OUTGOING .or. & particle_set%prt(i)%status == PRT_VIRTUAL .or. & particle_set%prt(i)%status == PRT_RESONANT) then if (allocated (particle_set%prt(i)%child)) then if (size (particle_set%prt(i)%child) > 1) cycle OUTER if (size (particle_set%prt(i)%child) == 1) then child_i = particle_set%prt(i)%child(1) else child_i = 0 end if else child_i = 0 end if pdg_i = particle_set%prt(i)%flv%get_pdg () p_i = particle_set%prt(i)%p do j = i + 1, particle_set%n_tot if (pdg_i == particle_set%prt(j)%flv%get_pdg ()) then if (all (nearly_equal (particle_set%prt(j)%p%p, p_i%p, & abs_smallness = smallness, & rel_smallness = 1E4_default * smallness))) then if (child_i == 0 .or. j == child_i) then to_remove(j) = i if (debug_on) call msg_debug2 (D_PARTICLES, & "Particles: Will remove duplicate of i", i) if (debug_on) call msg_debug2 (D_PARTICLES, & "Particles: j", j) end if cycle OUTER end if end if end do end if end do OUTER end subroutine find_duplicates @ <>= recursive function get_alive_index (try) result (alive) integer :: alive integer :: try if (map(try) > 0) then alive = map(try) else alive = get_alive_index (to_remove(try)) end if end function get_alive_index @ <>= subroutine strip_duplicates (particles) type(particle_t), dimension(:), allocatable, intent(out) :: particles integer :: kept, removed, i, j integer, dimension(:), allocatable :: old_children logical, dimension(:), allocatable :: parent_set if (debug_on) call msg_debug (D_PARTICLES, "Particles: Removing duplicates") if (debug_on) call msg_debug (D_PARTICLES, "Particles: n_removals", n_removals) if (debug2_active (D_PARTICLES)) then call msg_debug2 (D_PARTICLES, "Particles: Given set before removing:") call particle_set%write (summary=.true., compressed=.true.) end if allocate (particles (particle_set%n_tot - n_removals)) allocate (map (particle_set%n_tot)) allocate (parent_set (particle_set%n_tot)) parent_set = .false. map = 0 j = 0 do i = 1, particle_set%n_tot if (to_remove(i) == 0) then j = j + 1 map(i) = j call particles(j)%init (particle_set%prt(i)) end if end do do i = 1, particle_set%n_tot if (map(i) /= 0) then if (.not. parent_set(map(i))) then call particles(map(i))%set_parents & (map (particle_set%prt(i)%get_parents ())) end if call particles(map(i))%set_children & (map (particle_set%prt(i)%get_children ())) else removed = i kept = to_remove(i) if (particle_set%prt(removed)%has_children ()) then old_children = particle_set%prt(removed)%get_children () do j = 1, size (old_children) if (map(old_children(j)) > 0) then call particles(map(old_children(j)))%set_parents & ([get_alive_index (kept)]) parent_set(map(old_children(j))) = .true. call particles(get_alive_index (kept))%add_child & (map(old_children(j))) end if end do particles(get_alive_index (kept))%status = PRT_RESONANT else particles(get_alive_index (kept))%status = PRT_OUTGOING end if end if end do end subroutine strip_duplicates @ Given a subevent, reset status codes. If the new status is beam, incoming, or outgoing, we also make sure that the stored $p^2$ value is equal to the on-shell mass squared. <>= procedure :: reset_status => particle_set_reset_status <>= subroutine particle_set_reset_status (particle_set, index, status) class(particle_set_t), intent(inout) :: particle_set integer, dimension(:), intent(in) :: index integer, intent(in) :: status integer :: i if (allocated (particle_set%prt)) then do i = 1, size (index) call particle_set%prt(index(i))%reset_status (status) end do end if particle_set%n_beam = & count (particle_set%prt%get_status () == PRT_BEAM) particle_set%n_in = & count (particle_set%prt%get_status () == PRT_INCOMING) particle_set%n_out = & count (particle_set%prt%get_status () == PRT_OUTGOING) particle_set%n_vir = particle_set%n_tot & - particle_set%n_beam - particle_set%n_in - particle_set%n_out end subroutine particle_set_reset_status @ %def particle_set_reset_status @ Reduce a particle set to the essential entries. The entries kept are those with status [[INCOMING]], [[OUTGOING]] or [[RESONANT]]. [[BEAM]] is kept if [[keep_beams]] is true. Other entries are skipped. The correlated state matrix, if any, is also ignored. <>= procedure :: reduce => particle_set_reduce <>= subroutine particle_set_reduce (pset_in, pset_out, keep_beams) class(particle_set_t), intent(in) :: pset_in type(particle_set_t), intent(out) :: pset_out logical, intent(in), optional :: keep_beams integer, dimension(:), allocatable :: status, map integer :: i, j logical :: kb kb = .false.; if (present (keep_beams)) kb = keep_beams allocate (status (pset_in%n_tot)) pset_out%factorization_mode = pset_in%factorization_mode status = pset_in%prt%get_status () if (kb) pset_out%n_beam = count (status == PRT_BEAM) pset_out%n_in = count (status == PRT_INCOMING) pset_out%n_vir = count (status == PRT_RESONANT) pset_out%n_out = count (status == PRT_OUTGOING) pset_out%n_tot = & pset_out%n_beam + pset_out%n_in + pset_out%n_vir + pset_out%n_out allocate (pset_out%prt (pset_out%n_tot)) allocate (map (pset_in%n_tot)) map = 0 j = 0 if (kb) call copy_particles (PRT_BEAM) call copy_particles (PRT_INCOMING) call copy_particles (PRT_RESONANT) call copy_particles (PRT_OUTGOING) do i = 1, pset_in%n_tot if (map(i) == 0) cycle call pset_out%prt(map(i))%set_parents & (pset_in%get_real_parents (i, kb)) call pset_out%prt(map(i))%set_parents & (map (pset_out%prt(map(i))%parent)) call pset_out%prt(map(i))%set_children & (pset_in%get_real_children (i, kb)) call pset_out%prt(map(i))%set_children & (map (pset_out%prt(map(i))%child)) end do contains subroutine copy_particles (stat) integer, intent(in) :: stat integer :: i do i = 1, pset_in%n_tot if (status(i) == stat) then j = j + 1 map(i) = j call particle_init_particle (pset_out%prt(j), pset_in%prt(i)) end if end do end subroutine copy_particles end subroutine particle_set_reduce @ %def particles_set_reduce @ Remove the beam particles and beam remnants from the particle set if the keep beams flag is false. If keep beams is not given, the beam particles and the beam remnants are removed. The correlated state matrix, if any, is also ignored. <>= procedure :: filter_particles => particle_set_filter_particles <>= subroutine particle_set_filter_particles & (pset_in, pset_out, keep_beams, real_parents, keep_virtuals) class(particle_set_t), intent(in) :: pset_in type(particle_set_t), intent(out) :: pset_out logical, intent(in), optional :: keep_beams, real_parents, keep_virtuals integer, dimension(:), allocatable :: status, map logical, dimension(:), allocatable :: filter integer :: i, j logical :: kb, rp, kv kb = .false.; if (present (keep_beams)) kb = keep_beams rp = .false.; if (present (real_parents)) rp = real_parents kv = .true.; if (present (keep_virtuals)) kv = keep_virtuals if (debug_on) call msg_debug (D_PARTICLES, "filter_particles") if (debug2_active (D_PARTICLES)) then print *, 'keep_beams = ', kb print *, 'real_parents = ', rp print *, 'keep_virtuals = ', kv print *, '>>> pset_in : ' call pset_in%write(compressed=.true.) end if call count_and_allocate() map = 0 j = 0 filter = .false. if (.not. kb) filter = status == PRT_BEAM .or. status == PRT_BEAM_REMNANT if (.not. kv) filter = filter .or. status == PRT_VIRTUAL call copy_particles () do i = 1, pset_in%n_tot if (map(i) == 0) cycle if (rp) then call pset_out%prt(map(i))%set_parents & (map (pset_in%get_real_parents (i, kb))) call pset_out%prt(map(i))%set_children & (map (pset_in%get_real_children (i, kb))) else call pset_out%prt(map(i))%set_parents & (map (pset_in%prt(i)%get_parents ())) call pset_out%prt(map(i))%set_children & (map (pset_in%prt(i)%get_children ())) end if end do if (debug2_active (D_PARTICLES)) then print *, '>>> pset_out : ' call pset_out%write(compressed=.true.) end if contains <> end subroutine particle_set_filter_particles @ %def particles_set_filter_particles <>= subroutine copy_particles () integer :: i do i = 1, pset_in%n_tot if (.not. filter(i)) then j = j + 1 map(i) = j call particle_init_particle (pset_out%prt(j), pset_in%prt(i)) end if end do end subroutine copy_particles <>= subroutine count_and_allocate allocate (status (pset_in%n_tot)) status = particle_get_status (pset_in%prt) if (kb) pset_out%n_beam = count (status == PRT_BEAM) pset_out%n_in = count (status == PRT_INCOMING) if (kb .and. kv) then pset_out%n_vir = count (status == PRT_VIRTUAL) + & count (status == PRT_RESONANT) + & count (status == PRT_BEAM_REMNANT) else if (kb .and. .not. kv) then pset_out%n_vir = count (status == PRT_RESONANT) + & count (status == PRT_BEAM_REMNANT) else if (.not. kb .and. kv) then pset_out%n_vir = count (status == PRT_VIRTUAL) + & count (status == PRT_RESONANT) else pset_out%n_vir = count (status == PRT_RESONANT) end if pset_out%n_out = count (status == PRT_OUTGOING) pset_out%n_tot = & pset_out%n_beam + pset_out%n_in + pset_out%n_vir + pset_out%n_out allocate (pset_out%prt (pset_out%n_tot)) allocate (map (pset_in%n_tot)) allocate (filter (pset_in%n_tot)) end subroutine count_and_allocate @ Transform a particle set into HEPEVT-compatible form. In this form, for each particle, the parents and the children are contiguous in the particle array. Usually, this requires to clone some particles. We do not know in advance how many particles the canonical form will have. To be on the safe side, allocate four times the original size. <>= procedure :: to_hepevt_form => particle_set_to_hepevt_form <>= subroutine particle_set_to_hepevt_form (pset_in, pset_out) class(particle_set_t), intent(in) :: pset_in type(particle_set_t), intent(out) :: pset_out type :: particle_entry_t integer :: src = 0 integer :: status = 0 integer :: orig = 0 integer :: copy = 0 end type particle_entry_t type(particle_entry_t), dimension(:), allocatable :: prt integer, dimension(:), allocatable :: map1, map2 integer, dimension(:), allocatable :: parent, child integer :: n_tot, n_parents, n_children, i, j, c, n n_tot = pset_in%n_tot allocate (prt (4 * n_tot)) allocate (map1(4 * n_tot)) allocate (map2(4 * n_tot)) map1 = 0 map2 = 0 allocate (child (n_tot)) allocate (parent (n_tot)) n = 0 do i = 1, n_tot if (pset_in%prt(i)%get_n_parents () == 0) then call append (i) end if end do do i = 1, n_tot n_children = pset_in%prt(i)%get_n_children () if (n_children > 0) then child(1:n_children) = pset_in%prt(i)%get_children () c = child(1) if (map1(c) == 0) then n_parents = pset_in%prt(c)%get_n_parents () if (n_parents > 1) then parent(1:n_parents) = pset_in%prt(c)%get_parents () if (i == parent(1) .and. & any( [(map1(i)+j-1, j=1,n_parents)] /= & map1(parent(1:n_parents)))) then do j = 1, n_parents call append (parent(j)) end do end if else if (map1(i) == 0) then call append (i) end if do j = 1, n_children call append (child(j)) end do end if else if (map1(i) == 0) then call append (i) end if end do do i = n, 1, -1 if (prt(i)%status /= PRT_OUTGOING) then do j = 1, i-1 if (prt(j)%status == PRT_OUTGOING) then call append(prt(j)%src) end if end do exit end if end do pset_out%n_beam = count (prt(1:n)%status == PRT_BEAM) pset_out%n_in = count (prt(1:n)%status == PRT_INCOMING) pset_out%n_vir = count (prt(1:n)%status == PRT_RESONANT) pset_out%n_out = count (prt(1:n)%status == PRT_OUTGOING) pset_out%n_tot = n allocate (pset_out%prt (n)) do i = 1, n call particle_init_particle (pset_out%prt(i), pset_in%prt(prt(i)%src)) call pset_out%prt(i)%reset_status (prt(i)%status) if (prt(i)%orig == 0) then call pset_out%prt(i)%set_parents & (map2 (pset_in%prt(prt(i)%src)%get_parents ())) else call pset_out%prt(i)%set_parents ([ prt(i)%orig ]) end if if (prt(i)%copy == 0) then call pset_out%prt(i)%set_children & (map1 (pset_in%prt(prt(i)%src)%get_children ())) else call pset_out%prt(i)%set_children ([ prt(i)%copy ]) end if end do contains subroutine append (i) integer, intent(in) :: i n = n + 1 if (n > size (prt)) & call msg_bug ("Particle set transform to HEPEVT: insufficient space") prt(n)%src = i prt(n)%status = pset_in%prt(i)%get_status () if (map1(i) == 0) then map1(i) = n else prt(map2(i))%status = PRT_VIRTUAL prt(map2(i))%copy = n prt(n)%orig = map2(i) end if map2(i) = n end subroutine append end subroutine particle_set_to_hepevt_form @ %def particle_set_to_hepevt_form @ This procedure aims at reconstructing the momenta of an interaction, given a particle set. Since the particle orderings <>= procedure :: fill_interaction => particle_set_fill_interaction <>= subroutine particle_set_fill_interaction & (pset, int, n_in, recover_beams, check_match, state_flv) class(particle_set_t), intent(in) :: pset type(interaction_t), intent(inout) :: int integer, intent(in) :: n_in logical, intent(in), optional :: recover_beams, check_match type(state_flv_content_t), intent(in), optional :: state_flv integer, dimension(:), allocatable :: map, pdg integer, dimension(:), allocatable :: i_in, i_out, p_in, p_out logical, dimension(:), allocatable :: i_set integer :: n_out, i, p logical :: r_beams, check r_beams = .false.; if (present (recover_beams)) r_beams = recover_beams check = .true.; if (present (check_match)) check = check_match if (check) then call find_hard_process_in_int (i_in, i_out) call find_hard_process_in_pset (p_in, p_out) n_out = size (i_out) if (size (i_in) /= n_in) call err_int_n_in if (size (p_in) /= n_in) call err_pset_n_in if (size (p_out) /= n_out) call err_pset_n_out call extract_hard_process_from_pset (pdg) call determine_map_for_hard_process (map, state_flv) if (.not. r_beams) then select case (n_in) case (1) call recover_parents (p_in(1), map) case (2) do i = 1, 2 call recover_parents (p_in(i), map) end do do p = 1, 2 call recover_radiation (p, map) end do end select end if else allocate (map (int%get_n_tot ())) map = [(i, i = 1, size (map))] r_beams = .false. end if allocate (i_set (int%get_n_tot ()), source = .false.) do p = 1, size (map) if (map(p) /= 0) then i_set(map(p)) = .true. call int%set_momentum & (pset%prt(p)%get_momentum (), map(p)) end if end do if (r_beams) then do i = 1, n_in call reconstruct_beam_and_radiation (i, i_set) end do end if if (any (.not. i_set)) call err_map contains subroutine find_hard_process_in_pset (p_in, p_out) integer, dimension(:), allocatable, intent(out) :: p_in, p_out integer, dimension(:), allocatable :: p_status, p_idx integer :: n_out_p integer :: i allocate (p_status (pset%n_tot), p_idx (pset%n_tot)) p_status = pset%prt%get_status () p_idx = [(i, i = 1, pset%n_tot)] allocate (p_in (n_in)) p_in = pack (p_idx, p_status == PRT_INCOMING) if (size (p_in) == 0) call err_pset_hard i = p_in(1) n_out_p = particle_get_n_children (pset%prt(i)) allocate (p_out (n_out_p)) p_out = particle_get_children (pset%prt(i)) end subroutine find_hard_process_in_pset subroutine find_hard_process_in_int (i_in, i_out) integer, dimension(:), allocatable, intent(out) :: i_in, i_out integer :: n_in_i integer :: i i = int%get_n_tot () n_in_i = interaction_get_n_parents (int, i) if (n_in_i /= n_in) call err_int_n_in allocate (i_in (n_in)) i_in = interaction_get_parents (int, i) i = i_in(1) n_out = interaction_get_n_children (int, i) allocate (i_out (n_out)) i_out = interaction_get_children (int, i) end subroutine find_hard_process_in_int subroutine extract_hard_process_from_pset (pdg) integer, dimension(:), allocatable, intent(out) :: pdg integer, dimension(:), allocatable :: pdg_p logical, dimension(:), allocatable :: mask_p integer :: i allocate (pdg_p (pset%n_tot)) pdg_p = pset%prt%get_pdg () allocate (mask_p (pset%n_tot), source = .false.) mask_p (p_in) = .true. mask_p (p_out) = .true. allocate (pdg (n_in + n_out)) pdg = pack (pdg_p, mask_p) end subroutine extract_hard_process_from_pset subroutine determine_map_for_hard_process (map, state_flv) integer, dimension(:), allocatable, intent(out) :: map type(state_flv_content_t), intent(in), optional :: state_flv integer, dimension(:), allocatable :: pdg_i, map_i integer :: n_tot logical, dimension(:), allocatable :: mask_i, mask_p logical :: success n_tot = int%get_n_tot () if (present (state_flv)) then allocate (mask_i (n_tot), source = .false.) mask_i (i_in) = .true. mask_i (i_out) = .true. allocate (pdg_i (n_tot), map_i (n_tot)) pdg_i = unpack (pdg, mask_i, 0) call state_flv%match (pdg_i, success, map_i) allocate (mask_p (pset%n_tot), source = .false.) mask_p (p_in) = .true. mask_p (p_out) = .true. allocate (map (size (mask_p)), & source = unpack (pack (map_i, mask_i), mask_p, 0)) if (.not. success) call err_mismatch else allocate (map (n_tot), source = 0) map(p_in) = i_in map(p_out) = i_out end if end subroutine determine_map_for_hard_process recursive subroutine recover_parents (p, map) integer, intent(in) :: p integer, dimension(:), intent(inout) :: map integer :: i, n, n_p, q, k integer, dimension(:), allocatable :: i_parents, p_parents integer, dimension(1) :: pp i = map(p) n = interaction_get_n_parents (int, i) q = p n_p = particle_get_n_parents (pset%prt(q)) do while (n_p == 1) pp = particle_get_parents (pset%prt(q)) if (pset%prt(pp(1))%get_n_children () > 1) exit q = pp(1) n_p = pset%prt(q)%get_n_parents () end do if (n_p /= n) call err_map allocate (i_parents (n), p_parents (n)) i_parents = interaction_get_parents (int, i) p_parents = pset%prt(q)%get_parents () do k = 1, n q = p_parents(k) if (map(q) == 0) then map(q) = i_parents(k) call recover_parents (q, map) end if end do end subroutine recover_parents recursive subroutine recover_radiation (p, map) integer, intent(in) :: p integer, dimension(:), intent(inout) :: map integer :: i, n, n_p, q, k integer, dimension(:), allocatable :: i_children, p_children if (particle_get_status (pset%prt(p)) == PRT_INCOMING) return i = map(p) n = interaction_get_n_children (int, i) n_p = pset%prt(p)%get_n_children () if (n_p /= n) call err_map allocate (i_children (n), p_children (n)) i_children = interaction_get_children (int, i) p_children = pset%prt(p)%get_children () do k = 1, n q = p_children(k) if (map(q) == 0) then i = i_children(k) if (interaction_get_n_children (int, i) == 0) then map(q) = i else select case (n) case (2) select case (k) case (1); map(q) = i_children(2) case (2); map(q) = i_children(1) end select case (4) select case (k) case (1); map(q) = i_children(3) case (2); map(q) = i_children(4) case (3); map(q) = i_children(1) case (4); map(q) = i_children(2) end select case default call err_radiation end select end if else call recover_radiation (q, map) end if end do end subroutine recover_radiation subroutine reconstruct_beam_and_radiation (k, i_set) integer, intent(in) :: k logical, dimension(:), intent(inout) :: i_set integer :: k_src, k_in, k_rad type(interaction_t), pointer :: int_src integer, dimension(2) :: i_child call int%find_source (k, int_src, k_src) - call int%set_momentum (int_src%get_momentum (k_src), k) - i_set(k) = .true. - if (n_in == 2) then - i_child = interaction_get_children (int, k) - if (interaction_get_n_children (int, i_child(1)) > 0) then - k_in = i_child(1); k_rad = i_child(2) - else - k_in = i_child(2); k_rad = i_child(1) - end if - if (.not. i_set(k_in)) call err_beams - call int%set_momentum & + if (.not. i_set (k)) then + call int%set_momentum (int_src%get_momentum (k_src), k) + i_set(k) = .true. + if (n_in == 2) then + i_child = interaction_get_children (int, k) + if (interaction_get_n_children (int, i_child(1)) > 0) then + k_in = i_child(1); k_rad = i_child(2) + else + k_in = i_child(2); k_rad = i_child(1) + end if + if (.not. i_set(k_in)) call err_beams + call int%set_momentum & (int%get_momentum (k) - int%get_momentum (k_in), k_rad) - i_set(k_rad) = .true. + i_set(k_rad) = .true. + end if end if end subroutine reconstruct_beam_and_radiation subroutine err_pset_hard call msg_fatal ("Reading particle set: no particles marked as incoming") end subroutine err_pset_hard subroutine err_int_n_in integer :: n if (allocated (i_in)) then n = size (i_in) else n = 0 end if write (msg_buffer, "(A,I0,A,I0)") & "Filling hard process from particle set: expect ", n_in, & " incoming particle(s), found ", n call msg_bug end subroutine err_int_n_in subroutine err_pset_n_in write (msg_buffer, "(A,I0,A,I0)") & "Reading hard-process particle set: should contain ", n_in, & " incoming particle(s), found ", size (p_in) call msg_fatal end subroutine err_pset_n_in subroutine err_pset_n_out write (msg_buffer, "(A,I0,A,I0)") & "Reading hard-process particle set: should contain ", n_out, & " outgoing particle(s), found ", size (p_out) call msg_fatal end subroutine err_pset_n_out subroutine err_mismatch call pset%write () call state_flv%write () call msg_fatal ("Reading particle set: Flavor combination " & // "does not match requested process") end subroutine err_mismatch subroutine err_map call pset%write () call int%basic_write () call msg_fatal ("Reading hard-process particle set: " & // "Incomplete mapping from particle set to interaction") end subroutine err_map subroutine err_beams call pset%write () call int%basic_write () call msg_fatal ("Reading particle set: Beam structure " & // "does not match requested process") end subroutine err_beams subroutine err_radiation call int%basic_write () call msg_bug ("Reading particle set: Interaction " & // "contains inconsistent radiation pattern.") end subroutine err_radiation end subroutine particle_set_fill_interaction @ %def particle_set_fill_interaction @ This procedure reconstructs an array of vertex indices from the parent-child information in the particle entries, according to the HepMC scheme. For each particle, we determine which vertex it comes from and which vertex it goes to. We return the two arrays and the maximum vertex index. For each particle in the list, we first check its parents. If for any parent the vertex where it goes to is already known, this vertex index is assigned as the current 'from' vertex. Otherwise, a new index is created, assigned as the current 'from' vertex, and as the 'to' vertex for all parents. Then, the analogous procedure is done for the children. Furthermore, we assign to each vertex the vertex position from the parent(s). We check that these vertex positions coincide, and if not return a null vector. <>= procedure :: assign_vertices => particle_set_assign_vertices <>= subroutine particle_set_assign_vertices & (particle_set, v_from, v_to, n_vertices) class(particle_set_t), intent(in) :: particle_set integer, dimension(:), intent(out) :: v_from, v_to integer, intent(out) :: n_vertices integer, dimension(:), allocatable :: parent, child integer :: n_parents, n_children, vf, vt integer :: i, j, v v_from = 0 v_to = 0 vf = 0 vt = 0 do i = 1, particle_set%n_tot n_parents = particle_set%prt(i)%get_n_parents () if (n_parents /= 0) then allocate (parent (n_parents)) parent = particle_set%prt(i)%get_parents () SCAN_PARENTS: do j = 1, size (parent) v = v_to(parent(j)) if (v /= 0) then v_from(i) = v; exit SCAN_PARENTS end if end do SCAN_PARENTS if (v_from(i) == 0) then vf = vf + 1; v_from(i) = vf v_to(parent) = vf end if deallocate (parent) end if n_children = particle_set%prt(i)%get_n_children () if (n_children /= 0) then allocate (child (n_children)) child = particle_set%prt(i)%get_children () SCAN_CHILDREN: do j = 1, size (child) v = v_from(child(j)) if (v /= 0) then v_to(i) = v; exit SCAN_CHILDREN end if end do SCAN_CHILDREN if (v_to(i) == 0) then vt = vt + 1; v_to(i) = vt v_from(child) = vt end if deallocate (child) end if end do n_vertices = max (vf, vt) end subroutine particle_set_assign_vertices @ %def particle_set_assign_vertices @ \subsection{Expression interface} This converts a [[particle_set]] object as defined here to a more concise [[subevt]] object that can be used as the event root of an expression. In particular, the latter lacks virtual particles, spin correlations and parent-child relations. We keep beam particles, incoming partons, and outgoing partons. Furthermore, we keep radiated particles (a.k.a.\ beam remnants) if they have no children in the current particle set, and mark them as outgoing particles. If [[colorize]] is set and true, mark all particles in the subevent as colorized, and set color/anticolor flow indices where they are defined. Colorless particles do not get indices but are still marked as colorized, for consistency. <>= procedure :: to_subevt => particle_set_to_subevt <>= subroutine particle_set_to_subevt (particle_set, subevt, colorize) class(particle_set_t), intent(in) :: particle_set type(subevt_t), intent(out) :: subevt logical, intent(in), optional :: colorize integer :: n_tot, n_beam, n_in, n_out, n_rad integer :: i, k, n_active integer, dimension(2) :: hel logical :: keep n_tot = particle_set_get_n_tot (particle_set) n_beam = particle_set_get_n_beam (particle_set) n_in = particle_set_get_n_in (particle_set) n_out = particle_set_get_n_out (particle_set) n_rad = particle_set_get_n_remnants (particle_set) call subevt_init (subevt, n_beam + n_rad + n_in + n_out) k = 0 do i = 1, n_tot associate (prt => particle_set%prt(i)) keep = .false. select case (particle_get_status (prt)) case (PRT_BEAM) k = k + 1 call subevt_set_beam (subevt, k, & particle_get_pdg (prt), & particle_get_momentum (prt), & particle_get_p2 (prt)) keep = .true. case (PRT_INCOMING) k = k + 1 call subevt_set_incoming (subevt, k, & particle_get_pdg (prt), & particle_get_momentum (prt), & particle_get_p2 (prt)) keep = .true. case (PRT_OUTGOING) k = k + 1 call subevt_set_outgoing (subevt, k, & particle_get_pdg (prt), & particle_get_momentum (prt), & particle_get_p2 (prt)) keep = .true. case (PRT_BEAM_REMNANT) if (particle_get_n_children (prt) == 0) then k = k + 1 call subevt_set_outgoing (subevt, k, & particle_get_pdg (prt), & particle_get_momentum (prt), & particle_get_p2 (prt)) keep = .true. end if end select if (keep) then if (prt%polarization == PRT_DEFINITE_HELICITY) then if (prt%hel%is_diagonal ()) then hel = prt%hel%to_pair () call subevt_polarize (subevt, k, hel(1)) end if end if end if if (present (colorize)) then if (colorize) then call subevt_colorize & (subevt, i, prt%col%get_col (), prt%col%get_acl ()) end if end if end associate n_active = k end do call subevt_reset (subevt, n_active) end subroutine particle_set_to_subevt @ %def particle_set_to_subevt @ This replaces the [[particle\_set\%prt array]] with a given array of particles <>= procedure :: replace => particle_set_replace <>= subroutine particle_set_replace (particle_set, newprt) class(particle_set_t), intent(inout) :: particle_set type(particle_t), intent(in), dimension(:), allocatable :: newprt if (allocated (particle_set%prt)) deallocate (particle_set%prt) allocate (particle_set%prt(size (newprt))) particle_set%prt = newprt particle_set%n_tot = size (newprt) particle_set%n_beam = count (particle_get_status (newprt) == PRT_BEAM) particle_set%n_in = count (particle_get_status (newprt) == PRT_INCOMING) particle_set%n_out = count (particle_get_status (newprt) == PRT_OUTGOING) particle_set%n_vir = particle_set%n_tot & - particle_set%n_beam - particle_set%n_in - particle_set%n_out end subroutine particle_set_replace @ %def particle_set_replace @ This routines orders the outgoing particles into clusters of colorless particles and such of particles ordered corresponding to the indices of the color lines. All outgoing particles in the ordered set appear as child of the corresponding outgoing particle in the unordered set, including colored beam remnants. We always start continue via the anti-color line, such that color flows within each Lund string system is always continued from the anticolor of one particle to the identical color index of another particle. <>= procedure :: order_color_lines => particle_set_order_color_lines <>= subroutine particle_set_order_color_lines (pset_out, pset_in) class(particle_set_t), intent(inout) :: pset_out type(particle_set_t), intent(in) :: pset_in integer :: i, n, n_col_rem n_col_rem = 0 do i = 1, pset_in%n_tot if (pset_in%prt(i)%get_status () == PRT_BEAM_REMNANT .and. & any (pset_in%prt(i)%get_color () /= 0)) then n_col_rem = n_col_rem + 1 end if end do pset_out%n_beam = pset_in%n_beam pset_out%n_in = pset_in%n_in pset_out%n_vir = pset_in%n_vir + pset_in%n_out + n_col_rem pset_out%n_out = pset_in%n_out pset_out%n_tot = pset_in%n_tot + pset_in%n_out + n_col_rem pset_out%correlated_state = pset_in%correlated_state pset_out%factorization_mode = pset_in%factorization_mode allocate (pset_out%prt (pset_out%n_tot)) do i = 1, pset_in%n_tot call pset_out%prt(i)%init (pset_in%prt(i)) call pset_out%prt(i)%set_children (pset_in%prt(i)%child) call pset_out%prt(i)%set_parents (pset_in%prt(i)%parent) end do n = pset_in%n_tot do i = 1, pset_in%n_tot if (pset_out%prt(i)%get_status () == PRT_OUTGOING .and. & all (pset_out%prt(i)%get_color () == 0) .and. & .not. pset_out%prt(i)%has_children ()) then n = n + 1 call pset_out%prt(n)%init (pset_out%prt(i)) call pset_out%prt(i)%reset_status (PRT_VIRTUAL) call pset_out%prt(i)%add_child (n) call pset_out%prt(i)%set_parents ([i]) end if end do if (n_col_rem > 0) then do i = 1, n_col_rem end do end if end subroutine particle_set_order_color_lines @ %def particle_set_order_color_lines @ Eliminate numerical noise <>= public :: pacify <>= interface pacify module procedure pacify_particle module procedure pacify_particle_set end interface pacify <>= subroutine pacify_particle (prt) class(particle_t), intent(inout) :: prt real(default) :: e e = epsilon (1._default) * energy (prt%p) call pacify (prt%p, 10 * e) call pacify (prt%p2, 1e4 * e) end subroutine pacify_particle subroutine pacify_particle_set (pset) class(particle_set_t), intent(inout) :: pset integer :: i do i = 1, pset%n_tot call pacify (pset%prt(i)) end do end subroutine pacify_particle_set @ %def pacify @ \subsection{Unit tests} Test module, followed by the corresponding implementation module. <<[[particles_ut.f90]]>>= <> module particles_ut use unit_tests use particles_uti <> <> contains <> end module particles_ut @ %def particles_ut @ <<[[particles_uti.f90]]>>= <> module particles_uti <> use io_units use numeric_utils use constants, only: one, tiny_07 use lorentz use flavors use colors use helicities use quantum_numbers use state_matrices use interactions use evaluators use model_data use subevents use particles <> <> contains <> <> end module particles_uti @ %def particles_ut @ API: driver for the unit tests below. <>= public :: particles_test <>= subroutine particles_test (u, results) integer, intent(in) :: u type(test_results_t), intent(inout) :: results <> end subroutine particles_test @ %def particles_test @ Check the basic setup of the [[particle_set_t]] type: Set up a chain of production and decay and factorize the result into particles. The process is $d\bar d \to Z \to q\bar q$. <>= call test (particles_1, "particles_1", & "check particle_set routines", & u, results) <>= public :: particles_1 <>= subroutine particles_1 (u) use os_interface integer, intent(in) :: u type(model_data_t), target :: model type(flavor_t), dimension(3) :: flv type(color_t), dimension(3) :: col type(helicity_t), dimension(3) :: hel type(quantum_numbers_t), dimension(3) :: qn type(vector4_t), dimension(3) :: p type(interaction_t), target :: int1, int2 type(quantum_numbers_mask_t) :: qn_mask_conn type(evaluator_t), target :: eval type(interaction_t) :: int type(particle_set_t) :: particle_set1, particle_set2 type(particle_set_t) :: particle_set3, particle_set4 type(subevt_t) :: subevt logical :: ok integer :: unit, iostat write (u, "(A)") "* Test output: Particles" write (u, "(A)") "* Purpose: test particle_set routines" write (u, "(A)") write (u, "(A)") "* Reading model file" call model%init_sm_test () write (u, "(A)") write (u, "(A)") "* Initializing production process" call int1%basic_init (2, 0, 1, set_relations=.true.) call flv%init ([1, -1, 23], model) call col%init_col_acl ([0, 0, 0], [0, 0, 0]) call hel(3)%init (1, 1) call qn%init (flv, col, hel) call int1%add_state (qn, value=(0.25_default, 0._default)) call hel(3)%init (1,-1) call qn%init (flv, col, hel) call int1%add_state (qn, value=(0._default, 0.25_default)) call hel(3)%init (-1, 1) call qn%init (flv, col, hel) call int1%add_state (qn, value=(0._default,-0.25_default)) call hel(3)%init (-1,-1) call qn%init (flv, col, hel) call int1%add_state (qn, value=(0.25_default, 0._default)) call hel(3)%init (0, 0) call qn%init (flv, col, hel) call int1%add_state (qn, value=(0.5_default, 0._default)) call int1%freeze () p(1) = vector4_moving (45._default, 45._default, 3) p(2) = vector4_moving (45._default,-45._default, 3) p(3) = p(1) + p(2) call int1%set_momenta (p) write (u, "(A)") write (u, "(A)") "* Setup decay process" call int2%basic_init (1, 0, 2, set_relations=.true.) call flv%init ([23, 1, -1], model) call col%init_col_acl ([0, 501, 0], [0, 0, 501]) call hel%init ([1, 1, 1], [1, 1, 1]) call qn%init (flv, col, hel) call int2%add_state (qn, value=(1._default, 0._default)) call hel%init ([1, 1, 1], [-1,-1,-1]) call qn%init (flv, col, hel) call int2%add_state (qn, value=(0._default, 0.1_default)) call hel%init ([-1,-1,-1], [1, 1, 1]) call qn%init (flv, col, hel) call int2%add_state (qn, value=(0._default,-0.1_default)) call hel%init ([-1,-1,-1], [-1,-1,-1]) call qn%init (flv, col, hel) call int2%add_state (qn, value=(1._default, 0._default)) call hel%init ([0, 1,-1], [0, 1,-1]) call qn%init (flv, col, hel) call int2%add_state (qn, value=(4._default, 0._default)) call hel%init ([0,-1, 1], [0, 1,-1]) call qn%init (flv, col, hel) call int2%add_state (qn, value=(2._default, 0._default)) call hel%init ([0, 1,-1], [0,-1, 1]) call qn%init (flv, col, hel) call int2%add_state (qn, value=(2._default, 0._default)) call hel%init ([0,-1, 1], [0,-1, 1]) call qn%init (flv, col, hel) call int2%add_state (qn, value=(4._default, 0._default)) call flv%init ([23, 2, -2], model) call hel%init ([0, 1,-1], [0, 1,-1]) call qn%init (flv, col, hel) call int2%add_state (qn, value=(0.5_default, 0._default)) call hel%init ([0,-1, 1], [0,-1, 1]) call qn%init (flv, col, hel) call int2%add_state (qn, value=(0.5_default, 0._default)) call int2%freeze () p(2) = vector4_moving (45._default, 45._default, 2) p(3) = vector4_moving (45._default,-45._default, 2) call int2%set_momenta (p) call int2%set_source_link (1, int1, 3) call int1%basic_write (u) call int2%basic_write (u) write (u, "(A)") write (u, "(A)") "* Concatenate production and decay" call eval%init_product (int1, int2, qn_mask_conn, & connections_are_resonant=.true.) call eval%receive_momenta () call eval%evaluate () call eval%write (u) write (u, "(A)") write (u, "(A)") "* Factorize as subevent (complete, polarized)" write (u, "(A)") int = eval%interaction_t call particle_set1%init & (ok, int, int, FM_FACTOR_HELICITY, & [0.2_default, 0.2_default], .false., .true.) call particle_set1%write (u) write (u, "(A)") write (u, "(A)") "* Factorize as subevent (in/out only, selected helicity)" write (u, "(A)") int = eval%interaction_t call particle_set2%init & (ok, int, int, FM_SELECT_HELICITY, & [0.9_default, 0.9_default], .false., .false.) call particle_set2%write (u) call particle_set2%final () write (u, "(A)") write (u, "(A)") "* Factorize as subevent (complete, selected helicity)" write (u, "(A)") int = eval%interaction_t call particle_set2%init & (ok, int, int, FM_SELECT_HELICITY, & [0.7_default, 0.7_default], .false., .true.) call particle_set2%write (u) write (u, "(A)") write (u, "(A)") & "* Factorize (complete, polarized, correlated); write and read again" write (u, "(A)") int = eval%interaction_t call particle_set3%init & (ok, int, int, FM_FACTOR_HELICITY, & [0.7_default, 0.7_default], .true., .true.) call particle_set3%write (u) unit = free_unit () open (unit, action="readwrite", form="unformatted", status="scratch") call particle_set3%write_raw (unit) rewind (unit) call particle_set4%read_raw (unit, iostat=iostat) call particle_set4%set_model (model) close (unit) write (u, "(A)") write (u, "(A)") "* Result from reading" write (u, "(A)") call particle_set4%write (u) write (u, "(A)") write (u, "(A)") "* Transform to a subevt object" write (u, "(A)") call particle_set4%to_subevt (subevt) call subevt_write (subevt, u) write (u, "(A)") write (u, "(A)") "* Cleanup" call particle_set1%final () call particle_set2%final () call particle_set3%final () call particle_set4%final () call eval%final () call int1%final () call int2%final () call model%final () write (u, "(A)") write (u, "(A)") "* Test output end: particles_1" end subroutine particles_1 @ %def particles_1 @ Reconstruct a hard interaction from a particle set. <>= call test (particles_2, "particles_2", & "reconstruct hard interaction", & u, results) <>= public :: particles_2 <>= subroutine particles_2 (u) integer, intent(in) :: u type(interaction_t) :: int type(state_flv_content_t) :: state_flv type(particle_set_t) :: pset type(flavor_t), dimension(:), allocatable :: flv type(quantum_numbers_t), dimension(:), allocatable :: qn integer :: i, j write (u, "(A)") "* Test output: Particles" write (u, "(A)") "* Purpose: reconstruct simple interaction" write (u, "(A)") write (u, "(A)") "* Set up a 2 -> 3 interaction" write (u, "(A)") " + incoming partons marked as virtual" write (u, "(A)") " + no quantum numbers" write (u, "(A)") call reset_interaction_counter () call int%basic_init (0, 2, 3) do i = 1, 2 do j = 3, 5 call int%relate (i, j) end do end do allocate (qn (5)) call int%add_state (qn) call int%freeze () call int%basic_write (u) write (u, "(A)") write (u, "(A)") "* Manually set up a flavor-content record" write (u, "(A)") call state_flv%init (1, & mask = [.false., .false., .true., .true., .true.]) call state_flv%set_entry (1, & pdg = [11, 12, 3, 4, 5], & map = [1, 2, 3, 4, 5]) call state_flv%write (u) write (u, "(A)") write (u, "(A)") "* Manually create a matching particle set" write (u, "(A)") pset%n_beam = 0 pset%n_in = 2 pset%n_vir = 0 pset%n_out = 3 pset%n_tot = 5 allocate (pset%prt (pset%n_tot)) do i = 1, 2 call pset%prt(i)%reset_status (PRT_INCOMING) call pset%prt(i)%set_children ([3,4,5]) end do do i = 3, 5 call pset%prt(i)%reset_status (PRT_OUTGOING) call pset%prt(i)%set_parents ([1,2]) end do call pset%prt(1)%set_momentum (vector4_at_rest (1._default)) call pset%prt(2)%set_momentum (vector4_at_rest (2._default)) call pset%prt(3)%set_momentum (vector4_at_rest (5._default)) call pset%prt(4)%set_momentum (vector4_at_rest (4._default)) call pset%prt(5)%set_momentum (vector4_at_rest (3._default)) allocate (flv (5)) call flv%init ([11,12,5,4,3]) do i = 1, 5 call pset%prt(i)%set_flavor (flv(i)) end do call pset%write (u) write (u, "(A)") write (u, "(A)") "* Fill interaction from particle set" write (u, "(A)") call pset%fill_interaction (int, 2, state_flv=state_flv) call int%basic_write (u) write (u, "(A)") write (u, "(A)") "* Cleanup" call int%final () call pset%final () write (u, "(A)") write (u, "(A)") "* Test output end: particles_2" end subroutine particles_2 @ %def particles_2 @ Reconstruct an interaction with beam structure, e.g., a hadronic interaction, from a particle set. <>= call test (particles_3, "particles_3", & "reconstruct interaction with beam structure", & u, results) <>= public :: particles_3 <>= subroutine particles_3 (u) integer, intent(in) :: u type(interaction_t) :: int type(state_flv_content_t) :: state_flv type(particle_set_t) :: pset type(quantum_numbers_t), dimension(:), allocatable :: qn integer :: i, j write (u, "(A)") "* Test output: Particles" write (u, "(A)") "* Purpose: reconstruct simple interaction" write (u, "(A)") write (u, "(A)") "* Set up a 2 -> 2 -> 3 interaction with radiation" write (u, "(A)") " + no quantum numbers" write (u, "(A)") call reset_interaction_counter () call int%basic_init (0, 6, 3) call int%relate (1, 3) call int%relate (1, 4) call int%relate (2, 5) call int%relate (2, 6) do i = 4, 6, 2 do j = 7, 9 call int%relate (i, j) end do end do allocate (qn (9)) call int%add_state (qn) call int%freeze () call int%basic_write (u) write (u, "(A)") write (u, "(A)") "* Manually set up a flavor-content record" write (u, "(A)") call state_flv%init (1, & mask = [.false., .false., .false., .false., .false., .false., & .true., .true., .true.]) call state_flv%set_entry (1, & pdg = [2011, 2012, 91, 11, 92, 12, 3, 4, 5], & map = [1, 2, 3, 4, 5, 6, 7, 8, 9]) call state_flv%write (u) write (u, "(A)") write (u, "(A)") "* Manually create a matching particle set" write (u, "(A)") call create_test_particle_set_1 (pset) call pset%write (u) write (u, "(A)") write (u, "(A)") "* Fill interaction from particle set" write (u, "(A)") call pset%fill_interaction (int, 2, state_flv=state_flv) call int%basic_write (u) write (u, "(A)") write (u, "(A)") "* Cleanup" call int%final () call pset%final () write (u, "(A)") write (u, "(A)") "* Test output end: particles_3" end subroutine particles_3 @ %def particles_3 @ <>= subroutine create_test_particle_set_1 (pset) type(particle_set_t), intent(out) :: pset type(flavor_t), dimension(:), allocatable :: flv integer :: i pset%n_beam = 2 pset%n_in = 2 pset%n_vir = 2 pset%n_out = 3 pset%n_tot = 9 allocate (pset%prt (pset%n_tot)) call pset%prt(1)%reset_status (PRT_BEAM) call pset%prt(2)%reset_status (PRT_BEAM) call pset%prt(3)%reset_status (PRT_INCOMING) call pset%prt(4)%reset_status (PRT_INCOMING) call pset%prt(5)%reset_status (PRT_BEAM_REMNANT) call pset%prt(6)%reset_status (PRT_BEAM_REMNANT) call pset%prt(7)%reset_status (PRT_OUTGOING) call pset%prt(8)%reset_status (PRT_OUTGOING) call pset%prt(9)%reset_status (PRT_OUTGOING) call pset%prt(1)%set_children ([3,5]) call pset%prt(2)%set_children ([4,6]) call pset%prt(3)%set_children ([7,8,9]) call pset%prt(4)%set_children ([7,8,9]) call pset%prt(3)%set_parents ([1]) call pset%prt(4)%set_parents ([2]) call pset%prt(5)%set_parents ([1]) call pset%prt(6)%set_parents ([2]) call pset%prt(7)%set_parents ([3,4]) call pset%prt(8)%set_parents ([3,4]) call pset%prt(9)%set_parents ([3,4]) call pset%prt(1)%set_momentum (vector4_at_rest (1._default)) call pset%prt(2)%set_momentum (vector4_at_rest (2._default)) call pset%prt(3)%set_momentum (vector4_at_rest (4._default)) call pset%prt(4)%set_momentum (vector4_at_rest (6._default)) call pset%prt(5)%set_momentum (vector4_at_rest (3._default)) call pset%prt(6)%set_momentum (vector4_at_rest (5._default)) call pset%prt(7)%set_momentum (vector4_at_rest (7._default)) call pset%prt(8)%set_momentum (vector4_at_rest (8._default)) call pset%prt(9)%set_momentum (vector4_at_rest (9._default)) allocate (flv (9)) call flv%init ([2011, 2012, 11, 12, 91, 92, 3, 4, 5]) do i = 1, 9 call pset%prt(i)%set_flavor (flv(i)) end do end subroutine create_test_particle_set_1 @ %def create_test_particle_set_1 @ Reconstruct an interaction with beam structure, e.g., a hadronic interaction, from a particle set that is missing the beam information. <>= call test (particles_4, "particles_4", & "reconstruct interaction with missing beams", & u, results) <>= public :: particles_4 <>= subroutine particles_4 (u) integer, intent(in) :: u type(interaction_t) :: int type(interaction_t), target :: int_beams type(state_flv_content_t) :: state_flv type(particle_set_t) :: pset type(flavor_t), dimension(:), allocatable :: flv type(quantum_numbers_t), dimension(:), allocatable :: qn integer :: i, j write (u, "(A)") "* Test output: Particles" write (u, "(A)") "* Purpose: reconstruct beams" write (u, "(A)") call reset_interaction_counter () write (u, "(A)") "* Set up an interaction that contains beams only" write (u, "(A)") call int_beams%basic_init (0, 0, 2) call int_beams%set_momentum (vector4_at_rest (1._default), 1) call int_beams%set_momentum (vector4_at_rest (2._default), 2) allocate (qn (2)) call int_beams%add_state (qn) call int_beams%freeze () call int_beams%basic_write (u) write (u, "(A)") write (u, "(A)") "* Set up a 2 -> 2 -> 3 interaction with radiation" write (u, "(A)") " + no quantum numbers" write (u, "(A)") call int%basic_init (0, 6, 3) call int%relate (1, 3) call int%relate (1, 4) call int%relate (2, 5) call int%relate (2, 6) do i = 4, 6, 2 do j = 7, 9 call int%relate (i, j) end do end do do i = 1, 2 call int%set_source_link (i, int_beams, i) end do deallocate (qn) allocate (qn (9)) call int%add_state (qn) call int%freeze () call int%basic_write (u) write (u, "(A)") write (u, "(A)") "* Manually set up a flavor-content record" write (u, "(A)") call state_flv%init (1, & mask = [.false., .false., .false., .false., .false., .false., & .true., .true., .true.]) call state_flv%set_entry (1, & pdg = [2011, 2012, 91, 11, 92, 12, 3, 4, 5], & map = [1, 2, 3, 4, 5, 6, 7, 8, 9]) call state_flv%write (u) write (u, "(A)") write (u, "(A)") "* Manually create a matching particle set" write (u, "(A)") pset%n_beam = 0 pset%n_in = 2 pset%n_vir = 0 pset%n_out = 3 pset%n_tot = 5 allocate (pset%prt (pset%n_tot)) call pset%prt(1)%reset_status (PRT_INCOMING) call pset%prt(2)%reset_status (PRT_INCOMING) call pset%prt(3)%reset_status (PRT_OUTGOING) call pset%prt(4)%reset_status (PRT_OUTGOING) call pset%prt(5)%reset_status (PRT_OUTGOING) call pset%prt(1)%set_children ([3,4,5]) call pset%prt(2)%set_children ([3,4,5]) call pset%prt(3)%set_parents ([1,2]) call pset%prt(4)%set_parents ([1,2]) call pset%prt(5)%set_parents ([1,2]) call pset%prt(1)%set_momentum (vector4_at_rest (6._default)) call pset%prt(2)%set_momentum (vector4_at_rest (6._default)) call pset%prt(3)%set_momentum (vector4_at_rest (3._default)) call pset%prt(4)%set_momentum (vector4_at_rest (4._default)) call pset%prt(5)%set_momentum (vector4_at_rest (5._default)) allocate (flv (5)) call flv%init ([11, 12, 3, 4, 5]) do i = 1, 5 call pset%prt(i)%set_flavor (flv(i)) end do call pset%write (u) write (u, "(A)") write (u, "(A)") "* Fill interaction from particle set" write (u, "(A)") call pset%fill_interaction (int, 2, state_flv=state_flv, & recover_beams = .true.) call int%basic_write (u) write (u, "(A)") write (u, "(A)") "* Cleanup" call int%final () call pset%final () write (u, "(A)") write (u, "(A)") "* Test output end: particles_4" end subroutine particles_4 @ %def particles_4 @ Reconstruct an interaction with beam structure and cloned particles (radiated particles repeated in the event record, to maintain some canonical ordering). <>= call test (particles_5, "particles_5", & "reconstruct interaction with beams and duplicate entries", & u, results) <>= public :: particles_5 <>= subroutine particles_5 (u) integer, intent(in) :: u type(interaction_t) :: int type(state_flv_content_t) :: state_flv type(particle_set_t) :: pset type(flavor_t), dimension(:), allocatable :: flv type(quantum_numbers_t), dimension(:), allocatable :: qn integer :: i, j write (u, "(A)") "* Test output: Particles" write (u, "(A)") "* Purpose: reconstruct event with duplicate entries" write (u, "(A)") write (u, "(A)") "* Set up a 2 -> 2 -> 3 interaction with radiation" write (u, "(A)") " + no quantum numbers" write (u, "(A)") call reset_interaction_counter () call int%basic_init (0, 6, 3) call int%relate (1, 3) call int%relate (1, 4) call int%relate (2, 5) call int%relate (2, 6) do i = 4, 6, 2 do j = 7, 9 call int%relate (i, j) end do end do allocate (qn (9)) call int%add_state (qn) call int%freeze () call int%basic_write (u) write (u, "(A)") write (u, "(A)") "* Manually set up a flavor-content record" write (u, "(A)") call state_flv%init (1, & mask = [.false., .false., .false., .false., .false., .false., & .true., .true., .true.]) call state_flv%set_entry (1, & pdg = [2011, 2012, 91, 11, 92, 12, 3, 4, 5], & map = [1, 2, 3, 4, 5, 6, 7, 8, 9]) call state_flv%write (u) write (u, "(A)") write (u, "(A)") "* Manually create a matching particle set" write (u, "(A)") pset%n_beam = 2 pset%n_in = 2 pset%n_vir = 4 pset%n_out = 5 pset%n_tot = 13 allocate (pset%prt (pset%n_tot)) call pset%prt(1)%reset_status (PRT_BEAM) call pset%prt(2)%reset_status (PRT_BEAM) call pset%prt(3)%reset_status (PRT_VIRTUAL) call pset%prt(4)%reset_status (PRT_VIRTUAL) call pset%prt(5)%reset_status (PRT_VIRTUAL) call pset%prt(6)%reset_status (PRT_VIRTUAL) call pset%prt(7)%reset_status (PRT_INCOMING) call pset%prt(8)%reset_status (PRT_INCOMING) call pset%prt( 9)%reset_status (PRT_OUTGOING) call pset%prt(10)%reset_status (PRT_OUTGOING) call pset%prt(11)%reset_status (PRT_OUTGOING) call pset%prt(12)%reset_status (PRT_OUTGOING) call pset%prt(13)%reset_status (PRT_OUTGOING) call pset%prt(1)%set_children ([3,4]) call pset%prt(2)%set_children ([5,6]) call pset%prt(3)%set_children ([ 7]) call pset%prt(4)%set_children ([ 9]) call pset%prt(5)%set_children ([ 8]) call pset%prt(6)%set_children ([10]) call pset%prt(7)%set_children ([11,12,13]) call pset%prt(8)%set_children ([11,12,13]) call pset%prt(3)%set_parents ([1]) call pset%prt(4)%set_parents ([1]) call pset%prt(5)%set_parents ([2]) call pset%prt(6)%set_parents ([2]) call pset%prt( 7)%set_parents ([3]) call pset%prt( 8)%set_parents ([5]) call pset%prt( 9)%set_parents ([4]) call pset%prt(10)%set_parents ([6]) call pset%prt(11)%set_parents ([7,8]) call pset%prt(12)%set_parents ([7,8]) call pset%prt(13)%set_parents ([7,8]) call pset%prt(1)%set_momentum (vector4_at_rest (1._default)) call pset%prt(2)%set_momentum (vector4_at_rest (2._default)) call pset%prt(3)%set_momentum (vector4_at_rest (4._default)) call pset%prt(4)%set_momentum (vector4_at_rest (3._default)) call pset%prt(5)%set_momentum (vector4_at_rest (6._default)) call pset%prt(6)%set_momentum (vector4_at_rest (5._default)) call pset%prt(7)%set_momentum (vector4_at_rest (4._default)) call pset%prt(8)%set_momentum (vector4_at_rest (6._default)) call pset%prt( 9)%set_momentum (vector4_at_rest (3._default)) call pset%prt(10)%set_momentum (vector4_at_rest (5._default)) call pset%prt(11)%set_momentum (vector4_at_rest (7._default)) call pset%prt(12)%set_momentum (vector4_at_rest (8._default)) call pset%prt(13)%set_momentum (vector4_at_rest (9._default)) allocate (flv (13)) call flv%init ([2011, 2012, 11, 91, 12, 92, 11, 12, 91, 92, 3, 4, 5]) do i = 1, 13 call pset%prt(i)%set_flavor (flv(i)) end do call pset%write (u) write (u, "(A)") write (u, "(A)") "* Fill interaction from particle set" write (u, "(A)") call pset%fill_interaction (int, 2, state_flv=state_flv) call int%basic_write (u) write (u, "(A)") write (u, "(A)") "* Cleanup" call int%final () call pset%final () write (u, "(A)") write (u, "(A)") "* Test output end: particles_5" end subroutine particles_5 @ %def particles_5 @ Reconstruct an interaction with pair spectrum, e.g., beamstrahlung from a particle set. <>= call test (particles_6, "particles_6", & "reconstruct interaction with pair spectrum", & u, results) <>= public :: particles_6 <>= subroutine particles_6 (u) integer, intent(in) :: u type(interaction_t) :: int type(state_flv_content_t) :: state_flv type(particle_set_t) :: pset type(flavor_t), dimension(:), allocatable :: flv type(quantum_numbers_t), dimension(:), allocatable :: qn integer :: i, j write (u, "(A)") "* Test output: Particles" write (u, "(A)") "* Purpose: reconstruct interaction with pair spectrum" write (u, "(A)") write (u, "(A)") "* Set up a 2 -> 2 -> 3 interaction with radiation" write (u, "(A)") " + no quantum numbers" write (u, "(A)") call reset_interaction_counter () call int%basic_init (0, 6, 3) do i = 1, 2 do j = 3, 6 call int%relate (i, j) end do end do do i = 5, 6 do j = 7, 9 call int%relate (i, j) end do end do allocate (qn (9)) call int%add_state (qn) call int%freeze () call int%basic_write (u) write (u, "(A)") write (u, "(A)") "* Manually set up a flavor-content record" write (u, "(A)") call state_flv%init (1, & mask = [.false., .false., .false., .false., .false., .false., & .true., .true., .true.]) call state_flv%set_entry (1, & pdg = [1011, 1012, 21, 22, 11, 12, 3, 4, 5], & map = [1, 2, 3, 4, 5, 6, 7, 8, 9]) call state_flv%write (u) write (u, "(A)") write (u, "(A)") "* Manually create a matching particle set" write (u, "(A)") pset%n_beam = 2 pset%n_in = 2 pset%n_vir = 2 pset%n_out = 3 pset%n_tot = 9 allocate (pset%prt (pset%n_tot)) call pset%prt(1)%reset_status (PRT_BEAM) call pset%prt(2)%reset_status (PRT_BEAM) call pset%prt(3)%reset_status (PRT_INCOMING) call pset%prt(4)%reset_status (PRT_INCOMING) call pset%prt(5)%reset_status (PRT_OUTGOING) call pset%prt(6)%reset_status (PRT_OUTGOING) call pset%prt(7)%reset_status (PRT_OUTGOING) call pset%prt(8)%reset_status (PRT_OUTGOING) call pset%prt(9)%reset_status (PRT_OUTGOING) call pset%prt(1)%set_children ([3,4,5,6]) call pset%prt(2)%set_children ([3,4,5,6]) call pset%prt(3)%set_children ([7,8,9]) call pset%prt(4)%set_children ([7,8,9]) call pset%prt(3)%set_parents ([1,2]) call pset%prt(4)%set_parents ([1,2]) call pset%prt(5)%set_parents ([1,2]) call pset%prt(6)%set_parents ([1,2]) call pset%prt(7)%set_parents ([3,4]) call pset%prt(8)%set_parents ([3,4]) call pset%prt(9)%set_parents ([3,4]) call pset%prt(1)%set_momentum (vector4_at_rest (1._default)) call pset%prt(2)%set_momentum (vector4_at_rest (2._default)) call pset%prt(3)%set_momentum (vector4_at_rest (5._default)) call pset%prt(4)%set_momentum (vector4_at_rest (6._default)) call pset%prt(5)%set_momentum (vector4_at_rest (3._default)) call pset%prt(6)%set_momentum (vector4_at_rest (4._default)) call pset%prt(7)%set_momentum (vector4_at_rest (7._default)) call pset%prt(8)%set_momentum (vector4_at_rest (8._default)) call pset%prt(9)%set_momentum (vector4_at_rest (9._default)) allocate (flv (9)) call flv%init ([1011, 1012, 11, 12, 21, 22, 3, 4, 5]) do i = 1, 9 call pset%prt(i)%set_flavor (flv(i)) end do call pset%write (u) write (u, "(A)") write (u, "(A)") "* Fill interaction from particle set" write (u, "(A)") call pset%fill_interaction (int, 2, state_flv=state_flv) call int%basic_write (u) write (u, "(A)") write (u, "(A)") "* Cleanup" call int%final () call pset%final () write (u, "(A)") write (u, "(A)") "* Test output end: particles_6" end subroutine particles_6 @ %def particles_6 @ Reconstruct a hard decay interaction from a shuffled particle set. <>= call test (particles_7, "particles_7", & "reconstruct decay interaction with reordering", & u, results) <>= public :: particles_7 <>= subroutine particles_7 (u) integer, intent(in) :: u type(interaction_t) :: int type(state_flv_content_t) :: state_flv type(particle_set_t) :: pset type(flavor_t), dimension(:), allocatable :: flv type(quantum_numbers_t), dimension(:), allocatable :: qn integer :: i, j write (u, "(A)") "* Test output: Particles" write (u, "(A)") "* Purpose: reconstruct decay interaction with reordering" write (u, "(A)") write (u, "(A)") "* Set up a 1 -> 3 interaction" write (u, "(A)") " + no quantum numbers" write (u, "(A)") call reset_interaction_counter () call int%basic_init (0, 1, 3) do j = 2, 4 call int%relate (1, j) end do allocate (qn (4)) call int%add_state (qn) call int%freeze () call int%basic_write (u) write (u, "(A)") write (u, "(A)") "* Manually set up a flavor-content record" write (u, "(A)") "* assumed interaction: 6 12 5 -11" write (u, "(A)") call state_flv%init (1, & mask = [.false., .true., .true., .true.]) call state_flv%set_entry (1, & pdg = [6, 5, -11, 12], & map = [1, 4, 2, 3]) call state_flv%write (u) write (u, "(A)") write (u, "(A)") "* Manually create a matching particle set" write (u, "(A)") pset%n_beam = 0 pset%n_in = 1 pset%n_vir = 0 pset%n_out = 3 pset%n_tot = 4 allocate (pset%prt (pset%n_tot)) do i = 1, 1 call pset%prt(i)%reset_status (PRT_INCOMING) call pset%prt(i)%set_children ([2,3,4]) end do do i = 2, 4 call pset%prt(i)%reset_status (PRT_OUTGOING) call pset%prt(i)%set_parents ([1]) end do call pset%prt(1)%set_momentum (vector4_at_rest (1._default)) call pset%prt(2)%set_momentum (vector4_at_rest (3._default)) call pset%prt(3)%set_momentum (vector4_at_rest (2._default)) call pset%prt(4)%set_momentum (vector4_at_rest (4._default)) allocate (flv (4)) call flv%init ([6,5,12,-11]) do i = 1, 4 call pset%prt(i)%set_flavor (flv(i)) end do call pset%write (u) write (u, "(A)") write (u, "(A)") "* Fill interaction from particle set" write (u, "(A)") call pset%fill_interaction (int, 1, state_flv=state_flv) call int%basic_write (u) write (u, "(A)") write (u, "(A)") "* Cleanup" call int%final () call pset%final () write (u, "(A)") write (u, "(A)") "* Test output end: particles_7" end subroutine particles_7 @ %def particles_7 @ <>= call test (particles_8, "particles_8", & "Test functions on particle sets", u, results) <>= public :: particles_8 <>= subroutine particles_8 (u) integer, intent(in) :: u type(particle_set_t) :: particle_set type(particle_t), dimension(:), allocatable :: particles integer, allocatable, dimension(:) :: children, parents integer :: n_particles, i write (u, "(A)") "* Test output: particles_8" write (u, "(A)") "* Purpose: Test functions on particle sets" write (u, "(A)") call create_test_particle_set_1 (particle_set) call particle_set%write (u) call assert_equal (u, particle_set%n_tot, 9) call assert_equal (u, particle_set%n_beam, 2) allocate (children (particle_set%prt(3)%get_n_children ())) children = particle_set%prt(3)%get_children() call assert_equal (u, particle_set%prt(children(1))%get_pdg (), 3) call assert_equal (u, size (particle_set%prt(1)%get_children ()), 2) call assert_equal (u, size (particle_set%prt(2)%get_children ()), 2) call particle_set%without_hadronic_remnants & (particles, n_particles, 3) call particle_set%replace (particles) write (u, "(A)") call particle_set%write (u) call assert_equal (u, n_particles, 7) call assert_equal (u, size(particles), 10) call assert_equal (u, particle_set%n_tot, 10) call assert_equal (u, particle_set%n_beam, 2) do i = 3, 4 if (allocated (children)) deallocate (children) allocate (children (particle_set%prt(i)%get_n_children ())) children = particle_set%prt(i)%get_children() call assert_equal (u, particle_set%prt(children(1))%get_pdg (), 3) call assert_equal (u, particle_set%prt(children(2))%get_pdg (), 4) call assert_equal (u, particle_set%prt(children(3))%get_pdg (), 5) end do do i = 5, 7 if (allocated (parents)) deallocate (parents) allocate (parents (particle_set%prt(i)%get_n_parents ())) parents = particle_set%prt(i)%get_parents() call assert_equal (u, particle_set%prt(parents(1))%get_pdg (), 11) call assert_equal (u, particle_set%prt(parents(2))%get_pdg (), 12) end do call assert_equal (u, size (particle_set%prt(1)%get_children ()), & 1, "get children of 1") call assert_equal (u, size (particle_set%prt(2)%get_children ()), & 1, "get children of 2") call assert_equal (u, particle_set%find_particle & (particle_set%prt(1)%get_pdg (), particle_set%prt(1)%p), & 1, "find 1st particle") call assert_equal (u, particle_set%find_particle & (particle_set%prt(2)%get_pdg (), particle_set%prt(2)%p * & (one + tiny_07), rel_smallness=1.0E-6_default), & 2, "find 2nd particle fuzzy") write (u, "(A)") write (u, "(A)") "* Test output end: particles_8" end subroutine particles_8 @ %def particles_8 @ Order color lines into Lund string systems, without colored beam remnants first. <>= call test (particles_9, "particles_9", & "order into Lund strings, uncolored beam remnants", & u, results) <>= public :: particles_9 <>= subroutine particles_9 (u) integer, intent(in) :: u write (u, "(A)") "* Test output: particles_9" write (u, "(A)") "* Purpose: Order into Lund strings, " write (u, "(A)") "* uncolored beam remnants" write (u, "(A)") end subroutine particles_9 @ %def particles_9 Index: trunk/share/tests/Makefile.am =================================================================== --- trunk/share/tests/Makefile.am (revision 8373) +++ trunk/share/tests/Makefile.am (revision 8374) @@ -1,1463 +1,1465 @@ ## Makefile.am -- Makefile for WHIZARD tests ## ## Process this file with automake to produce Makefile.in ## ######################################################################## # # Copyright (C) 1999-2019 by # Wolfgang Kilian # Thorsten Ohl # Juergen Reuter # with contributions from # cf. main AUTHORS file # # WHIZARD 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 2, or (at your option) # any later version. # # WHIZARD 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 this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # ######################################################################## EXTRA_DIST = \ $(TESTSUITE_MACROS) $(TESTSUITES_M4) $(TESTSUITES_SIN) \ $(TESTSUITE_TOOLS) \ $(REF_OUTPUT_FILES) \ cascades2_lexer_1.fds \ cascades2_1.fds \ cascades2_2.fds \ functional_tests/structure_2_inc.sin functional_tests/testproc_3.phs \ functional_tests/user_cuts.f90 \ functional_tests/susyhit.in \ functional_tests/ufo_5_test.slha \ ext_tests_nmssm/nmssm.slha TESTSUITE_MACROS = testsuite.m4 TESTSUITE_TOOLS = \ check-debug-output.py \ check-debug-output-hadro.py \ check-hepmc-weights.py \ compare-integrals.py \ compare-integrals-multi.py \ compare-methods.py \ compare-histograms.py REF_OUTPUT_FILES = \ extra_integration_results.dat \ $(REF_OUTPUT_FILES_BASE) $(REF_OUTPUT_FILES_DOUBLE) \ $(REF_OUTPUT_FILES_PREC) $(REF_OUTPUT_FILES_EXT) \ $(REF_OUTPUT_FILES_QUAD) REF_OUTPUT_FILES_BASE = \ unit_tests/ref-output/analysis_1.ref \ unit_tests/ref-output/pdg_arrays_1.ref \ unit_tests/ref-output/pdg_arrays_2.ref \ unit_tests/ref-output/pdg_arrays_3.ref \ unit_tests/ref-output/pdg_arrays_4.ref \ unit_tests/ref-output/pdg_arrays_5.ref \ unit_tests/ref-output/expressions_1.ref \ unit_tests/ref-output/expressions_2.ref \ unit_tests/ref-output/expressions_3.ref \ unit_tests/ref-output/expressions_4.ref \ unit_tests/ref-output/su_algebra_1.ref \ unit_tests/ref-output/su_algebra_2.ref \ unit_tests/ref-output/su_algebra_3.ref \ unit_tests/ref-output/su_algebra_4.ref \ unit_tests/ref-output/bloch_vectors_1.ref \ unit_tests/ref-output/bloch_vectors_2.ref \ unit_tests/ref-output/bloch_vectors_3.ref \ unit_tests/ref-output/bloch_vectors_4.ref \ unit_tests/ref-output/bloch_vectors_5.ref \ unit_tests/ref-output/bloch_vectors_6.ref \ unit_tests/ref-output/bloch_vectors_7.ref \ unit_tests/ref-output/polarization_1.ref \ unit_tests/ref-output/polarization_2.ref \ unit_tests/ref-output/beam_1.ref \ unit_tests/ref-output/beam_2.ref \ unit_tests/ref-output/beam_3.ref \ unit_tests/ref-output/md5_1.ref \ unit_tests/ref-output/cputime_1.ref \ unit_tests/ref-output/cputime_2.ref \ unit_tests/ref-output/lexer_1.ref \ unit_tests/ref-output/parse_1.ref \ unit_tests/ref-output/color_1.ref \ unit_tests/ref-output/color_2.ref \ unit_tests/ref-output/os_interface_1.ref \ unit_tests/ref-output/evaluator_1.ref \ unit_tests/ref-output/evaluator_2.ref \ unit_tests/ref-output/evaluator_3.ref \ unit_tests/ref-output/evaluator_4.ref \ unit_tests/ref-output/format_1.ref \ unit_tests/ref-output/sorting_1.ref \ unit_tests/ref-output/grids_1.ref \ unit_tests/ref-output/grids_2.ref \ unit_tests/ref-output/grids_3.ref \ unit_tests/ref-output/grids_4.ref \ unit_tests/ref-output/grids_5.ref \ unit_tests/ref-output/solver_1.ref \ unit_tests/ref-output/state_matrix_1.ref \ unit_tests/ref-output/state_matrix_2.ref \ unit_tests/ref-output/state_matrix_3.ref \ unit_tests/ref-output/state_matrix_4.ref \ unit_tests/ref-output/state_matrix_5.ref \ unit_tests/ref-output/state_matrix_6.ref \ unit_tests/ref-output/state_matrix_7.ref \ unit_tests/ref-output/interaction_1.ref \ unit_tests/ref-output/xml_1.ref \ unit_tests/ref-output/xml_2.ref \ unit_tests/ref-output/xml_3.ref \ unit_tests/ref-output/xml_4.ref \ unit_tests/ref-output/sm_qcd_1.ref \ unit_tests/ref-output/sm_physics_1.ref \ unit_tests/ref-output/sm_physics_2.ref \ unit_tests/ref-output/models_1.ref \ unit_tests/ref-output/models_2.ref \ unit_tests/ref-output/models_3.ref \ unit_tests/ref-output/models_4.ref \ unit_tests/ref-output/models_5.ref \ unit_tests/ref-output/models_6.ref \ unit_tests/ref-output/models_7.ref \ unit_tests/ref-output/models_8.ref \ unit_tests/ref-output/models_9.ref \ unit_tests/ref-output/models_10.ref \ unit_tests/ref-output/auto_components_1.ref \ unit_tests/ref-output/auto_components_2.ref \ unit_tests/ref-output/auto_components_3.ref \ unit_tests/ref-output/radiation_generator_1.ref \ unit_tests/ref-output/radiation_generator_2.ref \ unit_tests/ref-output/radiation_generator_3.ref \ unit_tests/ref-output/radiation_generator_4.ref \ unit_tests/ref-output/particles_1.ref \ unit_tests/ref-output/particles_2.ref \ unit_tests/ref-output/particles_3.ref \ unit_tests/ref-output/particles_4.ref \ unit_tests/ref-output/particles_5.ref \ unit_tests/ref-output/particles_6.ref \ unit_tests/ref-output/particles_7.ref \ unit_tests/ref-output/particles_8.ref \ unit_tests/ref-output/particles_9.ref \ unit_tests/ref-output/beam_structures_1.ref \ unit_tests/ref-output/beam_structures_2.ref \ unit_tests/ref-output/beam_structures_3.ref \ unit_tests/ref-output/beam_structures_4.ref \ unit_tests/ref-output/beam_structures_5.ref \ unit_tests/ref-output/beam_structures_6.ref \ unit_tests/ref-output/sf_aux_1.ref \ unit_tests/ref-output/sf_aux_2.ref \ unit_tests/ref-output/sf_aux_3.ref \ unit_tests/ref-output/sf_aux_4.ref \ unit_tests/ref-output/sf_mappings_1.ref \ unit_tests/ref-output/sf_mappings_2.ref \ unit_tests/ref-output/sf_mappings_3.ref \ unit_tests/ref-output/sf_mappings_4.ref \ unit_tests/ref-output/sf_mappings_5.ref \ unit_tests/ref-output/sf_mappings_6.ref \ unit_tests/ref-output/sf_mappings_7.ref \ unit_tests/ref-output/sf_mappings_8.ref \ unit_tests/ref-output/sf_mappings_9.ref \ unit_tests/ref-output/sf_mappings_10.ref \ unit_tests/ref-output/sf_mappings_11.ref \ unit_tests/ref-output/sf_mappings_12.ref \ unit_tests/ref-output/sf_mappings_13.ref \ unit_tests/ref-output/sf_mappings_14.ref \ unit_tests/ref-output/sf_mappings_15.ref \ unit_tests/ref-output/sf_mappings_16.ref \ unit_tests/ref-output/sf_base_1.ref \ unit_tests/ref-output/sf_base_2.ref \ unit_tests/ref-output/sf_base_3.ref \ unit_tests/ref-output/sf_base_4.ref \ unit_tests/ref-output/sf_base_5.ref \ unit_tests/ref-output/sf_base_6.ref \ unit_tests/ref-output/sf_base_7.ref \ unit_tests/ref-output/sf_base_8.ref \ unit_tests/ref-output/sf_base_9.ref \ unit_tests/ref-output/sf_base_10.ref \ unit_tests/ref-output/sf_base_11.ref \ unit_tests/ref-output/sf_base_12.ref \ unit_tests/ref-output/sf_base_13.ref \ unit_tests/ref-output/sf_base_14.ref \ unit_tests/ref-output/sf_pdf_builtin_1.ref \ unit_tests/ref-output/sf_pdf_builtin_2.ref \ unit_tests/ref-output/sf_pdf_builtin_3.ref \ unit_tests/ref-output/sf_lhapdf5_1.ref \ unit_tests/ref-output/sf_lhapdf5_2.ref \ unit_tests/ref-output/sf_lhapdf5_3.ref \ unit_tests/ref-output/sf_lhapdf6_1.ref \ unit_tests/ref-output/sf_lhapdf6_2.ref \ unit_tests/ref-output/sf_lhapdf6_3.ref \ unit_tests/ref-output/sf_isr_1.ref \ unit_tests/ref-output/sf_isr_2.ref \ unit_tests/ref-output/sf_isr_3.ref \ unit_tests/ref-output/sf_isr_4.ref \ unit_tests/ref-output/sf_isr_5.ref \ unit_tests/ref-output/sf_epa_1.ref \ unit_tests/ref-output/sf_epa_2.ref \ unit_tests/ref-output/sf_epa_3.ref \ unit_tests/ref-output/sf_epa_4.ref \ unit_tests/ref-output/sf_epa_5.ref \ unit_tests/ref-output/sf_ewa_1.ref \ unit_tests/ref-output/sf_ewa_2.ref \ unit_tests/ref-output/sf_ewa_3.ref \ unit_tests/ref-output/sf_ewa_4.ref \ unit_tests/ref-output/sf_ewa_5.ref \ unit_tests/ref-output/sf_circe1_1.ref \ unit_tests/ref-output/sf_circe1_2.ref \ unit_tests/ref-output/sf_circe1_3.ref \ unit_tests/ref-output/sf_circe2_1.ref \ unit_tests/ref-output/sf_circe2_2.ref \ unit_tests/ref-output/sf_circe2_3.ref \ unit_tests/ref-output/sf_gaussian_1.ref \ unit_tests/ref-output/sf_gaussian_2.ref \ unit_tests/ref-output/sf_beam_events_1.ref \ unit_tests/ref-output/sf_beam_events_2.ref \ unit_tests/ref-output/sf_beam_events_3.ref \ unit_tests/ref-output/sf_escan_1.ref \ unit_tests/ref-output/sf_escan_2.ref \ unit_tests/ref-output/phs_base_1.ref \ unit_tests/ref-output/phs_base_2.ref \ unit_tests/ref-output/phs_base_3.ref \ unit_tests/ref-output/phs_base_4.ref \ unit_tests/ref-output/phs_base_5.ref \ unit_tests/ref-output/phs_none_1.ref \ unit_tests/ref-output/phs_single_1.ref \ unit_tests/ref-output/phs_single_2.ref \ unit_tests/ref-output/phs_single_3.ref \ unit_tests/ref-output/phs_single_4.ref \ unit_tests/ref-output/phs_rambo_1.ref \ unit_tests/ref-output/phs_rambo_2.ref \ unit_tests/ref-output/phs_rambo_3.ref \ unit_tests/ref-output/phs_rambo_4.ref \ unit_tests/ref-output/resonances_1.ref \ unit_tests/ref-output/resonances_2.ref \ unit_tests/ref-output/resonances_3.ref \ unit_tests/ref-output/resonances_4.ref \ unit_tests/ref-output/resonances_5.ref \ unit_tests/ref-output/resonances_6.ref \ unit_tests/ref-output/resonances_7.ref \ unit_tests/ref-output/phs_tree_1.ref \ unit_tests/ref-output/phs_tree_2.ref \ unit_tests/ref-output/phs_forest_1.ref \ unit_tests/ref-output/phs_forest_2.ref \ unit_tests/ref-output/phs_wood_1.ref \ unit_tests/ref-output/phs_wood_2.ref \ unit_tests/ref-output/phs_wood_3.ref \ unit_tests/ref-output/phs_wood_4.ref \ unit_tests/ref-output/phs_wood_5.ref \ unit_tests/ref-output/phs_wood_6.ref \ unit_tests/ref-output/phs_wood_vis_1.ref \ unit_tests/ref-output/phs_fks_generator_1.ref \ unit_tests/ref-output/phs_fks_generator_2.ref \ unit_tests/ref-output/phs_fks_generator_3.ref \ unit_tests/ref-output/phs_fks_generator_4.ref \ unit_tests/ref-output/phs_fks_generator_5.ref \ unit_tests/ref-output/phs_fks_generator_6.ref \ unit_tests/ref-output/phs_fks_generator_7.ref \ unit_tests/ref-output/fks_regions_1.ref \ unit_tests/ref-output/fks_regions_2.ref \ unit_tests/ref-output/fks_regions_3.ref \ unit_tests/ref-output/fks_regions_4.ref \ unit_tests/ref-output/fks_regions_5.ref \ unit_tests/ref-output/fks_regions_6.ref \ unit_tests/ref-output/fks_regions_7.ref \ unit_tests/ref-output/fks_regions_8.ref \ unit_tests/ref-output/real_subtraction_1.ref \ unit_tests/ref-output/prc_recola_1.ref \ unit_tests/ref-output/prc_recola_2.ref \ unit_tests/ref-output/rng_base_1.ref \ unit_tests/ref-output/rng_base_2.ref \ unit_tests/ref-output/rng_tao_1.ref \ unit_tests/ref-output/rng_tao_2.ref \ unit_tests/ref-output/rng_stream_1.ref \ unit_tests/ref-output/rng_stream_2.ref \ unit_tests/ref-output/rng_stream_3.ref \ unit_tests/ref-output/selectors_1.ref \ unit_tests/ref-output/selectors_2.ref \ unit_tests/ref-output/vegas_1.ref \ unit_tests/ref-output/vegas_2.ref \ unit_tests/ref-output/vegas_3.ref \ unit_tests/ref-output/vegas_4.ref \ unit_tests/ref-output/vegas_5.ref \ unit_tests/ref-output/vegas_6.ref \ unit_tests/ref-output/vamp2_1.ref \ unit_tests/ref-output/vamp2_2.ref \ unit_tests/ref-output/vamp2_3.ref \ unit_tests/ref-output/vamp2_4.ref \ unit_tests/ref-output/vamp2_5.ref \ unit_tests/ref-output/mci_base_1.ref \ unit_tests/ref-output/mci_base_2.ref \ unit_tests/ref-output/mci_base_3.ref \ unit_tests/ref-output/mci_base_4.ref \ unit_tests/ref-output/mci_base_5.ref \ unit_tests/ref-output/mci_base_6.ref \ unit_tests/ref-output/mci_base_7.ref \ unit_tests/ref-output/mci_base_8.ref \ unit_tests/ref-output/mci_none_1.ref \ unit_tests/ref-output/mci_midpoint_1.ref \ unit_tests/ref-output/mci_midpoint_2.ref \ unit_tests/ref-output/mci_midpoint_3.ref \ unit_tests/ref-output/mci_midpoint_4.ref \ unit_tests/ref-output/mci_midpoint_5.ref \ unit_tests/ref-output/mci_midpoint_6.ref \ unit_tests/ref-output/mci_midpoint_7.ref \ unit_tests/ref-output/mci_vamp_1.ref \ unit_tests/ref-output/mci_vamp_2.ref \ unit_tests/ref-output/mci_vamp_3.ref \ unit_tests/ref-output/mci_vamp_4.ref \ unit_tests/ref-output/mci_vamp_5.ref \ unit_tests/ref-output/mci_vamp_6.ref \ unit_tests/ref-output/mci_vamp_7.ref \ unit_tests/ref-output/mci_vamp_8.ref \ unit_tests/ref-output/mci_vamp_9.ref \ unit_tests/ref-output/mci_vamp_10.ref \ unit_tests/ref-output/mci_vamp_11.ref \ unit_tests/ref-output/mci_vamp_12.ref \ unit_tests/ref-output/mci_vamp_13.ref \ unit_tests/ref-output/mci_vamp_14.ref \ unit_tests/ref-output/mci_vamp_15.ref \ unit_tests/ref-output/mci_vamp_16.ref \ unit_tests/ref-output/mci_vamp2_1.ref \ unit_tests/ref-output/mci_vamp2_2.ref \ unit_tests/ref-output/mci_vamp2_3.ref \ unit_tests/ref-output/integration_results_1.ref \ unit_tests/ref-output/integration_results_2.ref \ unit_tests/ref-output/integration_results_3.ref \ unit_tests/ref-output/integration_results_4.ref \ unit_tests/ref-output/integration_results_5.ref \ unit_tests/ref-output/prclib_interfaces_1.ref \ unit_tests/ref-output/prclib_interfaces_2.ref \ unit_tests/ref-output/prclib_interfaces_3.ref \ unit_tests/ref-output/prclib_interfaces_4.ref \ unit_tests/ref-output/prclib_interfaces_5.ref \ unit_tests/ref-output/prclib_interfaces_6.ref \ unit_tests/ref-output/prclib_interfaces_7.ref \ unit_tests/ref-output/particle_specifiers_1.ref \ unit_tests/ref-output/particle_specifiers_2.ref \ unit_tests/ref-output/process_libraries_1.ref \ unit_tests/ref-output/process_libraries_2.ref \ unit_tests/ref-output/process_libraries_3.ref \ unit_tests/ref-output/process_libraries_4.ref \ unit_tests/ref-output/process_libraries_5.ref \ unit_tests/ref-output/process_libraries_6.ref \ unit_tests/ref-output/process_libraries_7.ref \ unit_tests/ref-output/process_libraries_8.ref \ unit_tests/ref-output/prclib_stacks_1.ref \ unit_tests/ref-output/prclib_stacks_2.ref \ unit_tests/ref-output/slha_1.ref \ unit_tests/ref-output/slha_2.ref \ unit_tests/ref-output/prc_test_1.ref \ unit_tests/ref-output/prc_test_2.ref \ unit_tests/ref-output/prc_test_3.ref \ unit_tests/ref-output/prc_test_4.ref \ unit_tests/ref-output/prc_template_me_1.ref \ unit_tests/ref-output/prc_template_me_2.ref \ unit_tests/ref-output/prc_omega_1.ref \ unit_tests/ref-output/prc_omega_2.ref \ unit_tests/ref-output/prc_omega_3.ref \ unit_tests/ref-output/prc_omega_4.ref \ unit_tests/ref-output/prc_omega_5.ref \ unit_tests/ref-output/prc_omega_6.ref \ unit_tests/ref-output/prc_omega_diags_1.ref \ unit_tests/ref-output/parton_states_1.ref \ unit_tests/ref-output/subevt_expr_1.ref \ unit_tests/ref-output/subevt_expr_2.ref \ unit_tests/ref-output/processes_1.ref \ unit_tests/ref-output/processes_2.ref \ unit_tests/ref-output/processes_3.ref \ unit_tests/ref-output/processes_4.ref \ unit_tests/ref-output/processes_5.ref \ unit_tests/ref-output/processes_6.ref \ unit_tests/ref-output/processes_7.ref \ unit_tests/ref-output/processes_8.ref \ unit_tests/ref-output/processes_9.ref \ unit_tests/ref-output/processes_10.ref \ unit_tests/ref-output/processes_11.ref \ unit_tests/ref-output/processes_12.ref \ unit_tests/ref-output/processes_13.ref \ unit_tests/ref-output/processes_14.ref \ unit_tests/ref-output/processes_15.ref \ unit_tests/ref-output/processes_16.ref \ unit_tests/ref-output/processes_17.ref \ unit_tests/ref-output/processes_18.ref \ unit_tests/ref-output/processes_19.ref \ unit_tests/ref-output/process_stacks_1.ref \ unit_tests/ref-output/process_stacks_2.ref \ unit_tests/ref-output/process_stacks_3.ref \ unit_tests/ref-output/process_stacks_4.ref \ unit_tests/ref-output/cascades_1.ref \ unit_tests/ref-output/cascades_2.ref \ unit_tests/ref-output/cascades2_lexer_1.ref \ unit_tests/ref-output/cascades2_1.ref \ unit_tests/ref-output/cascades2_2.ref \ unit_tests/ref-output/event_transforms_1.ref \ unit_tests/ref-output/recoil_kinematics_1.ref \ unit_tests/ref-output/recoil_kinematics_2.ref \ unit_tests/ref-output/recoil_kinematics_3.ref \ unit_tests/ref-output/recoil_kinematics_4.ref \ unit_tests/ref-output/recoil_kinematics_5.ref \ unit_tests/ref-output/resonance_insertion_1.ref \ unit_tests/ref-output/resonance_insertion_2.ref \ unit_tests/ref-output/resonance_insertion_3.ref \ unit_tests/ref-output/resonance_insertion_4.ref \ unit_tests/ref-output/resonance_insertion_5.ref \ unit_tests/ref-output/resonance_insertion_6.ref \ unit_tests/ref-output/isr_handler_1.ref \ unit_tests/ref-output/isr_handler_2.ref \ unit_tests/ref-output/isr_handler_3.ref \ unit_tests/ref-output/epa_handler_1.ref \ unit_tests/ref-output/epa_handler_2.ref \ unit_tests/ref-output/epa_handler_3.ref \ unit_tests/ref-output/decays_1.ref \ unit_tests/ref-output/decays_2.ref \ unit_tests/ref-output/decays_3.ref \ unit_tests/ref-output/decays_4.ref \ unit_tests/ref-output/decays_5.ref \ unit_tests/ref-output/decays_6.ref \ unit_tests/ref-output/shower_1.ref \ unit_tests/ref-output/shower_2.ref \ unit_tests/ref-output/shower_base_1.ref \ unit_tests/ref-output/events_1.ref \ unit_tests/ref-output/events_2.ref \ unit_tests/ref-output/events_3.ref \ unit_tests/ref-output/events_4.ref \ unit_tests/ref-output/events_5.ref \ unit_tests/ref-output/events_6.ref \ unit_tests/ref-output/events_7.ref \ unit_tests/ref-output/hep_events_1.ref \ unit_tests/ref-output/eio_data_1.ref \ unit_tests/ref-output/eio_data_2.ref \ unit_tests/ref-output/eio_base_1.ref \ unit_tests/ref-output/eio_direct_1.ref \ unit_tests/ref-output/eio_raw_1.ref \ unit_tests/ref-output/eio_raw_2.ref \ unit_tests/ref-output/eio_checkpoints_1.ref \ unit_tests/ref-output/eio_lhef_1.ref \ unit_tests/ref-output/eio_lhef_2.ref \ unit_tests/ref-output/eio_lhef_3.ref \ unit_tests/ref-output/eio_lhef_4.ref \ unit_tests/ref-output/eio_lhef_5.ref \ unit_tests/ref-output/eio_lhef_6.ref \ unit_tests/ref-output/eio_stdhep_1.ref \ unit_tests/ref-output/eio_stdhep_2.ref \ unit_tests/ref-output/eio_stdhep_3.ref \ unit_tests/ref-output/eio_stdhep_4.ref \ unit_tests/ref-output/eio_hepmc2_1.ref \ unit_tests/ref-output/eio_hepmc2_2.ref \ unit_tests/ref-output/eio_hepmc3_1.ref \ unit_tests/ref-output/eio_hepmc3_2.ref \ unit_tests/ref-output/eio_lcio_1.ref \ unit_tests/ref-output/eio_lcio_2.ref \ unit_tests/ref-output/eio_ascii_1.ref \ unit_tests/ref-output/eio_ascii_2.ref \ unit_tests/ref-output/eio_ascii_3.ref \ unit_tests/ref-output/eio_ascii_4.ref \ unit_tests/ref-output/eio_ascii_5.ref \ unit_tests/ref-output/eio_ascii_6.ref \ unit_tests/ref-output/eio_ascii_7.ref \ unit_tests/ref-output/eio_ascii_8.ref \ unit_tests/ref-output/eio_ascii_9.ref \ unit_tests/ref-output/eio_ascii_10.ref \ unit_tests/ref-output/eio_ascii_11.ref \ unit_tests/ref-output/eio_weights_1.ref \ unit_tests/ref-output/eio_weights_2.ref \ unit_tests/ref-output/eio_weights_3.ref \ unit_tests/ref-output/eio_dump_1.ref \ unit_tests/ref-output/iterations_1.ref \ unit_tests/ref-output/iterations_2.ref \ unit_tests/ref-output/rt_data_1.ref \ unit_tests/ref-output/rt_data_2.ref \ unit_tests/ref-output/rt_data_3.ref \ unit_tests/ref-output/rt_data_4.ref \ unit_tests/ref-output/rt_data_5.ref \ unit_tests/ref-output/rt_data_6.ref \ unit_tests/ref-output/rt_data_7.ref \ unit_tests/ref-output/rt_data_8.ref \ unit_tests/ref-output/rt_data_9.ref \ unit_tests/ref-output/rt_data_10.ref \ unit_tests/ref-output/rt_data_11.ref \ unit_tests/ref-output/dispatch_1.ref \ unit_tests/ref-output/dispatch_2.ref \ unit_tests/ref-output/dispatch_7.ref \ unit_tests/ref-output/dispatch_8.ref \ unit_tests/ref-output/dispatch_10.ref \ unit_tests/ref-output/dispatch_11.ref \ unit_tests/ref-output/dispatch_rng_1.ref \ unit_tests/ref-output/dispatch_phs_1.ref \ unit_tests/ref-output/dispatch_phs_2.ref \ unit_tests/ref-output/dispatch_mci_1.ref \ unit_tests/ref-output/dispatch_transforms_1.ref \ unit_tests/ref-output/dispatch_transforms_2.ref \ unit_tests/ref-output/process_configurations_1.ref \ unit_tests/ref-output/process_configurations_2.ref \ unit_tests/ref-output/event_streams_1.ref \ unit_tests/ref-output/event_streams_2.ref \ unit_tests/ref-output/event_streams_3.ref \ unit_tests/ref-output/event_streams_4.ref \ unit_tests/ref-output/compilations_1.ref \ unit_tests/ref-output/compilations_2.ref \ unit_tests/ref-output/compilations_3.ref \ unit_tests/ref-output/compilations_static_1.ref \ unit_tests/ref-output/compilations_static_2.ref \ unit_tests/ref-output/integrations_1.ref \ unit_tests/ref-output/integrations_2.ref \ unit_tests/ref-output/integrations_3.ref \ unit_tests/ref-output/integrations_4.ref \ unit_tests/ref-output/integrations_5.ref \ unit_tests/ref-output/integrations_6.ref \ unit_tests/ref-output/integrations_7.ref \ unit_tests/ref-output/integrations_8.ref \ unit_tests/ref-output/integrations_9.ref \ unit_tests/ref-output/integrations_history_1.ref \ unit_tests/ref-output/restricted_subprocesses_1.ref \ unit_tests/ref-output/restricted_subprocesses_2.ref \ unit_tests/ref-output/restricted_subprocesses_3.ref \ unit_tests/ref-output/restricted_subprocesses_4.ref \ unit_tests/ref-output/restricted_subprocesses_5.ref \ unit_tests/ref-output/restricted_subprocesses_6.ref \ unit_tests/ref-output/simulations_1.ref \ unit_tests/ref-output/simulations_2.ref \ unit_tests/ref-output/simulations_3.ref \ unit_tests/ref-output/simulations_4.ref \ unit_tests/ref-output/simulations_5.ref \ unit_tests/ref-output/simulations_6.ref \ unit_tests/ref-output/simulations_7.ref \ unit_tests/ref-output/simulations_8.ref \ unit_tests/ref-output/simulations_9.ref \ unit_tests/ref-output/simulations_10.ref \ unit_tests/ref-output/simulations_11.ref \ unit_tests/ref-output/simulations_12.ref \ unit_tests/ref-output/simulations_13.ref \ unit_tests/ref-output/simulations_14.ref \ unit_tests/ref-output/simulations_15.ref \ unit_tests/ref-output/commands_1.ref \ unit_tests/ref-output/commands_2.ref \ unit_tests/ref-output/commands_3.ref \ unit_tests/ref-output/commands_4.ref \ unit_tests/ref-output/commands_5.ref \ unit_tests/ref-output/commands_6.ref \ unit_tests/ref-output/commands_7.ref \ unit_tests/ref-output/commands_8.ref \ unit_tests/ref-output/commands_9.ref \ unit_tests/ref-output/commands_10.ref \ unit_tests/ref-output/commands_11.ref \ unit_tests/ref-output/commands_12.ref \ unit_tests/ref-output/commands_13.ref \ unit_tests/ref-output/commands_14.ref \ unit_tests/ref-output/commands_15.ref \ unit_tests/ref-output/commands_16.ref \ unit_tests/ref-output/commands_17.ref \ unit_tests/ref-output/commands_18.ref \ unit_tests/ref-output/commands_19.ref \ unit_tests/ref-output/commands_20.ref \ unit_tests/ref-output/commands_21.ref \ unit_tests/ref-output/commands_22.ref \ unit_tests/ref-output/commands_23.ref \ unit_tests/ref-output/commands_24.ref \ unit_tests/ref-output/commands_25.ref \ unit_tests/ref-output/commands_26.ref \ unit_tests/ref-output/commands_27.ref \ unit_tests/ref-output/commands_28.ref \ unit_tests/ref-output/commands_29.ref \ unit_tests/ref-output/commands_30.ref \ unit_tests/ref-output/commands_31.ref \ unit_tests/ref-output/commands_32.ref \ unit_tests/ref-output/commands_33.ref \ unit_tests/ref-output/commands_34.ref \ unit_tests/ref-output/jets_1.ref \ unit_tests/ref-output/hepmc2_interface_1.ref \ unit_tests/ref-output/hepmc3_interface_1.ref \ unit_tests/ref-output/lcio_interface_1.ref \ unit_tests/ref-output/ttv_formfactors_1.ref \ unit_tests/ref-output/ttv_formfactors_2.ref \ unit_tests/ref-output/blha_1.ref \ unit_tests/ref-output/blha_2.ref \ unit_tests/ref-output/blha_3.ref \ unit_tests/ref-output/whizard_lha_1.ref \ functional_tests/ref-output/pack_1.ref \ functional_tests/ref-output/structure_1.ref \ functional_tests/ref-output/structure_2.ref \ functional_tests/ref-output/structure_3.ref \ functional_tests/ref-output/structure_4.ref \ functional_tests/ref-output/structure_5.ref \ functional_tests/ref-output/structure_6.ref \ functional_tests/ref-output/structure_7.ref \ functional_tests/ref-output/structure_8.ref \ functional_tests/ref-output/vars.ref \ functional_tests/ref-output/extpar.ref \ functional_tests/ref-output/testproc_1.ref \ functional_tests/ref-output/testproc_2.ref \ functional_tests/ref-output/testproc_3.ref \ functional_tests/ref-output/testproc_4.ref \ functional_tests/ref-output/testproc_5.ref \ functional_tests/ref-output/testproc_6.ref \ functional_tests/ref-output/testproc_7.ref \ functional_tests/ref-output/testproc_8.ref \ functional_tests/ref-output/testproc_9.ref \ functional_tests/ref-output/testproc_10.ref \ functional_tests/ref-output/testproc_11.ref \ functional_tests/ref-output/testproc_12.ref \ functional_tests/ref-output/template_me_1.ref \ functional_tests/ref-output/template_me_2.ref \ functional_tests/ref-output/susyhit.ref \ functional_tests/ref-output/restrictions.ref \ functional_tests/ref-output/process_log.ref \ functional_tests/ref-output/static_1.ref \ functional_tests/ref-output/static_2.ref \ functional_tests/ref-output/libraries_1.ref \ functional_tests/ref-output/libraries_2.ref \ functional_tests/ref-output/libraries_4.ref \ functional_tests/ref-output/job_id_1.ref \ functional_tests/ref-output/job_id_2.ref \ functional_tests/ref-output/job_id_3.ref \ functional_tests/ref-output/job_id_4.ref \ functional_tests/ref-output/rebuild_2.ref \ functional_tests/ref-output/rebuild_3.ref \ functional_tests/ref-output/rebuild_4.ref \ functional_tests/ref-output/fatal.ref \ functional_tests/ref-output/cmdline_1.ref \ functional_tests/ref-output/model_change_1.ref \ functional_tests/ref-output/model_change_2.ref \ functional_tests/ref-output/model_change_3.ref \ functional_tests/ref-output/model_scheme_1.ref \ functional_tests/ref-output/model_test.ref \ functional_tests/ref-output/cuts.ref \ functional_tests/ref-output/user_cuts.ref \ functional_tests/ref-output/user_prc_threshold_1.ref \ functional_tests/ref-output/user_prc_threshold_2.ref \ functional_tests/ref-output/qedtest_1.ref \ functional_tests/ref-output/qedtest_2.ref \ functional_tests/ref-output/qedtest_5.ref \ functional_tests/ref-output/qedtest_6.ref \ functional_tests/ref-output/qedtest_7.ref \ functional_tests/ref-output/qedtest_8.ref \ functional_tests/ref-output/qedtest_9.ref \ functional_tests/ref-output/qedtest_10.ref \ functional_tests/ref-output/qcdtest_4.ref \ functional_tests/ref-output/qcdtest_5.ref \ functional_tests/ref-output/qcdtest_6.ref \ functional_tests/ref-output/rambo_vamp_1.ref \ functional_tests/ref-output/rambo_vamp_2.ref \ functional_tests/ref-output/beam_setup_1.ref \ functional_tests/ref-output/beam_setup_2.ref \ functional_tests/ref-output/beam_setup_3.ref \ functional_tests/ref-output/beam_setup_4.ref \ functional_tests/ref-output/observables_1.ref \ functional_tests/ref-output/event_weights_1.ref \ functional_tests/ref-output/event_weights_2.ref \ functional_tests/ref-output/event_eff_1.ref \ functional_tests/ref-output/event_eff_2.ref \ functional_tests/ref-output/event_dump_1.ref \ functional_tests/ref-output/event_dump_2.ref \ functional_tests/ref-output/reweight_1.ref \ functional_tests/ref-output/reweight_2.ref \ functional_tests/ref-output/reweight_3.ref \ functional_tests/ref-output/reweight_4.ref \ functional_tests/ref-output/reweight_5.ref \ functional_tests/ref-output/reweight_6.ref \ functional_tests/ref-output/reweight_7.ref \ functional_tests/ref-output/reweight_8.ref \ + functional_tests/ref-output/reweight_9.ref \ functional_tests/ref-output/analyze_1.ref \ functional_tests/ref-output/analyze_2.ref \ functional_tests/ref-output/analyze_3.ref \ functional_tests/ref-output/analyze_4.ref \ functional_tests/ref-output/analyze_5.ref \ functional_tests/ref-output/analyze_6.ref \ functional_tests/ref-output/bjet_cluster.ref \ functional_tests/ref-output/colors.ref \ functional_tests/ref-output/colors_hgg.ref \ functional_tests/ref-output/alphas.ref \ functional_tests/ref-output/jets_xsec.ref \ functional_tests/ref-output/shower_err_1.ref \ functional_tests/ref-output/parton_shower_1.ref \ functional_tests/ref-output/pythia6_1.ref \ functional_tests/ref-output/pythia6_2.ref \ functional_tests/ref-output/hadronize_1.ref \ functional_tests/ref-output/mlm_matching_fsr.ref \ functional_tests/ref-output/mlm_pythia6_isr.ref \ functional_tests/ref-output/hepmc_1.ref \ functional_tests/ref-output/hepmc_2.ref \ functional_tests/ref-output/hepmc_3.ref \ functional_tests/ref-output/hepmc_4.ref \ functional_tests/ref-output/hepmc_5.ref \ functional_tests/ref-output/hepmc_6.ref \ functional_tests/ref-output/hepmc_7.ref \ functional_tests/ref-output/hepmc_9.ref \ functional_tests/ref-output/hepmc_10.ref \ functional_tests/ref-output/lhef_1.ref \ functional_tests/ref-output/lhef_2.ref \ functional_tests/ref-output/lhef_3.ref \ functional_tests/ref-output/lhef_4.ref \ functional_tests/ref-output/lhef_5.ref \ functional_tests/ref-output/lhef_6.ref \ functional_tests/ref-output/lhef_9.ref \ functional_tests/ref-output/lhef_10.ref \ functional_tests/ref-output/lhef_11.ref \ functional_tests/ref-output/select_1.ref \ functional_tests/ref-output/select_2.ref \ functional_tests/ref-output/stdhep_1.ref \ functional_tests/ref-output/stdhep_2.ref \ functional_tests/ref-output/stdhep_3.ref \ functional_tests/ref-output/stdhep_4.ref \ functional_tests/ref-output/stdhep_5.ref \ functional_tests/ref-output/stdhep_6.ref \ functional_tests/ref-output/lcio_1.ref \ functional_tests/ref-output/lcio_3.ref \ functional_tests/ref-output/lcio_4.ref \ functional_tests/ref-output/lcio_5.ref \ functional_tests/ref-output/lcio_6.ref \ functional_tests/ref-output/lcio_8.ref \ functional_tests/ref-output/lcio_9.ref \ functional_tests/ref-output/lcio_10.ref \ functional_tests/ref-output/fatal_beam_decay.ref \ functional_tests/ref-output/smtest_1.ref \ functional_tests/ref-output/smtest_3.ref \ functional_tests/ref-output/smtest_4.ref \ functional_tests/ref-output/smtest_5.ref \ functional_tests/ref-output/smtest_6.ref \ functional_tests/ref-output/smtest_7.ref \ functional_tests/ref-output/smtest_9.ref \ functional_tests/ref-output/smtest_10.ref \ functional_tests/ref-output/smtest_11.ref \ functional_tests/ref-output/smtest_12.ref \ functional_tests/ref-output/smtest_13.ref \ functional_tests/ref-output/smtest_14.ref \ functional_tests/ref-output/smtest_15.ref \ functional_tests/ref-output/smtest_16.ref \ functional_tests/ref-output/photon_isolation_1.ref \ functional_tests/ref-output/photon_isolation_2.ref \ functional_tests/ref-output/sm_cms_1.ref \ functional_tests/ref-output/resonances_5.ref \ functional_tests/ref-output/resonances_6.ref \ functional_tests/ref-output/resonances_7.ref \ functional_tests/ref-output/resonances_8.ref \ functional_tests/ref-output/resonances_9.ref \ functional_tests/ref-output/resonances_12.ref \ functional_tests/ref-output/ufo_1.ref \ functional_tests/ref-output/ufo_2.ref \ functional_tests/ref-output/ufo_3.ref \ functional_tests/ref-output/ufo_4.ref \ functional_tests/ref-output/ufo_5.ref \ functional_tests/ref-output/nlo_1.ref \ functional_tests/ref-output/nlo_2.ref \ functional_tests/ref-output/nlo_6.ref \ functional_tests/ref-output/real_partition_1.ref \ functional_tests/ref-output/fks_res_2.ref \ functional_tests/ref-output/openloops_1.ref \ functional_tests/ref-output/openloops_2.ref \ functional_tests/ref-output/openloops_4.ref \ functional_tests/ref-output/openloops_5.ref \ functional_tests/ref-output/openloops_6.ref \ functional_tests/ref-output/openloops_7.ref \ functional_tests/ref-output/openloops_8.ref \ functional_tests/ref-output/openloops_9.ref \ functional_tests/ref-output/openloops_10.ref \ functional_tests/ref-output/openloops_11.ref \ functional_tests/ref-output/openloops_12.ref \ functional_tests/ref-output/openloops_13.ref \ functional_tests/ref-output/recola_1.ref \ functional_tests/ref-output/recola_2.ref \ functional_tests/ref-output/recola_3.ref \ functional_tests/ref-output/recola_4.ref \ functional_tests/ref-output/recola_5.ref \ functional_tests/ref-output/recola_6.ref \ functional_tests/ref-output/recola_7.ref \ functional_tests/ref-output/recola_8.ref \ functional_tests/ref-output/recola_9.ref \ functional_tests/ref-output/nlo_decay_1.ref \ functional_tests/ref-output/mssmtest_1.ref \ functional_tests/ref-output/mssmtest_2.ref \ functional_tests/ref-output/mssmtest_3.ref \ functional_tests/ref-output/spincor_1.ref \ functional_tests/ref-output/show_1.ref \ functional_tests/ref-output/show_2.ref \ functional_tests/ref-output/show_3.ref \ functional_tests/ref-output/show_4.ref \ functional_tests/ref-output/show_5.ref \ functional_tests/ref-output/method_ovm_1.ref \ functional_tests/ref-output/multi_comp_4.ref \ functional_tests/ref-output/flvsum_1.ref \ functional_tests/ref-output/br_redef_1.ref \ functional_tests/ref-output/decay_err_1.ref \ functional_tests/ref-output/decay_err_2.ref \ functional_tests/ref-output/decay_err_3.ref \ functional_tests/ref-output/polarized_1.ref \ functional_tests/ref-output/circe1_1.ref \ functional_tests/ref-output/circe1_2.ref \ functional_tests/ref-output/circe1_3.ref \ functional_tests/ref-output/circe1_6.ref \ functional_tests/ref-output/circe1_10.ref \ functional_tests/ref-output/circe1_errors_1.ref \ functional_tests/ref-output/circe2_1.ref \ functional_tests/ref-output/circe2_2.ref \ functional_tests/ref-output/circe2_3.ref \ functional_tests/ref-output/isr_1.ref \ functional_tests/ref-output/epa_1.ref \ functional_tests/ref-output/epa_2.ref \ functional_tests/ref-output/isr_epa_1.ref \ functional_tests/ref-output/ep_3.ref \ functional_tests/ref-output/ewa_4.ref \ functional_tests/ref-output/gaussian_1.ref \ functional_tests/ref-output/gaussian_2.ref \ functional_tests/ref-output/beam_events_1.ref \ functional_tests/ref-output/beam_events_4.ref \ functional_tests/ref-output/energy_scan_1.ref \ functional_tests/ref-output/cascades2_phs_1.ref \ functional_tests/ref-output/vamp2_1.ref \ functional_tests/ref-output/vamp2_2.ref \ ext_tests_nlo/ref-output/nlo_ee4j.ref \ ext_tests_nlo/ref-output/nlo_ee4t.ref \ ext_tests_nlo/ref-output/nlo_ee5j.ref \ ext_tests_nlo/ref-output/nlo_eejj.ref \ ext_tests_nlo/ref-output/nlo_eejjj.ref \ ext_tests_nlo/ref-output/nlo_eett.ref \ ext_tests_nlo/ref-output/nlo_eetth.ref \ ext_tests_nlo/ref-output/nlo_eetthh.ref \ ext_tests_nlo/ref-output/nlo_eetthj.ref \ ext_tests_nlo/ref-output/nlo_eetthz.ref \ ext_tests_nlo/ref-output/nlo_eettwjj.ref \ ext_tests_nlo/ref-output/nlo_eettww.ref \ ext_tests_nlo/ref-output/nlo_eettz.ref \ ext_tests_nlo/ref-output/nlo_eettzj.ref \ ext_tests_nlo/ref-output/nlo_eettzjj.ref \ ext_tests_nlo/ref-output/nlo_eettzz.ref \ ext_tests_nlo/ref-output/nlo_pptttt.ref \ ext_tests_nlo/ref-output/nlo_ppz.ref \ ext_tests_nlo/ref-output/nlo_ppw.ref \ ext_tests_nlo/ref-output/nlo_ppzw.ref \ ext_tests_nlo/ref-output/nlo_ppzz.ref # Reference files that depend on the numerical precision REF_OUTPUT_FILES_DOUBLE = \ functional_tests/ref-output-double/qedtest_3.ref \ functional_tests/ref-output-double/qedtest_4.ref \ functional_tests/ref-output-double/qcdtest_1.ref \ functional_tests/ref-output-double/qcdtest_2.ref \ functional_tests/ref-output-double/qcdtest_3.ref \ functional_tests/ref-output-double/smtest_2.ref \ functional_tests/ref-output-double/smtest_8.ref \ functional_tests/ref-output-double/observables_2.ref \ functional_tests/ref-output-double/colors_2.ref \ functional_tests/ref-output-double/resonances_1.ref \ functional_tests/ref-output-double/resonances_2.ref \ functional_tests/ref-output-double/resonances_3.ref \ functional_tests/ref-output-double/resonances_4.ref \ functional_tests/ref-output-double/resonances_10.ref \ functional_tests/ref-output-double/resonances_11.ref \ functional_tests/ref-output-double/beam_setup_5.ref \ functional_tests/ref-output-double/nlo_3.ref \ functional_tests/ref-output-double/nlo_4.ref \ functional_tests/ref-output-double/nlo_5.ref \ functional_tests/ref-output-double/fks_res_1.ref \ functional_tests/ref-output-double/fks_res_3.ref \ functional_tests/ref-output-double/openloops_3.ref \ functional_tests/ref-output-double/powheg_1.ref \ functional_tests/ref-output-double/defaultcuts.ref \ functional_tests/ref-output-double/parton_shower_2.ref \ functional_tests/ref-output-double/helicity.ref \ functional_tests/ref-output-double/lhef_7.ref \ functional_tests/ref-output-double/hepmc_8.ref \ functional_tests/ref-output-double/lcio_2.ref \ functional_tests/ref-output-double/lcio_7.ref \ functional_tests/ref-output-double/multi_comp_1.ref \ functional_tests/ref-output-double/multi_comp_2.ref \ functional_tests/ref-output-double/multi_comp_3.ref \ functional_tests/ref-output-double/pdf_builtin.ref \ functional_tests/ref-output-double/lhapdf5.ref \ functional_tests/ref-output-double/lhapdf6.ref \ functional_tests/ref-output-double/ep_1.ref \ functional_tests/ref-output-double/ep_2.ref \ functional_tests/ref-output-double/circe1_4.ref \ functional_tests/ref-output-double/circe1_5.ref \ functional_tests/ref-output-double/circe1_7.ref \ functional_tests/ref-output-double/circe1_8.ref \ functional_tests/ref-output-double/circe1_9.ref \ functional_tests/ref-output-double/circe1_photons_1.ref \ functional_tests/ref-output-double/circe1_photons_2.ref \ functional_tests/ref-output-double/circe1_photons_3.ref \ functional_tests/ref-output-double/circe1_photons_4.ref \ functional_tests/ref-output-double/circe1_photons_5.ref \ functional_tests/ref-output-double/isr_2.ref \ functional_tests/ref-output-double/isr_3.ref \ functional_tests/ref-output-double/isr_4.ref \ functional_tests/ref-output-double/isr_5.ref \ functional_tests/ref-output-double/pythia6_3.ref \ functional_tests/ref-output-double/pythia6_4.ref \ functional_tests/ref-output-double/tauola_1.ref \ functional_tests/ref-output-double/tauola_2.ref \ functional_tests/ref-output-double/mlm_matching_isr.ref \ functional_tests/ref-output-double/ewa_1.ref \ functional_tests/ref-output-double/ewa_2.ref \ functional_tests/ref-output-double/ewa_3.ref \ functional_tests/ref-output-double/ilc.ref \ functional_tests/ref-output-double/beam_events_2.ref \ functional_tests/ref-output-double/beam_events_3.ref REF_OUTPUT_FILES_PREC = \ functional_tests/ref-output-prec/qedtest_3.ref \ functional_tests/ref-output-prec/qedtest_4.ref \ functional_tests/ref-output-prec/qcdtest_1.ref \ functional_tests/ref-output-prec/qcdtest_2.ref \ functional_tests/ref-output-prec/qcdtest_3.ref \ functional_tests/ref-output-prec/smtest_2.ref \ functional_tests/ref-output-prec/smtest_8.ref \ functional_tests/ref-output-prec/colors_2.ref \ functional_tests/ref-output-prec/beam_setup_5.ref \ functional_tests/ref-output-prec/nlo_3.ref \ functional_tests/ref-output-prec/nlo_4.ref \ functional_tests/ref-output-prec/fks_res_1.ref \ functional_tests/ref-output-prec/fks_res_3.ref \ functional_tests/ref-output-prec/openloops_3.ref \ functional_tests/ref-output-prec/defaultcuts.ref \ functional_tests/ref-output-prec/parton_shower_2.ref \ functional_tests/ref-output-prec/helicity.ref \ functional_tests/ref-output-prec/lhef_7.ref \ functional_tests/ref-output-prec/multi_comp_1.ref \ functional_tests/ref-output-prec/multi_comp_2.ref \ functional_tests/ref-output-prec/multi_comp_3.ref \ functional_tests/ref-output-prec/pdf_builtin.ref \ functional_tests/ref-output-prec/lhapdf5.ref \ functional_tests/ref-output-prec/lhapdf6.ref \ functional_tests/ref-output-prec/ep_1.ref \ functional_tests/ref-output-prec/ep_2.ref \ functional_tests/ref-output-prec/ilc.ref \ functional_tests/ref-output-prec/circe1_9.ref \ functional_tests/ref-output-prec/circe1_photons_1.ref \ functional_tests/ref-output-prec/circe1_photons_2.ref \ functional_tests/ref-output-prec/circe1_photons_3.ref \ functional_tests/ref-output-prec/circe1_photons_4.ref \ functional_tests/ref-output-prec/circe1_photons_5.ref \ functional_tests/ref-output-prec/ewa_1.ref REF_OUTPUT_FILES_EXT = \ functional_tests/ref-output-ext/observables_2.ref \ functional_tests/ref-output-ext/resonances_1.ref \ functional_tests/ref-output-ext/resonances_2.ref \ functional_tests/ref-output-ext/resonances_3.ref \ functional_tests/ref-output-ext/resonances_4.ref \ functional_tests/ref-output-ext/resonances_10.ref \ functional_tests/ref-output-ext/resonances_11.ref \ functional_tests/ref-output-ext/circe1_4.ref \ functional_tests/ref-output-ext/circe1_5.ref \ functional_tests/ref-output-ext/circe1_7.ref \ functional_tests/ref-output-ext/circe1_8.ref \ functional_tests/ref-output-ext/isr_2.ref \ functional_tests/ref-output-ext/isr_3.ref \ functional_tests/ref-output-ext/isr_4.ref \ functional_tests/ref-output-ext/isr_5.ref \ functional_tests/ref-output-ext/nlo_5.ref \ functional_tests/ref-output-ext/powheg_1.ref \ functional_tests/ref-output-ext/pythia6_3.ref \ functional_tests/ref-output-ext/pythia6_4.ref \ functional_tests/ref-output-ext/tauola_1.ref \ functional_tests/ref-output-ext/tauola_2.ref \ functional_tests/ref-output-ext/ewa_2.ref \ functional_tests/ref-output-ext/ewa_3.ref \ functional_tests/ref-output-ext/beam_events_2.ref \ functional_tests/ref-output-ext/beam_events_3.ref \ functional_tests/ref-output-ext/mlm_matching_isr.ref \ functional_tests/ref-output-ext/hepmc_8.ref \ functional_tests/ref-output-ext/lcio_2.ref \ functional_tests/ref-output-ext/lcio_7.ref REF_OUTPUT_FILES_QUAD = \ functional_tests/ref-output-quad/observables_2.ref \ functional_tests/ref-output-quad/resonances_1.ref \ functional_tests/ref-output-quad/resonances_2.ref \ functional_tests/ref-output-quad/resonances_3.ref \ functional_tests/ref-output-quad/resonances_4.ref \ functional_tests/ref-output-quad/resonances_10.ref \ functional_tests/ref-output-quad/resonances_11.ref \ functional_tests/ref-output-quad/circe1_4.ref \ functional_tests/ref-output-quad/circe1_5.ref \ functional_tests/ref-output-quad/circe1_7.ref \ functional_tests/ref-output-quad/circe1_8.ref \ functional_tests/ref-output-quad/isr_2.ref \ functional_tests/ref-output-quad/isr_3.ref \ functional_tests/ref-output-quad/isr_4.ref \ functional_tests/ref-output-quad/isr_5.ref \ functional_tests/ref-output-quad/nlo_5.ref \ functional_tests/ref-output-quad/powheg_1.ref \ functional_tests/ref-output-quad/pythia6_3.ref \ functional_tests/ref-output-quad/pythia6_4.ref \ functional_tests/ref-output-quad/tauola_1.ref \ functional_tests/ref-output-quad/tauola_2.ref \ functional_tests/ref-output-quad/ewa_2.ref \ functional_tests/ref-output-quad/ewa_3.ref \ functional_tests/ref-output-quad/beam_events_2.ref \ functional_tests/ref-output-quad/beam_events_3.ref \ functional_tests/ref-output-quad/mlm_matching_isr.ref \ functional_tests/ref-output-quad/hepmc_8.ref \ functional_tests/ref-output-quad/lcio_2.ref \ functional_tests/ref-output-quad/lcio_7.ref TESTSUITES_M4 = \ $(MISC_TESTS_M4) \ $(EXT_MSSM_M4) \ $(EXT_NMSSM_M4) TESTSUITES_SIN = \ $(MISC_TESTS_SIN) \ $(EXT_ILC_SIN) \ $(EXT_MSSM_SIN) \ $(EXT_NMSSM_SIN) \ $(EXT_SHOWER_SIN) \ $(EXT_NLO_SIN) \ $(EXT_NLO_ADD_SIN) MISC_TESTS_M4 = MISC_TESTS_SIN = \ functional_tests/empty.sin \ functional_tests/fatal.sin \ functional_tests/cmdline_1_a.sin \ functional_tests/cmdline_1_b.sin \ functional_tests/cmdline_1.sin \ functional_tests/pack_1.sin \ functional_tests/defaultcuts.sin \ functional_tests/cuts.sin \ functional_tests/model_change_1.sin \ functional_tests/model_change_2.sin \ functional_tests/model_change_3.sin \ functional_tests/model_scheme_1.sin \ functional_tests/model_test.sin \ functional_tests/structure_1.sin \ functional_tests/structure_2.sin \ functional_tests/structure_3.sin \ functional_tests/structure_4.sin \ functional_tests/structure_5.sin \ functional_tests/structure_6.sin \ functional_tests/structure_7.sin \ functional_tests/structure_8.sin \ functional_tests/vars.sin \ functional_tests/extpar.sin \ functional_tests/testproc_1.sin \ functional_tests/testproc_2.sin \ functional_tests/testproc_3.sin \ functional_tests/testproc_4.sin \ functional_tests/testproc_5.sin \ functional_tests/testproc_6.sin \ functional_tests/testproc_7.sin \ functional_tests/testproc_8.sin \ functional_tests/testproc_9.sin \ functional_tests/testproc_10.sin \ functional_tests/testproc_11.sin \ functional_tests/testproc_12.sin \ functional_tests/template_me_1.sin \ functional_tests/template_me_2.sin \ functional_tests/libraries_1.sin \ functional_tests/libraries_2.sin \ functional_tests/libraries_3.sin \ functional_tests/libraries_4.sin \ functional_tests/job_id_1.sin \ functional_tests/job_id_2.sin \ functional_tests/job_id_3.sin \ functional_tests/job_id_4.sin \ functional_tests/rebuild_1.sin \ functional_tests/rebuild_2.sin \ functional_tests/rebuild_3.sin \ functional_tests/rebuild_4.sin \ functional_tests/rebuild_5.sin \ functional_tests/qedtest_1.sin \ functional_tests/qedtest_2.sin \ functional_tests/qedtest_3.sin \ functional_tests/qedtest_4.sin \ functional_tests/qedtest_5.sin \ functional_tests/qedtest_6.sin \ functional_tests/qedtest_7.sin \ functional_tests/qedtest_8.sin \ functional_tests/qedtest_9.sin \ functional_tests/qedtest_10.sin \ functional_tests/rambo_vamp_1.sin \ functional_tests/rambo_vamp_2.sin \ functional_tests/beam_setup_1.sin \ functional_tests/beam_setup_2.sin \ functional_tests/beam_setup_3.sin \ functional_tests/beam_setup_4.sin \ functional_tests/beam_setup_5.sin \ functional_tests/qcdtest_1.sin \ functional_tests/qcdtest_2.sin \ functional_tests/qcdtest_3.sin \ functional_tests/qcdtest_4.sin \ functional_tests/qcdtest_5.sin \ functional_tests/qcdtest_6.sin \ functional_tests/observables_1.sin \ functional_tests/observables_2.sin \ functional_tests/event_weights_1.sin \ functional_tests/event_weights_2.sin \ functional_tests/event_eff_1.sin \ functional_tests/event_eff_2.sin \ functional_tests/event_dump_1.sin \ functional_tests/event_dump_2.sin \ functional_tests/reweight_1.sin \ functional_tests/reweight_2.sin \ functional_tests/reweight_3.sin \ functional_tests/reweight_4.sin \ functional_tests/reweight_5.sin \ functional_tests/reweight_6.sin \ functional_tests/reweight_7.sin \ functional_tests/reweight_8.sin \ + functional_tests/reweight_9.sin \ functional_tests/analyze_1.sin \ functional_tests/analyze_2.sin \ functional_tests/analyze_3.sin \ functional_tests/analyze_4.sin \ functional_tests/analyze_5.sin \ functional_tests/analyze_6.sin \ functional_tests/bjet_cluster.sin \ functional_tests/colors.sin \ functional_tests/colors_2.sin \ functional_tests/colors_hgg.sin \ functional_tests/alphas.sin \ functional_tests/jets_xsec.sin \ functional_tests/lhef_1.sin \ functional_tests/lhef_2.sin \ functional_tests/lhef_3.sin \ functional_tests/lhef_4.sin \ functional_tests/lhef_5.sin \ functional_tests/lhef_6.sin \ functional_tests/lhef_7.sin \ functional_tests/lhef_8.sin \ functional_tests/lhef_9.sin \ functional_tests/lhef_10.sin \ functional_tests/lhef_11.sin \ functional_tests/select_1.sin \ functional_tests/select_2.sin \ functional_tests/shower_err_1.sin \ functional_tests/parton_shower_1.sin \ functional_tests/parton_shower_2.sin \ functional_tests/pythia6_1.sin \ functional_tests/pythia6_2.sin \ functional_tests/pythia6_3.sin \ functional_tests/pythia6_4.sin \ functional_tests/pythia8_1.sin \ functional_tests/pythia8_2.sin \ functional_tests/hadronize_1.sin \ functional_tests/tauola_1.sin \ functional_tests/tauola_2.sin \ functional_tests/mlm_matching_fsr.sin \ functional_tests/mlm_matching_isr.sin \ functional_tests/mlm_pythia6_isr.sin \ functional_tests/hepmc_1.sin \ functional_tests/hepmc_2.sin \ functional_tests/hepmc_3.sin \ functional_tests/hepmc_4.sin \ functional_tests/hepmc_5.sin \ functional_tests/hepmc_6.sin \ functional_tests/hepmc_7.sin \ functional_tests/hepmc_8.sin \ functional_tests/hepmc_9.sin \ functional_tests/hepmc_10.sin \ functional_tests/stdhep_1.sin \ functional_tests/stdhep_2.sin \ functional_tests/stdhep_3.sin \ functional_tests/stdhep_4.sin \ functional_tests/stdhep_5.sin \ functional_tests/stdhep_6.sin \ functional_tests/lcio_1.sin \ functional_tests/lcio_2.sin \ functional_tests/lcio_3.sin \ functional_tests/lcio_4.sin \ functional_tests/lcio_5.sin \ functional_tests/lcio_6.sin \ functional_tests/lcio_7.sin \ functional_tests/lcio_8.sin \ functional_tests/lcio_9.sin \ functional_tests/lcio_10.sin \ functional_tests/fatal_beam_decay.sin \ functional_tests/smtest_1.sin \ functional_tests/smtest_2.sin \ functional_tests/smtest_3.sin \ functional_tests/smtest_4.sin \ functional_tests/smtest_5.sin \ functional_tests/smtest_6.sin \ functional_tests/smtest_7.sin \ functional_tests/smtest_8.sin \ functional_tests/smtest_9.sin \ functional_tests/smtest_10.sin \ functional_tests/smtest_11.sin \ functional_tests/smtest_12.sin \ functional_tests/smtest_13.sin \ functional_tests/smtest_14.sin \ functional_tests/smtest_15.sin \ functional_tests/smtest_16.sin \ functional_tests/photon_isolation_1.sin \ functional_tests/photon_isolation_2.sin \ functional_tests/resonances_1.sin \ functional_tests/resonances_2.sin \ functional_tests/resonances_3.sin \ functional_tests/resonances_4.sin \ functional_tests/resonances_5.sin \ functional_tests/resonances_6.sin \ functional_tests/resonances_7.sin \ functional_tests/resonances_8.sin \ functional_tests/resonances_9.sin \ functional_tests/resonances_10.sin \ functional_tests/resonances_11.sin \ functional_tests/resonances_12.sin \ functional_tests/sm_cms_1.sin \ functional_tests/ufo_1.sin \ functional_tests/ufo_2.sin \ functional_tests/ufo_3.sin \ functional_tests/ufo_4.sin \ functional_tests/ufo_5.sin \ functional_tests/nlo_1.sin \ functional_tests/nlo_2.sin \ functional_tests/nlo_3.sin \ functional_tests/nlo_4.sin \ functional_tests/nlo_5.sin \ functional_tests/nlo_6.sin \ functional_tests/nlo_decay_1.sin \ functional_tests/real_partition_1.sin \ functional_tests/fks_res_1.sin \ functional_tests/fks_res_2.sin \ functional_tests/fks_res_3.sin \ functional_tests/openloops_1.sin \ functional_tests/openloops_2.sin \ functional_tests/openloops_3.sin \ functional_tests/openloops_4.sin \ functional_tests/openloops_5.sin \ functional_tests/openloops_6.sin \ functional_tests/openloops_7.sin \ functional_tests/openloops_8.sin \ functional_tests/openloops_9.sin \ functional_tests/openloops_10.sin \ functional_tests/openloops_11.sin \ functional_tests/openloops_12.sin \ functional_tests/openloops_13.sin \ functional_tests/recola_1.sin \ functional_tests/recola_2.sin \ functional_tests/recola_3.sin \ functional_tests/recola_4.sin \ functional_tests/recola_5.sin \ functional_tests/recola_6.sin \ functional_tests/recola_7.sin \ functional_tests/recola_8.sin \ functional_tests/recola_9.sin \ functional_tests/powheg_1.sin \ functional_tests/mssmtest_1.sin \ functional_tests/mssmtest_2.sin \ functional_tests/mssmtest_3.sin \ functional_tests/spincor_1.sin \ functional_tests/show_1.sin \ functional_tests/show_2.sin \ functional_tests/show_3.sin \ functional_tests/show_4.sin \ functional_tests/show_5.sin \ functional_tests/method_ovm_1.sin \ functional_tests/multi_comp_1.sin \ functional_tests/multi_comp_2.sin \ functional_tests/multi_comp_3.sin \ functional_tests/multi_comp_4.sin \ functional_tests/flvsum_1.sin \ functional_tests/br_redef_1.sin \ functional_tests/decay_err_1.sin \ functional_tests/decay_err_2.sin \ functional_tests/decay_err_3.sin \ functional_tests/polarized_1.sin \ functional_tests/pdf_builtin.sin \ functional_tests/lhapdf5.sin \ functional_tests/lhapdf6.sin \ functional_tests/ep_1.sin \ functional_tests/ep_2.sin \ functional_tests/ep_3.sin \ functional_tests/circe1_1.sin \ functional_tests/circe1_2.sin \ functional_tests/circe1_3.sin \ functional_tests/circe1_4.sin \ functional_tests/circe1_5.sin \ functional_tests/circe1_6.sin \ functional_tests/circe1_7.sin \ functional_tests/circe1_8.sin \ functional_tests/circe1_9.sin \ functional_tests/circe1_10.sin \ functional_tests/circe1_photons_1.sin \ functional_tests/circe1_photons_2.sin \ functional_tests/circe1_photons_3.sin \ functional_tests/circe1_photons_4.sin \ functional_tests/circe1_photons_5.sin \ functional_tests/circe1_errors_1.sin \ functional_tests/circe2_1.sin \ functional_tests/circe2_2.sin \ functional_tests/circe2_3.sin \ functional_tests/isr_1.sin \ functional_tests/isr_2.sin \ functional_tests/isr_3.sin \ functional_tests/isr_4.sin \ functional_tests/isr_5.sin \ functional_tests/epa_1.sin \ functional_tests/epa_2.sin \ functional_tests/isr_epa_1.sin \ functional_tests/ewa_1.sin \ functional_tests/ewa_2.sin \ functional_tests/ewa_3.sin \ functional_tests/ewa_4.sin \ functional_tests/ilc.sin \ functional_tests/gaussian_1.sin \ functional_tests/gaussian_2.sin \ functional_tests/beam_events_1.sin \ functional_tests/beam_events_2.sin \ functional_tests/beam_events_3.sin \ functional_tests/beam_events_4.sin \ functional_tests/energy_scan_1.sin \ functional_tests/susyhit.sin \ functional_tests/restrictions.sin \ functional_tests/helicity.sin \ functional_tests/process_log.sin \ functional_tests/static_1.sin \ functional_tests/static_1.exe.sin \ functional_tests/static_2.sin \ functional_tests/static_2.exe.sin \ functional_tests/user_cuts.sin \ functional_tests/user_prc_threshold_1.sin \ functional_tests/cascades2_phs_1.sin \ functional_tests/user_prc_threshold_2.sin \ functional_tests/vamp2_1.sin \ functional_tests/vamp2_2.sin EXT_MSSM_M4 = \ ext_tests_mssm/mssm_ext-ee.m4 \ ext_tests_mssm/mssm_ext-ee2.m4 \ ext_tests_mssm/mssm_ext-en.m4 \ ext_tests_mssm/mssm_ext-tn.m4 \ ext_tests_mssm/mssm_ext-uu.m4 \ ext_tests_mssm/mssm_ext-uu2.m4 \ ext_tests_mssm/mssm_ext-uuckm.m4 \ ext_tests_mssm/mssm_ext-dd.m4 \ ext_tests_mssm/mssm_ext-dd2.m4 \ ext_tests_mssm/mssm_ext-ddckm.m4 \ ext_tests_mssm/mssm_ext-bb.m4 \ ext_tests_mssm/mssm_ext-bt.m4 \ ext_tests_mssm/mssm_ext-tt.m4 \ ext_tests_mssm/mssm_ext-ug.m4 \ ext_tests_mssm/mssm_ext-dg.m4 \ ext_tests_mssm/mssm_ext-aa.m4 \ ext_tests_mssm/mssm_ext-wa.m4 \ ext_tests_mssm/mssm_ext-za.m4 \ ext_tests_mssm/mssm_ext-ww.m4 \ ext_tests_mssm/mssm_ext-wz.m4 \ ext_tests_mssm/mssm_ext-zz.m4 \ ext_tests_mssm/mssm_ext-gg.m4 \ ext_tests_mssm/mssm_ext-ga.m4 \ ext_tests_mssm/mssm_ext-gw.m4 \ ext_tests_mssm/mssm_ext-gz.m4 EXT_NMSSM_M4 = \ ext_tests_nmssm/nmssm_ext-aa.m4 \ ext_tests_nmssm/nmssm_ext-bb1.m4 \ ext_tests_nmssm/nmssm_ext-bb2.m4 \ ext_tests_nmssm/nmssm_ext-bt.m4 \ ext_tests_nmssm/nmssm_ext-dd1.m4 \ ext_tests_nmssm/nmssm_ext-dd2.m4 \ ext_tests_nmssm/nmssm_ext-ee1.m4 \ ext_tests_nmssm/nmssm_ext-ee2.m4 \ ext_tests_nmssm/nmssm_ext-en.m4 \ ext_tests_nmssm/nmssm_ext-ga.m4 \ ext_tests_nmssm/nmssm_ext-gg.m4 \ ext_tests_nmssm/nmssm_ext-gw.m4 \ ext_tests_nmssm/nmssm_ext-gz.m4 \ ext_tests_nmssm/nmssm_ext-qg.m4 \ ext_tests_nmssm/nmssm_ext-tn.m4 \ ext_tests_nmssm/nmssm_ext-tt1.m4 \ ext_tests_nmssm/nmssm_ext-tt2.m4 \ ext_tests_nmssm/nmssm_ext-uu1.m4 \ ext_tests_nmssm/nmssm_ext-uu2.m4 \ ext_tests_nmssm/nmssm_ext-wa.m4 \ ext_tests_nmssm/nmssm_ext-ww1.m4 \ ext_tests_nmssm/nmssm_ext-ww2.m4 \ ext_tests_nmssm/nmssm_ext-wz.m4 \ ext_tests_nmssm/nmssm_ext-za.m4 \ ext_tests_nmssm/nmssm_ext-zz1.m4 \ ext_tests_nmssm/nmssm_ext-zz2.m4 EXT_MSSM_SIN = $(EXT_MSSM_M4:.m4=.sin) EXT_NMSSM_SIN = $(EXT_NMSSM_M4:.m4=.sin) EXT_ILC_SIN = \ ext_tests_ilc/ilc_ext.sin EXT_SHOWER_SIN = \ ext_tests_shower/shower_1_norad.sin \ ext_tests_shower/shower_2_aall.sin \ ext_tests_shower/shower_3_bb.sin \ ext_tests_shower/shower_3_jj.sin \ ext_tests_shower/shower_3_qqqq.sin \ ext_tests_shower/shower_3_tt.sin \ ext_tests_shower/shower_3_z_nu.sin \ ext_tests_shower/shower_3_z_tau.sin \ ext_tests_shower/shower_4_ee.sin \ ext_tests_shower/shower_5.sin \ ext_tests_shower/shower_6.sin EXT_NLO_SIN = \ ext_tests_nlo/nlo_settings.sin \ ext_tests_nlo/nlo_eejj.sin \ ext_tests_nlo/nlo_eejjj.sin \ ext_tests_nlo/nlo_ee4j.sin \ ext_tests_nlo/nlo_ee5j.sin \ ext_tests_nlo/nlo_eebb.sin \ ext_tests_nlo/nlo_eebbj.sin \ ext_tests_nlo/nlo_eebbjj.sin \ ext_tests_nlo/nlo_ee4b.sin \ ext_tests_nlo/nlo_eett.sin \ ext_tests_nlo/nlo_eettj.sin \ ext_tests_nlo/nlo_eettjj.sin \ ext_tests_nlo/nlo_eettjjj.sin \ ext_tests_nlo/nlo_eettbb.sin \ ext_tests_nlo/nlo_eetta.sin \ ext_tests_nlo/nlo_eettaa.sin \ ext_tests_nlo/nlo_eettaj.sin \ ext_tests_nlo/nlo_eettajj.sin \ ext_tests_nlo/nlo_eettaz.sin \ ext_tests_nlo/nlo_eettah.sin \ ext_tests_nlo/nlo_eettz.sin \ ext_tests_nlo/nlo_eettzj.sin \ ext_tests_nlo/nlo_eettzjj.sin \ ext_tests_nlo/nlo_eettzz.sin \ ext_tests_nlo/nlo_eettwjj.sin \ ext_tests_nlo/nlo_eettww.sin \ ext_tests_nlo/nlo_eetth.sin \ ext_tests_nlo/nlo_eetthj.sin \ ext_tests_nlo/nlo_eetthjj.sin \ ext_tests_nlo/nlo_eetthh.sin \ ext_tests_nlo/nlo_eetthz.sin \ ext_tests_nlo/nlo_ee4t.sin \ ext_tests_nlo/nlo_ee4tj.sin \ ext_tests_nlo/nlo_ppz.sin \ ext_tests_nlo/nlo_ppw.sin \ ext_tests_nlo/nlo_ppzz.sin \ ext_tests_nlo/nlo_ppzw.sin \ ext_tests_nlo/nlo_pptttt.sin EXT_NLO_ADD_SIN = \ ext_tests_nlo_add/nlo_decay_tbw.sin \ ext_tests_nlo_add/nlo_tt.sin \ ext_tests_nlo_add/nlo_tt_powheg.sin \ ext_tests_nlo_add/nlo_tt_powheg_sudakov.sin \ ext_tests_nlo_add/nlo_uu.sin \ ext_tests_nlo_add/nlo_uu_powheg.sin \ ext_tests_nlo_add/nlo_qq_powheg.sin \ ext_tests_nlo_add/nlo_threshold.sin \ ext_tests_nlo_add/nlo_threshold_factorized.sin \ ext_tests_nlo_add/nlo_methods_gosam.sin \ ext_tests_nlo_add/nlo_jets.sin \ ext_tests_nlo_add/nlo_fks_delta_o_eejj.sin \ ext_tests_nlo_add/nlo_fks_delta_i_ppee.sin all-local: $(TESTSUITES_SIN) if M4_AVAILABLE SUFFIXES = .m4 .sin .m4.sin: case "$@" in \ */*) \ mkdir -p `sed 's,/.[^/]*$$,,g' <<< "$@"` ;; \ esac $(M4) $(srcdir)/$(TESTSUITE_MACROS) $< > $@ endif M4_AVAILABLE Index: trunk/share/tests/functional_tests/ref-output/reweight_9.ref =================================================================== --- trunk/share/tests/functional_tests/ref-output/reweight_9.ref (revision 0) +++ trunk/share/tests/functional_tests/ref-output/reweight_9.ref (revision 8374) @@ -0,0 +1,139 @@ +?openmp_logging = false +?vis_history = false +?integration_timer = false +$method = "omega" +$phs_method = "wood" +$integration_method = "vamp" +seed = 0 +| Switching to model 'QED' +?pacify = true +| Switching to model 'SM', scheme 'default' +| Process library 'reweight_9_lib': recorded process 'reweight_9_p' +| Process library 'reweight_9_lib': compiling ... +| Process library 'reweight_9_lib': writing makefile +| Process library 'reweight_9_lib': removing old files +| Process library 'reweight_9_lib': writing driver +| Process library 'reweight_9_lib': creating source code +| Process library 'reweight_9_lib': compiling sources +| Process library 'reweight_9_lib': linking +| Process library 'reweight_9_lib': loading +| Process library 'reweight_9_lib': ... success. +sqrts = 9.00000E+01 +| RNG: Initializing TAO random-number generator +| RNG: Setting seed for random-number generator to 0 +| Initializing integration for process reweight_9_p: +| Beam structure: e-, e+ +| Beam data (collision): +| e- (mass = 5.1099700E-04 GeV) +| e+ (mass = 5.1099700E-04 GeV) +| sqrts = 9.000000000000E+01 GeV +| Phase space: generating configuration ... +| Phase space: ... success. +| Phase space: writing configuration file 'reweight_9_p.i1.phs' +| ------------------------------------------------------------------------ +| Process [scattering]: 'reweight_9_p' +| Library name = 'reweight_9_lib' +| Process index = 1 +| Process components: +| 1: 'reweight_9_p_i1': e-, e+ => tau-, tau+ [omega] +| ------------------------------------------------------------------------ +| Phase space: 1 channels, 2 dimensions +| Phase space: found 1 channel, collected in 1 grove. +| Phase space: Using 1 equivalence between channels. +| Phase space: wood +Warning: No cuts have been defined. +| Starting integration for process 'reweight_9_p' +| Integrate: iterations = 2:1000 +| Integrator: 1 chains, 1 channels, 2 dimensions +| Integrator: Using VAMP channel equivalences +| Integrator: 1000 initial calls, 20 bins, stratified = T +| Integrator: VAMP +|=============================================================================| +| It Calls Integral[fb] Error[fb] Err[%] Acc Eff[%] Chi2 N[It] | +|=============================================================================| + 1 800 1.056E+06 9.33E+02 0.09 0.02 60.9 + 2 800 1.059E+06 9.71E+02 0.09 0.03 61.0 +|-----------------------------------------------------------------------------| + 2 1600 1.057E+06 6.73E+02 0.06 0.03 61.0 2.90 2 +|=============================================================================| +n_events = 2 +?write_raw = true +$sample = "reweight_9_in" +| Starting simulation for process 'reweight_9_p' +| Simulate: using integration grids from file 'reweight_9_p.m1.vg' +| RNG: Initializing TAO random-number generator +| RNG: Setting seed for random-number generator to 1 +| Simulation: requested number of events = 2 +| corr. to luminosity [fb-1] = 1.8913E-06 +| Events: writing to LHEF file 'reweight_9_in.lhe' +| Events: writing to weight stream file 'reweight_9_in.weights.dat' +| Events: writing to ASCII file 'reweight_9_in.debug' +| Events: writing to raw file 'reweight_9_in.evx' +| Events: generating 2 unweighted, unpolarized events ... +| Events: event normalization mode '1' +| ... event sample complete. +| Events: actual unweighting efficiency = 50.00 % +| Events: closing LHEF file 'reweight_9_in.lhe' +| Events: closing weight stream file 'reweight_9_in.weights.dat' +| Events: closing ASCII file 'reweight_9_in.debug' +| Events: closing raw file 'reweight_9_in.evx' +$rescan_input_format = "lhef" +?update_sqme = true +$sample = "reweight_9_raw" +| Starting simulation for process 'reweight_9_p' +| RNG: Initializing TAO random-number generator +| RNG: Setting seed for random-number generator to 2 +Warning: Reading phs file: MD5 sum check disabled +| Phase space: keeping configuration file 'reweight_9_p.i1.phs' +| RNG: Initializing TAO random-number generator +| RNG: Setting seed for random-number generator to 3 +| Simulation: requested number of events = 2 +| corr. to luminosity [fb-1] = 1.8913E-06 +| Recalculating observables +| Recalculating squared matrix elements +| Events: reading from LHEF file 'reweight_9_in.lhe' +| LHEF: Event file has been generated by WHIZARD 2.8.3 +| Events: writing to weight stream file 'reweight_9_raw.weights.dat' +| Events: writing to ASCII file 'reweight_9_raw.debug' +| Events: writing to raw file 'reweight_9_raw.evx' +| Rescanning unweighted events (process parameters updated) ... +| ... event file terminates after 2 events. +| Events: closing weight stream file 'reweight_9_raw.weights.dat' +| Events: closing ASCII file 'reweight_9_raw.debug' +| Events: closing raw file 'reweight_9_raw.evx' +| Events: closing LHEF file 'reweight_9_in.lhe' +$rescan_input_format = "lhef" +?update_sqme = true +$sample = "reweight_9_lhef" +| Starting simulation for process 'reweight_9_p' +| RNG: Initializing TAO random-number generator +| RNG: Setting seed for random-number generator to 4 +Warning: Reading phs file: MD5 sum check disabled +| Phase space: keeping configuration file 'reweight_9_p.i1.phs' +| RNG: Initializing TAO random-number generator +| RNG: Setting seed for random-number generator to 5 +| Simulation: requested number of events = 2 +| corr. to luminosity [fb-1] = 1.8913E-06 +| Recalculating observables +| Recalculating squared matrix elements +| Events: reading from LHEF file 'reweight_9_in.lhe' +| LHEF: Event file has been generated by WHIZARD 2.8.3 +| Events: writing to weight stream file 'reweight_9_lhef.weights.dat' +| Events: writing to raw file 'reweight_9_lhef.evx' +| Rescanning unweighted events (process parameters updated) ... +| ... event file terminates after 2 events. +| Events: closing weight stream file 'reweight_9_lhef.weights.dat' +| Events: closing raw file 'reweight_9_lhef.evx' +| Events: closing LHEF file 'reweight_9_in.lhe' +| There were no errors and 3 warning(s). +| WHIZARD run finished. +|=============================================================================| +Contents of reweight_9_in.weights.dat +0 1.0000000000E+00 1.3828479640E+00 1.3828479640E+00 1 +0 1.0000000000E+00 1.0778464949E+00 1.0778464949E+00 1 +Contents of reweight_9_raw.weights.dat +0 1.0000000000E+00 1.3828479640E+00 1.3828479640E+00 1 +0 1.0000000000E+00 1.0778464949E+00 1.0778464949E+00 1 +Contents of reweight_9_lhef.weights.dat +0 1.0000000000E+00 1.3828479640E+00 1.3828479640E+00 1 +0 1.0000000000E+00 1.0778464949E+00 1.0778464949E+00 1 Index: trunk/share/tests/functional_tests/reweight_9.sin =================================================================== --- trunk/share/tests/functional_tests/reweight_9.sin (revision 0) +++ trunk/share/tests/functional_tests/reweight_9.sin (revision 8374) @@ -0,0 +1,48 @@ +# SINDARIN input for WHIZARD self-test +# Process e- e+ -> mu- mu+ + +?logging = true +?openmp_logging = false +?vis_history = false +?integration_timer = false + +$method = "omega" +$phs_method = "wood" +$integration_method = "vamp" + +seed = 0 + +model = "QED" + +?pacify = true +model = SM +process reweight_9_p = e1, E1 => e3, E3 +compile +sqrts = 90 GeV +beams = e1, E1 +integrate (reweight_9_p) { + iterations = 2:1000 +} + +n_events = 2 +?write_raw = true + +simulate (reweight_9_p) { + $sample = "reweight_9_in" + sample_format = lhef, weight_stream, debug +} + +rescan "reweight_9_in" (reweight_9_p) { + $rescan_input_format = "lhef" + ?update_sqme = true + $sample = "reweight_9_raw" + sample_format = weight_stream, debug +} + +rescan "reweight_9_in" (reweight_9_p) { + $rescan_input_format = "lhef" + ?update_sqme = true + $sample = "reweight_9_lhef" + sample_format = weight_stream +} + Index: trunk/tests/functional_tests/Makefile.am =================================================================== --- trunk/tests/functional_tests/Makefile.am (revision 8373) +++ trunk/tests/functional_tests/Makefile.am (revision 8374) @@ -1,808 +1,809 @@ ## Makefile.am -- Makefile for executable WHIZARD test scripts ## ## Process this file with automake to produce Makefile.in ## ######################################################################## # # Copyright (C) 1999-2019 by # Wolfgang Kilian # Thorsten Ohl # Juergen Reuter # with contributions from # cf. main AUTHORS file # # WHIZARD 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 2, or (at your option) # any later version. # # WHIZARD 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 this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # ######################################################################## WHIZARD_DRIVER = run_whizard.sh TESTS_DEFAULT = \ empty.run \ fatal.run \ cmdline_1.run \ structure_1.run \ structure_2.run \ structure_3.run \ structure_4.run \ structure_5.run \ structure_6.run \ structure_7.run \ structure_8.run \ vars.run \ extpar.run \ testproc_1.run \ testproc_2.run \ testproc_3.run \ testproc_4.run \ testproc_5.run \ testproc_6.run \ testproc_7.run \ testproc_8.run \ testproc_9.run \ testproc_10.run \ testproc_11.run \ testproc_12.run \ template_me_1.run \ template_me_2.run \ model_scheme_1.run \ rebuild_1.run \ rebuild_4.run \ susyhit.run \ helicity.run \ libraries_4.run \ job_id_1.run \ pack_1.run XFAIL_TESTS_DEFAULT = TESTS_REQ_FASTJET = \ analyze_4.run \ bjet_cluster.run \ openloops_12.run \ openloops_13.run TESTS_REQ_OCAML = \ libraries_1.run \ libraries_2.run \ libraries_3.run \ rebuild_2.run \ rebuild_3.run \ rebuild_5.run \ defaultcuts.run \ cuts.run \ model_change_1.run \ model_change_2.run \ model_change_3.run \ model_test.run \ job_id_2.run \ job_id_3.run \ job_id_4.run \ qedtest_1.run \ qedtest_2.run \ qedtest_3.run \ qedtest_4.run \ qedtest_5.run \ qedtest_6.run \ qedtest_7.run \ qedtest_8.run \ qedtest_9.run \ qedtest_10.run \ rambo_vamp_1.run \ rambo_vamp_2.run \ beam_setup_1.run \ beam_setup_2.run \ beam_setup_3.run \ beam_setup_4.run \ beam_setup_5.run \ qcdtest_1.run \ qcdtest_2.run \ qcdtest_3.run \ qcdtest_4.run \ qcdtest_5.run \ qcdtest_6.run \ observables_1.run \ observables_2.run \ event_weights_1.run \ event_weights_2.run \ event_eff_1.run \ event_eff_2.run \ event_dump_1.run \ event_dump_2.run \ reweight_1.run \ reweight_2.run \ reweight_3.run \ reweight_4.run \ reweight_5.run \ reweight_6.run \ reweight_7.run \ reweight_8.run \ + reweight_9.run \ analyze_1.run \ analyze_2.run \ analyze_5.run \ analyze_6.run \ colors.run \ colors_2.run \ colors_hgg.run \ alphas.run \ jets_xsec.run \ lhef_1.run \ lhef_2.run \ lhef_3.run \ lhef_4.run \ lhef_5.run \ lhef_6.run \ lhef_7.run \ lhef_8.run \ lhef_9.run \ lhef_10.run \ lhef_11.run \ stdhep_1.run \ stdhep_2.run \ stdhep_3.run \ stdhep_4.run \ stdhep_5.run \ stdhep_6.run \ select_1.run \ select_2.run \ fatal_beam_decay.run \ smtest_1.run \ smtest_2.run \ smtest_3.run \ smtest_4.run \ smtest_5.run \ smtest_6.run \ smtest_7.run \ smtest_8.run \ smtest_9.run \ smtest_10.run \ smtest_11.run \ smtest_12.run \ smtest_13.run \ smtest_14.run \ smtest_15.run \ smtest_16.run \ photon_isolation_1.run \ photon_isolation_2.run \ resonances_1.run \ resonances_2.run \ resonances_3.run \ resonances_4.run \ resonances_5.run \ resonances_6.run \ resonances_7.run \ resonances_8.run \ resonances_9.run \ resonances_10.run \ resonances_11.run \ resonances_12.run \ mssmtest_1.run \ mssmtest_2.run \ mssmtest_3.run \ sm_cms_1.run \ ufo_1.run \ ufo_2.run \ ufo_3.run \ ufo_4.run \ ufo_5.run \ nlo_1.run \ nlo_2.run \ nlo_3.run \ nlo_4.run \ nlo_5.run \ nlo_6.run \ nlo_decay_1.run \ real_partition_1.run \ fks_res_1.run \ fks_res_2.run \ fks_res_3.run \ openloops_1.run \ openloops_2.run \ openloops_3.run \ openloops_4.run \ openloops_5.run \ openloops_6.run \ openloops_7.run \ openloops_8.run \ openloops_9.run \ openloops_10.run \ openloops_11.run \ recola_1.run \ recola_2.run \ recola_3.run \ recola_4.run \ recola_5.run \ recola_6.run \ recola_7.run \ recola_8.run \ recola_9.run \ powheg_1.run \ spincor_1.run \ show_1.run \ show_2.run \ show_3.run \ show_4.run \ show_5.run \ method_ovm_1.run \ multi_comp_1.run \ multi_comp_2.run \ multi_comp_3.run \ multi_comp_4.run \ flvsum_1.run \ br_redef_1.run \ decay_err_1.run \ decay_err_2.run \ decay_err_3.run \ polarized_1.run \ pdf_builtin.run \ ep_1.run \ ep_2.run \ ep_3.run \ circe1_1.run \ circe1_2.run \ circe1_3.run \ circe1_4.run \ circe1_5.run \ circe1_6.run \ circe1_7.run \ circe1_8.run \ circe1_9.run \ circe1_10.run \ circe1_photons_1.run \ circe1_photons_2.run \ circe1_photons_3.run \ circe1_photons_4.run \ circe1_photons_5.run \ circe1_errors_1.run \ circe2_1.run \ circe2_2.run \ circe2_3.run \ ewa_1.run \ ewa_2.run \ ewa_3.run \ ewa_4.run \ isr_1.run \ isr_2.run \ isr_3.run \ isr_4.run \ isr_5.run \ epa_1.run \ epa_2.run \ isr_epa_1.run \ ilc.run \ gaussian_1.run \ gaussian_2.run \ beam_events_1.run \ beam_events_2.run \ beam_events_3.run \ beam_events_4.run \ energy_scan_1.run \ restrictions.run \ process_log.run \ shower_err_1.run \ parton_shower_1.run \ parton_shower_2.run \ hadronize_1.run \ mlm_matching_fsr.run \ user_cuts.run \ user_prc_threshold_1.run \ cascades2_phs_1.run \ user_prc_threshold_2.run \ vamp2_1.run \ vamp2_2.run XFAIL_TESTS_REQ_OCAML = \ colors_hgg.run \ hadronize_1.run \ user_cuts.run TESTS_REQ_HEPMC = \ hepmc_1.run \ hepmc_2.run \ hepmc_3.run \ hepmc_4.run \ hepmc_5.run \ hepmc_6.run \ hepmc_7.run \ hepmc_8.run \ hepmc_9.run \ hepmc_10.run XFAIL_TESTS_REQ_HEPMC = TESTS_REQ_LCIO = \ lcio_1.run \ lcio_2.run \ lcio_3.run \ lcio_4.run \ lcio_5.run \ lcio_6.run \ lcio_7.run \ lcio_8.run \ lcio_9.run \ lcio_10.run XFAIL_TESTS_REQ_LCIO = TESTS_REQ_LHAPDF5 = \ lhapdf5.run TESTS_REQ_LHAPDF6 = \ lhapdf6.run XFAIL_TESTS_REQ_LHAPDF5 = XFAIL_TESTS_REQ_LHAPDF6 = TESTS_STATIC = \ static_1.run \ static_2.run XFAIL_TESTS_STATIC = TESTS_REQ_PYTHIA6 = \ pythia6_1.run \ pythia6_2.run \ pythia6_3.run \ pythia6_4.run \ tauola_1.run \ tauola_2.run \ isr_5.run \ mlm_pythia6_isr.run \ mlm_matching_isr.run XFAIL_TESTS_REQ_PYTHIA6 = TESTS_REQ_PYTHIA8 = # pythia8_1.run \ # pythia8_2.run XFAIL_TESTS_REQ_PYTHIA8 = TESTS_REQ_EV_ANA = \ analyze_3.run XFAIL_TESTS_REQ_EV_ANA = TESTS_REQ_GAMELAN = \ analyze_3.run TEST_DRIVERS_RUN = \ $(TESTS_DEFAULT) \ $(TESTS_REQ_OCAML) \ $(TESTS_REQ_LHAPDF5) \ $(TESTS_REQ_LHAPDF6) \ $(TESTS_REQ_HEPMC) \ $(TESTS_REQ_LCIO) \ $(TESTS_REQ_FASTJET) \ $(TESTS_REQ_PYTHIA6) \ $(TESTS_REQ_EV_ANA) \ $(TESTS_STATIC) TEST_DRIVERS_SH = $(TEST_DRIVERS_RUN:.run=.sh) ######################################################################## TESTS = XFAIL_TESTS = TESTS_SRC = TESTS += $(TESTS_DEFAULT) XFAIL_TESTS += $(XFAIL_TESTS_DEFAULT) TESTS += $(TESTS_REQ_OCAML) XFAIL_TESTS += $(XFAIL_TESTS_REQ_OCAML) TESTS += $(TESTS_REQ_HEPMC) XFAIL_TESTS += $(XFAIL_TESTS_REQ_HEPMC) TESTS += $(TESTS_REQ_LCIO) XFAIL_TESTS += $(XFAIL_TESTS_REQ_LCIO) TESTS += $(TESTS_REQ_FASTJET) XFAIL_TESTS += $(XFAIL_TESTS_REQ_FASTJET) TESTS += $(TESTS_REQ_LHAPDF5) XFAIL_TESTS += $(XFAIL_TESTS_REQ_LHAPDF5) TESTS += $(TESTS_REQ_LHAPDF6) XFAIL_TESTS += $(XFAIL_TESTS_REQ_LHAPDF6) TESTS += $(TESTS_REQ_PYTHIA6) XFAIL_TESTS += $(XFAIL_TESTS_REQ_PYTHIA6) TESTS += $(TESTS_REQ_PYTHIA8) XFAIL_TESTS += $(XFAIL_TESTS_REQ_PYTHIA8) TESTS += $(TESTS_REQ_EV_ANA) XFAIL_TESTS += $(XFAIL_TESTS_REQ_EV_ANA) TESTS += $(TESTS_STATIC) XFAIL_TESTS += $(XFAIL_TESTS_STATIC) EXTRA_DIST = $(TEST_DRIVERS_SH) \ $(TESTS_SRC) ######################################################################## VPATH = $(srcdir) SUFFIXES = .sh .run .sh.run: @rm -f $@ @if test -f $(top_builddir)/share/tests/functional_tests/$*.sin; then \ $(SED) 's|@script@|$(top_builddir)/share/tests/functional_tests/$*|g' $< > $@; \ elif test -f $(top_srcdir)/share/tests/functional_tests/$*.sin; then \ $(SED) 's|@script@|$(top_srcdir)/share/tests/functional_tests/$*|g' $< > $@; \ else \ echo "$*.sin not found!" 1>&2; \ exit 2; \ fi @chmod +x $@ cmdline_1.run: cmdline_1_a.sin cmdline_1_b.sin cmdline_1_a.sin: $(top_builddir)/share/tests/functional_tests/cmdline_1_a.sin cp $< $@ cmdline_1_b.sin: $(top_builddir)/share/tests/functional_tests/cmdline_1_b.sin cp $< $@ structure_2.run: structure_2_inc.sin structure_2_inc.sin: $(top_builddir)/share/tests/functional_tests/structure_2_inc.sin cp $< $@ testproc_3.run: testproc_3.phs testproc_3.phs: $(top_builddir)/share/tests/functional_tests/testproc_3.phs cp $< $@ static_1.run: static_1.exe.sin static_1.exe.sin: $(top_builddir)/share/tests/functional_tests/static_1.exe.sin cp $< $@ static_2.run: static_2.exe.sin static_2.exe.sin: $(top_builddir)/share/tests/functional_tests/static_2.exe.sin cp $< $@ susyhit.run: susyhit.in user_cuts.run: user_cuts.f90 user_cuts.f90: $(top_builddir)/share/tests/functional_tests/user_cuts.f90 cp $< $@ model_test.run: tdefs.$(FC_MODULE_EXT) tglue.$(FC_MODULE_EXT) \ threeshl.$(FC_MODULE_EXT) tscript.$(FC_MODULE_EXT) tdefs.mod: $(top_builddir)/src/models/threeshl_bundle/tdefs.$(FC_MODULE_EXT) cp $< $@ tglue.mod: $(top_builddir)/src/models/threeshl_bundle/tglue.$(FC_MODULE_EXT) cp $< $@ tscript.mod: $(top_builddir)/src/models/threeshl_bundle/tscript.$(FC_MODULE_EXT) cp $< $@ threeshl.mod: $(top_builddir)/src/models/threeshl_bundle/threeshl.$(FC_MODULE_EXT) cp $< $@ WT_OCAML_NATIVE_EXT=opt if OCAML_AVAILABLE OMEGA_QED = $(top_builddir)/omega/bin/omega_QED.$(WT_OCAML_NATIVE_EXT) OMEGA_QCD = $(top_builddir)/omega/bin/omega_QCD.$(WT_OCAML_NATIVE_EXT) OMEGA_MSSM = $(top_builddir)/omega/bin/omega_MSSM.$(WT_OCAML_NATIVE_EXT) omega_MSSM.$(WT_OMEGA_CACHE_SUFFIX): $(OMEGA_MSSM) $(OMEGA_MSSM) -initialize . UFO_TAG_FILE = __init__.py UFO_MODELPATH = ../models/UFO ufo_1.run: ufo_1_SM/$(UFO_TAG_FILE) ufo_2.run: ufo_2_SM/$(UFO_TAG_FILE) ufo_3.run: ufo_3_models/ufo_3_SM/$(UFO_TAG_FILE) ufo_4.run: ufo_4_models/ufo_4_SM/$(UFO_TAG_FILE) ufo_5.run: ufo_5_SM/$(UFO_TAG_FILE) ufo_1_SM/$(UFO_TAG_FILE): $(UFO_MODELPATH)/SM/$(UFO_TAG_FILE) mkdir -p ufo_1_SM cp $(UFO_MODELPATH)/SM/*.py ufo_1_SM ufo_2_SM/$(UFO_TAG_FILE): $(UFO_MODELPATH)/SM/$(UFO_TAG_FILE) mkdir -p ufo_2_SM cp $(UFO_MODELPATH)/SM/*.py ufo_2_SM ufo_3_models/ufo_3_SM/$(UFO_TAG_FILE): $(UFO_MODELPATH)/SM/$(UFO_TAG_FILE) mkdir -p ufo_3_models/ufo_3_SM cp $(UFO_MODELPATH)/SM/*.py ufo_3_models/ufo_3_SM ufo_4_models/ufo_4_SM/$(UFO_TAG_FILE): $(UFO_MODELPATH)/SM/$(UFO_TAG_FILE) mkdir -p ufo_4_models/ufo_4_SM cp $(UFO_MODELPATH)/SM/*.py ufo_4_models/ufo_4_SM ufo_5_SM/$(UFO_TAG_FILE): $(UFO_MODELPATH)/SM/$(UFO_TAG_FILE) mkdir -p ufo_5_SM cp $(UFO_MODELPATH)/SM/*.py ufo_5_SM ufo_5.run: ufo_5_test.slha ufo_5_test.slha: $(top_builddir)/share/tests/functional_tests/ufo_5_test.slha cp $< $@ $(UFO_MODELPATH)/SM/$(UFO_TAG_FILE): $(top_srcdir)/omega/tests/UFO/SM/$(UFO_TAG_FILE) $(MAKE) -C $(UFO_MODELPATH)/SM all endif OCAML_AVAILABLE if MPOST_AVAILABLE $(TESTS_REQ_GAMELAN): gamelan.sty gamelan.sty: $(top_builddir)/src/gamelan/gamelan.sty cp $< $@ $(top_builddir)/src/gamelan/gamelan.sty: $(MAKE) -C $(top_builddir)/src/gamelan gamelan.sty endif noinst_PROGRAMS = if OCAML_AVAILABLE noinst_PROGRAMS += resonances_1_count resonances_1_count_SOURCES = resonances_1_count.f90 resonances_1.run: resonances_1_count noinst_PROGRAMS += resonances_2_count resonances_2_count_SOURCES = resonances_2_count.f90 resonances_2.run: resonances_2_count noinst_PROGRAMS += resonances_3_count resonances_3_count_SOURCES = resonances_3_count.f90 resonances_3.run: resonances_3_count noinst_PROGRAMS += resonances_4_count resonances_4_count_SOURCES = resonances_4_count.f90 resonances_4.run: resonances_4_count noinst_PROGRAMS += resonances_9_count resonances_9_count_SOURCES = resonances_9_count.f90 resonances_9.run: resonances_9_count noinst_PROGRAMS += resonances_10_count resonances_10_count_SOURCES = resonances_10_count.f90 resonances_10.run: resonances_10_count noinst_PROGRAMS += resonances_11_count resonances_11_count_SOURCES = resonances_11_count.f90 resonances_11.run: resonances_11_count noinst_PROGRAMS += epa_2_count epa_2_count_SOURCES = epa_2_count.f90 epa_2.run: epa_2_count noinst_PROGRAMS += isr_epa_1_count isr_epa_1_count_SOURCES = isr_epa_1_count.f90 isr_epa_1.run: isr_epa_1_count noinst_PROGRAMS += analyze_6_check analyze_6_check_SOURCES = analyze_6_check.f90 analyze_6.run: analyze_6_check endif if HEPMC_AVAILABLE TESTS_SRC += $(hepmc_6_rd_SOURCES) noinst_PROGRAMS += hepmc_6_rd if HEPMC_IS_VERSION3 hepmc_6_rd_SOURCES = hepmc3_6_rd.cpp else hepmc_6_rd_SOURCES = hepmc2_6_rd.cpp endif hepmc_6_rd_CXXFLAGS = $(HEPMC_INCLUDES) $(AM_CXXFLAGS) hepmc_6_rd_LDADD = $(LDFLAGS_HEPMC) hepmc_6.run: hepmc_6_rd endif if LCIO_AVAILABLE TESTS_SRC += $(lcio_rd_SOURCES) noinst_PROGRAMS += lcio_rd lcio_rd_SOURCES = lcio_rd.cpp lcio_rd_CXXFLAGS = $(LCIO_INCLUDES) $(AM_CXXFLAGS) lcio_rd_LDADD = $(LDFLAGS_LCIO) lcio_1.run: lcio_rd lcio_2.run: lcio_rd lcio_3.run: lcio_rd lcio_4.run: lcio_rd lcio_5.run: lcio_rd lcio_10.run: lcio_rd endif stdhep_4.run: stdhep_rd stdhep_5.run: stdhep_rd stdhep_6.run: stdhep_rd polarized_1.run: stdhep_rd tauola_1.run: stdhep_rd tauola_2.run: stdhep_rd stdhep_rd: $(top_builddir)/src/xdr/stdhep_rd cp $< $@ susyhit.in: $(top_builddir)/share/tests/functional_tests/susyhit.in cp $< $@ BUILT_SOURCES = \ TESTFLAG \ HEPMC2_FLAG \ HEPMC3_FLAG \ LCIO_FLAG \ FASTJET_FLAG \ LHAPDF5_FLAG \ LHAPDF6_FLAG \ GAMELAN_FLAG \ MPI_FLAG \ EVENT_ANALYSIS_FLAG \ OCAML_FLAG \ PYTHIA6_FLAG \ PYTHIA8_FLAG \ OPENLOOPS_FLAG \ RECOLA_FLAG \ GZIP_FLAG \ STATIC_FLAG \ ref-output # If this file is found in the working directory, WHIZARD # will use the paths for the uninstalled version (source/build tree), # otherwise it uses the installed version TESTFLAG: touch $@ FASTJET_FLAG: if FASTJET_AVAILABLE touch $@ endif HEPMC2_FLAG: if HEPMC2_AVAILABLE touch $@ endif HEPMC3_FLAG: if HEPMC3_AVAILABLE touch $@ endif LCIO_FLAG: if LCIO_AVAILABLE touch $@ endif LHAPDF5_FLAG: if LHAPDF5_AVAILABLE touch $@ endif LHAPDF6_FLAG: if LHAPDF6_AVAILABLE touch $@ endif GAMELAN_FLAG: if MPOST_AVAILABLE touch $@ endif MPI_FLAG: if FC_USE_MPI touch $@ endif OCAML_FLAG: if OCAML_AVAILABLE touch $@ endif PYTHIA6_FLAG: if PYTHIA6_AVAILABLE touch $@ endif PYTHIA8_FLAG: if PYTHIA8_AVAILABLE touch $@ endif OPENLOOPS_FLAG: if OPENLOOPS_AVAILABLE touch $@ endif RECOLA_FLAG: if RECOLA_AVAILABLE touch $@ endif EVENT_ANALYSIS_FLAG: if EVENT_ANALYSIS_AVAILABLE touch $@ endif GZIP_FLAG: if GZIP_AVAILABLE touch $@ endif STATIC_FLAG: if STATIC_AVAILABLE touch $@ endif # The reference output files are in the source directory. Copy them here. if FC_QUAD ref-output: $(top_srcdir)/share/tests/functional_tests/ref-output mkdir -p ref-output for f in $> $name.log + cat ${name}_in.weights.dat >> $name.log + echo "Contents of ${name}_raw.weights.dat" >> $name.log + cat ${name}_raw.weights.dat >> $name.log + echo "Contents of ${name}_lhef.weights.dat" >> $name.log + cat ${name}_lhef.weights.dat >> $name.log + diff ref-output/`basename @script@`.ref `basename @script@`.log +else + echo "|=============================================================================|" + echo "No O'Mega matrix elements available, test skipped" + exit 77 +fi +