From ef5a9688f882294bcf5e4a9958b4319e63c310fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 12 Dec 2017 22:31:47 +0100 Subject: [PATCH 01/81] add option custom_photon_field --- src/PhotonBackground.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/PhotonBackground.cpp b/src/PhotonBackground.cpp index 18187bbfd..bc734f4d6 100644 --- a/src/PhotonBackground.cpp +++ b/src/PhotonBackground.cpp @@ -50,6 +50,7 @@ static PhotonFieldScaling scalingDominguez11("IRB_Dominguez11"); static PhotonFieldScaling scalingGilmore12("IRB_Gilmore12"); static PhotonFieldScaling scalingStecker16_upper("IRB_Stecker16_upper"); static PhotonFieldScaling scalingStecker16_lower("IRB_Stecker16_lower"); +static PhotonFieldScaling scalingCustomPhotonField("custom_photon_field"); double photonFieldScaling(PhotonField photonField, double z) { switch (photonField) { @@ -79,6 +80,8 @@ double photonFieldScaling(PhotonField photonField, double z) { return pow((1 + 0.8) / (1 + z), 4); else return 0; + case custom_photon_field: + return custom_photon_field.scalingFactor(z); default: throw std::runtime_error("PhotonField: unknown photon background"); } @@ -107,6 +110,8 @@ std::string photonFieldName(PhotonField photonField) { return "IRB_Stecker16_lower"; case URB_Protheroe96: return "URB_Protheroe96"; + case custom_photon_field: + return "custom_photon_field" default: throw std::runtime_error("PhotonField: unknown photon background"); } From 13a9a877ccdc59560eeaf770124237d97a7e7143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 12 Dec 2017 22:51:57 +0100 Subject: [PATCH 02/81] reset original content --- src/PhotonBackground.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/PhotonBackground.cpp b/src/PhotonBackground.cpp index bc734f4d6..18187bbfd 100644 --- a/src/PhotonBackground.cpp +++ b/src/PhotonBackground.cpp @@ -50,7 +50,6 @@ static PhotonFieldScaling scalingDominguez11("IRB_Dominguez11"); static PhotonFieldScaling scalingGilmore12("IRB_Gilmore12"); static PhotonFieldScaling scalingStecker16_upper("IRB_Stecker16_upper"); static PhotonFieldScaling scalingStecker16_lower("IRB_Stecker16_lower"); -static PhotonFieldScaling scalingCustomPhotonField("custom_photon_field"); double photonFieldScaling(PhotonField photonField, double z) { switch (photonField) { @@ -80,8 +79,6 @@ double photonFieldScaling(PhotonField photonField, double z) { return pow((1 + 0.8) / (1 + z), 4); else return 0; - case custom_photon_field: - return custom_photon_field.scalingFactor(z); default: throw std::runtime_error("PhotonField: unknown photon background"); } @@ -110,8 +107,6 @@ std::string photonFieldName(PhotonField photonField) { return "IRB_Stecker16_lower"; case URB_Protheroe96: return "URB_Protheroe96"; - case custom_photon_field: - return "custom_photon_field" default: throw std::runtime_error("PhotonField: unknown photon background"); } From 99fbb85068953b4ec3e084a69e531c32c6f03331 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 17:55:50 +0100 Subject: [PATCH 03/81] - adapt input and output parameters of the new SOPHIA code - update docstrings --- libs/sophia/sophia.h | 51 ++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/libs/sophia/sophia.h b/libs/sophia/sophia.h index fe7e1b6dd..b2e092892 100644 --- a/libs/sophia/sophia.h +++ b/libs/sophia/sophia.h @@ -1,37 +1,36 @@ #ifndef _SOPHIA_H #define _SOPHIA_H + extern "C" { -void sophiaevent_(int& channel, double& inputenergy, double momentum[][2000], - int id[], int& n, double& redshift, int& photonbackground, double& maxz, - int&, double[], double[]); +void sophiaevent_(int& type, double& inputEnergy, double& e, double momentum[2000], + int id[], int& n); } + +// void sophiaevent_(int& nature, // channel: 0 -> p, 1 -> n +// double& Ein, // input energy of nucleon in GeV +// double momentaList[][2000], // list of 4-momenta + masses of output particles (in GeV) +// double particleList[2000], +// int& nParticles, // number of output particles +// double& eps // energy of target photon in eV +// ); +// } + + /* - The arguments are the following - - channel: 0 -> p, 1 -> n - - input energy of nucleon in GeV - - list of 4-momenta + masses of output particles (in GeV) - list of output particle ids - 13 proton - 14 neutron - -13 antiproton - -14 antineutron - 1 photon - 2 e+ - 3 e- - 15 nu_e - 16 antinu_e - 17 nu_muon - 18 antinu_muon - - number of output particles - - redshift - - photon background flag: 1 -> CMB, 2 -> IRB Kneiske - (Primack et al. (1999) IRB is outcommented in sophia_interface.f on line 16320 - - maximum redshift: the photon density of IRB is null above this redshift - - dummy1 - - dummy2 - - dummy3 + 13 proton + 14 neutron + -13 antiproton + -14 antineutron + 1 photon + 2 e+ + 3 e- + 15 nu_e + 16 antinu_e + 17 nu_muon + 18 antinu_muon */ #endif From cb44195dd93db11665672138467adb8c68287fea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 17:58:58 +0100 Subject: [PATCH 04/81] - remove unused parts of the code - remove internal background photon sampling - remove unused input- and output parameters - rename some variables to gain readability - replace GOTO statements by safe control structures - implement unified indentation scheme - simplify functions where appropriate --- libs/sophia/sophia_interface.f | 11399 +++++-------------------------- 1 file changed, 1776 insertions(+), 9623 deletions(-) diff --git a/libs/sophia/sophia_interface.f b/libs/sophia/sophia_interface.f index c1dd4ac84..d47c5a064 100644 --- a/libs/sophia/sophia_interface.f +++ b/libs/sophia/sophia_interface.f @@ -18,12 +18,11 @@ c***************************************************************************** - subroutine eventgen(L0,E0,eps,theta,Imode) - + SUBROUTINE eventgen(L0,E0,eps,theta,Imode) c******************************************************* -c** subroutine for photopion production of ** +c** SUBROUTINE for photopion production of ** c** relativistic nucleons in a soft photon field ** -c** subroutine for SOPHIA inVersion 1.2 ** +c** SUBROUTINE for SOPHIA inVersion 1.2 ** c****** INPUT ****************************************** c E0 = energy of incident proton (in lab frame) [in GeV] c eps = energy of incident photon [in GeV] (in lab frame) @@ -33,22 +32,15 @@ subroutine eventgen(L0,E0,eps,theta,Imode) c P(2000,5) = 5-momentum of produced particles c LLIST(2000) = code numbers of produced particles c NP = number of produced particles -c*************************************************************** -c** Date: 20/01/98 ** -c** correct.:19/02/98 ** -c** change: 23/05/98 ** -c** last change:06/09/98 ** -c** authors: A.Muecke ** -c** R.Engel ** -c************************** +C c*************************************************************** IMPLICIT DOUBLE PRECISION (A-H,O-Z) SAVE - COMMON /S_RUN/ SQS, S, Q2MIN, XMIN, ZMIN, kb, kt, a1, a2, Nproc - COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb - COMMON /S_MASS1/ AM(49), AM2(49) - COMMON /S_CHP/ S_LIFE(49), ICHP(49), ISTR(49), IBAR(49) - COMMON /S_CSYDEC/ CBR(102), IDB(49), KDEC(612), LBARP(49) + COMMON /S_RUN/ SQS, S, Q2MIN, XMIN, ZMIN, kb, kt, a1, a2, Nproc + COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb + COMMON /S_MASS1/ AM(49), AM2(49) + COMMON /S_CHP/ S_LIFE(49), ICHP(49), ISTR(49), IBAR(49) + COMMON /S_CSYDEC/ CBR(102), IDB(49), KDEC(612), LBARP(49) CHARACTER NAMPRES*6 COMMON /RES_PROP/ AMRES(9), SIG0(9),WIDTH(9), @@ -62,153 +54,95 @@ subroutine eventgen(L0,E0,eps,theta,Imode) COMMON /RES_PROPn/ AMRESn(9), BGAMMAn(9),WIDTHn(9), + RATIOJn(9),NAMPRESn(0:9) - DOUBLE PRECISION P_nuc(4),P_gam(4),P_sum(4),PC(4),GamBet(4) - - DATA pi /3.141593D0/ - DATA IRESMAX /9/ - DATA Icount / 0 / + DOUBLE PRECISION P_nuc(4),P_gam(4),P_sum(4),PC(4),GamBet(4) -c****** INPUT ************************************************** -c E0 = energy of incident proton (in lab frame) [in GeV] -c eps = energy of incident photon [in GeV] (in lab frame) -c theta = angle between incident proton and photon [in degrees] -c L0 = code number of the incident nucleon + DATA pi /3.141593D0/ + DATA IRESMAX /9/ + DATA Icount / 0 / c*************************************************************** -c** calculate eps_prime = photon energy in nuclear rest frame, -c** sqrt(s) = CMF energy of the N\gamma-system - -c... declare stable particles: +c** calculate eps_prime = photon energy in nuclear rest frame, +c** sqrt(s) = CMF energy of the N\gamma-system -C muons stable -c IDB(4) = -ABS(IDB(4)) -c IDB(5) = -ABS(IDB(5)) -C -C pi+,pi0,pi- stable -c IDB(6) = -ABS(IDB(6)) -c IDB(7) = -ABS(IDB(7)) -c IDB(8) = -ABS(IDB(8)) -C -C Deltas stable -C IDB(40) = -ABS(IDB(40)) -C IDB(41) = -ABS(IDB(41)) -C IDB(42) = -ABS(IDB(42)) -C IDB(43) = -ABS(IDB(43)) -C rho, omega, phi stable -C IDB(25) = -ABS(IDB(25)) -C IDB(26) = -ABS(IDB(26)) -C IDB(27) = -ABS(IDB(27)) -C IDB(32) = -ABS(IDB(32)) -C IDB(33) = -ABS(IDB(33)) -C print *,' WARNING: Deltas, eta, VMs are stable in this version' - -C rho0,omega stable -c IDB(27) = -ABS(IDB(27)) -c IDB(32) = -ABS(IDB(32)) - -C STRANGE PARTICLES: -C kaons stable -c IDB(9) = -ABS(IDB(9)) -c IDB(10) = -ABS(IDB(10)) - -C IDB(11) = -ABS(IDB(11)) -C IDB(12) = -ABS(IDB(12)) -C IDB(21) = -ABS(IDB(21)) -C IDB(22) = -ABS(IDB(22)) -C kaons* stable -c IDB(28) = -ABS(IDB(28)) -c IDB(29) = -ABS(IDB(29)) -c IDB(30) = -ABS(IDB(30)) -c IDB(31) = -ABS(IDB(31)) - -C eta stable -C IDB(23) = -ABS(IDB(23)) - - -C incoming nucleon - pm = AM(L0) - P_nuc(1) = 0.D0 - P_nuc(2) = 0.D0 - P_nuc(3) = SQRT(MAX((E0-pm)*(E0+pm),0.D0)) - P_nuc(4) = E0 -C incoming photon - P_gam(1) = EPS*SIN(theta*pi/180.D0) - P_gam(2) = 0.D0 - P_gam(3) = -EPS*COS(theta*pi/180.D0) - P_gam(4) = EPS - - Esum = P_nuc(4)+P_gam(4) - PXsum = P_nuc(1)+P_gam(1) - PYsum = P_nuc(2)+P_gam(2) - PZsum = P_nuc(3)+P_gam(3) - IQchr = ICHP(1)+ICHP(L0) - IQbar = IBAR(1)+IBAR(L0) - - gammap = E0/pm - xx = 1.D0/gammap - if(gammap.gt.1000.D0) then - betap = 1.D0 - 0.5D0*xx**2 - 0.125D0*xx**4 - else - betap = sqrt(1.D0-xx)*sqrt(1.D0+xx) - endif -c Etot = E0+eps - s = pm*pm + 2.D0*eps*E0*(1.D0-betap*cos(theta*pi/180.D0)) - - sqsm = sqrt(s) - eps_prime = (s-pm*pm)/2.D0/pm - -C calculate Lorentz boots and rotation - P_sum(1) = P_nuc(1)+P_gam(1) - P_sum(2) = P_nuc(2)+P_gam(2) - P_sum(3) = P_nuc(3)+P_gam(3) - P_sum(4) = P_nuc(4)+P_gam(4) -C Lorentz transformation into c.m. system +C incoming nucleon + pm = AM(L0) + P_nuc(1) = 0.D0 + P_nuc(2) = 0.D0 + P_nuc(3) = SQRT(MAX((E0-pm)*(E0+pm),0.D0)) + P_nuc(4) = E0 +C incoming photon + P_gam(1) = EPS*SIN(theta*pi/180.D0) + P_gam(2) = 0.D0 + P_gam(3) = -EPS*COS(theta*pi/180.D0) + P_gam(4) = EPS + + Esum = P_nuc(4)+P_gam(4) + PXsum = P_nuc(1)+P_gam(1) + PYsum = P_nuc(2)+P_gam(2) + PZsum = P_nuc(3)+P_gam(3) + IQchr = ICHP(1)+ICHP(L0) + IQbar = IBAR(1)+IBAR(L0) + + gammap = E0/pm + xx = 1.D0/gammap + if(gammap.gt.1000.D0) then + betap = 1.D0 - 0.5D0*xx**2 - 0.125D0*xx**4 + else + betap = sqrt(1.D0-xx)*sqrt(1.D0+xx) + endif + s = pm*pm + 2.D0*eps*E0*(1.D0-betap*cos(theta*pi/180.D0)) + sqsm = sqrt(s) + eps_prime = (s-pm*pm)/2.D0/pm +C calculate Lorentz boots and rotation + P_sum(1) = P_nuc(1)+P_gam(1) + P_sum(2) = P_nuc(2)+P_gam(2) + P_sum(3) = P_nuc(3)+P_gam(3) + P_sum(4) = P_nuc(4)+P_gam(4) +C Lorentz transformation into c.m. system DO I=1,4 - GamBet(I) = P_sum(I)/sqsm + GamBet(I) = P_sum(I)/sqsm ENDDO -C calculate rotation angles - IF(GamBet(4).lt.1.d5) then -C transform nucleon vector - GamBet(1) = -GamBet(1) - GamBet(2) = -GamBet(2) - GamBet(3) = -GamBet(3) - CALL PO_ALTRA(GamBet(4),GamBet(1),GamBet(2),GamBet(3), - & P_nuc(1),P_nuc(2),P_nuc(3),P_nuc(4),Ptot, - & PC(1),PC(2),PC(3),PC(4)) - GamBet(1) = -GamBet(1) - GamBet(2) = -GamBet(2) - GamBet(3) = -GamBet(3) -C rotation angle: nucleon moves along +z - COD = PC(3)/Ptot - SID = SQRT(PC(1)**2+PC(2)**2)/Ptot - COF = 1.D0 - SIF = 0.D0 - IF(Ptot*SID.GT.1.D-5) THEN - COF=PC(1)/(SID*Ptot) - SIF=PC(2)/(SID*Ptot) - Anorf=SQRT(COF*COF+SIF*SIF) - COF=COF/Anorf - SIF=SIF/Anorf - ENDIF +C calculate rotation angles + if (GamBet(4).lt.1.d5) then +C transform nucleon vector + GamBet(1) = -GamBet(1) + GamBet(2) = -GamBet(2) + GamBet(3) = -GamBet(3) + CALL PO_ALTRA(GamBet(4),GamBet(1),GamBet(2),GamBet(3), + & P_nuc(1),P_nuc(2),P_nuc(3),P_nuc(4),Ptot, + & PC(1),PC(2),PC(3),PC(4)) + GamBet(1) = -GamBet(1) + GamBet(2) = -GamBet(2) + GamBet(3) = -GamBet(3) +C rotation angle: nucleon moves along +z + COD = PC(3)/Ptot + SID = SQRT(PC(1)**2+PC(2)**2)/Ptot + COF = 1.D0 + SIF = 0.D0 + IF(Ptot*SID.GT.1.D-5) THEN + COF=PC(1)/(SID*Ptot) + SIF=PC(2)/(SID*Ptot) + Anorf=SQRT(COF*COF+SIF*SIF) + COF=COF/Anorf + SIF=SIF/Anorf + ENDIF else - COD = 1.D0 - SID = 0.D0 - COF = 1.D0 - SIF = 0.D0 + COD = 1.D0 + SID = 0.D0 + COF = 1.D0 + SIF = 0.D0 endif - c... check for threshold: - sth = 1.1646D0 - if (s.lt.sth) then - print*,'input energy below threshold for photopion production !' - print*,'sqrt(s) = ',sqrt(s) - NP = 0 - RETURN - endif - - 200 continue + sth = 1.1646D0 + if (s.lt.sth) then + PRINT*,'input energy below threshold for + & photopion production !' + PRINT*,'sqrt(s) = ',sqrt(s) + NP = 0 + RETURN + endif + Icount = Icount+1 Imode = 0 - c******************************************************************* c decide which process occurs: *** c (1) decay of resonance *** @@ -216,99 +150,89 @@ subroutine eventgen(L0,E0,eps,theta,Imode) c virtual pions in nucleon cloud) and diffractive scattering *** c (3) multipion production *** c******************************************************************* - - call dec_inter3(eps_prime,Imode,L0) - + call dec_inter3(eps_prime,Imode,L0) c********************************************* c******* PARTICLE PRODUCTION ***************** c********************************************* -c 42 continue - if (Imode.le.5) then + if (Imode.le.5) then c... direct/multipion/diffractive scattering production channel: - call GAMMA_H(sqsm,L0,Imode,Ifbad) - if(Ifbad.ne.0) then - print *,' eventgen: simulation of particle production failed' - goto 200 - endif + call GAMMA_H(sqsm,L0,Imode,Ifbad) + if(Ifbad.ne.0) then + PRINT *,' eventgen: simulation of particle + & production failed' + endif else if (Imode.eq.6) then -c... Resonances: -c... decide which resonance decays with ID=IRES in list: -c... IRESMAX = number of considered resonances = 9 so far - IRES = 0 - 46 call dec_res2(eps_prime,IRES,IRESMAX,L0) - Nproc = 10+IRES - call dec_proc2(eps_prime,IPROC,IRANGE,IRES,L0) +c... Resonances: +c... decide which resonance decays with ID=IRES in list: +c... IRESMAX = number of considered resonances = 9 so far + IRES = 0 + 46 call dec_res2(eps_prime,IRES,IRESMAX,L0) + Nproc = 10+IRES + call dec_proc2(eps_prime,IPROC,IRANGE,IRES,L0) c 2-particle decay of resonance in CM system: - NP = 2 - call res_decay3(IRES,IPROC,IRANGE,s,L0,nbad) - if (nbad.eq.1) then - print *,' eventgen: event rejected by res_decay3' - goto 46 - endif - call DECSIB + NP = 2 + call res_decay3(IRES,IPROC,IRANGE,s,L0,nbad) + if (nbad.eq.1) then + PRINT *,' eventgen: event rejected by res_decay3' + goto 46 + endif + call DECSIB else - print*,'invalid Imode !!' + PRINT*,'invalid Imode !!' STOP endif - c... consider only stable particles: - 18 istable=0 - do 16 i=1,NP - if (abs(LLIST(i)).lt.10000) then - istable = istable+1 - LLIST(istable) = LLIST(i) - P(istable,1) = P(i,1) - P(istable,2) = P(i,2) - P(istable,3) = P(i,3) - P(istable,4) = P(i,4) - P(istable,5) = P(i,5) - endif - 16 continue - if (NP.gt.istable) then - do i=istable+1,NP - LLIST(i) = 0 - P(i,1) = 0. - P(i,2) = 0. - P(i,3) = 0. - P(i,4) = 0. - P(i,5) = 0. + istable=0 + do 16 i=1,NP + if (abs(LLIST(i)).lt.10000) then + istable = istable+1 + LLIST(istable) = LLIST(i) + P(istable,1) = P(i,1) + P(istable,2) = P(i,2) + P(istable,3) = P(i,3) + P(istable,4) = P(i,4) + P(istable,5) = P(i,5) + endif + 16 CONTINUE + if (NP.gt.istable) then + do i=istable+1,NP + LLIST(i) = 0 + P(i,1) = 0. + P(i,2) = 0. + P(i,3) = 0. + P(i,4) = 0. + P(i,5) = 0. enddo - endif - NP = istable - + endif + NP = istable c*********************************************** c transformation from CM-system to lab-system: * c*********************************************** - DO I=1,NP - CALL PO_TRANS(P(I,1),P(I,2),P(I,3),COD,SID,COF,SIF, - & PC(1),PC(2),PC(3)) - PC(4) = P(I,4) - CALL PO_ALTRA(GamBet(4),GamBet(1),GamBet(2),GamBet(3), - & PC(1),PC(2),PC(3),PC(4),Ptot, - & P(I,1),P(I,2),P(I,3),P(I,4)) + CALL PO_TRANS(P(I,1),P(I,2),P(I,3),COD,SID,COF,SIF, + & PC(1),PC(2),PC(3)) + PC(4) = P(I,4) + CALL PO_ALTRA(GamBet(4),GamBet(1),GamBet(2),GamBet(3), + & PC(1),PC(2),PC(3),PC(4),Ptot, + & P(I,1),P(I,2),P(I,3),P(I,4)) ENDDO -c call check_event(Icount,Esum,PXsum,PYsum,PZsum,IQchr,IQbar,Irej) -c if(Irej.ne.0) then -c print *,' eventgen: event rejected by check_event' -c goto 200 -c endif - - return - - END + RETURN + END SUBROUTINE eventgen -c***************************** -c*** List of SUBROUTINES ***** -C***************************** +c******************************* +c*** FUNCTIONS & SUBROUTINES *** +C******************************* DOUBLE PRECISION function crossection(x,NDIR,NL0) - +c***************************************************** +C calculates crossection of Nucleon-gamma-interaction +C (see thesis of J.Rachen, p.45ff and corrections +C report from 27/04/98, 5/05/98, 22/05/98 of J.Rachen) +C***************************************************** IMPLICIT DOUBLE PRECISION (A-M,O-Z) IMPLICIT INTEGER (N) - SAVE CHARACTER NAMPRES*6 @@ -318,278 +242,211 @@ DOUBLE PRECISION function crossection(x,NDIR,NL0) DIMENSION sig_res(9) - external breitwigner, Ef, singleback, twoback + EXTERNAL breitwigner, Ef, singleback, twoback - DATA sth /1.1646D0/ + DATA sth /1.1646D0/ -c***************************************************** -C calculates crossection of N-gamma-interaction -C (see thesis of J.Rachen, p.45ff and corrections -C report from 27/04/98, 5/05/98, 22/05/98 of J.Rachen) -C***************************************************** -c** Date: 20/01/98 ** -c** correct.:27/04/98** -c** update: 23/05/98 ** -c** author: A.Muecke ** -c********************** -c -c x = eps_prime in GeV - pm = AM(NL0) - s = pm*pm+2.D0*pm*x +c x = eps_prime in GeV + pm = AM(NL0) + s = pm*pm+2.D0*pm*x - if (s.lt.sth) then - crossection = 0. - RETURN - endif - if (x.gt.10.D0) then -c only multipion production: - cross_res = 0.D0 - cross_dir = 0.D0 - cross_dir1 = 0.D0 - cross_dir2 = 0.D0 - goto 10 - endif - + if (s.lt.sth) then + crossection = 0. + RETURN + endif + if (x.gt.10.D0) then +c only multipion production: + cross_res = 0.D0 + cross_dir = 0.D0 + cross_dir1 = 0.D0 + cross_dir2 = 0.D0 + goto 10 + endif c**************************** c RESONANCES: c**************************** - cross_res = 0.D0 - cross_res = breitwigner(SIG0(1),WIDTH(1),AMRES(1),x) - & *Ef(x,0.152D0,0.17D0) - sig_res(1) = cross_res - DO N=2,9 - - sig_res(N) = breitwigner(SIG0(N),WIDTH(N),AMRES(N),x) - & *Ef(x,0.15D0,0.38D0) - cross_res = cross_res + sig_res(N) + & * Ef(x,0.152D0,0.17D0) + sig_res(1) = cross_res + DO N=2,9 + sig_res(N) = breitwigner(SIG0(N),WIDTH(N),AMRES(N),x) + & * Ef(x,0.15D0,0.38D0) + cross_res = cross_res + sig_res(N) ENDDO - c**************************** c DIRECT CHANNEL: c**************************** - - if((x.gt.0.1D0).and.(x.lt.0.6D0)) then - cross_dir1 = singleback(x) + if((x.gt.0.1D0).and.(x.lt.0.6D0)) then + cross_dir1 = singleback(x) & + 40.D0*exp(-(x-0.29D0)**2/0.002D0) & - 15.D0*exp(-(x-0.37D0)**2/0.002D0) - else - cross_dir1 = singleback(x) - endif - cross_dir2 = twoback(x) - - cross_dir = cross_dir1 + cross_dir2 - + else + cross_dir1 = singleback(x) + endif + cross_dir2 = twoback(x) + cross_dir = cross_dir1 + cross_dir2 c**************************** c FRAGMENTATION 2: c**************************** - 10 continue - if (NL0.eq.13) then - cross_frag2 = 80.3D0*Ef(x,0.5D0,0.1D0)*(s**(-0.34D0)) - else if (NL0.eq.14) then - cross_frag2 = 60.2D0*Ef(x,0.5D0,0.1D0)*(s**(-0.34D0)) - endif - + 10 CONTINUE + if (NL0.eq.13) then + cross_frag2 = 80.3D0*Ef(x,0.5D0,0.1D0)*(s**(-0.34D0)) + else if (NL0.eq.14) then + cross_frag2 = 60.2D0*Ef(x,0.5D0,0.1D0)*(s**(-0.34D0)) + endif c**************************************************** c MULTIPION PRODUCTION/FRAGMENTATION 1 CROSS SECTION c**************************************************** - if (x.gt.0.85D0) then - ss1 = (x-.85D0)/.69D0 - if (NL0.eq.13) then - ss2 = 29.3D0*(s**(-.34D0))+59.3D0*(s**.095D0) - else if (NL0.eq.14) then - ss2 = 26.4D0*(s**(-.34D0))+59.3D0*(s**.095D0) - endif - cs_multidiff = (1.-exp(-ss1))*ss2 - cs_multi = 0.89D0*cs_multidiff - + if (x.gt.0.85D0) then + ss1 = (x-.85D0)/.69D0 + if (NL0.eq.13) then + ss2 = 29.3D0*(s**(-.34D0))+59.3D0*(s**.095D0) + else if (NL0.eq.14) then + ss2 = 26.4D0*(s**(-.34D0))+59.3D0*(s**.095D0) + endif + cs_multidiff = (1.-exp(-ss1))*ss2 + cs_multi = 0.89D0*cs_multidiff c**************************** c DIFFRACTIVE SCATTERING: c**************************** - - cross_diffr1 = .099D0*cs_multidiff - cross_diffr2 = .011D0*cs_multidiff - cross_diffr = 0.11D0*cs_multidiff - + cross_diffr1 = .099D0*cs_multidiff + cross_diffr2 = .011D0*cs_multidiff + cross_diffr = 0.11D0*cs_multidiff C*********************************************************************** - - ss1 = ((x-.85D0)**.75D0)/.64D0 - ss2 = 74.1D0*(x**(-.44D0))+62.D0*(s**.08D0) - cs_tmp = 0.96D0*(1.D0-exp(-ss1))*ss2 - cross_diffr1 = 0.14D0*cs_tmp - cross_diffr2 = 0.013D0*cs_tmp - cs_delta = cross_frag2 - (cross_diffr1+cross_diffr2-cross_diffr) - if(cs_delta.lt.0.D0) then - cross_frag2 = 0.D0 - cs_multi = cs_multi+cs_delta - else - cross_frag2 = cs_delta - endif - cross_diffr = cross_diffr1 + cross_diffr2 - cs_multidiff = cs_multi + cross_diffr - + ss1 = ((x-.85D0)**.75D0)/.64D0 + ss2 = 74.1D0*(x**(-.44D0))+62.D0*(s**.08D0) + cs_tmp = 0.96D0*(1.D0-exp(-ss1))*ss2 + cross_diffr1 = 0.14D0*cs_tmp + cross_diffr2 = 0.013D0*cs_tmp + cs_delta = cross_frag2 + & - (cross_diffr1+cross_diffr2-cross_diffr) + if(cs_delta.lt.0.D0) then + cross_frag2 = 0.D0 + cs_multi = cs_multi+cs_delta + else + cross_frag2 = cs_delta + endif + cross_diffr = cross_diffr1 + cross_diffr2 + cs_multidiff = cs_multi + cross_diffr C*********************************************************************** + else + cross_diffr = 0.D0 + cross_diffr1 = 0.D0 + cross_diffr2 = 0.D0 + cs_multidiff = 0.D0 + cs_multi = 0.D0 + endif - - else - cross_diffr = 0.D0 - cross_diffr1 = 0.D0 - cross_diffr2 = 0.D0 - cs_multidiff = 0.D0 - cs_multi = 0.D0 - endif - - if (NDIR.eq.3) then - - crossection = cross_res+cross_dir+cs_multidiff+cross_frag2 - RETURN - - else if (NDIR.eq.0) then - - crossection = cross_res+cross_dir+cross_diffr+cross_frag2 - RETURN - - else if (NDIR.eq.2) then - - crossection = cross_res+cross_dir - RETURN - - else if (NDIR.eq.1) then - - crossection = cross_res - RETURN - - else if (NDIR.eq.4) then - - crossection = cross_dir - RETURN - - else if (NDIR.eq.5) then - - crossection = cs_multi - RETURN - - else if (NDIR.eq.6) then - - crossection = cross_res+cross_dir2 - RETURN - - else if (NDIR.eq.7) then - - crossection = cross_res+cross_dir1 - RETURN - - else if (NDIR.eq.8) then - - crossection = cross_res+cross_dir+cross_diffr1 - RETURN - - else if (NDIR.eq.9) then - - crossection = cross_res+cross_dir+cross_diffr - RETURN - - else if (NDIR.eq.10) then - - crossection = cross_diffr - RETURN - - else if ((NDIR.ge.11).and.(NDIR.le.19)) then - - crossection = sig_res(NDIR-10) - RETURN - - else - - print*,'wrong input NDIR in crossection.f !' - STOP - - endif + if (NDIR.eq.3) then + crossection = cross_res+cross_dir+cs_multidiff+cross_frag2 + RETURN + else if (NDIR.eq.0) then + crossection = cross_res+cross_dir+cross_diffr+cross_frag2 + RETURN + else if (NDIR.eq.2) then + crossection = cross_res+cross_dir + RETURN + else if (NDIR.eq.1) then + crossection = cross_res + RETURN + else if (NDIR.eq.4) then + crossection = cross_dir + RETURN + else if (NDIR.eq.5) then + crossection = cs_multi + RETURN + else if (NDIR.eq.6) then + crossection = cross_res+cross_dir2 + RETURN + else if (NDIR.eq.7) then + crossection = cross_res+cross_dir1 + RETURN + else if (NDIR.eq.8) then + crossection = cross_res+cross_dir+cross_diffr1 + RETURN + else if (NDIR.eq.9) then + crossection = cross_res+cross_dir+cross_diffr + RETURN + else if (NDIR.eq.10) then + crossection = cross_diffr + RETURN + else if ((NDIR.ge.11).and.(NDIR.le.19)) then + crossection = sig_res(NDIR-10) + RETURN + else + PRINT*,'wrong input NDIR in crossection.f !' + STOP + endif - END + END FUNCTION crossection - DOUBLE PRECISION function breitwigner(sigma_0,Gamma, - & DMM,eps_prime) - - IMPLICIT DOUBLE PRECISION (A-M,O-Z) - IMPLICIT INTEGER (N) - - SAVE - + DOUBLE PRECISION function breitwigner(sigma_0,Gamma,DMM,eps_prime) c*************************************************************************** c calculates Breit-Wigner cross section of a resonance with width Gamma [GeV], c mass DMM [GeV], max. cross section sigma_0 [mubarn] and total mass of the c interaction s [GeV] c*************************************************************************** - pm = 0.93827D0 - s = pm*pm+2.D0*pm*eps_prime - gam2s = Gamma*Gamma*s - breitwigner = sigma_0 - & *(s/eps_prime**2)*gam2s/((s-DMM*DMM)**2+gam2s) + IMPLICIT DOUBLE PRECISION (A-M,O-Z) + IMPLICIT INTEGER (N) + SAVE - RETURN - - END + pm = 0.93827D0 + s = pm*pm+2.D0*pm*eps_prime + gam2s = Gamma*Gamma*s + breitwigner = sigma_0 + & * (s/eps_prime**2)*gam2s/((s-DMM*DMM)**2+gam2s) + + RETURN + END FUNCTION breitwigner DOUBLE PRECISION function Pl(x,xth,xmax,alpha) IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) + SAVE - SAVE - - if (xth.gt.x) then - Pl = 0. - RETURN - endif + if (xth.gt.x) then + Pl = 0. + RETURN + endif - a = alpha*xmax/xth - prod1 = ((x-xth)/(xmax-xth))**(a-alpha) - prod2 = (x/xmax)**(-a) - Pl = prod1*prod2 + a = alpha*xmax/xth + prod1 = ((x-xth)/(xmax-xth))**(a-alpha) + prod2 = (x/xmax)**(-a) + Pl = prod1*prod2 - END + END FUNCTION Pl DOUBLE PRECISION function Ef(x,th,w) IMPLICIT DOUBLE PRECISION (A-M,O-Z) IMPLICIT INTEGER (N) + SAVE - SAVE - - wth = w+th - if (x.le.th) then - Ef = 0. - RETURN - else if (x.gt.th.and.x.lt.wth) then - Ef = (x-th)/w - RETURN - else if (x.ge.wth) then - Ef = 1. - RETURN - else - print*,'error in function EF' - STOP - endif - - END - - - - subroutine dec_inter3(eps_prime,Imode,L0) + wth = w+th + if (x.le.th) then + Ef = 0. + RETURN + else if (x.gt.th.and.x.lt.wth) then + Ef = (x-th)/w + RETURN + else if (x.ge.wth) then + Ef = 1. + RETURN + else + PRINT*,'error in function EF' + STOP + endif - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) - SAVE + END FUNCTION Ef - DOUBLE PRECISION RNDM - external RNDM + SUBROUTINE dec_inter3(eps_prime,Imode,L0) c*** decides which process takes place at eps_prime ******** c (6) excitation/decay of resonance *** c (2) direct pion production: N\gamma --> N \pi *** @@ -599,68 +456,56 @@ subroutine dec_inter3(eps_prime,Imode,L0) c (0) multipion production (fragmentation) *** c (5) fragmentation in resonance region *** c*********************************************************** -c** Date: 15/04/98 ** -c** author: A.Muecke ** -c********************** - tot = crossection(eps_prime,3,L0) - if (tot.eq.0.) tot = 1.D0 - prob1 = crossection(eps_prime,1,L0)/tot - prob2 = crossection(eps_prime,7,L0)/tot - prob3 = crossection(eps_prime,2,L0)/tot - prob4 = crossection(eps_prime,8,L0)/tot - prob5 = crossection(eps_prime,9,L0)/tot - prob6 = crossection(eps_prime,0,L0)/tot - prob7 = 1.D0 - rn = RNDM(0) - if (rn.lt.prob1) then - Imode = 6 -c ... --> resonance decay - RETURN - else if (prob1.le.rn.and.rn.lt.prob2) then - Imode = 2 -c ... --> direct channel: N\gamma --> N\pi - RETURN - else if (prob2.le.rn.and.rn.lt.prob3) then - Imode = 3 -c ... --> direct channel: N\gamma --> \Delta \pi - RETURN - else if (prob3.le.rn.and.rn.lt.prob4) then - Imode = 1 -c ... --> diffractive scattering: N\gamma --> N \rho - RETURN - else if (prob4.le.rn.and.rn.lt.prob5) then - Imode = 4 -c ... --> diffractive scattering: N\gamma --> N \omega - RETURN - else if (prob5.le.rn.and.rn.lt.prob6) then - Imode = 5 -c ... --> fragmentation (2) in resonance region - return - else if (prob6.le.rn.and.rn.lt.1.D0) then - Imode = 0 -c ... --> fragmentation mode/multipion production - RETURN - else if (rn.eq.1.D0) then - Imode = 0 - RETURN - else - print*,'error in dec_inter.f !' - STOP - endif - - END - - - SUBROUTINE PROC_TWOPART(LA,LB,AMD,Lres,Pres,costheta,nbad) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) - - COMMON /S_MASS1/ AM(49), AM2(49) - COMMON /RES_FLAG/ FRES(49),XLIMRES(49) SAVE - DIMENSION Pres(2000,5),Lres(2000) + DOUBLE PRECISION RNDM + EXTERNAL RNDM + + tot = crossection(eps_prime,3,L0) + if (tot.eq.0.) tot = 1.D0 + prob1 = crossection(eps_prime,1,L0)/tot + prob2 = crossection(eps_prime,7,L0)/tot + prob3 = crossection(eps_prime,2,L0)/tot + prob4 = crossection(eps_prime,8,L0)/tot + prob5 = crossection(eps_prime,9,L0)/tot + prob6 = crossection(eps_prime,0,L0)/tot + prob7 = 1.D0 + rn = RNDM(0) + if (rn.lt.prob1) then + Imode = 6 ! --> resonance decay + RETURN + else if (prob1.le.rn.and.rn.lt.prob2) then + Imode = 2 ! --> direct channel: N\gamma --> N\pi + RETURN + else if (prob2.le.rn.and.rn.lt.prob3) then + Imode = 3 ! --> direct channel: N\gamma --> \Delta \pi + RETURN + else if (prob3.le.rn.and.rn.lt.prob4) then + Imode = 1 ! --> diffractive scattering: N\gamma --> N \rho + RETURN + else if (prob4.le.rn.and.rn.lt.prob5) then + Imode = 4 ! --> diffractive scattering: N\gamma --> N \omega + RETURN + else if (prob5.le.rn.and.rn.lt.prob6) then + Imode = 5 ! --> fragmentation (2) in resonance region + RETURN + else if (prob6.le.rn.and.rn.lt.1.D0) then + Imode = 0 ! --> fragmentation mode/multipion production + RETURN + else if (rn.eq.1.D0) then + Imode = 0 + RETURN + else + PRINT*,'error in dec_inter.f !' + STOP + endif + + END SUBROUTINE dec_inter3 + + + SUBROUTINE PROC_TWOPART(LA,LB,AMD,Lres,Pres,costheta,nbad) c*********************************************************** c 2-particle decay of CMF mass AMD INTO M1 + M2 C NUCLEON ENERGY E0 [in GeV]; @@ -673,362 +518,309 @@ SUBROUTINE PROC_TWOPART(LA,LB,AMD,Lres,Pres,costheta,nbad) c resonances; if yes, it is also allowed to decay a c mass AMD < M1 + M2 by using the width of the resonance(s) c*********************************************************** -c** Date: 20/01/98 ** -c** correct.:19/02/98** -c** author: A.Muecke ** -c********************** - - nbad = 0 - SM1 = AM(LA) - if (LB.eq.0) then - SM2 = 2.D0*AM(7) - else - SM2 = AM(LB) - endif - E1 = (AMD*AMD + SM1*SM1 - SM2*SM2)/AMD/2.D0 - E2 = (AMD*AMD + SM2*SM2 - SM1*SM1)/AMD/2.D0 -c... check if SM1+SM2 < AMD: - if ((SM1+SM2).gt.AMD) then -c... if one of the decay products is a resonance, this 'problem' can -c be solved by using a reduced mass for the resonance and assume that -c this resonance is produced at its threshold; - if (FRES(LA).eq.1.D0) then -c ... particle LA is a resonance: - SM1 = AMD-SM2 - E1 = SM1 - E2 = AMD-E1 - if (E1.lt.XLIMRES(LA).or.E2.lt.XLIMRES(LB)) nbad = 1 - endif - if (FRES(LB).eq.1.D0) then -c ... particle LB is a resonance: - SM2 = AMD-SM1 - E2 = SM2 - E1 = AMD-E2 - if (E1.lt.XLIMRES(LA).or.E2.lt.XLIMRES(LB)) nbad = 1 - endif + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + + COMMON /S_MASS1/ AM(49), AM2(49) + COMMON /RES_FLAG/ FRES(49),XLIMRES(49) + SAVE + + DIMENSION Pres(2000,5),Lres(2000) + + nbad = 0 + SM1 = AM(LA) + if (LB.eq.0) then + SM2 = 2.D0*AM(7) + else + SM2 = AM(LB) + endif + + E1 = (AMD*AMD + SM1*SM1 - SM2*SM2)/AMD/2.D0 + E2 = (AMD*AMD + SM2*SM2 - SM1*SM1)/AMD/2.D0 +c... check if SM1+SM2 < AMD: + if ((SM1+SM2).gt.AMD) then +c... if one of the decay products is a resonance, this 'problem' can +c be solved by using a reduced mass for the resonance and assume that +c this resonance is produced at its threshold; + if (FRES(LA).eq.1.D0) then +c ... particle LA is a resonance: + SM1 = AMD-SM2 + E1 = SM1 + E2 = AMD-E1 + if (E1.lt.XLIMRES(LA).or.E2.lt.XLIMRES(LB)) nbad = 1 + endif + if (FRES(LB).eq.1.D0) then +c ... particle LB is a resonance: + SM2 = AMD-SM1 + E2 = SM2 + E1 = AMD-E2 + if (E1.lt.XLIMRES(LA).or.E2.lt.XLIMRES(LB)) nbad = 1 + endif c ... both particles are NOT resonances: -> error ! - if (FRES(LA).eq.0.D0.and.FRES(LB).eq.0.D0) then - print*,'SM1 + SM2 > AMD in PROC_TWOPART',SM1,SM2,AMD,LA,LB - STOP - endif - endif - - if (nbad.eq.0) then - PC = SQRT((E1*E1 - SM1*SM1)) - Pres(1,4) = E1 - Pres(2,4) = E2 - Pres(1,5) = SM1 - Pres(2,5) = SM2 - - + if (FRES(LA).eq.0.D0.and.FRES(LB).eq.0.D0) then + PRINT*,'SM1 + SM2 > AMD in PROC_TWOPART',SM1,SM2,AMD,LA,LB + STOP + endif + endif + + if (nbad.eq.0) then + PC = SQRT((E1*E1 - SM1*SM1)) + Pres(1,4) = E1 + Pres(2,4) = E2 + Pres(1,5) = SM1 + Pres(2,5) = SM2 C ********************************************************* c theta is scattering angle in CM frame: - r = RNDM(0) - P1Z= PC*costheta - P2Z=-PC*costheta - - P1X = sqrt(r*(PC*PC-P1Z*P1Z)) - P2X = sqrt(r*(PC*PC-P2Z*P2Z)) - P1Y = sqrt((1.D0-r)*(PC*PC-P1Z*P1Z)) - P2Y = sqrt((1.D0-r)*(PC*PC-P2Z*P2Z)) - if(RNDM(0).lt.0.5D0) then - P1X = -P1X - else - P2X = -P2X - endif - if(RNDM(0).lt.0.5D0) then - P1Y = -P1Y - else - P2Y = -P2Y - endif - - Pres(1,1) = P1X - Pres(1,2) = P1Y - Pres(1,3) = P1Z - Pres(2,1) = P2X - Pres(2,2) = P2Y - Pres(2,3) = P2Z - Lres(1) = LA - Lres(2) = LB - endif - - RETURN - - END - - - subroutine dec_res2(eps_prime,IRES,IRESMAX,L0) + r = RNDM(0) + P1Z= PC*costheta + P2Z=-PC*costheta + + P1X = sqrt(r*(PC*PC-P1Z*P1Z)) + P2X = sqrt(r*(PC*PC-P2Z*P2Z)) + P1Y = sqrt((1.D0-r)*(PC*PC-P1Z*P1Z)) + P2Y = sqrt((1.D0-r)*(PC*PC-P2Z*P2Z)) + if(RNDM(0).lt.0.5D0) then + P1X = -P1X + else + P2X = -P2X + endif + if(RNDM(0).lt.0.5D0) then + P1Y = -P1Y + else + P2Y = -P2Y + endif - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) + Pres(1,1) = P1X + Pres(1,2) = P1Y + Pres(1,3) = P1Z + Pres(2,1) = P2X + Pres(2,2) = P2Y + Pres(2,3) = P2Z + Lres(1) = LA + Lres(2) = LB + endif + + RETURN + END SUBROUTINE PROC_TWOPART - SAVE + SUBROUTINE dec_res2(eps_prime,IRES,IRESMAX,L0) + + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + SAVE c***************************************************************************** c*** decides which resonance with ID=IRES in list takes place at eps_prime *** c***************************************************************************** -c** Date: 20/01/98 ** -c** author: A.Muecke ** -c********************** - - DIMENSION prob_sum(9) - - -c*** sum of all resonances: - sumres = 0.D0 - do 12 j=1,IRESMAX - j10 = j+10 - sumres = sumres+crossection(eps_prime,j10,L0) - prob_sum(j) = sumres - 12 continue - - - r = RNDM(0) - - IRES = 0 - i = 0 - prob = 0.D0 - 10 continue - i = i+1 - probold = prob - prob = prob_sum(i)/sumres - if (r.ge.probold.and.r.lt.prob) then - IRES = i - RETURN - endif - if (i.lt.IRESMAX) goto 10 - if (r.eq.1.D0) IRES = i - if (IRES.eq.0) then - print*,'no resonance possible !' - STOP - endif - - RETURN + DIMENSION prob_sum(9) +c*** sum of all resonances: + sumres = 0.D0 + do 12 j=1,IRESMAX + j10 = j+10 + sumres = sumres+crossection(eps_prime,j10,L0) + prob_sum(j) = sumres + 12 CONTINUE + + r = RNDM(0) + IRES = 0 + i = 0 + prob = 0.D0 + + 10 CONTINUE + i = i+1 + probold = prob + prob = prob_sum(i)/sumres + if (r.ge.probold.and.r.lt.prob) then + IRES = i + RETURN + endif + if (i.lt.IRESMAX) goto 10 + if (r.eq.1.D0) IRES = i + if (IRES.eq.0) then + PRINT*,'no resonance possible !' + STOP + endif - END + RETURN + END SUBROUTINE dec_res2 - subroutine dec_proc2(x,IPROC,IRANGE,IRES,L0) + SUBROUTINE dec_proc2(x,IPROC,IRANGE,IRES,L0) IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) - - SAVE - + SAVE c********************************************************************** c*** decide which decay with ID=IPROC of resonance IRES takes place *** c********************************************************************** -c** Date: 20/01/98 ** -c** correct.: 27/04/98* -c** author: A.Muecke ** -c********************** - - COMMON /S_RESp/ CBRRES1p(18),CBRRES2p(36),CBRRES3p(26), - + RESLIMp(36),ELIMITSp(9),KDECRES1p(90),KDECRES2p(180), - + KDECRES3p(130),IDBRES1p(9),IDBRES2p(9),IDBRES3p(9) - COMMON /S_RESn/ CBRRES1n(18),CBRRES2n(36),CBRRES3n(22), - + RESLIMn(36),ELIMITSn(9),KDECRES1n(90),KDECRES2n(180), - + KDECRES3n(110),IDBRES1n(9),IDBRES2n(9),IDBRES3n(9) + COMMON /S_RESp/ CBRRES1p(18),CBRRES2p(36),CBRRES3p(26), + + RESLIMp(36),ELIMITSp(9),KDECRES1p(90),KDECRES2p(180), + + KDECRES3p(130),IDBRES1p(9),IDBRES2p(9),IDBRES3p(9) + COMMON /S_RESn/ CBRRES1n(18),CBRRES2n(36),CBRRES3n(22), + + RESLIMn(36),ELIMITSn(9),KDECRES1n(90),KDECRES2n(180), + + KDECRES3n(110),IDBRES1n(9),IDBRES2n(9),IDBRES3n(9) DIMENSION prob_sum(0:9) - -c x = eps_prime c ... choose arrays /S_RESp/ for charged resonances, c ... arrays /S_RESn/ for neutral resonances - if (L0.eq.13) then + if (L0.eq.13) then c ... charged resonances: + r = RNDM(0) +c... determine the energy range of the resonance: + nlim = ELIMITSp(IRES) + istart = (IRES-1)*4+1 + if (nlim.gt.0) then + do ie=istart,nlim-2+istart + reslimp1 = RESLIMp(ie) + reslimp2 = RESLIMp(ie+1) + if (x.le.reslimp2.and.x.gt.reslimp1) then + IRANGE = ie+1-istart + endif + enddo + else + irange = 1 + 13 endif - r = RNDM(0) -c... determine the energy range of the resonance: - nlim = ELIMITSp(IRES) - istart = (IRES-1)*4+1 - if (nlim.gt.0) then - do ie=istart,nlim-2+istart - reslimp1 = RESLIMp(ie) - reslimp2 = RESLIMp(ie+1) - if (x.le.reslimp2.and.x.gt.reslimp1) then - IRANGE = ie+1-istart + IPROC = -1 + i = 0 + prob_sum(0) = 0.D0 + + if (IRANGE.eq.1) then + j = IDBRES1p(IRES)-1 + if (j.eq.-1) then + PRINT*,'invalid resonance in energy range 1' + endif + 10 CONTINUE + j = j+1 + i = i+1 + prob_sum(i) = CBRRES1p(j) + if (r.ge.prob_sum(i-1).and.r.lt.prob_sum(i)) IPROC = j + if (prob_sum(i).lt.1.D0) goto 10 + if (r.eq.1.D0) IPROC = j + if (IPROC.eq.-1) then + PRINT*,'no resonance decay possible !' + endif + else if (IRANGE.eq.2) then + j = IDBRES2p(IRES)-1 + if (j.eq.-1) then + PRINT*,'invalid resonance in energy range 2' + endif + 11 CONTINUE + j = j+1 + i = i+1 + prob_sum(i) = CBRRES2p(j) + if (r.ge.prob_sum(i-1).and.r.lt.prob_sum(i)) IPROC = j + if (prob_sum(i).lt.1.D0) goto 11 + if (r.eq.1.D0) IPROC = j + if (IPROC.eq.-1) then + PRINT*,'no resonance decay possible !' + endif + else if (IRANGE.eq.3) then + j = IDBRES3p(IRES)-1 + if (j.eq.-1) then + PRINT*,'invalid resonance in energy range 3' + endif + 12 CONTINUE + j = j+1 + i = i+1 + prob_sum(i) = CBRRES3p(j) + if (r.ge.prob_sum(i-1).and.r.lt.prob_sum(i)) IPROC = j + if (prob_sum(i).lt.1.D0) goto 12 + if (r.eq.1.D0) IPROC = j + if (IPROC.eq.-1) then + PRINT*,'no resonance decay possible !' + endif + else + PRINT*,'invalid IRANGE in DEC_PROC2' endif - enddo - else - irange = 1 - 13 endif - - - - IPROC = -1 - i = 0 - prob_sum(0) = 0.D0 - - if (IRANGE.eq.1) then - j = IDBRES1p(IRES)-1 - if (j.eq.-1) then - print*,'invalid resonance in energy range 1' - endif - 10 continue - j = j+1 - i = i+1 - prob_sum(i) = CBRRES1p(j) - if (r.ge.prob_sum(i-1).and.r.lt.prob_sum(i)) then - IPROC = j - endif - if (prob_sum(i).lt.1.D0) goto 10 - if (r.eq.1.D0) IPROC = j - if (IPROC.eq.-1) then - print*,'no resonance decay possible !' - endif - - else if (IRANGE.eq.2) then - j = IDBRES2p(IRES)-1 - if (j.eq.-1) then - print*,'invalid resonance in energy range 2' - endif - 11 continue - j = j+1 - i = i+1 - prob_sum(i) = CBRRES2p(j) - if (r.ge.prob_sum(i-1).and.r.lt.prob_sum(i)) then - IPROC = j - endif - if (prob_sum(i).lt.1.D0) goto 11 - if (r.eq.1.D0) IPROC = j - if (IPROC.eq.-1) then - print*,'no resonance decay possible !' - endif - - else if (IRANGE.eq.3) then - j = IDBRES3p(IRES)-1 - if (j.eq.-1) then - print*,'invalid resonance in energy range 3' - endif - 12 continue - j = j+1 - i = i+1 - prob_sum(i) = CBRRES3p(j) - if (r.ge.prob_sum(i-1).and.r.lt.prob_sum(i)) then - IPROC = j - endif - if (prob_sum(i).lt.1.D0) goto 12 - if (r.eq.1.D0) IPROC = j - if (IPROC.eq.-1) then - print*,'no resonance decay possible !' - endif - - else - print*,'invalid IRANGE in DEC_PROC2' - endif - - RETURN - - - else if (L0.eq.14) then + RETURN + else if (L0.eq.14) then c ... neutral resonances: - - r = RNDM(0) + r = RNDM(0) c... determine the energy range of the resonance: - nlim = ELIMITSn(IRES) - istart = (IRES-1)*4+1 - if (nlim.gt.0) then - do ie=istart,nlim-2+istart - if (x.le.RESLIMn(ie+1).and.x.gt.RESLIMn(ie)) then - IRANGE = ie+1-istart + nlim = ELIMITSn(IRES) + istart = (IRES-1)*4+1 + if (nlim.gt.0) then + do ie=istart,nlim-2+istart + if (x.le.RESLIMn(ie+1).and.x.gt.RESLIMn(ie)) then + IRANGE = ie+1-istart + endif + enddo + else + irange = 1 endif - enddo - else - irange = 1 - endif - - - IPROC = -1 - i = 0 - prob_sum(0) = 0.D0 - - if (IRANGE.eq.1) then - j = IDBRES1n(IRES)-1 - if (j.eq.-1) then - print*,'invalid resonance in this energy range' - endif - 20 continue - j = j+1 - i = i+1 - prob_sum(i) = CBRRES1n(j) - if (r.ge.prob_sum(i-1).and.r.lt.prob_sum(i)) then - IPROC = j - endif - if (prob_sum(i).lt.1.D0) goto 20 - if (r.eq.1.D0) IPROC = j - if (IPROC.eq.-1) then - print*,'no resonance decay possible !' - endif - - else if (IRANGE.eq.2) then - j = IDBRES2n(IRES)-1 - if (j.eq.-1) then - print*,'invalid resonance in this energy range' - endif - 21 continue - j = j+1 - i = i+1 - prob_sum(i) = CBRRES2n(j) - if (r.ge.prob_sum(i-1).and.r.lt.prob_sum(i)) then - IPROC = j - endif - if (prob_sum(i).lt.1.D0) goto 21 - if (r.eq.1.) IPROC = j - if (IPROC.eq.-1) then - print*,'no resonance decay possible !' - endif - - else if (IRANGE.eq.3) then - j = IDBRES3n(IRES)-1 - if (j.eq.-1) then - print*,'invalid resonance in this energy range' - endif - 22 continue - j = j+1 - i = i+1 - prob_sum(i) = CBRRES3n(j) - if (r.ge.prob_sum(i-1).and.r.lt.prob_sum(i)) then - IPROC = j - endif - if (prob_sum(i).lt.1.D0) goto 22 - if (r.eq.1.D0) IPROC = j - if (IPROC.eq.-1) then - print*,'no resonance decay possible !' - endif - - else - print*,'invalid IRANGE in DEC_PROC2' - endif - - RETURN - - else - print*,'no valid L0 in DEC_PROC !' - STOP - endif - - END - - - SUBROUTINE RES_DECAY3(IRES,IPROC,IRANGE,s,L0,nbad) + IPROC = -1 + i = 0 + prob_sum(0) = 0.D0 + if (IRANGE.eq.1) then + j = IDBRES1n(IRES)-1 + if (j.eq.-1) then + PRINT*,'invalid resonance in this energy range' + endif + 20 CONTINUE + j = j+1 + i = i+1 + prob_sum(i) = CBRRES1n(j) + if (r.ge.prob_sum(i-1).and.r.lt.prob_sum(i)) IPROC = j + if (prob_sum(i).lt.1.D0) goto 20 + if (r.eq.1.D0) IPROC = j + if (IPROC.eq.-1) then + PRINT*,'no resonance decay possible !' + endif + else if (IRANGE.eq.2) then + j = IDBRES2n(IRES)-1 + if (j.eq.-1) then + PRINT*,'invalid resonance in this energy range' + endif + 21 CONTINUE + j = j+1 + i = i+1 + prob_sum(i) = CBRRES2n(j) + if (r.ge.prob_sum(i-1).and.r.lt.prob_sum(i)) IPROC = j + if (prob_sum(i).lt.1.D0) goto 21 + if (r.eq.1.) IPROC = j + if (IPROC.eq.-1) then + PRINT*,'no resonance decay possible !' + endif + else if (IRANGE.eq.3) then + j = IDBRES3n(IRES)-1 + if (j.eq.-1) then + PRINT*,'invalid resonance in this energy range' + endif + 22 CONTINUE + j = j+1 + i = i+1 + prob_sum(i) = CBRRES3n(j) + if (r.ge.prob_sum(i-1).and.r.lt.prob_sum(i)) IPROC = j + if (prob_sum(i).lt.1.D0) goto 22 + if (r.eq.1.D0) IPROC = j + if (IPROC.eq.-1) then + PRINT*,'no resonance decay possible !' + endif + else + PRINT*,'invalid IRANGE in DEC_PROC2' + endif + RETURN + else + PRINT*,'no valid L0 in DEC_PROC !' + STOP + endif + + END SUBROUTINE dec_proc2 + + + SUBROUTINE RES_DECAY3(IRES,IPROC,IRANGE,s,L0,nbad) IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) + SAVE - SAVE - - COMMON /S_RESp/ CBRRES1p(18),CBRRES2p(36),CBRRES3p(26), + COMMON /S_RESp/ CBRRES1p(18),CBRRES2p(36),CBRRES3p(26), + RESLIMp(36),ELIMITSp(9),KDECRES1p(90),KDECRES2p(180), + KDECRES3p(130),IDBRES1p(9),IDBRES2p(9),IDBRES3p(9) - COMMON /S_RESn/ CBRRES1n(18),CBRRES2n(36),CBRRES3n(22), + COMMON /S_RESn/ CBRRES1n(18),CBRRES2n(36),CBRRES3n(22), + RESLIMn(36),ELIMITSn(9),KDECRES1n(90),KDECRES2n(180), + KDECRES3n(110),IDBRES1n(9),IDBRES2n(9),IDBRES3n(9) - COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb -c COMMON /S_CNAM/ NAMP (0:49) -c CHARACTER NAMP*6, NAMPRESp*6, NAMPRESn*6 - -* external scatangle, proc_twopart - + COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb c******************************************************** c RESONANCE AMD with code number IRES INTO M1 + M2 C PROTON ENERGY E0 [in GeV] IN DMM [in GeV] @@ -1038,59 +830,50 @@ SUBROUTINE RES_DECAY3(IRES,IPROC,IRANGE,s,L0,nbad) c resulting momenta are calculated in CM frame; c ANGLESCAT is cos of scattering angle in CM frame c******************************************************** -c** Date: 20/01/98 ** -c** correct.:28/04/98** -c** author: A.Muecke ** -c********************** - c... determine decay products LA, LB: - NP = 2 - if (L0.eq.13) then + NP = 2 + if (L0.eq.13) then c ... proton is incident nucleon: - if (IRANGE.eq.1) then - LA = KDECRES1p(5*(IPROC-1)+3) - LB = KDECRES1p(5*(IPROC-1)+4) - else if (IRANGE.eq.2) then - LA = KDECRES2p(5*(IPROC-1)+3) - LB = KDECRES2p(5*(IPROC-1)+4) - else if (IRANGE.eq.3) then - LA = KDECRES3p(5*(IPROC-1)+3) - LB = KDECRES3p(5*(IPROC-1)+4) - else - print*,'error in res_decay3' - endif - else if (L0.eq.14) then + if (IRANGE.eq.1) then + LA = KDECRES1p(5*(IPROC-1)+3) + LB = KDECRES1p(5*(IPROC-1)+4) + else if (IRANGE.eq.2) then + LA = KDECRES2p(5*(IPROC-1)+3) + LB = KDECRES2p(5*(IPROC-1)+4) + else if (IRANGE.eq.3) then + LA = KDECRES3p(5*(IPROC-1)+3) + LB = KDECRES3p(5*(IPROC-1)+4) + else + PRINT*,'error in res_decay3' + endif + else if (L0.eq.14) then c ... neutron is incident nucleon: - if (IRANGE.eq.1) then - LA = KDECRES1n(5*(IPROC-1)+3) - LB = KDECRES1n(5*(IPROC-1)+4) - else if (IRANGE.eq.2) then - LA = KDECRES2n(5*(IPROC-1)+3) - LB = KDECRES2n(5*(IPROC-1)+4) - else if (IRANGE.eq.3) then - LA = KDECRES3n(5*(IPROC-1)+3) - LB = KDECRES3n(5*(IPROC-1)+4) - else - print*,'error in res_decay3' - endif - - else - print*,'no valid L0 in RES_DECAY' - STOP - endif - - LLIST(1) = LA - LLIST(2) = LB + if (IRANGE.eq.1) then + LA = KDECRES1n(5*(IPROC-1)+3) + LB = KDECRES1n(5*(IPROC-1)+4) + else if (IRANGE.eq.2) then + LA = KDECRES2n(5*(IPROC-1)+3) + LB = KDECRES2n(5*(IPROC-1)+4) + else if (IRANGE.eq.3) then + LA = KDECRES3n(5*(IPROC-1)+3) + LB = KDECRES3n(5*(IPROC-1)+4) + else + PRINT*,'error in res_decay3' + endif + else + PRINT*,'no valid L0 in RES_DECAY' + STOP + endif -c... sample scattering angle: - call scatangle(anglescat,IRES,L0) - + LLIST(1) = LA + LLIST(2) = LB +c... sample scattering angle: + call scatangle(anglescat,IRES,L0) c ... 2-particle decay: - call proc_twopart(LA,LB,sqrt(s),LLIST,P,anglescat,nbad) + call proc_twopart(LA,LB,sqrt(s),LLIST,P,anglescat,nbad) - RETURN - - END + RETURN + END SUBROUTINE RES_DECAY3 c*********************************************************** C calculates functions for crossection of direct channel @@ -1099,45 +882,33 @@ SUBROUTINE RES_DECAY3(IRES,IPROC,IRANGE,s,L0,nbad) C (see thesis of J.Rachen, p.45ff) c note: neglect strange- and eta-channel C*********************************************************** -c** Date: 27/04/98 ** -c** last chg:23/05/98** -c** author: A.Muecke ** -c********************** -c - - DOUBLE PRECISION FUNCTION singleback(x) + DOUBLE PRECISION FUNCTION singleback(x) c**************************** c SINGLE PION CHANNEL c**************************** IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) + SAVE - SAVE - singleback = 92.7D0*Pl(x,.152D0,.25D0,2.D0) + singleback = 92.7D0*Pl(x,.152D0,.25D0,2.D0) - END + END FUNCTION singleback - DOUBLE PRECISION FUNCTION twoback(x) + DOUBLE PRECISION FUNCTION twoback(x) c***************************** c TWO PION PRODUCTION c***************************** IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) + SAVE - SAVE - twoback = 37.7D0*Pl(x,.4D0,.6D0,2.D0) - - END - - - subroutine scatangle(anglescat,IRES,L0) + twoback = 37.7D0*Pl(x,.4D0,.6D0,2.D0) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) + END FUNCTION twoback - SAVE + SUBROUTINE scatangle(anglescat,IRES,L0) c******************************************************************* c This routine samples the cos of the scattering angle for a given * c resonance IRES and incident nucleon L0; it is exact for ** @@ -1147,158 +918,124 @@ subroutine scatangle(anglescat,IRES,L0) c for decay channels other than the one-pion decay a isotropic ** c distribution is used ** c******************************************************************* -c** Date: 16/02/98 ** -c** author: A.Muecke ** -c********************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + SAVE - COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb + COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb c ... use rejection method for sampling: - LA = LLIST(1) - LB = LLIST(2) - 10 continue - r = RNDM(0) + LA = LLIST(1) + LB = LLIST(2) + 10 CONTINUE + + r = RNDM(0) c*** sample anglescat random between -1 ... 1 ** anglescat = 2.D0*(r-0.5D0) c ... distribution is isotropic for other than one-pion decays: - if ((LA.eq.13.or.LA.eq.14).and.LB.ge.6.and.LB.le.8) then - prob = probangle(IRES,L0,anglescat) - else - prob = 0.5D0 - endif - r = RNDM(0) - if (r.le.prob) then + if ((LA.eq.13.or.LA.eq.14).and.LB.ge.6.and.LB.le.8) then + prob = probangle(IRES,L0,anglescat) + else + prob = 0.5D0 + endif + + r = RNDM(0) + if (r.le.prob) then RETURN - else - goto 10 - endif - 12 continue - - END - - DOUBLE PRECISION function probangle(IRES,L0,z) + else + goto 10 + endif - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) + END SUBROUTINE scatangle - SAVE + DOUBLE PRECISION function probangle(IRES,L0,z) c******************************************************************** c probability distribution for scattering angle of given resonance ** c IRES and incident nucleon L0 ; ** c z is cosine of scattering angle in CMF frame ** c******************************************************************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + SAVE - if (IRES.eq.4.or.IRES.eq.5.or.IRES.eq.2) then + if (IRES.eq.4.or.IRES.eq.5.or.IRES.eq.2) then c ... N1535 andf N1650 decay isotropically. - probangle = 0.5D0 - return - endif - - if (IRES.eq.1) then + probangle = 0.5D0 + RETURN + else if (IRES.eq.1) then c ... for D1232: - probangle = 0.636263D0 - 0.408790D0*z*z - return - endif - - if (IRES.eq.3.and.L0.eq.14) then + probangle = 0.636263D0 - 0.408790D0*z*z + RETURN + else if (IRES.eq.3.and.L0.eq.14) then c ... for N1520 and incident n: - probangle = 0.673669D0 - 0.521007D0*z*z - return - endif - - if (IRES.eq.3.and.L0.eq.13) then + probangle = 0.673669D0 - 0.521007D0*z*z + RETURN + else if (IRES.eq.3.and.L0.eq.13) then c ... for N1520 and incident p: - probangle = 0.739763D0 - 0.719288D0*z*z - return - endif - - if (IRES.eq.6.and.L0.eq.14) then + probangle = 0.739763D0 - 0.719288D0*z*z + RETURN + else if (IRES.eq.6.and.L0.eq.14) then c ... for N1680 (more precisely: N1675) and incident n: - q=z*z - probangle = 0.254005D0 + 1.427918D0*q - 1.149888D0*q*q - return - endif - - - if (IRES.eq.6.and.L0.eq.13) then + q=z*z + probangle = 0.254005D0 + 1.427918D0*q - 1.149888D0*q*q + RETURN + else if (IRES.eq.6.and.L0.eq.13) then c ... for N1680 and incident p: - q=z*z - probangle = 0.189855D0 + 2.582610D0*q - 2.753625D0*q*q - return - endif - - if (IRES.eq.7) then + q=z*z + probangle = 0.189855D0 + 2.582610D0*q - 2.753625D0*q*q + RETURN + else if (IRES.eq.7) then c ... for D1700: - probangle = 0.450238D0 + 0.149285D0*z*z - return - endif - - - if (IRES.eq.8) then + probangle = 0.450238D0 + 0.149285D0*z*z + RETURN + else if (IRES.eq.8) then c ... for D1905: - q=z*z - probangle = 0.230034D0 + 1.859396D0*q - 1.749161D0*q*q - return - endif - - - if (IRES.eq.9) then + q=z*z + probangle = 0.230034D0 + 1.859396D0*q - 1.749161D0*q*q + RETURN + else if (IRES.eq.9) then c ... for D1950: - q=z*z - probangle = 0.397430D0 - 1.498240D0*q + 5.880814D0*q*q - & - 4.019252D0*q*q*q - return + q=z*z + probangle = 0.397430D0 - 1.498240D0*q + 5.880814D0*q*q + & - 4.019252D0*q*q*q + RETURN endif - print*,'error in function probangle !' + PRINT*,'error in function probangle !' + STOP - END + END FUNCTION probangle -C-> - DOUBLE PRECISION FUNCTION GAUSS (FUN, A,B) + + DOUBLE PRECISION FUNCTION GAUSS(FUN, A,B) c********************************************************* -C Returns the 8 points Gauss-Legendre integral -C of function FUN from A to B -c this routine was provided by T.Stanev +C RETURNs the 8 points Gauss-Legendre integral of function FUN from A to B c********************************************************* -c** Date: 20/01/98 ** -c** A.Muecke ** -c********************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) -c SAVE c modified Sept 2005 because of recursive calls in Total_rate_ir EXTERNAL FUN - C........................................................... - DIMENSION X(8), W(8) - DATA X /.0950125098D0,.2816035507D0,.4580167776D0,.6178762444D0 - + ,.7554044083D0,.8656312023D0,.9445750230D0,.9894009349D0/ - DATA W /.1894506104D0,.1826034150D0,.1691565193D0,.1495959888D0 - + ,.1246289712D0,.0951585116D0,.0622535239D0, .0271524594D0/ - - XM = 0.5D0*(B+A) - XR = 0.5D0*(B-A) - SS = 0.D0 - DO NJ=1,8 - DX = XR*X(NJ) - SS = SS + W(NJ) * (FUN(XM+DX) + FUN(XM-DX)) - ENDDO - GAUSS = XR*SS - RETURN - END - - - + DIMENSION X(8), W(8) + DATA X /.0950125098D0,.2816035507D0,.4580167776D0,.6178762444D0 + + ,.7554044083D0,.8656312023D0,.9445750230D0,.9894009349D0/ + DATA W /.1894506104D0,.1826034150D0,.1691565193D0,.1495959888D0 + + ,.1246289712D0,.0951585116D0,.0622535239D0,.0271524594D0/ + + XM = 0.5D0*(B+A) + XR = 0.5D0*(B-A) + SS = 0.D0 + DO NJ=1,8 + DX = XR*X(NJ) + SS = SS + W(NJ) * (FUN(XM+DX) + FUN(XM-DX)) + ENDDO + GAUSS = XR*SS + + RETURN + END FUNCTION gauss -C-> -c*************************** -c** last change: 12/10/98 ** -c** author: A.Muecke ** -c*************************** BLOCK DATA DATDEC IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) @@ -1521,7 +1258,8 @@ BLOCK DATA DATDEC + 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., + 0.,0.,0./ END -C-> + + BLOCK DATA PARAM_INI C....This block data contains default values C. of the parameters used in fragmentation @@ -1562,8 +1300,6 @@ SUBROUTINE gamma_h(Ecm,ip1,Imode,ifbad) C interface to Lund / JETSET 7.4 fragmentation C (R.E. 08/98) C -C -C C input: ip1 incoming particle C 13 - p C 14 - n @@ -1582,7 +1318,6 @@ SUBROUTINE gamma_h(Ecm,ip1,Imode,ifbad) C 1 generation of interaction not possible) C C********************************************************************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) @@ -1616,193 +1351,175 @@ SUBROUTINE gamma_h(Ecm,ip1,Imode,ifbad) S = SQS*SQS Ic = Ic+1 - IF((Imode.eq.1).or.(Imode.eq.4)) THEN - C*********************************************************************** - C simulation of diffraction + ipa = ip1 + ipb = ip2 + if(Imode.eq.1) then + Nproc = 1 + if(ip1.eq.1) then + ipa = 27 + else if(ip2.eq.1) then + ipb = 27 + endif + else if(Imode.eq.4) then + Nproc = 4 + if(ip1.eq.1) then + ipa = 32 + else if(ip2.eq.1) then + ipb = 32 + endif + endif - ipa = ip1 - ipb = ip2 - - if(Imode.eq.1) then - Nproc = 1 - if(ip1.eq.1) then - ipa = 27 - else if(ip2.eq.1) then - ipb = 27 + am_a = AM(ipa) + am_b = AM(ipb) + if(am_a+am_b.ge.Ecm-1.D-2) am_a = Ecm - am_b-1.D-2 +C find t range + e1 = 0.5D0*(Ecm + AM(ip1)**2/Ecm - AM(ip2)**2/Ecm) + if(e1.gt.100.D0*AM(ip1)) then + pcm1 = e1 - 0.5D0*AM(ip1)**2/e1 + else + pcm1 = sqrt((e1-AM(ip1))*(e1+AM(ip1))) endif - else if(Imode.eq.4) then - Nproc = 4 - if(ip1.eq.1) then - ipa = 32 - else if(ip2.eq.1) then - ipb = 32 + e3 = 0.5D0*(Ecm + am_a**2/Ecm - am_b**2/Ecm) + if(e3.gt.100.D0*am_a) then + pcm3 = e3 - 0.5D0*am_a**2/e3 + else + pcm3 = sqrt((e3-am_a)*(e3+am_a)) + endif + t0 = ((AM(ip1)**2-am_a**2-AM(ip2)**2+am_b**2)/(2.D0*Ecm))**2 + & -(pcm1-pcm3)**2-0.0001D0 + t1 = ((AM(ip1)**2-am_a**2-AM(ip2)**2+am_b**2)/(2.D0*Ecm))**2 + & -(pcm1+pcm3)**2+0.0001D0 +C sample t + b = 6.5D0+2.D0*alphap*log(S) + t = 1.D0/b*log((exp(b*t0)-exp(b*t1))*RNDM(0)+exp(b*t1)) +C kinematics + pl = (2.D0*e1*e3+t-AM(ip1)**2-am_a**2)/(2.D0*pcm1) + pt = (pcm3-pl)*(pcm3+pl) + if(pt.lt.0.D0) then + pl = sign(pcm3,pl) + pt = 1.D-6 + else + pt = sqrt(pt) endif - endif - - am_a = AM(ipa) - am_b = AM(ipb) - if(am_a+am_b.ge.Ecm-1.D-2) am_a = Ecm - am_b-1.D-2 - -C find t range - e1 = 0.5D0*(Ecm + AM(ip1)**2/Ecm - AM(ip2)**2/Ecm) - if(e1.gt.100.D0*AM(ip1)) then - pcm1 = e1 - 0.5D0*AM(ip1)**2/e1 - else - pcm1 = sqrt((e1-AM(ip1))*(e1+AM(ip1))) - endif - e3 = 0.5D0*(Ecm + am_a**2/Ecm - am_b**2/Ecm) - if(e3.gt.100.D0*am_a) then - pcm3 = e3 - 0.5D0*am_a**2/e3 - else - pcm3 = sqrt((e3-am_a)*(e3+am_a)) - endif - t0 = ((AM(ip1)**2-am_a**2-AM(ip2)**2+am_b**2)/(2.D0*Ecm))**2 - & -(pcm1-pcm3)**2-0.0001D0 - t1 = ((AM(ip1)**2-am_a**2-AM(ip2)**2+am_b**2)/(2.D0*Ecm))**2 - & -(pcm1+pcm3)**2+0.0001D0 - -C sample t - b = 6.5D0+2.D0*alphap*log(S) - t = 1.D0/b*log((exp(b*t0)-exp(b*t1))*RNDM(0)+exp(b*t1)) - -C kinematics - pl = (2.D0*e1*e3+t-AM(ip1)**2-am_a**2)/(2.D0*pcm1) - pt = (pcm3-pl)*(pcm3+pl) - if(pt.lt.0.D0) then - pl = sign(pcm3,pl) - pt = 1.D-6 - else - pt = sqrt(pt) - endif - phi = 6.28318530717959D0*RNDM(0) - - LLIST(1) = ipa - P(1,4) = e3 - P(1,1) = SIN(phi)*pt - P(1,2) = COS(phi)*pt - P(1,3) = pl - P(1,5) = am_a - LLIST(2) = ipb - P(2,1) = -P(1,1) - P(2,2) = -P(1,2) - P(2,3) = -P(1,3) - P(2,4) = Ecm - P(1,4) - P(2,5) = am_b - np = 2 - - call DECSIB + phi = 6.28318530717959D0*RNDM(0) + + LLIST(1) = ipa + P(1,4) = e3 + P(1,1) = SIN(phi)*pt + P(1,2) = COS(phi)*pt + P(1,3) = pl + P(1,5) = am_a + LLIST(2) = ipb + P(2,1) = -P(1,1) + P(2,2) = -P(1,2) + P(2,3) = -P(1,3) + P(2,4) = Ecm - P(1,4) + P(2,5) = am_b + np = 2 - ELSE IF((Imode.eq.2).or.(Imode.eq.3)) THEN + call DECSIB + ELSE IF((Imode.eq.2).or.(Imode.eq.3)) THEN C*********************************************************************** +C simulation of direct p-gamma process + if(ip1.eq.13) then +C projectile is a proton + if(Imode.eq.2) then + Nproc = 2 + ipa = 14 + ipb = 7 + else + Nproc = 3 + if(rndm(0).gt.0.25) then + ipa = 40 + ipb = 8 + else + ipa = 42 + ipb = 7 + endif + endif + else if(ip1.eq.14) then +C projectile is a neutron + if(Imode.eq.2) then + Nproc = 2 + ipa = 13 + ipb = 8 + else + Nproc = 3 + if(rndm(0).gt.0.25) then + ipa = 43 + ipb = 7 + else + ipa = 41 + ipb = 8 + endif + endif + endif -C simulation of direct p-gamma process - - if(ip1.eq.13) then -C projectile is a proton - if(Imode.eq.2) then - Nproc = 2 - ipa = 14 - ipb = 7 + am_a = AM(ipa) + am_b = AM(ipb) + if(am_a+am_b.ge.Ecm-1.e-3) am_a = Ecm - am_b-1.D-3 +C find t range + e1 = 0.5D0*(Ecm + AM(ip1)**2/Ecm - AM(ip2)**2/Ecm) + if(e1.gt.100.D0*AM(ip1)) then + pcm1 = e1 - 0.5D0*AM(ip1)**2/e1 else - Nproc = 3 - if(rndm(0).gt.0.25) then - ipa = 40 - ipb = 8 - else - ipa = 42 - ipb = 7 - endif + pcm1 = sqrt((e1-AM(ip1))*(e1+AM(ip1))) endif - else if(ip1.eq.14) then -C projectile is a neutron - if(Imode.eq.2) then - Nproc = 2 - ipa = 13 - ipb = 8 + e3 = 0.5D0*(Ecm + am_a**2/Ecm - am_b**2/Ecm) + if(e3.gt.100.D0*am_a) then + pcm3 = e3 - 0.5D0*am_a**2/e3 else - Nproc = 3 - if(rndm(0).gt.0.25) then - ipa = 43 - ipb = 7 - else - ipa = 41 - ipb = 8 - endif + pcm3 = sqrt((e3-am_a)*(e3+am_a)) endif - endif - - am_a = AM(ipa) - am_b = AM(ipb) - if(am_a+am_b.ge.Ecm-1.e-3) am_a = Ecm - am_b-1.D-3 - -C find t range - e1 = 0.5D0*(Ecm + AM(ip1)**2/Ecm - AM(ip2)**2/Ecm) - if(e1.gt.100.D0*AM(ip1)) then - pcm1 = e1 - 0.5D0*AM(ip1)**2/e1 - else - pcm1 = sqrt((e1-AM(ip1))*(e1+AM(ip1))) - endif - e3 = 0.5D0*(Ecm + am_a**2/Ecm - am_b**2/Ecm) - if(e3.gt.100.D0*am_a) then - pcm3 = e3 - 0.5D0*am_a**2/e3 - else - pcm3 = sqrt((e3-am_a)*(e3+am_a)) - endif - t0 = ((AM(ip1)**2-am_a**2-AM(ip2)**2+am_b**2)/(2.D0*Ecm))**2 - & -(pcm1-pcm3)**2-0.0001D0 - t1 = ((AM(ip1)**2-am_a**2-AM(ip2)**2+am_b**2)/(2.D0*Ecm))**2 - & -(pcm1+pcm3)**2+0.0001D0 - -C sample t - b = 12.D0 - t = 1./b*log((exp(b*t0)-exp(b*t1))*RNDM(0)+exp(b*t1)) - -C kinematics - pl = (2.D0*e1*e3+t-AM(ip1)**2-am_a**2)/(2.D0*pcm1) - pt = (pcm3-pl)*(pcm3+pl) - if(pt.lt.0.D0) then - pl = sign(pcm3,pl) - pt = 1.D-6 - else - pt = sqrt(pt) - endif - phi = 6.28318530717959D0*RNDM(0) - - LLIST(1) = ipa - P(1,4) = e3 - P(1,1) = SIN(phi)*pt - P(1,2) = COS(phi)*pt - P(1,3) = pl - P(1,5) = am_a - LLIST(2) = ipb - P(2,1) = -P(1,1) - P(2,2) = -P(1,2) - P(2,3) = -P(1,3) - P(2,4) = Ecm - P(1,4) - P(2,5) = am_b - np = 2 - - call DECSIB + t0 = ((AM(ip1)**2-am_a**2-AM(ip2)**2+am_b**2)/(2.D0*Ecm))**2 + & -(pcm1-pcm3)**2-0.0001D0 + t1 = ((AM(ip1)**2-am_a**2-AM(ip2)**2+am_b**2)/(2.D0*Ecm))**2 + & -(pcm1+pcm3)**2+0.0001D0 +C sample t + b = 12.D0 + t = 1./b*log((exp(b*t0)-exp(b*t1))*RNDM(0)+exp(b*t1)) +C kinematics + pl = (2.D0*e1*e3+t-AM(ip1)**2-am_a**2)/(2.D0*pcm1) + pt = (pcm3-pl)*(pcm3+pl) + if(pt.lt.0.D0) then + pl = sign(pcm3,pl) + pt = 1.D-6 + else + pt = sqrt(pt) + endif + phi = 6.28318530717959D0*RNDM(0) + + LLIST(1) = ipa + P(1,4) = e3 + P(1,1) = SIN(phi)*pt + P(1,2) = COS(phi)*pt + P(1,3) = pl + P(1,5) = am_a + LLIST(2) = ipb + P(2,1) = -P(1,1) + P(2,2) = -P(1,2) + P(2,3) = -P(1,3) + P(2,4) = Ecm - P(1,4) + P(2,5) = am_b + np = 2 + call DECSIB ELSE - C*********************************************************************** - C simulation of multiparticle production via fragmentation - Nproc = 0 SIG_reg = 129.D0*(S-AM(13)**2)**(-0.4525D0) SIG_pom = 67.7D0*(S-AM(13)**2)**0.0808D0 if(S.gt.2.6D0) then - prob_reg = SIG_reg/(SIG_pom+SIG_reg) + prob_reg = SIG_reg/(SIG_pom+SIG_reg) else - prob_reg = 1.D0 + prob_reg = 1.D0 endif ptu =.36D0+.08D0*log10(sqs/30.D0) @@ -1811,236 +1528,222 @@ SUBROUTINE gamma_h(Ecm,ip1,Imode,ifbad) s2 = 0.6D0 as1 = s1**2/S as2 = s2**2/S - if(s1+s2.ge.sqs-0.2) then - prob_reg = 1.D0 - endif + if(s1+s2.ge.sqs-0.2) prob_reg = 1.D0 itry = 0 - 100 continue - Istring = 0 + 100 CONTINUE + Istring = 0 C avoid infinite looping itry = itry+1 if(itry.gt.50) then - print *,' gamma_h: more than 50 internal rejections,' - print *,' called with ip1,ip2,Ecm,Imode:',ip1,ip2,Ecm,Imode -C PAUSE - ifbad = 1 - return + PRINT *,' gamma_h: more than 50 internal rejections,' + PRINT *,' called with ip1,ip2,Ecm,Imode:' + & ,ip1,ip2,Ecm,Imode + ifbad = 1 + RETURN endif - -C simulate reggeon (one-string topology) - +C simulate reggeon (one-string topology) if(RNDM(0).lt.prob_reg) then - - do i=1,1000 - call valences(IP1,Ifl1a,Ifl1b) - call valences(IP2,Ifl2a,Ifl2b) - if(Ifl1b.eq.-Ifl2b) goto 200 - enddo - print *,'gamma_h: simulation of reggeon impossible:',ip1,ip2 - goto 100 + do i=1,1000 + call valences(IP1,Ifl1a,Ifl1b) + call valences(IP2,Ifl2a,Ifl2b) + if(Ifl1b.eq.-Ifl2b) goto 200 + enddo + PRINT *,'gamma_h: simulation of reggeon impossible:' + & ,ip1,ip2 + goto 100 - 200 continue + 200 CONTINUE + np = 0 + Istring = 1 - np = 0 - Istring = 1 + ee = Ecm/2.D0 - ee = Ecm/2.D0 - 250 continue + 250 CONTINUE pt = ptu*sqrt(-log(max(1.D-10,RNDM(0)))) - if(pt.ge.ee) goto 250 - phi = 6.2831853D0*RNDM(0) - px = pt*COS(phi) - py = pt*SIN(phi) - - pz = SQRT(ee**2-px**2-py**2) - call lund_put(1,Ifl1a,px,py,pz,ee) - px = -px - py = -py - pz = -pz - call lund_put(2,Ifl2a,px,py,pz,ee) - Ijoin(1) = 1 - Ijoin(2) = 2 - call lujoin(2,Ijoin) - - call lund_frag(Ecm,NP) - if(NP.lt.0) then - if(Ideb.ge.5) - & print *,' gamma_h: rejection (1) by lund_frag, sqs:',Ecm - NP = 0 - goto 100 - endif - - do i=1,NP - call lund_get(i,LLIST(i), - & P(i,1),P(i,2),P(i,3),P(i,4),P(i,5)) - enddo - + if(pt.ge.ee) goto 250 + phi = 6.2831853D0*RNDM(0) + px = pt*COS(phi) + py = pt*SIN(phi) + + pz = SQRT(ee**2-px**2-py**2) + call lund_put(1,Ifl1a,px,py,pz,ee) + px = -px + py = -py + pz = -pz + call lund_put(2,Ifl2a,px,py,pz,ee) + Ijoin(1) = 1 + Ijoin(2) = 2 + call lujoin(2,Ijoin) + + call lund_frag(Ecm,NP) + if(NP.lt.0) then + if(Ideb.ge.5) + & PRINT *,' gamma_h: rejection (1) by lund_frag, + & sqs:',Ecm + NP = 0 + goto 100 + endif + do i=1,NP + call lund_get(i,LLIST(i), + & P(i,1),P(i,2),P(i,3),P(i,4),P(i,5)) + enddo C simulate pomeron (two-string topology) - else + call valences(IP1,Ifl1a,Ifl1b) + call valences(IP2,Ifl2a,Ifl2b) + if(Ifl1a*Ifl2a.lt.0) then + j = Ifl2a + Ifl2a = Ifl2b + Ifl2b = j + endif - call valences(IP1,Ifl1a,Ifl1b) - call valences(IP2,Ifl2a,Ifl2b) - if(Ifl1a*Ifl2a.lt.0) then - j = Ifl2a - Ifl2a = Ifl2b - Ifl2b = j - endif - - pl1 = (1.D0+as1-as2) - ps1 = 0.25D0*pl1**2-as1 - if(ps1.le.0.D0) then - if(Ideb.ge.5) print *,' rejection by x-limits (1) ',Ecm - prob_reg = 1.D0 - goto 100 - endif - ps1 = sqrt(ps1) - xmi(1) = 0.5D0*pl1-ps1 - xma(1) = 0.5D0*pl1+ps1 - - pl2 = (1.D0+as2-as1) - ps2 = 0.25D0*pl2**2-as2 - if(ps2.le.0.D0) then - if(Ideb.ge.5) print *,' rejection by x-limits (2) ',Ecm - prob_reg = 1.D0 - goto 100 - endif - ps2 = sqrt(ps2) - xmi(2) = 0.5D0*pl2-ps2 - xma(2) = 0.5D0*pl2+ps2 - - if((xmi(1).ge.xma(1)+0.05D0).or. - & (xmi(2).ge.xma(2)+0.05D0)) then - if(Ideb.ge.5) print *,' rejection by x-limits (3) ',Ecm - prob_reg = 1.D0 - goto 100 - endif - call PO_SELSX2(xs1,xs2,xmi,xma,as1,as2,Irej) - if(Irej.ne.0) then - if(Ideb.ge.5) print *, - & 'gamma_h: rejection by PO_SELSX2, sqs,m1,m2:',Ecm,s1,s2 - prob_reg = 1.D0 - goto 100 - endif + pl1 = (1.D0+as1-as2) + ps1 = 0.25D0*pl1**2-as1 + if(ps1.le.0.D0) then + if(Ideb.ge.5) PRINT*,' rejection by x-limits (1) ',Ecm + prob_reg = 1.D0 + goto 100 + endif + ps1 = sqrt(ps1) + xmi(1) = 0.5D0*pl1-ps1 + xma(1) = 0.5D0*pl1+ps1 + + pl2 = (1.D0+as2-as1) + ps2 = 0.25D0*pl2**2-as2 + if(ps2.le.0.D0) then + if(Ideb.ge.5) PRINT*,' rejection by x-limits (2) ',Ecm + prob_reg = 1.D0 + goto 100 + endif + ps2 = sqrt(ps2) + xmi(2) = 0.5D0*pl2-ps2 + xma(2) = 0.5D0*pl2+ps2 + + if((xmi(1).ge.xma(1)+0.05D0).or. + & (xmi(2).ge.xma(2)+0.05D0)) then + if(Ideb.ge.5) PRINT*,' rejection by x-limits (3) ',Ecm + prob_reg = 1.D0 + goto 100 + endif + call PO_SELSX2(xs1,xs2,xmi,xma,as1,as2,Irej) + if(Irej.ne.0) then + if(Ideb.ge.5) PRINT *,'gamma_h: rejection by PO_SELSX2 + & , sqs,m1,m2:',Ecm,s1,s2 + prob_reg = 1.D0 + goto 100 + endif - NP = 0 - Istring = 1 + NP = 0 + Istring = 1 + + ee = SQRT(XS1(1)*XS2(1))*Ecm/2.D0 - ee = SQRT(XS1(1)*XS2(1))*Ecm/2.D0 - 260 continue + 260 CONTINUE pt = ptu*sqrt(-log(max(1.D-10,RNDM(0)))) - if(pt.ge.ee) goto 260 - phi = 6.2831853D0*RNDM(0) - px = pt*COS(phi) - py = pt*SIN(phi) - - PA1(1) = px - PA1(2) = py - PA1(3) = XS1(1)*Ecm/2.D0 - PA1(4) = PA1(3) - - PA2(1) = -px - PA2(2) = -py - PA2(3) = -XS2(1)*Ecm/2.D0 - PA2(4) = -PA2(3) - - XM1 = 0.D0 - XM2 = 0.D0 - call PO_MSHELL(PA1,PA2,XM1,XM2,P1,P2) - px = P1(1) - py = P1(2) - pz = P1(3) - ee = P1(4) - call lund_put(1,Ifl1a,px,py,pz,ee) - px = P2(1) - py = P2(2) - pz = P2(3) - ee = P2(4) - call lund_put(2,Ifl2a,px,py,pz,ee) - - Ijoin(1) = 1 - Ijoin(2) = 2 - call lujoin(2,Ijoin) - - ee = SQRT(XS1(2)*XS2(2))*Ecm/2.D0 - 270 continue + if(pt.ge.ee) goto 260 + phi = 6.2831853D0*RNDM(0) + px = pt*COS(phi) + py = pt*SIN(phi) + + PA1(1) = px + PA1(2) = py + PA1(3) = XS1(1)*Ecm/2.D0 + PA1(4) = PA1(3) + + PA2(1) = -px + PA2(2) = -py + PA2(3) = -XS2(1)*Ecm/2.D0 + PA2(4) = -PA2(3) + + XM1 = 0.D0 + XM2 = 0.D0 + call PO_MSHELL(PA1,PA2,XM1,XM2,P1,P2) + px = P1(1) + py = P1(2) + pz = P1(3) + ee = P1(4) + call lund_put(1,Ifl1a,px,py,pz,ee) + px = P2(1) + py = P2(2) + pz = P2(3) + ee = P2(4) + call lund_put(2,Ifl2a,px,py,pz,ee) + + Ijoin(1) = 1 + Ijoin(2) = 2 + call lujoin(2,Ijoin) + + ee = SQRT(XS1(2)*XS2(2))*Ecm/2.D0 + + 270 CONTINUE pt = ptu*sqrt(-log(max(1.D-10,RNDM(0)))) - if(pt.ge.ee) goto 270 - phi = 6.2831853D0*RNDM(0) - px = pt*COS(phi) - py = pt*SIN(phi) - - PA1(1) = px - PA1(2) = py - PA1(3) = XS1(2)*Ecm/2.D0 - PA1(4) = PA1(3) - - PA2(1) = -px - PA2(2) = -py - PA2(3) = -XS2(2)*Ecm/2.D0 - PA2(4) = -PA2(3) - - XM1 = 0.D0 - XM2 = 0.D0 - call PO_MSHELL(PA1,PA2,XM1,XM2,P1,P2) - - px = P1(1) - py = P1(2) - pz = P1(3) - ee = P1(4) - call lund_put(3,Ifl1b,px,py,pz,ee) - px = P2(1) - py = P2(2) - pz = P2(3) - ee = P2(4) - call lund_put(4,Ifl2b,px,py,pz,ee) - - Ijoin(1) = 3 - Ijoin(2) = 4 - call lujoin(2,Ijoin) - - call lund_frag(Ecm,NP) - if(NP.lt.0) then - if(Ideb.ge.5) - & print *,' gamma_h: rejection (2) by lund_frag, sqs:',Ecm - NP = 0 - prob_reg = prob_reg+0.1D0 - goto 100 - endif - - do i=1,NP - call lund_get(i,LLIST(i), - & P(i,1),P(i,2),P(i,3),P(i,4),P(i,5)) - enddo - - endif + if(pt.ge.ee) goto 270 + phi = 6.2831853D0*RNDM(0) + px = pt*COS(phi) + py = pt*SIN(phi) + + PA1(1) = px + PA1(2) = py + PA1(3) = XS1(2)*Ecm/2.D0 + PA1(4) = PA1(3) + + PA2(1) = -px + PA2(2) = -py + PA2(3) = -XS2(2)*Ecm/2.D0 + PA2(4) = -PA2(3) + + XM1 = 0.D0 + XM2 = 0.D0 + call PO_MSHELL(PA1,PA2,XM1,XM2,P1,P2) + + px = P1(1) + py = P1(2) + pz = P1(3) + ee = P1(4) + call lund_put(3,Ifl1b,px,py,pz,ee) + px = P2(1) + py = P2(2) + pz = P2(3) + ee = P2(4) + call lund_put(4,Ifl2b,px,py,pz,ee) + + Ijoin(1) = 3 + Ijoin(2) = 4 + call lujoin(2,Ijoin) + + call lund_frag(Ecm,NP) + if(NP.lt.0) then + if(Ideb.ge.5) + & PRINT *,' gamma_h: rejection (2) by lund_frag, sqs:' + & ,Ecm + NP = 0 + prob_reg = prob_reg+0.1D0 + goto 100 + endif - if(Ideb.ge.10) then - print *,' multi-pion event',Istring,NP - call print_event(1) + do i=1,NP + call lund_get(i,LLIST(i), + & P(i,1),P(i,2),P(i,3),P(i,4),P(i,5)) + enddo endif - -C... for fragmentation in resonance region: + if(Ideb.ge.10) PRINT *,' multi-pion event',Istring,NP +C... for fragmentation in resonance region: if (Imode.eq.5) goto 400 - -C leading baryon/meson effect - +C leading baryon/meson effect do j=1,np - if(((LLIST(J).eq.13).or.(LLIST(J).eq.14)) - & .and.(p(j,3).lt.0.D0)) then - if(rndm(0).lt.(2.D0*p(j,4)/Ecm)**2) goto 100 - endif - if((LLIST(J).ge.6).and.(LLIST(J).le.8) - & .and.(p(j,3).lt.-0.4D0)) then - if(rndm(0).lt.(2.D0*p(j,4)/Ecm)**2) goto 100 - endif + if(((LLIST(J).eq.13).or.(LLIST(J).eq.14)) + & .and.(p(j,3).lt.0.D0)) then + if(rndm(0).lt.(2.D0*p(j,4)/Ecm)**2) goto 100 + endif + if((LLIST(J).ge.6).and.(LLIST(J).le.8) + & .and.(p(j,3).lt.-0.4D0)) then + if(rndm(0).lt.(2.D0*p(j,4)/Ecm)**2) goto 100 + endif enddo - -C remove elastic/diffractive channels - +C remove elastic/diffractive channels ima_0 = 0 imb_0 = 0 ima_1 = 0 @@ -2050,394 +1753,277 @@ SUBROUTINE gamma_h(Ecm,ip1,Imode,ifbad) imul = 0 if(ip1.eq.1) then - iba_0 = 6 - iba_1 = 27 - iba_2 = 32 + iba_0 = 6 + iba_1 = 27 + iba_2 = 32 else - iba_0 = ip1 - iba_1 = ip1 - iba_2 = ip1 + iba_0 = ip1 + iba_1 = ip1 + iba_2 = ip1 endif if(ip2.eq.1) then - ibb_0 = 6 - ibb_1 = 27 - ibb_2 = 32 + ibb_0 = 6 + ibb_1 = 27 + ibb_2 = 32 else - ibb_0 = ip2 - ibb_1 = ip2 - ibb_2 = ip2 + ibb_0 = ip2 + ibb_1 = ip2 + ibb_2 = ip2 endif do j=1,np - l1 = abs(LLIST(J)) - if(l1.lt.10000) then - if(LLIST(J).eq.iba_0) ima_0 = 1 - if(LLIST(J).eq.iba_1) ima_1 = 1 - if(LLIST(J).eq.iba_2) ima_2 = 1 - if(LLIST(J).eq.ibb_0) imb_0 = 1 - if(LLIST(J).eq.ibb_1) imb_1 = 1 - if(LLIST(J).eq.ibb_2) imb_2 = 1 - imul = imul+1 - endif + l1 = abs(LLIST(J)) + if(l1.lt.10000) then + if(LLIST(J).eq.iba_0) ima_0 = 1 + if(LLIST(J).eq.iba_1) ima_1 = 1 + if(LLIST(J).eq.iba_2) ima_2 = 1 + if(LLIST(J).eq.ibb_0) imb_0 = 1 + if(LLIST(J).eq.ibb_1) imb_1 = 1 + if(LLIST(J).eq.ibb_2) imb_2 = 1 + imul = imul+1 + endif enddo if(imul.eq.2) then - if(ima_0*imb_0.eq.1) goto 100 - if(ima_1*imb_1.eq.1) goto 100 - if(ima_2*imb_2.eq.1) goto 100 + if(ima_0*imb_0.eq.1) goto 100 + if(ima_1*imb_1.eq.1) goto 100 + if(ima_2*imb_2.eq.1) goto 100 endif C remove direct channels - if((imul.eq.2).and. - & (ip2.eq.1).and.((ip1.eq.13).or.(ip1.eq.14))) then - - ima_0 = 0 - imb_0 = 0 - ima_1 = 0 - imb_1 = 0 - ima_2 = 0 - imb_2 = 0 - ima_3 = 0 - imb_3 = 0 - - if(ip1.eq.13) then - iba_0 = 14 - ibb_0 = 7 - iba_1 = 40 - ibb_1 = 8 - iba_2 = 42 - ibb_2 = 7 - iba_3 = 13 - ibb_3 = 23 - else - iba_0 = 13 - ibb_0 = 8 - iba_1 = 43 - ibb_1 = 7 - iba_2 = 41 - ibb_2 = 8 - iba_3 = 14 - ibb_3 = 23 - endif - - do j=1,np - l1 = abs(LLIST(J)) - if(l1.lt.10000) then - if(LLIST(J).eq.iba_0) ima_0 = 1 - if(LLIST(J).eq.iba_1) ima_1 = 1 - if(LLIST(J).eq.iba_2) ima_2 = 1 - if(LLIST(J).eq.iba_3) ima_3 = 1 - if(LLIST(J).eq.ibb_0) imb_0 = 1 - if(LLIST(J).eq.ibb_1) imb_1 = 1 - if(LLIST(J).eq.ibb_2) imb_2 = 1 - if(LLIST(J).eq.ibb_3) imb_3 = 1 + & (ip2.eq.1).and.((ip1.eq.13).or.(ip1.eq.14))) then + + ima_0 = 0 + imb_0 = 0 + ima_1 = 0 + imb_1 = 0 + ima_2 = 0 + imb_2 = 0 + ima_3 = 0 + imb_3 = 0 + + if(ip1.eq.13) then + iba_0 = 14 + ibb_0 = 7 + iba_1 = 40 + ibb_1 = 8 + iba_2 = 42 + ibb_2 = 7 + iba_3 = 13 + ibb_3 = 23 + else + iba_0 = 13 + ibb_0 = 8 + iba_1 = 43 + ibb_1 = 7 + iba_2 = 41 + ibb_2 = 8 + iba_3 = 14 + ibb_3 = 23 endif - enddo - - if(ima_0*imb_0.eq.1) goto 100 - if(ima_1*imb_1.eq.1) goto 100 - if(ima_2*imb_2.eq.1) goto 100 - if(ima_3*imb_3.eq.1) goto 100 - + do j=1,np + l1 = abs(LLIST(J)) + if(l1.lt.10000) then + if(LLIST(J).eq.iba_0) ima_0 = 1 + if(LLIST(J).eq.iba_1) ima_1 = 1 + if(LLIST(J).eq.iba_2) ima_2 = 1 + if(LLIST(J).eq.iba_3) ima_3 = 1 + if(LLIST(J).eq.ibb_0) imb_0 = 1 + if(LLIST(J).eq.ibb_1) imb_1 = 1 + if(LLIST(J).eq.ibb_2) imb_2 = 1 + if(LLIST(J).eq.ibb_3) imb_3 = 1 + endif + enddo + if(ima_0*imb_0.eq.1) goto 100 + if(ima_1*imb_1.eq.1) goto 100 + if(ima_2*imb_2.eq.1) goto 100 + if(ima_3*imb_3.eq.1) goto 100 endif - -C suppress events with many pi0's - +C suppress events with many pi0's ima_0 = 0 imb_0 = 0 do j=1,np -C neutral mesons - if(LLIST(J).eq.6) ima_0 = ima_0+1 - if(LLIST(J).eq.11) ima_0 = ima_0+1 - if(LLIST(J).eq.12) ima_0 = ima_0+1 - if(LLIST(J).eq.21) ima_0 = ima_0+1 - if(LLIST(J).eq.22) ima_0 = ima_0+1 - if(LLIST(J).eq.23) ima_0 = ima_0+1 - if(LLIST(J).eq.24) ima_0 = ima_0+1 - if(LLIST(J).eq.27) ima_0 = ima_0+1 - if(LLIST(J).eq.32) ima_0 = ima_0+1 - if(LLIST(J).eq.33) ima_0 = ima_0+1 -C charged mesons - if(LLIST(J).eq.7) imb_0 = imb_0+1 - if(LLIST(J).eq.8) imb_0 = imb_0+1 - if(LLIST(J).eq.9) imb_0 = imb_0+1 - if(LLIST(J).eq.10) imb_0 = imb_0+1 - if(LLIST(J).eq.25) imb_0 = imb_0+1 - if(LLIST(J).eq.26) imb_0 = imb_0+1 +C neutral mesons + if(LLIST(J).eq.6) ima_0 = ima_0+1 + if(LLIST(J).eq.11) ima_0 = ima_0+1 + if(LLIST(J).eq.12) ima_0 = ima_0+1 + if(LLIST(J).eq.21) ima_0 = ima_0+1 + if(LLIST(J).eq.22) ima_0 = ima_0+1 + if(LLIST(J).eq.23) ima_0 = ima_0+1 + if(LLIST(J).eq.24) ima_0 = ima_0+1 + if(LLIST(J).eq.27) ima_0 = ima_0+1 + if(LLIST(J).eq.32) ima_0 = ima_0+1 + if(LLIST(J).eq.33) ima_0 = ima_0+1 +C charged mesons + if(LLIST(J).eq.7) imb_0 = imb_0+1 + if(LLIST(J).eq.8) imb_0 = imb_0+1 + if(LLIST(J).eq.9) imb_0 = imb_0+1 + if(LLIST(J).eq.10) imb_0 = imb_0+1 + if(LLIST(J).eq.25) imb_0 = imb_0+1 + if(LLIST(J).eq.26) imb_0 = imb_0+1 enddo prob_1 = a1*DBLE(imb_0)/max(DBLE(ima_0+imb_0),1.D0)+a2 if(RNDM(0).GT.prob_1) goto 100 - - -C correct multiplicity at very low energies - +C correct multiplicity at very low energies ND = 0 E_ref_1 = 1.6D0 E_ref_2 = 1.95D0 if((imul.eq.3) - & .and.(Ecm.gt.E_ref_1).and.(Ecm.lt.E_ref_2)) then - - ima_0 = 0 - ima_1 = 0 - ima_2 = 0 - imb_0 = 0 - imb_1 = 0 - iba_0 = 0 - iba_1 = 0 - iba_2 = 0 - ibb_0 = 0 - ibb_1 = 0 -C incoming proton - if(ip1.eq.13) then - iba_0 = 13 - iba_1 = 7 - iba_2 = 8 - ibb_0 = 14 - ibb_1 = 6 -C incoming neutron - else if(ip1.eq.14) then - iba_0 = 14 - iba_1 = 7 - iba_2 = 8 - ibb_0 = 13 - ibb_1 = 6 - endif - do j=1,np - if(LLIST(J).eq.iba_0) ima_0 = ima_0+1 - if(LLIST(J).eq.iba_1) ima_1 = ima_1+1 - if(LLIST(J).eq.iba_2) ima_2 = ima_2+1 - if(LLIST(J).eq.ibb_0) imb_0 = imb_0+1 - if(LLIST(J).eq.ibb_1) imb_1 = imb_1+1 - enddo - + & .and.(Ecm.gt.E_ref_1).and.(Ecm.lt.E_ref_2)) then + + ima_0 = 0 + ima_1 = 0 + ima_2 = 0 + imb_0 = 0 + imb_1 = 0 + iba_0 = 0 + iba_1 = 0 + iba_2 = 0 + ibb_0 = 0 + ibb_1 = 0 +C incoming proton + if(ip1.eq.13) then + iba_0 = 13 + iba_1 = 7 + iba_2 = 8 + ibb_0 = 14 + ibb_1 = 6 +C incoming neutron + else if(ip1.eq.14) then + iba_0 = 14 + iba_1 = 7 + iba_2 = 8 + ibb_0 = 13 + ibb_1 = 6 + endif + do j=1,np + if(LLIST(J).eq.iba_0) ima_0 = ima_0+1 + if(LLIST(J).eq.iba_1) ima_1 = ima_1+1 + if(LLIST(J).eq.iba_2) ima_2 = ima_2+1 + if(LLIST(J).eq.ibb_0) imb_0 = imb_0+1 + if(LLIST(J).eq.ibb_1) imb_1 = imb_1+1 + enddo C N gamma --> N pi+ pi- - if(ima_0*ima_1*ima_2.eq.1) then - Elog = LOG(Ecm) - Elog_1 = LOG(E_ref_1) - Elog_2 = LOG(E_ref_2) - prob = 0.1D0*4.D0/(Elog_2-Elog_1)**2 - & *(Elog-Elog_1)*(Elog_2-Elog) - - if(RNDM(0).lt.prob) then - LL(1) = ip1 - LL(2) = 7 - LL(3) = 8 - LL(4) = 6 - ND = 4 + if(ima_0*ima_1*ima_2.eq.1) then + Elog = LOG(Ecm) + Elog_1 = LOG(E_ref_1) + Elog_2 = LOG(E_ref_2) + prob = 0.1D0*4.D0/(Elog_2-Elog_1)**2 + & *(Elog-Elog_1)*(Elog_2-Elog) + if(RNDM(0).lt.prob) then + LL(1) = ip1 + LL(2) = 7 + LL(3) = 8 + LL(4) = 6 + ND = 4 + endif endif - - endif - endif - E_ref_1 = 1.95D0 E_ref_2 = 2.55D0 if((imul.eq.4) - & .and.(Ecm.gt.E_ref_1).and.(Ecm.lt.E_ref_2)) then - - ima_0 = 0 - ima_1 = 0 - ima_2 = 0 - imb_0 = 0 - imb_1 = 0 - iba_0 = 0 - iba_1 = 0 - iba_2 = 0 - ibb_0 = 0 - ibb_1 = 0 -C incoming proton - if(ip1.eq.13) then - iba_0 = 13 - iba_1 = 7 - iba_2 = 8 - ibb_0 = 14 - ibb_1 = 6 -C incoming neutron - else if(ip1.eq.14) then - iba_0 = 14 - iba_1 = 7 - iba_2 = 8 - ibb_0 = 13 - ibb_1 = 6 - endif - do j=1,np - if(LLIST(J).eq.iba_0) ima_0 = ima_0+1 - if(LLIST(J).eq.iba_1) ima_1 = ima_1+1 - if(LLIST(J).eq.iba_2) ima_2 = ima_2+1 - if(LLIST(J).eq.ibb_0) imb_0 = imb_0+1 - if(LLIST(J).eq.ibb_1) imb_1 = imb_1+1 - enddo - -C N gamma --> N pi+ pi- pi0 - if(ima_0*ima_1*ima_2*imb_1.eq.1) then - Elog = LOG(Ecm) - Elog_2 = LOG(E_ref_2) - Elog_1 = LOG(E_ref_1) - prob = 0.1D0*4.D0/(Elog_2-Elog_1)**2 - & *(Elog-Elog_1)*(Elog_2-Elog) - - if(RNDM(0).lt.prob) then - if(ip1.eq.13) then - LL(1) = 14 - LL(2) = 7 - LL(3) = 7 - LL(4) = 8 - else - LL(1) = 13 - LL(2) = 7 - LL(3) = 8 - LL(4) = 8 - endif - ND = 4 + & .and.(Ecm.gt.E_ref_1).and.(Ecm.lt.E_ref_2)) then + ima_0 = 0 + ima_1 = 0 + ima_2 = 0 + imb_0 = 0 + imb_1 = 0 + iba_0 = 0 + iba_1 = 0 + iba_2 = 0 + ibb_0 = 0 + ibb_1 = 0 +C incoming proton + if(ip1.eq.13) then + iba_0 = 13 + iba_1 = 7 + iba_2 = 8 + ibb_0 = 14 + ibb_1 = 6 +C incoming neutron + else if(ip1.eq.14) then + iba_0 = 14 + iba_1 = 7 + iba_2 = 8 + ibb_0 = 13 + ibb_1 = 6 + endif + do j=1,np + if(LLIST(J).eq.iba_0) ima_0 = ima_0+1 + if(LLIST(J).eq.iba_1) ima_1 = ima_1+1 + if(LLIST(J).eq.iba_2) ima_2 = ima_2+1 + if(LLIST(J).eq.ibb_0) imb_0 = imb_0+1 + if(LLIST(J).eq.ibb_1) imb_1 = imb_1+1 + enddo +C N gamma --> N pi+ pi- pi0 + if(ima_0*ima_1*ima_2*imb_1.eq.1) then + Elog = LOG(Ecm) + Elog_2 = LOG(E_ref_2) + Elog_1 = LOG(E_ref_1) + prob = 0.1D0*4.D0/(Elog_2-Elog_1)**2 + & *(Elog-Elog_1)*(Elog_2-Elog) + if(RNDM(0).lt.prob) then + if(ip1.eq.13) then + LL(1) = 14 + LL(2) = 7 + LL(3) = 7 + LL(4) = 8 + else + LL(1) = 13 + LL(2) = 7 + LL(3) = 8 + LL(4) = 8 + endif + ND = 4 + endif endif - - endif - endif - - if(ND.gt.0) then - P_in(1) = 0.D0 - P_in(2) = 0.D0 - P_in(3) = 0.D0 - P_in(4) = Ecm - P_in(5) = Ecm - call DECPAR(0,P_in,ND,LL,P_dec) - Iflip = 0 - do j=1,ND - LLIST(j) = LL(j) - do k=1,5 - P(j,k) = P_dec(j,k) - enddo - if(((LLIST(j).eq.13).or.(LLIST(j).eq.14)) - & .and.(P(j,3).lt.0.D0)) Iflip = 1 - enddo - if(Iflip.ne.0) then + P_in(1) = 0.D0 + P_in(2) = 0.D0 + P_in(3) = 0.D0 + P_in(4) = Ecm + P_in(5) = Ecm + call DECPAR(0,P_in,ND,LL,P_dec) + Iflip = 0 do j=1,ND - P(j,3) = -P(j,3) + LLIST(j) = LL(j) + do k=1,5 + P(j,k) = P_dec(j,k) + enddo + if(((LLIST(j).eq.13).or.(LLIST(j).eq.14)) + & .and.(P(j,3).lt.0.D0)) Iflip = 1 enddo - endif - NP = ND + if(Iflip.ne.0) then + do j=1,ND + P(j,3) = -P(j,3) + enddo + endif + NP = ND endif - -C... for fragmentation in resonance region: - 400 continue - +C... for fragmentation in resonance region: + 400 CONTINUE call DECSIB - ENDIF - if(Ideb.ge.10) then - if(Ideb.ge.20) then - call print_event(2) - else - call print_event(1) - endif - endif - IQchr = ICHP(ip1)+ICHP(ip2) IQbar = IBAR(ip1)+IBAR(ip2) call check_event(-Ic,Ecm,0.D0,0.D0,0.D0,IQchr,IQbar,Irej) - end - - - SUBROUTINE print_event(Iout) -C********************************************************************* -C -C print final state particles -C -C (R.E. 03/98) -C -C********************************************************************** - - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) - - COMMON /S_RUN/ SQS, S, Q2MIN, XMIN, ZMIN, kb, kt, a1, a2, Nproc - COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb - COMMON /S_CSYDEC/ CBR(102), IDB(49), KDEC(612), LBARP(49) - COMMON /S_CHP/ S_LIFE(49), ICHP(49), ISTR(49), IBAR(49) - COMMON /S_MASS1/ AM(49), AM2(49) - COMMON /S_CNAM/ NAMP (0:49) - CHARACTER*6 NAMP - CHARACTER CODE*18 - SAVE - - if(iout.gt.0) then - - print *,' --------------------------------------------------' - - if(Nproc.eq.1) then - print *,' diffractive rho-0 production',Nproc - else if(Nproc.eq.2) then - print *,' direct interaction 1',Nproc - else if(Nproc.eq.3) then - print *,' direct interaction 2',Nproc - else if(Nproc.eq.4) then - print *,' diffractive omega production',Nproc - else if(Nproc.eq.0) then - print *,' multi-pion/fragmentation contribution',Nproc - else if((Nproc.gt.10).and.(Nproc.lt.20)) then - print *,' resonance production and decay',Nproc-10 - else - print *,' unknown process',Nproc - endif - - i0 = 0 - px = 0.D0 - py = 0.D0 - pz = 0.D0 - ee = 0.D0 - ichar = 0 - ibary = 0 - do j=1,np - l1 = abs(LLIST(J)) - l = mod(llist(j),10000) - if(l1.lt.10000) then - px = px + P(j,1) - py = py + P(j,2) - pz = pz + P(j,3) - ee = ee + P(j,4) - ichar = ichar+sign(1,l)*ICHP(iabs(l)) - ibary = ibary+sign(1,l)*IBAR(iabs(l)) - endif - if((l1.lt.10000).or.(Iout.GE.2)) then - i0 = i0+1 - code = ' ' - code(1:6) = namp(iabs(l)) - if (l .lt. 0) code(7:9) = 'bar' - write (6,120) i0,CODE,l1*sign(1,l),sign(1,l)*ICHP(iabs(l)), - & (P(j,k),k=1,4) - endif - enddo - write (6,122) ' sum: ',px,py,pz,ee - print *,' charge QN: ',ichar,' baryon QN: ',ibary - print *,' --------------------------------------------------' -120 FORMAT(1X,I4,1X,A18,1X,I6,1X,I2,1X,2(F9.3,2X),2(E9.3,2X)) -122 FORMAT(7X,A8,20X,2(F9.3,2X),2(E9.3,2X)) - - endif - - END + END SUBROUTINE gamma_h SUBROUTINE check_event(Ic,Esum,PXsum,PYsum,PZsum,IQchr,IQbar,Irej) C*********************************************************************** -C C check energy-momentum and quantum number conservation -C -C (R.E. 08/98) -C C*********************************************************************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) @@ -2456,136 +2042,121 @@ SUBROUTINE check_event(Ic,Esum,PXsum,PYsum,PZsum,IQchr,IQbar,Irej) ee = 0.D0 ichar = 0 ibary = 0 - Iprint = 0 + IPRINT = 0 PLscale = Esum PTscale = 1.D0 do j=1,np - l1 = abs(LLIST(J)) - l = mod(llist(j),10000) - if(l1.lt.10000) then - px = px + P(j,1) - py = py + P(j,2) - pz = pz + P(j,3) - ee = ee + P(j,4) - ichar = ichar+sign(1,l)*ICHP(iabs(l)) - ibary = ibary+sign(1,l)*IBAR(iabs(l)) - endif + l1 = abs(LLIST(J)) + l = mod(llist(j),10000) + if(l1.lt.10000) then + px = px + P(j,1) + py = py + P(j,2) + pz = pz + P(j,3) + ee = ee + P(j,4) + ichar = ichar+sign(1,l)*ICHP(iabs(l)) + ibary = ibary+sign(1,l)*IBAR(iabs(l)) + endif enddo if(ichar.ne.IQchr) then - print *,' charge conservation violated',Ic - Iprint = 1 - endif - if(ibary.ne.IQbar) then - print *,' baryon number conservation violated',Ic - Iprint = 1 - endif - if(abs((px-PXsum)/MAX(PXsum,PTscale)).gt.1.D-3) then - print *,' x momentum conservation violated',Ic - Iprint = 1 - endif - if(abs((py-PYsum)/MAX(PYsum,PTscale)).gt.1.D-3) then - print *,' y momentum conservation violated',Ic - Iprint = 1 - endif - if(abs((pz-Pzsum)/MAX(ABS(PZsum),PLscale)).gt.1.D-3) then - print *,' z momentum conservation violated',Ic - Iprint = 1 - endif - if(abs((ee-Esum)/MAX(Esum,1.D0)).gt.1.D-3) then - print *,' energy conservation violated',Ic - Iprint = 1 + PRINT *,' charge conservation violated',Ic + IPRINT = 1 + else if(ibary.ne.IQbar) then + PRINT *,' baryon number conservation violated',Ic + IPRINT = 1 + else if(abs((px-PXsum)/MAX(PXsum,PTscale)).gt.1.D-3) then + PRINT *,' x momentum conservation violated',Ic + IPRINT = 1 + else if(abs((py-PYsum)/MAX(PYsum,PTscale)).gt.1.D-3) then + PRINT *,' y momentum conservation violated',Ic + IPRINT = 1 + else if(abs((pz-Pzsum)/MAX(ABS(PZsum),PLscale)).gt.1.D-3) then + PRINT *,' z momentum conservation violated',Ic + IPRINT = 1 + else if(abs((ee-Esum)/MAX(Esum,1.D0)).gt.1.D-3) then + PRINT *,' energy conservation violated',Ic + IPRINT = 1 endif - if(Iprint.ne.0) call print_event(1) + Irej = IPRINT - Irej = Iprint - - END + END SUBROUTINE check_event SUBROUTINE valences(ip,ival1,ival2) C********************************************************************** -C C valence quark composition of various particles (R.E. 03/98) C (with special treatment of photons) -C C********************************************************************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) - SAVE if(ip.eq.1) then - if(rndm(0).gt.0.2D0) then - ival1 = 1 - ival2 = -1 - else - ival1 = 2 - ival2 = -2 - endif + if(rndm(0).gt.0.2D0) then + ival1 = 1 + ival2 = -1 + else + ival1 = 2 + ival2 = -2 + endif else if(ip.eq.6) then - if(rndm(0).gt.0.5D0) then + if(rndm(0).gt.0.5D0) then + ival1 = 1 + ival2 = -1 + else + ival1 = 2 + ival2 = -2 + endif + else if(ip.eq.7) then ival1 = 1 - ival2 = -1 - else - ival1 = 2 ival2 = -2 - endif - else if(ip.eq.7) then - ival1 = 1 - ival2 = -2 else if(ip.eq.8) then - ival1 = 2 - ival2 = -1 + ival1 = 2 + ival2 = -1 else if(ip.eq.13) then - Xi = rndm(0) - if(Xi.lt.0.3333D0) then - ival1 = 12 - ival2 = 1 - else if(Xi.lt.0.6666D0) then - ival1 = 21 - ival2 = 1 - else - ival1 = 11 - ival2 = 2 - endif + Xi = rndm(0) + if(Xi.lt.0.3333D0) then + ival1 = 12 + ival2 = 1 + else if(Xi.lt.0.6666D0) then + ival1 = 21 + ival2 = 1 + else + ival1 = 11 + ival2 = 2 + endif else if(ip.eq.14) then - Xi = rndm(0) - if(Xi.lt.0.3333D0) then - ival1 = 12 - ival2 = 2 - else if(Xi.lt.0.6666D0) then - ival1 = 21 - ival2 = 2 - else - ival1 = 22 - ival2 = 1 - endif + Xi = rndm(0) + if(Xi.lt.0.3333D0) then + ival1 = 12 + ival2 = 2 + else if(Xi.lt.0.6666D0) then + ival1 = 21 + ival2 = 2 + else + ival1 = 22 + ival2 = 1 + endif endif if((ip.lt.13).and.(rndm(0).lt.0.5D0)) then - k = ival1 - ival1 = ival2 - ival2 = k + k = ival1 + ival1 = ival2 + ival2 = k endif - END + END SUBROUTINE valences SUBROUTINE DECSIB C*********************************************************************** -C C Decay all unstable particle in SIBYLL C decayed particle have the code increased by 10000 -C C (taken from SIBYLL 1.7, R.E. 04/98) -C C*********************************************************************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) @@ -2598,27 +2169,27 @@ SUBROUTINE DECSIB NN = 1 DO J=1,NP - LLIST1(J) = 0 + LLIST1(J) = 0 ENDDO DO WHILE (NN .LE. NP) - L= LLIST(NN) - IF (IDB(IABS(L)) .GT. 0) THEN - DO K=1,5 - P0(K) = P(NN,K) - ENDDO - ND = 0 - CALL DECPAR (L,P0,ND,LL,PD) - LLIST(NN) = LLIST(NN)+ISIGN(10000,LLIST(NN)) - DO J=1,ND - DO K=1,5 - P(NP+J,K) = PD(J,K) - ENDDO - LLIST(NP+J)=LL(J) - LLIST1(NP+J)=NN - ENDDO - NP=NP+ND - ENDIF - NN = NN+1 + L= LLIST(NN) + IF (IDB(IABS(L)) .GT. 0) THEN + DO K=1,5 + P0(K) = P(NN,K) + ENDDO + ND = 0 + CALL DECPAR (L,P0,ND,LL,PD) + LLIST(NN) = LLIST(NN)+ISIGN(10000,LLIST(NN)) + DO J=1,ND + DO K=1,5 + P(NP+J,K) = PD(J,K) + ENDDO + LLIST(NP+J)=LL(J) + LLIST1(NP+J)=NN + ENDDO + NP=NP+ND + ENDIF + NN = NN+1 ENDDO END @@ -2626,8 +2197,7 @@ SUBROUTINE DECSIB SUBROUTINE DECPAR(LA,P0,ND,LL,P) C*********************************************************************** -C -C This subroutine generates the decay of a particle +C This SUBROUTINE generates the decay of a particle C with ID = LA, and 5-momentum P0(1:5) C into ND particles of 5-momenta P(j,1:5) (j=1:ND) C @@ -2637,13 +2207,11 @@ SUBROUTINE DECPAR(LA,P0,ND,LL,P) C particles of codes LL(1:nd) C C (taken from SIBYLL 1.7, muon decay corrected, R.E. 04/98) -C C*********************************************************************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) - COMMON /S_CSYDEC/ CBR(102), IDB(49), KDEC(612), LBARP(49) + COMMON /S_CSYDEC/ CBR(102), IDB(49), KDEC(612), LBARP(49) COMMON /S_MASS1/ AM(49), AM2(49) SAVE @@ -2654,34 +2222,32 @@ SUBROUTINE DECPAR(LA,P0,ND,LL,P) + 1500.D0,12000.D0,120000.D0/ DATA PI /3.1415926D0/ -C...c.m.s. Momentum in two particle decays +C... c.m.s. Momentum in two particle decays PAWT(A,B,C) = SQRT((A**2-(B+C)**2)*(A**2-(B-C)**2))/(2.D0*A) - -C...Phase space decay into the particles in the list - IF (LA .EQ. 0) THEN +C... Phase space decay into the particles in the list + IF (LA .EQ. 0) THEN MAT = 0 MBST = 0 PS = 0. DO J=1,ND - P (J,5) = AM(IABS(LL(J))) - PV(J,5) = AM(IABS(LL(J))) - PS = PS+P(J,5) + P (J,5) = AM(IABS(LL(J))) + PV(J,5) = AM(IABS(LL(J))) + PS = PS+P(J,5) ENDDO DO J=1,4 - PV(1,J) = P0(J) + PV(1,J) = P0(J) ENDDO PV(1,5) = P0(5) GOTO 140 ENDIF - -C...Choose decay channel +C... Choose decay channel L = IABS(LA) ND=0 IDC = IDB(L)-1 - IF (IDC+1 .LE.0) RETURN + IF (IDC+1 .LE.0) RETURN RBR = RNDM(0) 110 IDC=IDC+1 - IF(RBR.GT.CBR(IDC)) GOTO 110 + IF(RBR.GT.CBR(IDC)) GOTO 110 KD =6*(IDC-1)+1 ND = KDEC(KD) @@ -2694,119 +2260,108 @@ SUBROUTINE DECPAR(LA,P0,ND,LL,P) PS = 0.D0 DO J=1,ND - LL(J) = KDEC(KD+1+J) - P(J,5) = AM(LL(J)) - PV(J,5) = AM(LL(J)) - PS = PS + P(J,5) + LL(J) = KDEC(KD+1+J) + P(J,5) = AM(LL(J)) + PV(J,5) = AM(LL(J)) + PS = PS + P(J,5) ENDDO DO J=1,4 - PV(1,J) = 0.D0 - IF (MBST .EQ. 0) PV(1,J) = P0(J) + PV(1,J) = 0.D0 + IF (MBST .EQ. 0) PV(1,J) = P0(J) ENDDO - IF (MBST .EQ. 1) PV(1,4) = P0(5) + IF (MBST .EQ. 1) PV(1,4) = P0(5) PV(1,5) = P0(5) 140 IF (ND .EQ. 2) GOTO 280 - IF (ND .EQ. 1) THEN - DO J=1,4 - P(1,J) = P0(J) - ENDDO - RETURN + IF (ND .EQ. 1) THEN + DO J=1,4 + P(1,J) = P0(J) + ENDDO + RETURN ENDIF - -C...Calculate maximum weight for ND-particle decay +C... Calculate maximum weight for ND-particle decay WWTMAX = 1.D0/FACN(ND) PMAX=PV(1,5)-PS+P(ND,5) PMIN=0.D0 DO IL=ND-1,1,-1 - PMAX = PMAX+P(IL,5) - PMIN = PMIN+P(IL+1,5) - WWTMAX = WWTMAX*PAWT(PMAX,PMIN,P(IL,5)) + PMAX = PMAX+P(IL,5) + PMIN = PMIN+P(IL+1,5) + WWTMAX = WWTMAX*PAWT(PMAX,PMIN,P(IL,5)) ENDDO - -C...generation of the masses, compute weight, if rejected try again +C... generation of the masses, compute weight, if rejected try again 240 RORD(1) = 1.D0 DO 260 IL1=2,ND-1 - RSAV = RNDM(0) - DO 250 IL2=IL1-1,1,-1 - IF(RSAV.LE.RORD(IL2)) GOTO 260 -250 RORD(IL2+1)=RORD(IL2) -260 RORD(IL2+1)=RSAV + RSAV = RNDM(0) + DO 250 IL2=IL1-1,1,-1 + IF(RSAV.LE.RORD(IL2)) GOTO 260 +250 RORD(IL2+1)=RORD(IL2) +260 RORD(IL2+1)=RSAV RORD(ND) = 0.D0 WT = 1.D0 DO 270 IL=ND-1,1,-1 - PV(IL,5)=PV(IL+1,5)+P(IL,5)+(RORD(IL)-RORD(IL+1))*(PV(1,5)-PS) + PV(IL,5)=PV(IL+1,5)+P(IL,5)+(RORD(IL)-RORD(IL+1))*(PV(1,5)-PS) 270 WT=WT*PAWT(PV(IL,5),PV(IL+1,5),P(IL,5)) - IF (WT.LT.RNDM(0)*WWTMAX) GOTO 240 - -C...Perform two particle decays in respective cm frame + IF (WT.LT.RNDM(0)*WWTMAX) GOTO 240 +C... Perform two particle decays in respective cm frame 280 DO 300 IL=1,ND-1 - PA=PAWT(PV(IL,5),PV(IL+1,5),P(IL,5)) - UE(3)=2.D0*RNDM(0)-1.D0 - PHI=2.D0*PI*RNDM(0) - UT = SQRT(1.D0-UE(3)**2) - UE(1) = UT*COS(PHI) - UE(2) = UT*SIN(PHI) - DO 290 J=1,3 - P(IL,J)=PA*UE(J) -290 PV(IL+1,J)=-PA*UE(J) - P(IL,4)=SQRT(PA**2+P(IL,5)**2) + PA=PAWT(PV(IL,5),PV(IL+1,5),P(IL,5)) + UE(3)=2.D0*RNDM(0)-1.D0 + PHI=2.D0*PI*RNDM(0) + UT = SQRT(1.D0-UE(3)**2) + UE(1) = UT*COS(PHI) + UE(2) = UT*SIN(PHI) + DO 290 J=1,3 + P(IL,J)=PA*UE(J) +290 PV(IL+1,J)=-PA*UE(J) + P(IL,4)=SQRT(PA**2+P(IL,5)**2) 300 PV(IL+1,4)=SQRT(PA**2+PV(IL+1,5)**2) - -C...Lorentz transform decay products to lab frame +C... Lorentz transform decay products to lab frame DO 310 J=1,4 -310 P(ND,J)=PV(ND,J) +310 P(ND,J)=PV(ND,J) DO 340 IL=ND-1,1,-1 - DO 320 J=1,3 -320 BE(J)=PV(IL,J)/PV(IL,4) - GA=PV(IL,4)/PV(IL,5) + DO 320 J=1,3 +320 BE(J)=PV(IL,J)/PV(IL,4) + GA=PV(IL,4)/PV(IL,5) DO 340 I=IL,ND - BEP = BE(1)*P(I,1)+BE(2)*P(I,2)+BE(3)*P(I,3) - DO 330 J=1,3 -330 P(I,J)=P(I,J)+GA*(GA*BEP/(1.+GA)+P(I,4))*BE(J) -340 P(I,4)=GA*(P(I,4)+BEP) - -C...Weak decays - IF (MAT .EQ. 1) THEN - F1=P(2,4)*P(3,4)-P(2,1)*P(3,1)-P(2,2)*P(3,2)-P(2,3)*P(3,3) - IF (MBST.EQ.1) WT = P0(5)*P(1,4)*F1 - IF (MBST.EQ.0) - + WT=F1*(P(1,4)*P0(4)-P(1,1)*P0(1)-P(1,2)*P0(2)-P(1,3)*P0(3)) - WTMAX = P0(5)**4/16.D0 - IF(WT.LT.RNDM(0)*WTMAX) GOTO 240 - ENDIF - - -C...Boost back for rapidly moving particle + BEP = BE(1)*P(I,1)+BE(2)*P(I,2)+BE(3)*P(I,3) + DO 330 J=1,3 +330 P(I,J)=P(I,J)+GA*(GA*BEP/(1.+GA)+P(I,4))*BE(J) +340 P(I,4)=GA*(P(I,4)+BEP) +C... Weak decays + IF (MAT .EQ. 1) THEN + F1=P(2,4)*P(3,4)-P(2,1)*P(3,1)-P(2,2)*P(3,2)-P(2,3)*P(3,3) + IF (MBST.EQ.1) WT = P0(5)*P(1,4)*F1 + IF (MBST.EQ.0) + + WT=F1*(P(1,4)*P0(4)-P(1,1)*P0(1)-P(1,2)*P0(2)-P(1,3)*P0(3)) + WTMAX = P0(5)**4/16.D0 + IF(WT.LT.RNDM(0)*WTMAX) GOTO 240 + ENDIF +C... sBoost back for rapidly moving particle IF (MBST .EQ. 1) THEN - DO 440 J=1,3 -440 BE(J)=P0(J)/P0(4) - GA= P0(4)/P0(5) - DO 460 I=1,ND - BEP=BE(1)*P(I,1)+BE(2)*P(I,2)+BE(3)*P(I,3) - DO 450 J=1,3 -450 P(I,J)=P(I,J)+GA*(GA*BEP/(1.+GA)+P(I,4))*BE(J) -460 P(I,4)=GA*(P(I,4)+BEP) + DO 440 J=1,3 +440 BE(J)=P0(J)/P0(4) + GA= P0(4)/P0(5) + DO 460 I=1,ND + BEP=BE(1)*P(I,1)+BE(2)*P(I,2)+BE(3)*P(I,3) + DO 450 J=1,3 +450 P(I,J)=P(I,J)+GA*(GA*BEP/(1.+GA)+P(I,4))*BE(J) +460 P(I,4)=GA*(P(I,4)+BEP) ENDIF - C...labels for antiparticle decay IF (LA .LT. 0 .AND. L .GT. 18) THEN - DO J=1,ND - LL(J) = LBARP(LL(J)) - ENDDO + DO J=1,ND + LL(J) = LBARP(LL(J)) + ENDDO ENDIF - END + END SUBROUTINE DECPAR SUBROUTINE PO_ALTRA(GA,BGX,BGY,BGZ,PCX,PCY,PCZ,EC,P,PX,PY,PZ,E) C********************************************************************* -C C arbitrary Lorentz transformation -C C (taken from PHOJET v1.12, R.E. 08/98) -C C********************************************************************* IMPLICIT DOUBLE PRECISION (A-H,O-Z) SAVE @@ -2819,17 +2374,14 @@ SUBROUTINE PO_ALTRA(GA,BGX,BGY,BGZ,PCX,PCY,PCZ,EC,P,PX,PY,PZ,E) P=SQRT(PX*PX+PY*PY+PZ*PZ) E=GA*EC+EP - END + END SUBROUTINE PO_ALTRA SUBROUTINE PO_TRANS(XO,YO,ZO,CDE,SDE,CFE,SFE,X,Y,Z) C********************************************************************** -C C rotation of coordinate frame (1) de rotation around y axis C (2) fe rotation around z axis -C C (taken from PHOJET v1.12, R.E. 08/98) -C C********************************************************************** IMPLICIT DOUBLE PRECISION (A-H,O-Z) SAVE @@ -2838,16 +2390,13 @@ SUBROUTINE PO_TRANS(XO,YO,ZO,CDE,SDE,CFE,SFE,X,Y,Z) Y= CDE*SFE*XO+CFE*YO+SDE*SFE*ZO Z=-SDE *XO +CDE *ZO - END + END SUBROUTINE PO_TRANS SUBROUTINE PO_SELSX2(XS1,XS2,XMIN,XMAX,AS1,AS2,IREJ) C*********************************************************************** -C C select x values of soft string ends using PO_RNDBET -C C (taken from PHOJET v1.12, R.E. 08/98) -C C*********************************************************************** IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) @@ -2865,34 +2414,30 @@ SUBROUTINE PO_SELSX2(XS1,XS2,XMIN,XMAX,AS1,AS2,IREJ) ITRY0 = 0 DO 100 I=1,100 - - ITRY1 = 0 - 10 CONTINUE + ITRY1 = 0 + 10 CONTINUE X1 = PO_RNDBET(GAM1,BET1) ITRY1 = ITRY1+1 IF(ITRY1.GE.50) THEN - IREJ = 1 - RETURN + IREJ = 1 + RETURN ENDIF - IF((X1.LE.XMIN(1)).OR.(X1.GE.XMAX(1))) GOTO 10 - - ITRY2 = 0 - 11 CONTINUE + IF((X1.LE.XMIN(1)).OR.(X1.GE.XMAX(1))) GOTO 10 + ITRY2 = 0 + 11 CONTINUE X2 = PO_RNDBET(GAM2,BET2) ITRY2 = ITRY2+1 IF(ITRY2.GE.50) THEN - IREJ = 2 - RETURN + IREJ = 2 + RETURN ENDIF - IF((X2.LE.XMIN(2)).OR.(X2.GE.XMAX(2))) GOTO 11 - - X3 = 1.D0 - X1 - X4 = 1.D0 - X2 - IF(X1*X2.GT.AS1) THEN - IF(X3*X4.GT.AS2) GOTO 300 - ENDIF - ITRY0 = ITRY0+1 - + IF((X2.LE.XMIN(2)).OR.(X2.GE.XMAX(2))) GOTO 11 + X3 = 1.D0 - X1 + X4 = 1.D0 - X2 + IF(X1*X2.GT.AS1) THEN + IF(X3*X4.GT.AS2) GOTO 300 + ENDIF + ITRY0 = ITRY0+1 100 CONTINUE IREJ = 3 @@ -2906,19 +2451,16 @@ SUBROUTINE PO_SELSX2(XS1,XS2,XMIN,XMAX,AS1,AS2,IREJ) XS2(1) = X2 XS2(2) = X4 - END + END SUBROUTINE PO_SELSX2 DOUBLE PRECISION FUNCTION PO_RNDBET(GAM,ETA) C******************************************************************** -C C random number generation from beta C distribution in region 0 < X < 1. C F(X) = X**(GAM-1.)*(1.-X)**(ETA-1)*GAMM(ETA+GAM) / (GAMM(GAM C *GAMM(ETA)) -C C (taken from PHOJET v1.12, R.E. 08/98) -C C******************************************************************** IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) @@ -2928,17 +2470,14 @@ DOUBLE PRECISION FUNCTION PO_RNDBET(GAM,ETA) Z = PO_RNDGAM(1.D0,ETA) PO_RNDBET = Y/(Y+Z) - END + END FUNCTION PO_RNDBET DOUBLE PRECISION FUNCTION PO_RNDGAM(ALAM,ETA) C******************************************************************** -C C random number selection from gamma distribution C F(X) = ALAM**ETA*X**(ETA-1)*EXP(-ALAM*X) / GAM(ETA) -C C (taken from PHOJET v1.12, R.E. 08/98) -C C******************************************************************** IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) @@ -2968,18 +2507,13 @@ DOUBLE PRECISION FUNCTION PO_RNDGAM(ALAM,ETA) Y = Y-LOG(Z+1.D-7) 70 PO_RNDGAM = Y/ALAM - END + END FUNCTION PO_RNDGAM SUBROUTINE lund_frag(SQS,NP) C*********************************************************************** -C C interface to Lund/Jetset fragmentation -C -C (R.E. 08/98) -C C*********************************************************************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) @@ -2990,76 +2524,52 @@ SUBROUTINE lund_frag(SQS,NP) DATA init / 0 / - if(init.eq.0) then - -C no title page - - MSTU(12) = 0 - -C define some particles as stable - - MSTJ(22) = 2 - -C in addition pi0 stable - - KC=LUCOMP(111) - MDCY(KC,1)=0 - -C switch popcorn effect off - - MSTJ(12) = 1 - -C suppress all warning and error messages - - MSTU(22) = 0 - MSTU(25) = 0 - - init = 1 - +C no title page + MSTU(12) = 0 +C define some particles as stable + MSTJ(22) = 2 +C in addition pi0 stable + KC=LUCOMP(111) + MDCY(KC,1)=0 +C switch popcorn effect off + MSTJ(12) = 1 +C suppress all warning and error messages + MSTU(22) = 0 + MSTU(25) = 0 + + init = 1 endif - - -C set energy dependent parameters - +C set energy-dependent parameters IF(SQS.LT.2.D0) THEN - PARJ(36) = 0.1D0 + PARJ(36) = 0.1D0 ELSE IF(SQS.LT.4.D0) THEN - PARJ(36) = 0.7D0*(SQS-2.D0)/2.D0+0.1D0 + PARJ(36) = 0.7D0*(SQS-2.D0)/2.D0+0.1D0 ELSE - PARJ(36) = 0.8D0 + PARJ(36) = 0.8D0 ENDIF - -C fragment string configuration - +C fragment string configuration II = MSTU(21) MSTU(21) = 1 CALL LUEXEC MSTU(21) = II - -C event accepted? - +C event accepted? if(MSTU(24).ne.0) then - NP = -1 - return + NP = -1 + RETURN endif CALL LUEDIT(1) NP = KLU(0,1) - END + END SUBROUTINE lund_frag SUBROUTINE lund_put(I,IFL,PX,PY,PZ,EE) C*********************************************************************** -C -C store initial configuration into Lund common block -C -C (R.E. 08/98) -C +C store initial configuration into Lund COMMON block C*********************************************************************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) @@ -3069,23 +2579,23 @@ SUBROUTINE lund_put(I,IFL,PX,PY,PZ,EE) SAVE if(IFL.eq.1) then - Il = 2 + Il = 2 else if(IFL.eq.-1) then - Il = -2 + Il = -2 else if(IFL.eq.2) then - Il = 1 + Il = 1 else if(IFL.eq.-2) then - Il = -1 + Il = -1 else if(IFL.eq.11) then - Il = 2203 + Il = 2203 else if(IFL.eq.12) then - Il = 2101 + Il = 2101 else if(IFL.eq.21) then - Il = 2103 + Il = 2103 else if(IFL.eq.22) then - Il = 1103 + Il = 1103 else - print *,' lund_put: unkown flavor code',IFL + PRINT *,' lund_put: unkown flavor code',IFL endif P(I,1) = PX @@ -3102,18 +2612,13 @@ SUBROUTINE lund_put(I,IFL,PX,PY,PZ,EE) N = I - END + END SUBROUTINE lund_put SUBROUTINE lund_get(I,IFL,PX,PY,PZ,EE,XM) C*********************************************************************** -C -C read final states from Lund common block -C -C (R.E. 08/98) -C +C read final states from Lund COMMON block C*********************************************************************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) @@ -3129,22 +2634,15 @@ SUBROUTINE lund_get(I,IFL,PX,PY,PZ,EE,XM) XM = PLU(I,5) Il = KLU(I,8) - -C convert particle ID - +C convert particle ID IFL = ICON_PDG_SIB(Il) - END - - + END SUBROUTINE lund_get + INTEGER FUNCTION ICON_PDG_SIB(ID) C************************************************************************ -C C convert PDG particle codes to SIBYLL particle codes -C -C (R.E. 09/97) -C C************************************************************************ SAVE @@ -3157,49 +2655,41 @@ INTEGER FUNCTION ICON_PDG_SIB(ID) & 3114, 3324, 3314, 3334 / IDPDG = ID - - 100 CONTINUE IDA = ABS(ID) IF(IDA.GT.1000) THEN - IS = IDA - IC = SIGN(1,IDPDG) + IS = IDA + IC = SIGN(1,IDPDG) ELSE - IS = IDPDG - IC = 1 + IS = IDPDG + IC = 1 ENDIF DO I=1,49 - IF(IS.EQ.ITABLE(I)) THEN - ICON_PDG_SIB = I*IC - RETURN - ENDIF + IF(IS.EQ.ITABLE(I)) THEN + ICON_PDG_SIB = I*IC + RETURN + ENDIF ENDDO IF(IDPDG.EQ.80000) THEN - ICON_PDG_SIB = 13 + ICON_PDG_SIB = 13 ELSE - print *,'ICON_PDG_DTU: no particle found for ',IDPDG - ICON_PDG_SIB = 0 - RETURN + PRINT *,'ICON_PDG_DTU: no particle found for ',IDPDG + ICON_PDG_SIB = 0 + RETURN ENDIF - END - + END FUNCTION ICON_PDG_SIB SUBROUTINE PO_MSHELL(PA1,PA2,XM1,XM2,P1,P2) C******************************************************************** -C -C rescaling of momenta of two partons to put both -C on mass shell -C +C rescaling of momenta of two partons to put both on mass shell C input: PA1,PA2 input momentum vectors C XM1,2 desired masses of particles afterwards C P1,P2 changed momentum vectors -C C (taken from PHOJET 1.12, R.E. 08/98) -C C******************************************************************** IMPLICIT DOUBLE PRECISION (A-H,O-Z) SAVE @@ -3221,45 +2711,42 @@ SUBROUTINE PO_MSHELL(PA1,PA2,XM1,XM2,P1,P2) GAM = EE/XMS CALL PO_ALTRA(GAM,-BGX,-BGY,-BGZ,PA1(1),PA1(2),PA1(3), & PA1(4),PTOT1,P1(1),P1(2),P1(3),P1(4)) -C rotation angles +C rotation angles PTOT1 = MAX(DEPS,PTOT1) COD= P1(3)/PTOT1 SID= SQRT((1.D0-COD)*(1.D0+COD)) COF=1.D0 SIF=0.D0 IF(PTOT1*SID.GT.1.D-5) THEN - COF=P1(1)/(SID*PTOT1) - SIF=P1(2)/(SID*PTOT1) - ANORF=SQRT(COF*COF+SIF*SIF) - COF=COF/ANORF - SIF=SIF/ANORF + COF=P1(1)/(SID*PTOT1) + SIF=P1(2)/(SID*PTOT1) + ANORF=SQRT(COF*COF+SIF*SIF) + COF=COF/ANORF + SIF=SIF/ANORF ENDIF -C new CM momentum and energies (for masses XM1,XM2) +C new CM momentum and energies (for masses XM1,XM2) XM12 = XM1**2 XM22 = XM2**2 SS = XMS**2 PCMP = PO_XLAM(SS,XM12,XM22)/(2.D0*XMS) EE1 = SQRT(XM12+PCMP**2) EE2 = XMS-EE1 -C back rotation +C back rotation CALL PO_TRANS(0.D0,0.D0,PCMP,COD,SID,COF,SIF,XX,YY,ZZ) CALL PO_ALTRA(GAM,BGX,BGY,BGZ,XX,YY,ZZ,EE1, & PTOT1,P1(1),P1(2),P1(3),P1(4)) CALL PO_ALTRA(GAM,BGX,BGY,BGZ,-XX,-YY,-ZZ,EE2, & PTOT2,P2(1),P2(2),P2(3),P2(4)) - END + END SUBROUTINE PO_MSHELL DOUBLE PRECISION FUNCTION PO_XLAM(X,Y,Z) C********************************************************************** -C C auxiliary function for two/three particle decay mode C (standard LAMBDA**(1/2) function) -C C (taken from PHOJET 1.12, R.E. 08/98) -C C********************************************************************** IMPLICIT DOUBLE PRECISION (A-H,O-Z) SAVE @@ -3269,12 +2756,10 @@ DOUBLE PRECISION FUNCTION PO_XLAM(X,Y,Z) IF(XLAM.LT.0.D0) XLAM=-XLAM PO_XLAM=SQRT(XLAM) - END - - + END FUNCTION PO_XLAM + SUBROUTINE INITIAL(L0) - c******************************************************************* c initialization routine for setting parameters of resonances c******************************************************************* @@ -3290,693 +2775,39 @@ SUBROUTINE INITIAL(L0) CHARACTER NAMPRESp*6, NAMPRESn*6 CHARACTER NAMPRES*6 - if (L0.eq.13) then - do i=1,9 - SIG0(i) = 4.893089117D0/AM2(13)*RATIOJp(i)*BGAMMAp(i) - AMRES(i) = AMRESp(i) - WIDTH(i) = WIDTHp(i) - NAMPRES(i) = NAMPRESp(i) - enddo - endif - - if (L0.eq.14) then - do i=1,9 - SIG0(i) = 4.893089117D0/AM2(14)*RATIOJn(i)*BGAMMAn(i) - AMRES(i) = AMRESn(i) - WIDTH(i) = WIDTHn(i) - NAMPRES(i) = NAMPRESn(i) - enddo - endif - - RETURN - END -c***************************************************************************** -c**!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*** -c**!! IF YOU USE THIS PROGRAM, PLEASE CITE: !!*** -c**!! A.M"ucke, Ralph Engel, J.P.Rachen, R.J.Protheroe and Todor Stanev, !!*** -c**!! 1999, astro-ph/9903478, to appear in Comp.Phys.Commun. !!*** -c**!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*** -c***************************************************************************** -c** Further SOPHIA related papers: *** -c** (1) M"ucke A., et al 1999, astro-ph/9808279, to appear in PASA. *** -c** (2) M"ucke A., et al 1999, to appear in: Proc. of the *** -c** 19th Texas Symposium on Relativistic Astrophysics, Paris, France, *** -c** Dec. 1998. Eds.: J.~Paul, T.~Montmerle \& E.~Aubourg (CEA Saclay) *** -c** (3) M"ucke A., et al 1999, astro-ph/9905153, to appear in: Proc. of *** -c** 19th Texas Symposium on Relativistic Astrophysics, Paris, France, *** -c** Dec. 1998. Eds.: J.~Paul, T.~Montmerle \& E.~Aubourg (CEA Saclay) *** -c** (4) M"ucke A., et al 1999, to appear in: Proc. of 26th Int.Cosmic Ray *** -c** Conf. (Salt Lake City, Utah) *** -c***************************************************************************** - - -c********************************* -c*** Routines related to output: * -c********************************* - - - subroutine LISTDISTR(E0,Dg,Dnum,Dnuma,Dnue,Dnuea,Dp,Dn,Dem, - & Dep,nbins,delx) - -c********************************************************************* -c** calculates distribution of energy of given particle to incident ** -c** proton energy; considered particles are: ** -c** photons, protons, neutrons, e-neutrinos, nu-neutrinos ** -c** Note: Dg(),Dnum(),Dnue(),Dp(),Dn(),Dem(),Dep(),Dnuea(),Dnuma() ** -c** gives # of photons per logarithmic bin width: dN/dlog(f) ** -c********************************************************************* -c** Date: 20/01/98 ** -c** author: A.Muecke ** -c********************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) - SAVE - - COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb - DIMENSION Dg(201),Dnum(201),Dnue(201),Dp(201),Dn(201) - DIMENSION Dem(201),Dep(201),Dnuea(201),Dnuma(201) - - do i=1,201 - Dg(i) = 0. - Dnum(i) = 0. - Dnue(i) = 0. - Dp(i) = 0. - Dn(i) = 0. - Dem(i) = 0. - Dep(i) = 0. - Dnuma(i) = 0. - Dnuea(i) = 0. - enddo - - xini = -nbins*delx -c go through LLIST: - do 10 i=1,NP - LA = abs(LLIST(i)) - EI = abs(P(i,4)) - Ep = E0/1.D10 - r = EI/Ep/1.D10 - x = log10(r) - if (LA.lt.10000) then -c** gamma ray distribution - if (LA.eq.1) then - do 20 j=1,nbins - x1 = xini+delx*(j-1) - x2 = xini+delx*j - if (x.ge.x1.and.x.lt.x2) then - Dg(j) = Dg(j)+1.D0 - endif - if (x.eq.0.D0) then - Dg(nbins) = Dg(nbins)+1.D0 - endif - 20 continue - endif -c** neutron distribution - if (LA.eq.14) then - do 21 j=1,nbins - x1 = xini+delx*(j-1) - x2 = xini+delx*j - if (x.ge.x1.and.x.lt.x2) then - Dn(j) = Dn(j)+1.D0 - endif - if (x.eq.0.D0) then - Dn(nbins) = Dn(nbins)+1.D0 - endif - 21 continue - endif -c** proton distribution - if (LA.eq.13) then - do 22 j=1,nbins - x1 = xini+delx*(j-1) - x2 = xini+delx*j - if (x.ge.x1.and.x.lt.x2) then - Dp(j) = Dp(j)+1.D0 - endif - if (x.eq.0.D0) then - Dp(nbins) = Dp(nbins)+1.D0 - endif - 22 continue - endif -c** neutrino distribution - if (LA.eq.17) then - do 23 j=1,nbins - x1 = xini+delx*(j-1) - x2 = xini+delx*j - if (x.ge.x1.and.x.lt.x2) then - Dnum(j) = Dnum(j)+1.D0 - endif - if (x.eq.0.D0) then - Dnum(nbins) = Dnum(nbins)+1.D0 - endif - 23 continue - endif - - if (LA.eq.18) then - do 27 j=1,nbins - x1 = xini+delx*(j-1) - x2 = xini+delx*j - if (x.ge.x1.and.x.lt.x2) then - Dnuma(j) = Dnuma(j)+1.D0 - endif - if (x.eq.0.D0) then - Dnuma(nbins) = Dnuma(nbins)+1.D0 - endif - 27 continue - endif - - - if (LA.eq.15) then - do 24 j=1,nbins - x1 = xini+delx*(j-1) - x2 = xini+delx*j - if (x.ge.x1.and.x.lt.x2) then - Dnue(j) = Dnue(j)+1.D0 - endif - if (x.eq.0.D0) then - Dnue(nbins) = Dnue(nbins)+1.D0 - endif - 24 continue - endif - - if (LA.eq.16) then - do 28 j=1,nbins - x1 = xini+delx*(j-1) - x2 = xini+delx*j - if (x.ge.x1.and.x.lt.x2) then - Dnuea(j) = Dnuea(j)+1.D0 - endif - if (x.eq.0.D0) then - Dnuea(nbins) = Dnuea(nbins)+1.D0 - endif - 28 continue - endif - -c** electron distribution - if (LA.eq.3) then - do 25 j=1,nbins - x1 = xini+delx*(j-1) - x2 = xini+delx*j - if (x.ge.x1.and.x.lt.x2) then - Dem(j) = Dem(j)+1.D0 - endif - if (x.eq.0.D0) then - Dem(nbins) = Dem(nbins)+1.D0 - endif - 25 continue - endif - -c** positron distribution - if (LA.eq.2) then - do 26 j=1,nbins - x1 = xini+delx*(j-1) - x2 = xini+delx*j - if (x.ge.x1.and.x.lt.x2) then - Dep(j) = Dep(j)+1.D0 - endif - if (x.eq.0.D0) then - Dep(nbins) = Dep(nbins)+1.D0 - endif - 26 continue - endif - - endif - 10 continue - - RETURN - - END - - subroutine output(Dg,Dnum,Dnuma,Dnue,Dnuea,Dp,Dn,Dem,Dep,nbins, - & ninc,nameinc,delx,Emin,Emax,E0_arr,epsmin,epsmax) - -c******************************************************************** -c*** OUTPUT ROUTINE for particle spectra: ******* -c*** considered particles: ******* -c*** photons, protons, neutrons, e-neutrinos, nu-neutrinos, ******* -c*** electron, positron ******* -c*** spectra of each particle stored in separate files ******* -c******************************************************************** -c** Date: 20/02/98 ** -c** author: A.Muecke ** -c********************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-M) - SAVE - - COMMON/input/ tbb,E0,alpha1,alpha2, - & epsm1,epsm2,epsb,L0 - - DIMENSION Dg(101,201),Dnum(101,201),Dnue(101,201) - DIMENSION Dp(101,201),Dn(101,201),Dnuma(101,201),E0_arr(101) - DIMENSION Dem(101,201),Dep(101,201),Dnuea(101,201) - character*5 particle - character*7 spart,fpart - character*13 filename - character*6 nameinc - character mat*20, strnm1*2 - character mat1*20, strnm11*2 - character mat2*20, strnm12*2 - - 571 format(2(3x,E10.5),3x,I3,5(3x,E10.5), - & 3x,I3,3x,E10.5,3x,A10,3x,A10) - 572 format(E10.5,3x,2(I3,3x)) - 573 format(2x,E10.5) - - print* - print*,'OUTPUT files:' -c********************************************** -c******** GAMMA spectra: ********************** - particle = 'gamma' - filename = nameinc // '.' // particle - print*,'filename = ',filename - if (L0.eq.13) spart = 'proton' - if (L0.eq.14) spart = 'neutron' - fpart = 'photon' - if (tbb.gt.0.) then - target1 = tbb - target2 = 0. - else - target1 = alpha1 - target2 = alpha2 + if (L0.eq.13) then + do i=1,9 + SIG0(i) = 4.893089117D0/AM2(13)*RATIOJp(i)*BGAMMAp(i) + AMRES(i) = AMRESp(i) + WIDTH(i) = WIDTHp(i) + NAMPRES(i) = NAMPRESp(i) + enddo endif - open(1,file=filename) -c... write input parameters: - write(1,571) Emin,Emax,ninc,target1,target2, - & epsmin,epsb,epsmax,nbins,delx,spart,fpart -c... nucleon energy loop: - do i=1,ninc -c ... determine j-range = range of energy bins not equal zero - jini = 0 - jfin = 0 -c... particle spectrum loop: - do j=1,nbins - if (Dg(i,j).gt.0.D0) then - jfin = j - if (jini.eq.0) jini = j - endif - enddo - nm = jfin-jini+1 - nm1 = nm+1 - write(strnm1,'(I2)') nm1 - mat = '(' // strnm1 // '(5X,E10.4))' - nmc = 81 - nmc2 = 82 - write(strnm11,'(I2)') nmc2 - mat1 = '(' // strnm11 // '(5X,E10.4))' - nmcf = jfin-jini-80+1 - nmcf2 = nmcf+1 - write(strnm12,'(I2)') nmcf2 - mat2 = '(' // strnm12 // '(5X,E10.4))' - if (jfin.gt.0) then - write(1,572) E0_arr(i),jini,jfin -c... values written in one line: - if (jfin-jini.lt.80) then - write(1,FMT=mat) (Dg(i,jl),jl=jini,jfin) - else - jfin0 = jini+80 - write(1,FMT=mat1) (Dg(i,jl),jl=jini,jfin0) - write(1,FMT=mat2) (Dg(i,jl),jl=jfin0+1,jfin) - endif - endif - enddo - close(1) -c********************************************** -c******** MU-NEUTRINO spectra: ********************** - particle = 'muneu' - filename = nameinc // '.' // particle - print*,'filename = ',filename - open(1,file=filename) - write(1,571) Emin,Emax,ninc,target1,target2, - & epsmin,epsb,epsmax,nbins,delx,spart,fpart -c... nucleon energy loop: - do i=1,ninc -c ... determine j-range = range of energy bins not equal zero - jini = 0 - jfin = 0 -c... particle spectrum loop: - do j=1,nbins - if (Dnum(i,j).gt.0.D0) then - jfin = j - if (jini.eq.0) jini = j - endif - enddo - nm = jfin-jini+1 - nm1 = nm+1 - write(strnm1,'(I2)') nm1 - mat = '(' // strnm1 // '(5X,E10.4))' - nmc = 81 - nmc2 = 82 - write(strnm11,'(I2)') nmc2 - mat1 = '(' // strnm11 // '(5X,E10.4))' - nmcf = jfin-jini-80+1 - nmcf2 = nmcf+1 - write(strnm12,'(I2)') nmcf2 - mat2 = '(' // strnm12 // '(5X,E10.4))' - if (jfin.gt.0) then - write(1,572) E0_arr(i),jini,jfin -c... values written in one line: - if (jfin-jini.lt.80) then - write(1,FMT=mat) (Dnum(i,jl),jl=jini,jfin) - else - jfin0 = jini+80 - write(1,FMT=mat1) (Dnum(i,jl),jl=jini,jfin0) - write(1,FMT=mat2) (Dnum(i,jl),jl=jfin0+1,jfin) - endif - endif - enddo - close(1) - - particle = 'muane' - filename = nameinc // '.' // particle - print*,'filename = ',filename - open(1,file=filename) - write(1,571) Emin,Emax,ninc,target1,target2, - & epsmin,epsb,epsmax,nbins,delx,spart,fpart -c... nucleon energy loop: - do i=1,ninc -c ... determine j-range = range of energy bins not equal zero - jini = 0 - jfin = 0 -c... particle spectrum loop: - do j=1,nbins - if (Dnuma(i,j).gt.0.D0) then - jfin = j - if (jini.eq.0) jini = j - endif - enddo - nm = jfin-jini+1 - nm1 = nm+1 - write(strnm1,'(I2)') nm1 - mat = '(' // strnm1 // '(5X,E10.4))' - nmc = 81 - nmc2 = 82 - write(strnm11,'(I2)') nmc2 - mat1 = '(' // strnm11 // '(5X,E10.4))' - nmcf = jfin-jini-80+1 - nmcf2 = nmcf+1 - write(strnm12,'(I2)') nmcf2 - mat2 = '(' // strnm12 // '(5X,E10.4))' - if (jfin.gt.0) then - write(1,572) E0_arr(i),jini,jfin -c... values written in one line: - if (jfin-jini.lt.80) then - write(1,FMT=mat) (Dnuma(i,jl),jl=jini,jfin) - else - jfin0 = jini+80 - write(1,FMT=mat1) (Dnuma(i,jl),jl=jini,jfin0) - write(1,FMT=mat2) (Dnuma(i,jl),jl=jfin0+1,jfin) - endif - endif - enddo - close(1) - -c********************************************** -c******** ELECTRON NEUTRINO spectra: ********** - particle = 'e_neu' - filename = nameinc // '.' // particle - print*,'filename = ',filename - open(1,file=filename) - write(1,571) Emin,Emax,ninc,target1,target2, - & epsmin,epsb,epsmax,nbins,delx,spart,fpart -c... nucleon energy loop: - do i=1,ninc -c ... determine j-range = range of energy bins not equal zero - jini = 0 - jfin = 0 -c... particle spectrum loop: - do j=1,nbins - if (Dnue(i,j).gt.0.D0) then - jfin = j - if (jini.eq.0) jini = j - endif - enddo - nm = jfin-jini+1 - nm1 = nm+1 - write(strnm1,'(I2)') nm1 - mat = '(' // strnm1 // '(5X,E10.4))' - nmc = 81 - nmc2 = 82 - write(strnm11,'(I2)') nmc2 - mat1 = '(' // strnm11 // '(5X,E10.4))' - nmcf = jfin-jini-80+1 - nmcf2 = nmcf+1 - write(strnm12,'(I2)') nmcf2 - mat2 = '(' // strnm12 // '(5X,E10.4))' - if (jfin.gt.0) then - write(1,572) E0_arr(i),jini,jfin -c... values written in one line: - if (jfin-jini.lt.80) then - write(1,FMT=mat) (Dnue(i,jl),jl=jini,jfin) - else - jfin0 = jini+80 - write(1,FMT=mat1) (Dnue(i,jl),jl=jini,jfin0) - write(1,FMT=mat2) (Dnue(i,jl),jl=jfin0+1,jfin) - endif - endif - enddo - close(1) - - particle = 'eaneu' - filename = nameinc // '.' // particle - print*,'filename = ',filename - open(1,file=filename) - write(1,571) Emin,Emax,ninc,target1,target2, - & epsmin,epsb,epsmax,nbins,delx,spart,fpart -c... nucleon energy loop: - do i=1,ninc -c ... determine j-range = range of energy bins not equal zero - jini = 0 - jfin = 0 -c... particle spectrum loop: - do j=1,nbins - if (Dnuea(i,j).gt.0.D0) then - jfin = j - if (jini.eq.0) jini = j - endif - enddo - nm = jfin-jini+1 - nm1 = nm+1 - write(strnm1,'(I2)') nm1 - mat = '(' // strnm1 // '(5X,E10.4))' - nmc = 81 - nmc2 = 82 - write(strnm11,'(I2)') nmc2 - mat1 = '(' // strnm11 // '(5X,E10.4))' - nmcf = jfin-jini-80+1 - nmcf2 = nmcf+1 - write(strnm12,'(I2)') nmcf2 - mat2 = '(' // strnm12 // '(5X,E10.4))' - if (jfin.gt.0) then - write(1,572) E0_arr(i),jini,jfin -c... values written in one line: - if (jfin-jini.lt.80) then - write(1,FMT=mat) (Dnuea(i,jl),jl=jini,jfin) - else - jfin0 = jini+80 - write(1,FMT=mat1) (Dnuea(i,jl),jl=jini,jfin0) - write(1,FMT=mat2) (Dnuea(i,jl),jl=jfin0+1,jfin) - endif - endif - enddo - close(1) + if (L0.eq.14) then + do i=1,9 + SIG0(i) = 4.893089117D0/AM2(14)*RATIOJn(i)*BGAMMAn(i) + AMRES(i) = AMRESn(i) + WIDTH(i) = WIDTHn(i) + NAMPRES(i) = NAMPRESn(i) + enddo + endif -c********************************************** -c******** ELECTRON spectra: ********************** - particle = 'elect' - filename = nameinc // '.' // particle - print*,'filename = ',filename - open(1,file=filename) - write(1,571) Emin,Emax,ninc,target1,target2, - & epsmin,epsb,epsmax,nbins,delx,spart,fpart -c... nucleon energy loop: - do i=1,ninc -c ... determine j-range = range of energy bins not equal zero - jini = 0 - jfin = 0 -c... particle spectrum loop: - do j=1,nbins - if (Dem(i,j).gt.0.D0) then - jfin = j - if (jini.eq.0) jini = j - endif - enddo - nm = jfin-jini+1 - nm1 = nm+1 - write(strnm1,'(I2)') nm1 - mat = '(' // strnm1 // '(5X,E10.4))' - nmc = 81 - nmc2 = 82 - write(strnm11,'(I2)') nmc2 - mat1 = '(' // strnm11 // '(5X,E10.4))' - nmcf = jfin-jini-80+1 - nmcf2 = nmcf+1 - write(strnm12,'(I2)') nmcf2 - mat2 = '(' // strnm12 // '(5X,E10.4))' - if (jfin.gt.0) then - write(1,572) E0_arr(i),jini,jfin -c... values written in one line: - if (jfin-jini.lt.80) then - write(1,FMT=mat) (Dem(i,jl),jl=jini,jfin) - else - jfin0 = jini+80 - write(1,FMT=mat1) (Dem(i,jl),jl=jini,jfin0) - write(1,FMT=mat2) (Dem(i,jl),jl=jfin0+1,jfin) - endif - endif - enddo - close(1) + RETURN + END SUBROUTINE initial -c********************************************** -c******** POSITRON spectra: ********************** - particle = 'posit' - filename = nameinc // '.' // particle - print*,'filename = ',filename - open(1,file=filename) - write(1,571) Emin,Emax,ninc,target1,target2, - & epsmin,epsb,epsmax,nbins,delx,spart,fpart -c... nucleon energy loop: - do i=1,ninc -c ... determine j-range = range of energy bins not equal zero - jini = 0 - jfin = 0 -c... particle spectrum loop: - do j=1,nbins - if (Dep(i,j).gt.0.D0) then - jfin = j - if (jini.eq.0) jini = j - endif - enddo - nm = jfin-jini+1 - nm1 = nm+1 - write(strnm1,'(I2)') nm1 - mat = '(' // strnm1 // '(5X,E10.4))' - nmc = 81 - nmc2 = 82 - write(strnm11,'(I2)') nmc2 - mat1 = '(' // strnm11 // '(5X,E10.4))' - nmcf = jfin-jini-80+1 - nmcf2 = nmcf+1 - write(strnm12,'(I2)') nmcf2 - mat2 = '(' // strnm12 // '(5X,E10.4))' - if (jfin.gt.0) then - write(1,572) E0_arr(i),jini,jfin -c... values written in one line: - if (jfin-jini.lt.80) then - write(1,FMT=mat) (Dep(i,jl),jl=jini,jfin) - else - jfin0 = jini+80 - write(1,FMT=mat1) (Dep(i,jl),jl=jini,jfin0) - write(1,FMT=mat2) (Dep(i,jl),jl=jfin0+1,jfin) - endif - endif - enddo - close(1) -c********************************************** -c******** PROTON spectra: ********************** - particle = 'proto' - filename = nameinc // '.' // particle - print*,'filename = ',filename - open(1,file=filename) - write(1,571) Emin,Emax,ninc,target1,target2, - & epsmin,epsb,epsmax,nbins,delx,spart,fpart -c... nucleon energy loop: - do i=1,ninc -c ... determine j-range = range of energy bins not equal zero - jini = 0 - jfin = 0 -c... particle spectrum loop: - do j=1,nbins - if (Dp(i,j).gt.0.D0) then - jfin = j - if (jini.eq.0) jini = j - endif - enddo - nm = jfin-jini+1 - nm1 = nm+1 - write(strnm1,'(I2)') nm1 - mat = '(' // strnm1 // '(5X,E10.4))' - nmc = 81 - nmc2 = 82 - write(strnm11,'(I2)') nmc2 - mat1 = '(' // strnm11 // '(5X,E10.4))' - nmcf = jfin-jini-80+1 - nmcf2 = nmcf+1 - write(strnm12,'(I2)') nmcf2 - mat2 = '(' // strnm12 // '(5X,E10.4))' - if (jfin.gt.0) then - write(1,572) E0_arr(i),jini,jfin -c... values written in one line: - if (jfin-jini.lt.80) then - write(1,FMT=mat) (Dp(i,jl),jl=jini,jfin) - else - jfin0 = jini+80 - write(1,FMT=mat1) (Dp(i,jl),jl=jini,jfin0) - write(1,FMT=mat2) (Dp(i,jl),jl=jfin0+1,jfin) - endif - endif - enddo - close(1) +C################################################################### +C Here, SOPHIA ends and JETSET v7.4 begins. Later, SOPHIA resumes. # +C################################################################### -c********************************************** -c******** NEUTRON spectra: ********************** - particle = 'neutr' - filename = nameinc // '.' // particle - print*,'filename = ',filename - open(1,file=filename) - write(1,571) Emin,Emax,ninc,target1,target2, - & epsmin,epsb,epsmax,nbins,delx,spart,fpart -c... nucleon energy loop: - do i=1,ninc -c ... determine j-range = range of energy bins not equal zero - jini = 0 - jfin = 0 -c... particle spectrum loop: - do j=1,nbins - if (Dn(i,j).gt.0.D0) then - jfin = j - if (jini.eq.0) jini = j - endif - enddo - nm = jfin-jini+1 - nm1 = nm+1 - write(strnm1,'(I2)') nm1 - mat = '(' // strnm1 // '(5X,E10.4))' - nmc = 81 - nmc2 = 82 - write(strnm11,'(I2)') nmc2 - mat1 = '(' // strnm11 // '(5X,E10.4))' - nmcf = jfin-jini-80+1 - nmcf2 = nmcf+1 - write(strnm12,'(I2)') nmcf2 - mat2 = '(' // strnm12 // '(5X,E10.4))' - if (jfin.gt.0) then - write(1,572) E0_arr(i),jini,jfin -c... values written in one line: - if (jfin-jini.lt.80) then - write(1,FMT=mat) (Dn(i,jl),jl=jini,jfin) - else - jfin0 = jini+80 - write(1,FMT=mat1) (Dn(i,jl),jl=jini,jfin0) - write(1,FMT=mat2) (Dn(i,jl),jl=jfin0+1,jfin) - endif - endif - enddo - close(1) - RETURN - END cFrom eng@lepton.bartol.udel.edu cDate: Sun, 15 Nov 1998 18:18:44 -0500 cFrom: Ralph R Engel cTo: amuecke@physics.adelaide.edu.au cSubject: File: jetset74dp.f -c -C -C WARNING: this file has been changed to double precision, -C alignment problems made it necessary to change also -C /LUJETS/, /PYSUBS/, and /PYINT5/ -C + C********************************************************************* C********************************************************************* C* ** @@ -4004,14 +2835,9 @@ subroutine output(Dg,Dnum,Dnuma,Dnue,Dnuea,Dp,Dn,Dem,Dep,nbins, C********************************************************************* C * C List of subprograms in order of appearance, with main purpose * -C (S = subroutine, F = function, B = block data) * -C * -C S LU1ENT to fill one entry (= parton or particle) * -C S LU2ENT to fill two entries * -C S LU3ENT to fill three entries * -C S LU4ENT to fill four entries * +C (S = SUBROUTINE, F = function, B = block data) * +C C S LUJOIN to connect entries with colour flow information * -C S LUGIVE to fill (or query) commonblock variables * C S LUEXEC to administrate fragmentation and decay chain * C S LUPREP to rearrange showered partons along strings * C S LUSTRF to do string fragmentation of jet system * @@ -4023,963 +2849,111 @@ subroutine output(Dg,Dnum,Dnuma,Dnue,Dnuea,Dp,Dn,Dem,Dep,nbins, C S LUSHOW to do timelike parton shower evolution * C S LUBOEI to include Bose-Einstein effects (crudely) * C F ULMASS to give the mass of a particle or parton * -C S LUNAME to give the name of a particle or parton * C F LUCHGE to give three times the electric charge * C F LUCOMP to compress standard KF flavour code to internal KC * C S LUERRM to write error messages and abort faulty run * -C F ULALEM to give the alpha_electromagnetic value * -C F ULALPS to give the alpha_strong value * C F ULANGL to give the angle from known x and y components * C F RLU to provide a random number generator * -C S RLUGET to save the state of the random number generator * -C S RLUSET to set the state of the random number generator * C S LUROBO to rotate and/or boost an event * C S LUEDIT to remove unwanted entries from record * -C S LULIST to list event record or particle data * -C S LULOGO to write a logo for JETSET and PYTHIA * -C S LUUPDA to update particle data * -C F KLU to provide integer-valued event information * +C F KLU to provide INTEGER-valued event information * C F PLU to provide real-valued event information * -C S LUSPHE to perform sphericity analysis * -C S LUTHRU to perform thrust analysis * -C S LUCLUS to perform three-dimensional cluster analysis * -C S LUCELL to perform cluster analysis in (eta, phi, E_T) * -C S LUJMAS to give high and low jet mass of event * -C S LUFOWO to give Fox-Wolfram moments * -C S LUTABU to analyze events, with tabular output * -C * -C S LUEEVT to administrate the generation of an e+e- event * -C S LUXTOT to give the total cross-section at given CM energy * -C S LURADK to generate initial state photon radiation * -C S LUXKFL to select flavour of primary qqbar pair * -C S LUXJET to select (matrix element) jet multiplicity * -C S LUX3JT to select kinematics of three-jet event * -C S LUX4JT to select kinematics of four-jet event * -C S LUXDIF to select angular orientation of event * -C S LUONIA to perform generation of onium decay to gluons * -C * -C S LUHEPC to convert between /LUJETS/ and /HEPEVT/ records * -C S LUTEST to test the proper functioning of the package * C B LUDATA to contain default values and particle data * C * C********************************************************************* - -CDECK ID>, LU1ENT - SUBROUTINE LU1ENT(IP,KF,PE,THE,PHI) + +CDECK ID>, LUJOIN + SUBROUTINE LUJOIN(NJOIN,IJOIN) IMPLICIT DOUBLE PRECISION (A-H,O-Z) -C...Purpose: to store one parton/particle in commonblock LUJETS. - COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N +C...Purpose: to connect a sequence of partons with colour flow indices, +C...as required for subsequent shower evolution (or other operations). + COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + DIMENSION IJOIN(*) -C...Standard checks. - MSTU(28)=0 - IF(MSTU(12).GE.1) CALL LULIST(0) - IPA=MAX(1,IABS(IP)) - IF(IPA.GT.MSTU(4)) CALL LUERRM(21, - &'(LU1ENT:) writing outside LUJETS memory') - KC=LUCOMP(KF) - IF(KC.EQ.0) CALL LUERRM(12,'(LU1ENT:) unknown flavour code') - -C...Find mass. Reset K, P and V vectors. - PM=0. - IF(MSTU(10).EQ.1) PM=P(IPA,5) - IF(MSTU(10).GE.2) PM=ULMASS(KF) - DO 100 J=1,5 - K(IPA,J)=0 - P(IPA,J)=0. - V(IPA,J)=0. +C...Check that partons are of right types to be connected. + IF(NJOIN.LT.2) GOTO 120 + KQSUM=0 + DO 100 IJN=1,NJOIN + I=IJOIN(IJN) + IF(I.LE.0.OR.I.GT.N) GOTO 120 + IF(K(I,1).LT.1.OR.K(I,1).GT.3) GOTO 120 + KC=LUCOMP(K(I,2)) + IF(KC.EQ.0) GOTO 120 + KQ=KCHG(KC,2)*ISIGN(1,K(I,2)) + IF(KQ.EQ.0) GOTO 120 + IF(IJN.NE.1.AND.IJN.NE.NJOIN.AND.KQ.NE.2) GOTO 120 + IF(KQ.NE.2) KQSUM=KQSUM+KQ + IF(IJN.EQ.1) KQS=KQ 100 CONTINUE + IF(KQSUM.NE.0) GOTO 120 + +C...Connect the partons sequentially (closing for gluon loop). + KCS=(9-KQS)/2 + IF(KQS.EQ.2) KCS=INT(4.5+RLU(0)) + DO 110 IJN=1,NJOIN + I=IJOIN(IJN) + K(I,1)=3 + IF(IJN.NE.1) IP=IJOIN(IJN-1) + IF(IJN.EQ.1) IP=IJOIN(NJOIN) + IF(IJN.NE.NJOIN) IN=IJOIN(IJN+1) + IF(IJN.EQ.NJOIN) IN=IJOIN(1) + K(I,KCS)=MSTU(5)*IN + K(I,9-KCS)=MSTU(5)*IP + IF(IJN.EQ.1.AND.KQS.NE.2) K(I,9-KCS)=0 + IF(IJN.EQ.NJOIN.AND.KQS.NE.2) K(I,KCS)=0 + 110 CONTINUE -C...Store parton/particle in K and P vectors. - K(IPA,1)=1 - IF(IP.LT.0) K(IPA,1)=2 - K(IPA,2)=KF - P(IPA,5)=PM - P(IPA,4)=MAX(PE,PM) - PA=SQRT(P(IPA,4)**2-P(IPA,5)**2) - P(IPA,1)=PA*SIN(THE)*COS(PHI) - P(IPA,2)=PA*SIN(THE)*SIN(PHI) - P(IPA,3)=PA*COS(THE) - -C...Set N. Optionally fragment/decay. - N=IPA - IF(IP.EQ.0) CALL LUEXEC +C...Error exit: no action taken. + RETURN + 120 CALL LUERRM(12, + &'(LUJOIN:) given entries can not be joined by one string') RETURN - END + END SUBROUTINE LUJOIN C********************************************************************* -CDECK ID>, LU2ENT - SUBROUTINE LU2ENT(IP,KF1,KF2,PECM) +CDECK ID>, LUEXEC + SUBROUTINE LUEXEC IMPLICIT DOUBLE PRECISION (A-H,O-Z) -C...Purpose: to store two partons/particles in their CM frame, -C...with the first along the +z axis. +C...Purpose: to administrate the fragmentation and decay chain. COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ + COMMON/LUDAT3/MDCY(500,3),MDME(2000,2),BRAT(2000),KFDP(2000,5) + SAVE /LUJETS/,/LUDAT1/,/LUDAT2/,/LUDAT3/ + DIMENSION PS(2,6) -C...Standard checks. - MSTU(28)=0 - IF(MSTU(12).GE.1) CALL LULIST(0) - IPA=MAX(1,IABS(IP)) - IF(IPA.GT.MSTU(4)-1) CALL LUERRM(21, - &'(LU2ENT:) writing outside LUJETS memory') - KC1=LUCOMP(KF1) - KC2=LUCOMP(KF2) - IF(KC1.EQ.0.OR.KC2.EQ.0) CALL LUERRM(12, - &'(LU2ENT:) unknown flavour code') - -C...Find masses. Reset K, P and V vectors. - PM1=0. - IF(MSTU(10).EQ.1) PM1=P(IPA,5) - IF(MSTU(10).GE.2) PM1=ULMASS(KF1) - PM2=0. - IF(MSTU(10).EQ.1) PM2=P(IPA+1,5) - IF(MSTU(10).GE.2) PM2=ULMASS(KF2) - DO 110 I=IPA,IPA+1 - DO 100 J=1,5 - K(I,J)=0 - P(I,J)=0. - V(I,J)=0. +C...Initialize and reset. + MSTU(24)=0 + IF(MSTU(12).GE.1) PRINT*, "LULIST(0), Method removed." + MSTU(31)=MSTU(31)+1 + MSTU(1)=0 + MSTU(2)=0 + MSTU(3)=0 + IF(MSTU(17).LE.0) MSTU(90)=0 + MCONS=1 + +C...Sum up momentum, energy and charge for starting entries. + NSAV=N + DO 110 I=1,2 + DO 100 J=1,6 + PS(I,J)=0. 100 CONTINUE 110 CONTINUE - -C...Check flavours. - KQ1=KCHG(KC1,2)*ISIGN(1,KF1) - KQ2=KCHG(KC2,2)*ISIGN(1,KF2) - IF(MSTU(19).EQ.1) THEN - MSTU(19)=0 - ELSE - IF(KQ1+KQ2.NE.0.AND.KQ1+KQ2.NE.4) CALL LUERRM(2, - & '(LU2ENT:) unphysical flavour combination') - ENDIF - K(IPA,2)=KF1 - K(IPA+1,2)=KF2 - -C...Store partons/particles in K vectors for normal case. - IF(IP.GE.0) THEN - K(IPA,1)=1 - IF(KQ1.NE.0.AND.KQ2.NE.0) K(IPA,1)=2 - K(IPA+1,1)=1 - -C...Store partons in K vectors for parton shower evolution. - ELSE - K(IPA,1)=3 - K(IPA+1,1)=3 - K(IPA,4)=MSTU(5)*(IPA+1) - K(IPA,5)=K(IPA,4) - K(IPA+1,4)=MSTU(5)*IPA - K(IPA+1,5)=K(IPA+1,4) - ENDIF - -C...Check kinematics and store partons/particles in P vectors. - IF(PECM.LE.PM1+PM2) CALL LUERRM(13, - &'(LU2ENT:) energy smaller than sum of masses') - PA=SQRT(MAX(0.D0,(PECM**2-PM1**2-PM2**2)**2-(2.*PM1*PM2)**2))/ - &(2.*PECM) - P(IPA,3)=PA - P(IPA,4)=SQRT(PM1**2+PA**2) - P(IPA,5)=PM1 - P(IPA+1,3)=-PA - P(IPA+1,4)=SQRT(PM2**2+PA**2) - P(IPA+1,5)=PM2 - -C...Set N. Optionally fragment/decay. - N=IPA+1 - IF(IP.EQ.0) CALL LUEXEC - - RETURN - END - -C********************************************************************* - -CDECK ID>, LU3ENT - SUBROUTINE LU3ENT(IP,KF1,KF2,KF3,PECM,X1,X3) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to store three partons or particles in their CM frame, -C...with the first along the +z axis and the third in the (x,z) -C...plane with x > 0. - COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ - -C...Standard checks. - MSTU(28)=0 - IF(MSTU(12).GE.1) CALL LULIST(0) - IPA=MAX(1,IABS(IP)) - IF(IPA.GT.MSTU(4)-2) CALL LUERRM(21, - &'(LU3ENT:) writing outside LUJETS memory') - KC1=LUCOMP(KF1) - KC2=LUCOMP(KF2) - KC3=LUCOMP(KF3) - IF(KC1.EQ.0.OR.KC2.EQ.0.OR.KC3.EQ.0) CALL LUERRM(12, - &'(LU3ENT:) unknown flavour code') - -C...Find masses. Reset K, P and V vectors. - PM1=0. - IF(MSTU(10).EQ.1) PM1=P(IPA,5) - IF(MSTU(10).GE.2) PM1=ULMASS(KF1) - PM2=0. - IF(MSTU(10).EQ.1) PM2=P(IPA+1,5) - IF(MSTU(10).GE.2) PM2=ULMASS(KF2) - PM3=0. - IF(MSTU(10).EQ.1) PM3=P(IPA+2,5) - IF(MSTU(10).GE.2) PM3=ULMASS(KF3) - DO 110 I=IPA,IPA+2 - DO 100 J=1,5 - K(I,J)=0 - P(I,J)=0. - V(I,J)=0. - 100 CONTINUE - 110 CONTINUE - -C...Check flavours. - KQ1=KCHG(KC1,2)*ISIGN(1,KF1) - KQ2=KCHG(KC2,2)*ISIGN(1,KF2) - KQ3=KCHG(KC3,2)*ISIGN(1,KF3) - IF(MSTU(19).EQ.1) THEN - MSTU(19)=0 - ELSEIF(KQ1.EQ.0.AND.KQ2.EQ.0.AND.KQ3.EQ.0) THEN - ELSEIF(KQ1.NE.0.AND.KQ2.EQ.2.AND.(KQ1+KQ3.EQ.0.OR. - &KQ1+KQ3.EQ.4)) THEN - ELSE - CALL LUERRM(2,'(LU3ENT:) unphysical flavour combination') - ENDIF - K(IPA,2)=KF1 - K(IPA+1,2)=KF2 - K(IPA+2,2)=KF3 - -C...Store partons/particles in K vectors for normal case. - IF(IP.GE.0) THEN - K(IPA,1)=1 - IF(KQ1.NE.0.AND.(KQ2.NE.0.OR.KQ3.NE.0)) K(IPA,1)=2 - K(IPA+1,1)=1 - IF(KQ2.NE.0.AND.KQ3.NE.0) K(IPA+1,1)=2 - K(IPA+2,1)=1 - -C...Store partons in K vectors for parton shower evolution. - ELSE - K(IPA,1)=3 - K(IPA+1,1)=3 - K(IPA+2,1)=3 - KCS=4 - IF(KQ1.EQ.-1) KCS=5 - K(IPA,KCS)=MSTU(5)*(IPA+1) - K(IPA,9-KCS)=MSTU(5)*(IPA+2) - K(IPA+1,KCS)=MSTU(5)*(IPA+2) - K(IPA+1,9-KCS)=MSTU(5)*IPA - K(IPA+2,KCS)=MSTU(5)*IPA - K(IPA+2,9-KCS)=MSTU(5)*(IPA+1) - ENDIF - -C...Check kinematics. - MKERR=0 - IF(0.5*X1*PECM.LE.PM1.OR.0.5*(2.-X1-X3)*PECM.LE.PM2.OR. - &0.5*X3*PECM.LE.PM3) MKERR=1 - PA1=SQRT(MAX(1D-10,(0.5*X1*PECM)**2-PM1**2)) - PA2=SQRT(MAX(1D-10,(0.5*(2.-X1-X3)*PECM)**2-PM2**2)) - PA3=SQRT(MAX(1D-10,(0.5*X3*PECM)**2-PM3**2)) - CTHE2=(PA3**2-PA1**2-PA2**2)/(2.*PA1*PA2) - CTHE3=(PA2**2-PA1**2-PA3**2)/(2.*PA1*PA3) - IF(ABS(CTHE2).GE.1.001.OR.ABS(CTHE3).GE.1.001) MKERR=1 - CTHE3=MAX(-1.D0,MIN(1.D0,CTHE3)) - IF(MKERR.NE.0) CALL LUERRM(13, - &'(LU3ENT:) unphysical kinematical variable setup') - -C...Store partons/particles in P vectors. - P(IPA,3)=PA1 - P(IPA,4)=SQRT(PA1**2+PM1**2) - P(IPA,5)=PM1 - P(IPA+2,1)=PA3*SQRT(1.-CTHE3**2) - P(IPA+2,3)=PA3*CTHE3 - P(IPA+2,4)=SQRT(PA3**2+PM3**2) - P(IPA+2,5)=PM3 - P(IPA+1,1)=-P(IPA+2,1) - P(IPA+1,3)=-P(IPA,3)-P(IPA+2,3) - P(IPA+1,4)=SQRT(P(IPA+1,1)**2+P(IPA+1,3)**2+PM2**2) - P(IPA+1,5)=PM2 - -C...Set N. Optionally fragment/decay. - N=IPA+2 - IF(IP.EQ.0) CALL LUEXEC - - RETURN - END - -C********************************************************************* - -CDECK ID>, LU4ENT - SUBROUTINE LU4ENT(IP,KF1,KF2,KF3,KF4,PECM,X1,X2,X4,X12,X14) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to store four partons or particles in their CM frame, with -C...the first along the +z axis, the last in the xz plane with x > 0 -C...and the second having y < 0 and y > 0 with equal probability. - COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ - -C...Standard checks. - MSTU(28)=0 - IF(MSTU(12).GE.1) CALL LULIST(0) - IPA=MAX(1,IABS(IP)) - IF(IPA.GT.MSTU(4)-3) CALL LUERRM(21, - &'(LU4ENT:) writing outside LUJETS momory') - KC1=LUCOMP(KF1) - KC2=LUCOMP(KF2) - KC3=LUCOMP(KF3) - KC4=LUCOMP(KF4) - IF(KC1.EQ.0.OR.KC2.EQ.0.OR.KC3.EQ.0.OR.KC4.EQ.0) CALL LUERRM(12, - &'(LU4ENT:) unknown flavour code') - -C...Find masses. Reset K, P and V vectors. - PM1=0. - IF(MSTU(10).EQ.1) PM1=P(IPA,5) - IF(MSTU(10).GE.2) PM1=ULMASS(KF1) - PM2=0. - IF(MSTU(10).EQ.1) PM2=P(IPA+1,5) - IF(MSTU(10).GE.2) PM2=ULMASS(KF2) - PM3=0. - IF(MSTU(10).EQ.1) PM3=P(IPA+2,5) - IF(MSTU(10).GE.2) PM3=ULMASS(KF3) - PM4=0. - IF(MSTU(10).EQ.1) PM4=P(IPA+3,5) - IF(MSTU(10).GE.2) PM4=ULMASS(KF4) - DO 110 I=IPA,IPA+3 - DO 100 J=1,5 - K(I,J)=0 - P(I,J)=0. - V(I,J)=0. - 100 CONTINUE - 110 CONTINUE - -C...Check flavours. - KQ1=KCHG(KC1,2)*ISIGN(1,KF1) - KQ2=KCHG(KC2,2)*ISIGN(1,KF2) - KQ3=KCHG(KC3,2)*ISIGN(1,KF3) - KQ4=KCHG(KC4,2)*ISIGN(1,KF4) - IF(MSTU(19).EQ.1) THEN - MSTU(19)=0 - ELSEIF(KQ1.EQ.0.AND.KQ2.EQ.0.AND.KQ3.EQ.0.AND.KQ4.EQ.0) THEN - ELSEIF(KQ1.NE.0.AND.KQ2.EQ.2.AND.KQ3.EQ.2.AND.(KQ1+KQ4.EQ.0.OR. - &KQ1+KQ4.EQ.4)) THEN - ELSEIF(KQ1.NE.0.AND.KQ1+KQ2.EQ.0.AND.KQ3.NE.0.AND.KQ3+KQ4.EQ.0.) - &THEN - ELSE - CALL LUERRM(2,'(LU4ENT:) unphysical flavour combination') - ENDIF - K(IPA,2)=KF1 - K(IPA+1,2)=KF2 - K(IPA+2,2)=KF3 - K(IPA+3,2)=KF4 - -C...Store partons/particles in K vectors for normal case. - IF(IP.GE.0) THEN - K(IPA,1)=1 - IF(KQ1.NE.0.AND.(KQ2.NE.0.OR.KQ3.NE.0.OR.KQ4.NE.0)) K(IPA,1)=2 - K(IPA+1,1)=1 - IF(KQ2.NE.0.AND.KQ1+KQ2.NE.0.AND.(KQ3.NE.0.OR.KQ4.NE.0)) - & K(IPA+1,1)=2 - K(IPA+2,1)=1 - IF(KQ3.NE.0.AND.KQ4.NE.0) K(IPA+2,1)=2 - K(IPA+3,1)=1 - -C...Store partons for parton shower evolution from q-g-g-qbar or -C...g-g-g-g event. - ELSEIF(KQ1+KQ2.NE.0) THEN - K(IPA,1)=3 - K(IPA+1,1)=3 - K(IPA+2,1)=3 - K(IPA+3,1)=3 - KCS=4 - IF(KQ1.EQ.-1) KCS=5 - K(IPA,KCS)=MSTU(5)*(IPA+1) - K(IPA,9-KCS)=MSTU(5)*(IPA+3) - K(IPA+1,KCS)=MSTU(5)*(IPA+2) - K(IPA+1,9-KCS)=MSTU(5)*IPA - K(IPA+2,KCS)=MSTU(5)*(IPA+3) - K(IPA+2,9-KCS)=MSTU(5)*(IPA+1) - K(IPA+3,KCS)=MSTU(5)*IPA - K(IPA+3,9-KCS)=MSTU(5)*(IPA+2) - -C...Store partons for parton shower evolution from q-qbar-q-qbar event. - ELSE - K(IPA,1)=3 - K(IPA+1,1)=3 - K(IPA+2,1)=3 - K(IPA+3,1)=3 - K(IPA,4)=MSTU(5)*(IPA+1) - K(IPA,5)=K(IPA,4) - K(IPA+1,4)=MSTU(5)*IPA - K(IPA+1,5)=K(IPA+1,4) - K(IPA+2,4)=MSTU(5)*(IPA+3) - K(IPA+2,5)=K(IPA+2,4) - K(IPA+3,4)=MSTU(5)*(IPA+2) - K(IPA+3,5)=K(IPA+3,4) - ENDIF - -C...Check kinematics. - MKERR=0 - IF(0.5*X1*PECM.LE.PM1.OR.0.5*X2*PECM.LE.PM2.OR.0.5*(2.-X1-X2-X4)* - &PECM.LE.PM3.OR.0.5*X4*PECM.LE.PM4) MKERR=1 - PA1=SQRT(MAX(1D-10,(0.5*X1*PECM)**2-PM1**2)) - PA2=SQRT(MAX(1D-10,(0.5*X2*PECM)**2-PM2**2)) - PA4=SQRT(MAX(1D-10,(0.5*X4*PECM)**2-PM4**2)) - X24=X1+X2+X4-1.-X12-X14+(PM3**2-PM1**2-PM2**2-PM4**2)/PECM**2 - CTHE4=(X1*X4-2.*X14)*PECM**2/(4.*PA1*PA4) - IF(ABS(CTHE4).GE.1.002) MKERR=1 - CTHE4=MAX(-1.D0,MIN(1.D0,CTHE4)) - STHE4=SQRT(1.-CTHE4**2) - CTHE2=(X1*X2-2.*X12)*PECM**2/(4.*PA1*PA2) - IF(ABS(CTHE2).GE.1.002) MKERR=1 - CTHE2=MAX(-1.D0,MIN(1.D0,CTHE2)) - STHE2=SQRT(1.-CTHE2**2) - CPHI2=((X2*X4-2.*X24)*PECM**2-4.*PA2*CTHE2*PA4*CTHE4)/ - &MAX(1D-8*PECM**2,4.*PA2*STHE2*PA4*STHE4) - IF(ABS(CPHI2).GE.1.05) MKERR=1 - CPHI2=MAX(-1.D0,MIN(1.D0,CPHI2)) - IF(MKERR.EQ.1) CALL LUERRM(13, - &'(LU4ENT:) unphysical kinematical variable setup') - -C...Store partons/particles in P vectors. - P(IPA,3)=PA1 - P(IPA,4)=SQRT(PA1**2+PM1**2) - P(IPA,5)=PM1 - P(IPA+3,1)=PA4*STHE4 - P(IPA+3,3)=PA4*CTHE4 - P(IPA+3,4)=SQRT(PA4**2+PM4**2) - P(IPA+3,5)=PM4 - P(IPA+1,1)=PA2*STHE2*CPHI2 - P(IPA+1,2)=PA2*STHE2*SQRT(1.-CPHI2**2)*(-1.)**INT(RLU(0)+0.5) - P(IPA+1,3)=PA2*CTHE2 - P(IPA+1,4)=SQRT(PA2**2+PM2**2) - P(IPA+1,5)=PM2 - P(IPA+2,1)=-P(IPA+1,1)-P(IPA+3,1) - P(IPA+2,2)=-P(IPA+1,2) - P(IPA+2,3)=-P(IPA,3)-P(IPA+1,3)-P(IPA+3,3) - P(IPA+2,4)=SQRT(P(IPA+2,1)**2+P(IPA+2,2)**2+P(IPA+2,3)**2+PM3**2) - P(IPA+2,5)=PM3 - -C...Set N. Optionally fragment/decay. - N=IPA+3 - IF(IP.EQ.0) CALL LUEXEC - - RETURN - END - -C********************************************************************* - -CDECK ID>, LUJOIN - SUBROUTINE LUJOIN(NJOIN,IJOIN) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to connect a sequence of partons with colour flow indices, -C...as required for subsequent shower evolution (or other operations). - COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ - DIMENSION IJOIN(*) - -C...Check that partons are of right types to be connected. - IF(NJOIN.LT.2) GOTO 120 - KQSUM=0 - DO 100 IJN=1,NJOIN - I=IJOIN(IJN) - IF(I.LE.0.OR.I.GT.N) GOTO 120 - IF(K(I,1).LT.1.OR.K(I,1).GT.3) GOTO 120 - KC=LUCOMP(K(I,2)) - IF(KC.EQ.0) GOTO 120 - KQ=KCHG(KC,2)*ISIGN(1,K(I,2)) - IF(KQ.EQ.0) GOTO 120 - IF(IJN.NE.1.AND.IJN.NE.NJOIN.AND.KQ.NE.2) GOTO 120 - IF(KQ.NE.2) KQSUM=KQSUM+KQ - IF(IJN.EQ.1) KQS=KQ - 100 CONTINUE - IF(KQSUM.NE.0) GOTO 120 - -C...Connect the partons sequentially (closing for gluon loop). - KCS=(9-KQS)/2 - IF(KQS.EQ.2) KCS=INT(4.5+RLU(0)) - DO 110 IJN=1,NJOIN - I=IJOIN(IJN) - K(I,1)=3 - IF(IJN.NE.1) IP=IJOIN(IJN-1) - IF(IJN.EQ.1) IP=IJOIN(NJOIN) - IF(IJN.NE.NJOIN) IN=IJOIN(IJN+1) - IF(IJN.EQ.NJOIN) IN=IJOIN(1) - K(I,KCS)=MSTU(5)*IN - K(I,9-KCS)=MSTU(5)*IP - IF(IJN.EQ.1.AND.KQS.NE.2) K(I,9-KCS)=0 - IF(IJN.EQ.NJOIN.AND.KQS.NE.2) K(I,KCS)=0 - 110 CONTINUE - -C...Error exit: no action taken. - RETURN - 120 CALL LUERRM(12, - &'(LUJOIN:) given entries can not be joined by one string') - - RETURN - END - -C********************************************************************* - -CDECK ID>, LUGIVE - SUBROUTINE LUGIVE(CHIN) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to set values of commonblock variables (also in PYTHIA!). - COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - COMMON/LUDAT3/MDCY(500,3),MDME(2000,2),BRAT(2000),KFDP(2000,5) - COMMON/LUDAT4/CHAF(500) - CHARACTER CHAF*8 - COMMON/LUDATR/MRLU(6),RRLU(100) - COMMON/PYSUBS/MSUB(200),KFIN(2,-40:40),CKIN(200),MSEL - COMMON/PYPARS/MSTP(200),PARP(200),MSTI(200),PARI(200) - COMMON/PYINT1/MINT(400),VINT(400) - COMMON/PYINT2/ISET(200),KFPR(200,2),COEF(200,20),ICOL(40,4,2) - COMMON/PYINT3/XSFX(2,-40:40),ISIG(1000,3),SIGH(1000) - COMMON/PYINT4/WIDP(21:40,0:40),WIDE(21:40,0:40),WIDS(21:40,3) - COMMON/PYINT5/XSEC(0:200,3),NGEN(0:200,3) - COMMON/PYINT6/PROC(0:200) - COMMON/PYINT7/SIGT(0:6,0:6,0:5) - CHARACTER PROC*28 - SAVE /LUJETS/,/LUDAT1/,/LUDAT2/,/LUDAT3/,/LUDAT4/,/LUDATR/ - SAVE /PYSUBS/,/PYPARS/,/PYINT1/,/PYINT2/,/PYINT3/,/PYINT4/, - &/PYINT5/,/PYINT6/,/PYINT7/ - CHARACTER CHIN*(*),CHFIX*104,CHBIT*104,CHOLD*8,CHNEW*8,CHOLD2*28, - &CHNEW2*28,CHNAM*4,CHVAR(43)*4,CHALP(2)*26,CHIND*8,CHINI*10, - &CHINR*16 - DIMENSION MSVAR(43,8) - -C...For each variable to be translated give: name, -C...integer/real/character, no. of indices, lower&upper index bounds. - DATA CHVAR/'N','K','P','V','MSTU','PARU','MSTJ','PARJ','KCHG', - &'PMAS','PARF','VCKM','MDCY','MDME','BRAT','KFDP','CHAF','MRLU', - &'RRLU','MSEL','MSUB','KFIN','CKIN','MSTP','PARP','MSTI','PARI', - &'MINT','VINT','ISET','KFPR','COEF','ICOL','XSFX','ISIG','SIGH', - &'WIDP','WIDE','WIDS','NGEN','XSEC','PROC','SIGT'/ - DATA ((MSVAR(I,J),J=1,8),I=1,43)/ 1,7*0, 1,2,1,4000,1,5,2*0, - & 2,2,1,4000,1,5,2*0, 2,2,1,4000,1,5,2*0, 1,1,1,200,4*0, - & 2,1,1,200,4*0, 1,1,1,200,4*0, 2,1,1,200,4*0, - & 1,2,1,500,1,3,2*0, 2,2,1,500,1,4,2*0, 2,1,1,2000,4*0, - & 2,2,1,4,1,4,2*0, 1,2,1,500,1,3,2*0, 1,2,1,2000,1,2,2*0, - & 2,1,1,2000,4*0, 1,2,1,2000,1,5,2*0, 3,1,1,500,4*0, - & 1,1,1,6,4*0, 2,1,1,100,4*0, - & 1,7*0, 1,1,1,200,4*0, 1,2,1,2,-40,40,2*0, 2,1,1,200,4*0, - & 1,1,1,200,4*0, 2,1,1,200,4*0, 1,1,1,200,4*0, 2,1,1,200,4*0, - & 1,1,1,400,4*0, 2,1,1,400,4*0, 1,1,1,200,4*0, - & 1,2,1,200,1,2,2*0, 2,2,1,200,1,20,2*0, 1,3,1,40,1,4,1,2, - & 2,2,1,2,-40,40,2*0, 1,2,1,1000,1,3,2*0, 2,1,1,1000,4*0, - & 2,2,21,40,0,40,2*0, 2,2,21,40,0,40,2*0, 2,2,21,40,1,3,2*0, - & 1,2,0,200,1,3,2*0, 2,2,0,200,1,3,2*0, 4,1,0,200,4*0, - & 2,3,0,6,0,6,0,5/ - DATA CHALP/'abcdefghijklmnopqrstuvwxyz', - &'ABCDEFGHIJKLMNOPQRSTUVWXYZ'/ - -C...Length of character variable. Subdivide it into instructions. - IF(MSTU(12).GE.1) CALL LULIST(0) - CHBIT=CHIN//' ' - LBIT=101 - 100 LBIT=LBIT-1 - IF(CHBIT(LBIT:LBIT).EQ.' ') GOTO 100 - LTOT=0 - DO 110 LCOM=1,LBIT - IF(CHBIT(LCOM:LCOM).EQ.' ') GOTO 110 - LTOT=LTOT+1 - CHFIX(LTOT:LTOT)=CHBIT(LCOM:LCOM) - 110 CONTINUE - LLOW=0 - 120 LHIG=LLOW+1 - 130 LHIG=LHIG+1 - IF(LHIG.LE.LTOT.AND.CHFIX(LHIG:LHIG).NE.';') GOTO 130 - LBIT=LHIG-LLOW-1 - CHBIT(1:LBIT)=CHFIX(LLOW+1:LHIG-1) - -C...Identify commonblock variable. - LNAM=1 - 140 LNAM=LNAM+1 - IF(CHBIT(LNAM:LNAM).NE.'('.AND.CHBIT(LNAM:LNAM).NE.'='.AND. - &LNAM.LE.4) GOTO 140 - CHNAM=CHBIT(1:LNAM-1)//' ' - DO 160 LCOM=1,LNAM-1 - DO 150 LALP=1,26 - IF(CHNAM(LCOM:LCOM).EQ.CHALP(1)(LALP:LALP)) CHNAM(LCOM:LCOM)= - &CHALP(2)(LALP:LALP) - 150 CONTINUE - 160 CONTINUE - IVAR=0 - DO 170 IV=1,43 - IF(CHNAM.EQ.CHVAR(IV)) IVAR=IV - 170 CONTINUE - IF(IVAR.EQ.0) THEN - CALL LUERRM(18,'(LUGIVE:) do not recognize variable '//CHNAM) - LLOW=LHIG - IF(LLOW.LT.LTOT) GOTO 120 - RETURN - ENDIF - -C...Identify any indices. - I1=0 - I2=0 - I3=0 - NINDX=0 - IF(CHBIT(LNAM:LNAM).EQ.'(') THEN - LIND=LNAM - 180 LIND=LIND+1 - IF(CHBIT(LIND:LIND).NE.')'.AND.CHBIT(LIND:LIND).NE.',') GOTO 180 - CHIND=' ' - IF((CHBIT(LNAM+1:LNAM+1).EQ.'C'.OR.CHBIT(LNAM+1:LNAM+1).EQ.'c'). - & AND.(IVAR.EQ.9.OR.IVAR.EQ.10.OR.IVAR.EQ.13.OR.IVAR.EQ.17)) THEN - CHIND(LNAM-LIND+11:8)=CHBIT(LNAM+2:LIND-1) - READ(CHIND,'(I8)') KF - I1=LUCOMP(KF) - ELSEIF(CHBIT(LNAM+1:LNAM+1).EQ.'C'.OR.CHBIT(LNAM+1:LNAM+1).EQ. - & 'c') THEN - CALL LUERRM(18,'(LUGIVE:) not allowed to use C index for '// - & CHNAM) - LLOW=LHIG - IF(LLOW.LT.LTOT) GOTO 120 - RETURN - ELSE - CHIND(LNAM-LIND+10:8)=CHBIT(LNAM+1:LIND-1) - READ(CHIND,'(I8)') I1 - ENDIF - LNAM=LIND - IF(CHBIT(LNAM:LNAM).EQ.')') LNAM=LNAM+1 - NINDX=1 - ENDIF - IF(CHBIT(LNAM:LNAM).EQ.',') THEN - LIND=LNAM - 190 LIND=LIND+1 - IF(CHBIT(LIND:LIND).NE.')'.AND.CHBIT(LIND:LIND).NE.',') GOTO 190 - CHIND=' ' - CHIND(LNAM-LIND+10:8)=CHBIT(LNAM+1:LIND-1) - READ(CHIND,'(I8)') I2 - LNAM=LIND - IF(CHBIT(LNAM:LNAM).EQ.')') LNAM=LNAM+1 - NINDX=2 - ENDIF - IF(CHBIT(LNAM:LNAM).EQ.',') THEN - LIND=LNAM - 200 LIND=LIND+1 - IF(CHBIT(LIND:LIND).NE.')'.AND.CHBIT(LIND:LIND).NE.',') GOTO 200 - CHIND=' ' - CHIND(LNAM-LIND+10:8)=CHBIT(LNAM+1:LIND-1) - READ(CHIND,'(I8)') I3 - LNAM=LIND+1 - NINDX=3 - ENDIF - -C...Check that indices allowed. - IERR=0 - IF(NINDX.NE.MSVAR(IVAR,2)) IERR=1 - IF(NINDX.GE.1.AND.(I1.LT.MSVAR(IVAR,3).OR.I1.GT.MSVAR(IVAR,4))) - &IERR=2 - IF(NINDX.GE.2.AND.(I2.LT.MSVAR(IVAR,5).OR.I2.GT.MSVAR(IVAR,6))) - &IERR=3 - IF(NINDX.EQ.3.AND.(I3.LT.MSVAR(IVAR,7).OR.I3.GT.MSVAR(IVAR,8))) - &IERR=4 - IF(CHBIT(LNAM:LNAM).NE.'=') IERR=5 - IF(IERR.GE.1) THEN - CALL LUERRM(18,'(LUGIVE:) unallowed indices for '// - & CHBIT(1:LNAM-1)) - LLOW=LHIG - IF(LLOW.LT.LTOT) GOTO 120 - RETURN - ENDIF - -C...Save old value of variable. - IF(IVAR.EQ.1) THEN - IOLD=N - ELSEIF(IVAR.EQ.2) THEN - IOLD=K(I1,I2) - ELSEIF(IVAR.EQ.3) THEN - ROLD=P(I1,I2) - ELSEIF(IVAR.EQ.4) THEN - ROLD=V(I1,I2) - ELSEIF(IVAR.EQ.5) THEN - IOLD=MSTU(I1) - ELSEIF(IVAR.EQ.6) THEN - ROLD=PARU(I1) - ELSEIF(IVAR.EQ.7) THEN - IOLD=MSTJ(I1) - ELSEIF(IVAR.EQ.8) THEN - ROLD=PARJ(I1) - ELSEIF(IVAR.EQ.9) THEN - IOLD=KCHG(I1,I2) - ELSEIF(IVAR.EQ.10) THEN - ROLD=PMAS(I1,I2) - ELSEIF(IVAR.EQ.11) THEN - ROLD=PARF(I1) - ELSEIF(IVAR.EQ.12) THEN - ROLD=VCKM(I1,I2) - ELSEIF(IVAR.EQ.13) THEN - IOLD=MDCY(I1,I2) - ELSEIF(IVAR.EQ.14) THEN - IOLD=MDME(I1,I2) - ELSEIF(IVAR.EQ.15) THEN - ROLD=BRAT(I1) - ELSEIF(IVAR.EQ.16) THEN - IOLD=KFDP(I1,I2) - ELSEIF(IVAR.EQ.17) THEN - CHOLD=CHAF(I1) - ELSEIF(IVAR.EQ.18) THEN - IOLD=MRLU(I1) - ELSEIF(IVAR.EQ.19) THEN - ROLD=RRLU(I1) - ELSEIF(IVAR.EQ.20) THEN - IOLD=MSEL - ELSEIF(IVAR.EQ.21) THEN - IOLD=MSUB(I1) - ELSEIF(IVAR.EQ.22) THEN - IOLD=KFIN(I1,I2) - ELSEIF(IVAR.EQ.23) THEN - ROLD=CKIN(I1) - ELSEIF(IVAR.EQ.24) THEN - IOLD=MSTP(I1) - ELSEIF(IVAR.EQ.25) THEN - ROLD=PARP(I1) - ELSEIF(IVAR.EQ.26) THEN - IOLD=MSTI(I1) - ELSEIF(IVAR.EQ.27) THEN - ROLD=PARI(I1) - ELSEIF(IVAR.EQ.28) THEN - IOLD=MINT(I1) - ELSEIF(IVAR.EQ.29) THEN - ROLD=VINT(I1) - ELSEIF(IVAR.EQ.30) THEN - IOLD=ISET(I1) - ELSEIF(IVAR.EQ.31) THEN - IOLD=KFPR(I1,I2) - ELSEIF(IVAR.EQ.32) THEN - ROLD=COEF(I1,I2) - ELSEIF(IVAR.EQ.33) THEN - IOLD=ICOL(I1,I2,I3) - ELSEIF(IVAR.EQ.34) THEN - ROLD=XSFX(I1,I2) - ELSEIF(IVAR.EQ.35) THEN - IOLD=ISIG(I1,I2) - ELSEIF(IVAR.EQ.36) THEN - ROLD=SIGH(I1) - ELSEIF(IVAR.EQ.37) THEN - ROLD=WIDP(I1,I2) - ELSEIF(IVAR.EQ.38) THEN - ROLD=WIDE(I1,I2) - ELSEIF(IVAR.EQ.39) THEN - ROLD=WIDS(I1,I2) - ELSEIF(IVAR.EQ.40) THEN - IOLD=NGEN(I1,I2) - ELSEIF(IVAR.EQ.41) THEN - ROLD=XSEC(I1,I2) - ELSEIF(IVAR.EQ.42) THEN - CHOLD2=PROC(I1) - ELSEIF(IVAR.EQ.43) THEN - ROLD=SIGT(I1,I2,I3) - ENDIF - -C...Print current value of variable. Loop back. - IF(LNAM.GE.LBIT) THEN - CHBIT(LNAM:14)=' ' - CHBIT(15:60)=' has the value ' - IF(MSVAR(IVAR,1).EQ.1) THEN - WRITE(CHBIT(51:60),'(I10)') IOLD - ELSEIF(MSVAR(IVAR,1).EQ.2) THEN - WRITE(CHBIT(47:60),'(F14.5)') ROLD - ELSEIF(MSVAR(IVAR,1).EQ.3) THEN - CHBIT(53:60)=CHOLD - ELSE - CHBIT(33:60)=CHOLD - ENDIF - IF(MSTU(13).GE.1) WRITE(MSTU(11),5000) CHBIT(1:60) - LLOW=LHIG - IF(LLOW.LT.LTOT) GOTO 120 - RETURN - ENDIF - -C...Read in new variable value. - IF(MSVAR(IVAR,1).EQ.1) THEN - CHINI=' ' - CHINI(LNAM-LBIT+11:10)=CHBIT(LNAM+1:LBIT) - READ(CHINI,'(I10)') INEW - ELSEIF(MSVAR(IVAR,1).EQ.2) THEN - CHINR=' ' - CHINR(LNAM-LBIT+17:16)=CHBIT(LNAM+1:LBIT) - READ(CHINR,'(F16.2)') RNEW - ELSEIF(MSVAR(IVAR,1).EQ.3) THEN - CHNEW=CHBIT(LNAM+1:LBIT)//' ' - ELSE - CHNEW2=CHBIT(LNAM+1:LBIT)//' ' - ENDIF - -C...Store new variable value. - IF(IVAR.EQ.1) THEN - N=INEW - ELSEIF(IVAR.EQ.2) THEN - K(I1,I2)=INEW - ELSEIF(IVAR.EQ.3) THEN - P(I1,I2)=RNEW - ELSEIF(IVAR.EQ.4) THEN - V(I1,I2)=RNEW - ELSEIF(IVAR.EQ.5) THEN - MSTU(I1)=INEW - ELSEIF(IVAR.EQ.6) THEN - PARU(I1)=RNEW - ELSEIF(IVAR.EQ.7) THEN - MSTJ(I1)=INEW - ELSEIF(IVAR.EQ.8) THEN - PARJ(I1)=RNEW - ELSEIF(IVAR.EQ.9) THEN - KCHG(I1,I2)=INEW - ELSEIF(IVAR.EQ.10) THEN - PMAS(I1,I2)=RNEW - ELSEIF(IVAR.EQ.11) THEN - PARF(I1)=RNEW - ELSEIF(IVAR.EQ.12) THEN - VCKM(I1,I2)=RNEW - ELSEIF(IVAR.EQ.13) THEN - MDCY(I1,I2)=INEW - ELSEIF(IVAR.EQ.14) THEN - MDME(I1,I2)=INEW - ELSEIF(IVAR.EQ.15) THEN - BRAT(I1)=RNEW - ELSEIF(IVAR.EQ.16) THEN - KFDP(I1,I2)=INEW - ELSEIF(IVAR.EQ.17) THEN - CHAF(I1)=CHNEW - ELSEIF(IVAR.EQ.18) THEN - MRLU(I1)=INEW - ELSEIF(IVAR.EQ.19) THEN - RRLU(I1)=RNEW - ELSEIF(IVAR.EQ.20) THEN - MSEL=INEW - ELSEIF(IVAR.EQ.21) THEN - MSUB(I1)=INEW - ELSEIF(IVAR.EQ.22) THEN - KFIN(I1,I2)=INEW - ELSEIF(IVAR.EQ.23) THEN - CKIN(I1)=RNEW - ELSEIF(IVAR.EQ.24) THEN - MSTP(I1)=INEW - ELSEIF(IVAR.EQ.25) THEN - PARP(I1)=RNEW - ELSEIF(IVAR.EQ.26) THEN - MSTI(I1)=INEW - ELSEIF(IVAR.EQ.27) THEN - PARI(I1)=RNEW - ELSEIF(IVAR.EQ.28) THEN - MINT(I1)=INEW - ELSEIF(IVAR.EQ.29) THEN - VINT(I1)=RNEW - ELSEIF(IVAR.EQ.30) THEN - ISET(I1)=INEW - ELSEIF(IVAR.EQ.31) THEN - KFPR(I1,I2)=INEW - ELSEIF(IVAR.EQ.32) THEN - COEF(I1,I2)=RNEW - ELSEIF(IVAR.EQ.33) THEN - ICOL(I1,I2,I3)=INEW - ELSEIF(IVAR.EQ.34) THEN - XSFX(I1,I2)=RNEW - ELSEIF(IVAR.EQ.35) THEN - ISIG(I1,I2)=INEW - ELSEIF(IVAR.EQ.36) THEN - SIGH(I1)=RNEW - ELSEIF(IVAR.EQ.37) THEN - WIDP(I1,I2)=RNEW - ELSEIF(IVAR.EQ.38) THEN - WIDE(I1,I2)=RNEW - ELSEIF(IVAR.EQ.39) THEN - WIDS(I1,I2)=RNEW - ELSEIF(IVAR.EQ.40) THEN - NGEN(I1,I2)=INEW - ELSEIF(IVAR.EQ.41) THEN - XSEC(I1,I2)=RNEW - ELSEIF(IVAR.EQ.42) THEN - PROC(I1)=CHNEW2 - ELSEIF(IVAR.EQ.43) THEN - SIGT(I1,I2,I3)=RNEW - ENDIF - -C...Write old and new value. Loop back. - CHBIT(LNAM:14)=' ' - CHBIT(15:60)=' changed from to ' - IF(MSVAR(IVAR,1).EQ.1) THEN - WRITE(CHBIT(33:42),'(I10)') IOLD - WRITE(CHBIT(51:60),'(I10)') INEW - IF(MSTU(13).GE.1) WRITE(MSTU(11),5000) CHBIT(1:60) - ELSEIF(MSVAR(IVAR,1).EQ.2) THEN - WRITE(CHBIT(29:42),'(F14.5)') ROLD - WRITE(CHBIT(47:60),'(F14.5)') RNEW - IF(MSTU(13).GE.1) WRITE(MSTU(11),5000) CHBIT(1:60) - ELSEIF(MSVAR(IVAR,1).EQ.3) THEN - CHBIT(35:42)=CHOLD - CHBIT(53:60)=CHNEW - IF(MSTU(13).GE.1) WRITE(MSTU(11),5000) CHBIT(1:60) - ELSE - CHBIT(15:88)=' changed from '//CHOLD2//' to '//CHNEW2 - IF(MSTU(13).GE.1) WRITE(MSTU(11),5100) CHBIT(1:88) - ENDIF - LLOW=LHIG - IF(LLOW.LT.LTOT) GOTO 120 - -C...Format statement for output on unit MSTU(11) (by default 6). - 5000 FORMAT(5X,A60) - 5100 FORMAT(5X,A88) - - RETURN - END - -C********************************************************************* - -CDECK ID>, LUEXEC - SUBROUTINE LUEXEC - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to administrate the fragmentation and decay chain. - COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - COMMON/LUDAT3/MDCY(500,3),MDME(2000,2),BRAT(2000),KFDP(2000,5) - SAVE /LUJETS/,/LUDAT1/,/LUDAT2/,/LUDAT3/ - DIMENSION PS(2,6) - -C...Initialize and reset. - MSTU(24)=0 - IF(MSTU(12).GE.1) CALL LULIST(0) - MSTU(31)=MSTU(31)+1 - MSTU(1)=0 - MSTU(2)=0 - MSTU(3)=0 - IF(MSTU(17).LE.0) MSTU(90)=0 - MCONS=1 - -C...Sum up momentum, energy and charge for starting entries. - NSAV=N - DO 110 I=1,2 - DO 100 J=1,6 - PS(I,J)=0. - 100 CONTINUE - 110 CONTINUE - DO 130 I=1,N - IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 130 - DO 120 J=1,4 - PS(1,J)=PS(1,J)+P(I,J) - 120 CONTINUE - PS(1,6)=PS(1,6)+LUCHGE(K(I,2)) - 130 CONTINUE - PARU(21)=PS(1,4) + DO 130 I=1,N + IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 130 + DO 120 J=1,4 + PS(1,J)=PS(1,J)+P(I,J) + 120 CONTINUE + PS(1,6)=PS(1,6)+LUCHGE(K(I,2)) + 130 CONTINUE + PARU(21)=PS(1,4) C...Prepare system for subsequent fragmentation/decay. CALL LUPREP(0) @@ -6382,7 +4356,7 @@ SUBROUTINE LUSTRF(IP) P(I,5)=ULMASS(K(I,2)) PR(JR)=P(I,5)**2+(PX(JR)-PX(3))**2+(PY(JR)-PY(3))**2 -C...Final two hadrons: find common setup of four-vectors. +C...Final two hadrons: find COMMON setup of four-vectors. JQ=1 IF(P(IN(4)+2,3)*P(IN(5)+2,3)*FOUR(IN(4),IN(5)).LT.P(IN(7),3)* &P(IN(8),3)*FOUR(IN(7),IN(8))) JQ=2 @@ -7052,7 +5026,7 @@ SUBROUTINE LUDECY(IP) RETURN ENDIF -C...Interface to external tau decay library (for tau polarization). +C...Interface to EXTERNAL tau decay library (for tau polarization). IF(KFA.EQ.15.AND.MSTJ(28).GE.1) THEN C...Starting values for pointers and momenta. @@ -9329,7 +7303,7 @@ SUBROUTINE LUSHOW(IP1,IP2,QMAX) ENDIF ENDIF -C...Continue loop over partons that may branch, until none left. +C...CONTINUE loop over partons that may branch, until none left. IF(IGM.GE.0) K(IM,1)=14 N=N+NEP NEP=2 @@ -9708,150 +7682,6 @@ FUNCTION ULMASS(KF) C********************************************************************* -CDECK ID>, LUNAME - SUBROUTINE LUNAME(KF,CHAU) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to give the particle/parton name as a character string. - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - COMMON/LUDAT4/CHAF(500) - CHARACTER CHAF*8 - SAVE /LUDAT1/,/LUDAT2/,/LUDAT4/ - CHARACTER CHAU*16 - -C...Initial values. Charge. Subdivide code. - CHAU=' ' - KFA=IABS(KF) - KC=LUCOMP(KF) - IF(KC.EQ.0) RETURN - KQ=LUCHGE(KF) - KFLA=MOD(KFA/1000,10) - KFLB=MOD(KFA/100,10) - KFLC=MOD(KFA/10,10) - KFLS=MOD(KFA,10) - KFLR=MOD(KFA/10000,10) - -C...Read out root name and spin for simple particle. - IF(KFA.LE.100.OR.(KFA.GT.100.AND.KC.GT.100)) THEN - CHAU=CHAF(KC) - LEN=0 - DO 100 LEM=1,8 - IF(CHAU(LEM:LEM).NE.' ') LEN=LEM - 100 CONTINUE - -C...Construct root name for diquark. Add on spin. - ELSEIF(KFLC.EQ.0) THEN - CHAU(1:2)=CHAF(KFLA)(1:1)//CHAF(KFLB)(1:1) - IF(KFLS.EQ.1) CHAU(3:4)='_0' - IF(KFLS.EQ.3) CHAU(3:4)='_1' - LEN=4 - -C...Construct root name for heavy meson. Add on spin and heavy flavour. - ELSEIF(KFLA.EQ.0) THEN - IF(KFLB.EQ.5) CHAU(1:1)='B' - IF(KFLB.EQ.6) CHAU(1:1)='T' - IF(KFLB.EQ.7) CHAU(1:1)='L' - IF(KFLB.EQ.8) CHAU(1:1)='H' - LEN=1 - IF(KFLR.EQ.0.AND.KFLS.EQ.1) THEN - ELSEIF(KFLR.EQ.0.AND.KFLS.EQ.3) THEN - CHAU(2:2)='*' - LEN=2 - ELSEIF(KFLR.EQ.1.AND.KFLS.EQ.3) THEN - CHAU(2:3)='_1' - LEN=3 - ELSEIF(KFLR.EQ.1.AND.KFLS.EQ.1) THEN - CHAU(2:4)='*_0' - LEN=4 - ELSEIF(KFLR.EQ.2) THEN - CHAU(2:4)='*_1' - LEN=4 - ELSEIF(KFLS.EQ.5) THEN - CHAU(2:4)='*_2' - LEN=4 - ENDIF - IF(KFLC.GE.3.AND.KFLR.EQ.0.AND.KFLS.LE.3) THEN - CHAU(LEN+1:LEN+2)='_'//CHAF(KFLC)(1:1) - LEN=LEN+2 - ELSEIF(KFLC.GE.3) THEN - CHAU(LEN+1:LEN+1)=CHAF(KFLC)(1:1) - LEN=LEN+1 - ENDIF - -C...Construct root name and spin for heavy baryon. - ELSE - IF(KFLB.LE.2.AND.KFLC.LE.2) THEN - CHAU='Sigma ' - IF(KFLC.GT.KFLB) CHAU='Lambda' - IF(KFLS.EQ.4) CHAU='Sigma*' - LEN=5 - IF(CHAU(6:6).NE.' ') LEN=6 - ELSEIF(KFLB.LE.2.OR.KFLC.LE.2) THEN - CHAU='Xi ' - IF(KFLA.GT.KFLB.AND.KFLB.GT.KFLC) CHAU='Xi''' - IF(KFLS.EQ.4) CHAU='Xi*' - LEN=2 - IF(CHAU(3:3).NE.' ') LEN=3 - ELSE - CHAU='Omega ' - IF(KFLA.GT.KFLB.AND.KFLB.GT.KFLC) CHAU='Omega''' - IF(KFLS.EQ.4) CHAU='Omega*' - LEN=5 - IF(CHAU(6:6).NE.' ') LEN=6 - ENDIF - -C...Add on heavy flavour content for heavy baryon. - CHAU(LEN+1:LEN+2)='_'//CHAF(KFLA)(1:1) - LEN=LEN+2 - IF(KFLB.GE.KFLC.AND.KFLC.GE.4) THEN - CHAU(LEN+1:LEN+2)=CHAF(KFLB)(1:1)//CHAF(KFLC)(1:1) - LEN=LEN+2 - ELSEIF(KFLB.GE.KFLC.AND.KFLB.GE.4) THEN - CHAU(LEN+1:LEN+1)=CHAF(KFLB)(1:1) - LEN=LEN+1 - ELSEIF(KFLC.GT.KFLB.AND.KFLB.GE.4) THEN - CHAU(LEN+1:LEN+2)=CHAF(KFLC)(1:1)//CHAF(KFLB)(1:1) - LEN=LEN+2 - ELSEIF(KFLC.GT.KFLB.AND.KFLC.GE.4) THEN - CHAU(LEN+1:LEN+1)=CHAF(KFLC)(1:1) - LEN=LEN+1 - ENDIF - ENDIF - -C...Add on bar sign for antiparticle (where necessary). - IF(KF.GT.0.OR.LEN.EQ.0) THEN - ELSEIF(KFA.GT.10.AND.KFA.LE.40.AND.KQ.NE.0.AND.MOD(KQ,3).EQ.0) - &THEN - ELSEIF(KFA.EQ.89.OR.(KFA.GE.91.AND.KFA.LE.99)) THEN - ELSEIF(KFA.GT.100.AND.KFLA.EQ.0.AND.KQ.NE.0) THEN - ELSEIF(MSTU(15).LE.1) THEN - CHAU(LEN+1:LEN+1)='~' - LEN=LEN+1 - ELSE - CHAU(LEN+1:LEN+3)='bar' - LEN=LEN+3 - ENDIF - -C...Add on charge where applicable (conventional cases skipped). - IF(KQ.EQ.6) CHAU(LEN+1:LEN+2)='++' - IF(KQ.EQ.-6) CHAU(LEN+1:LEN+2)='--' - IF(KQ.EQ.3) CHAU(LEN+1:LEN+1)='+' - IF(KQ.EQ.-3) CHAU(LEN+1:LEN+1)='-' - IF(KQ.EQ.0.AND.(KFA.LE.22.OR.LEN.EQ.0)) THEN - ELSEIF(KQ.EQ.0.AND.(KFA.GE.81.AND.KFA.LE.100)) THEN - ELSEIF(KFA.EQ.28.OR.KFA.EQ.29) THEN - ELSEIF(KFA.GT.100.AND.KFLA.EQ.0.AND.KFLB.EQ.KFLC.AND. - &KFLB.NE.1) THEN - ELSEIF(KQ.EQ.0) THEN - CHAU(LEN+1:LEN+1)='0' - ENDIF - - RETURN - END - -C********************************************************************* - CDECK ID>, LUCHGE FUNCTION LUCHGE(KF) IMPLICIT DOUBLE PRECISION (A-H,O-Z) @@ -10001,7 +7831,7 @@ FUNCTION LUCOMP(KF) ENDIF RETURN - END + END FUNCTION LUCOMP C********************************************************************* @@ -10022,7 +7852,7 @@ SUBROUTINE LUERRM(MERR,CHMESS) IF(MSTU(25).EQ.1.AND.MSTU(27).LE.MSTU(26)) WRITE(MSTU(11),5000) & MERR,MSTU(31),CHMESS -C...Write first few errors, then be silent or stop program. +C...Write first few errors, then be silent or STOP program. ELSEIF(MERR.LE.20) THEN MSTU(23)=MSTU(23)+1 MSTU(24)=MERR-10 @@ -10031,11 +7861,11 @@ SUBROUTINE LUERRM(MERR,CHMESS) IF(MSTU(21).GE.2.AND.MSTU(23).GT.MSTU(22)) THEN WRITE(MSTU(11),5100) MERR-10,MSTU(31),CHMESS WRITE(MSTU(11),5200) - IF(MERR.NE.17) CALL LULIST(2) + IF(MERR.NE.17) PRINT*, "LULIST(2), Method removed" STOP ENDIF -C...Stop program in case of irreparable error. +C...STOP program in case of irreparable error. ELSE WRITE(MSTU(11),5300) MERR-20,MSTU(31),CHMESS STOP @@ -10046,143 +7876,45 @@ SUBROUTINE LUERRM(MERR,CHMESS) &' LUEXEC calls:'/5X,A) 5100 FORMAT(/5X,'Error type',I2,' has occured after',I6, &' LUEXEC calls:'/5X,A) - 5200 FORMAT(5X,'Execution will be stopped after listing of last ', + 5200 FORMAT(5X,'Execution will be STOPped after listing of last ', &'event!') 5300 FORMAT(/5X,'Fatal error type',I2,' has occured after',I6, - &' LUEXEC calls:'/5X,A/5X,'Execution will now be stopped!') + &' LUEXEC calls:'/5X,A/5X,'Execution will now be STOPped!') RETURN END C********************************************************************* -CDECK ID>, ULALEM - FUNCTION ULALEM(Q2) +CDECK ID>, ULANGL + FUNCTION ULANGL(X,Y) IMPLICIT DOUBLE PRECISION (A-H,O-Z) -C...Purpose: to calculate the running alpha_electromagnetic. +C...Purpose: to reconstruct an angle from given x and y coordinates. COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) SAVE /LUDAT1/ -C...Calculate real part of photon vacuum polarization. -C...For leptons simplify by using asymptotic (Q^2 >> m^2) expressions. -C...For hadrons use parametrization of H. Burkhardt et al. -C...See R. Kleiss et al, CERN 89-08, vol. 3, pp. 129-131. - AEMPI=PARU(101)/(3.*PARU(1)) - IF(MSTU(101).LE.0.OR.Q2.LT.2D-6) THEN - RPIGG=0. - ELSEIF(MSTU(101).EQ.2.AND.Q2.LT.PARU(104)) THEN - RPIGG=0. - ELSEIF(MSTU(101).EQ.2) THEN - RPIGG=1.-PARU(101)/PARU(103) - ELSEIF(Q2.LT.0.09) THEN - RPIGG=AEMPI*(13.4916+LOG(Q2))+0.00835*LOG(1.+Q2) - ELSEIF(Q2.LT.9.) THEN - RPIGG=AEMPI*(16.3200+2.*LOG(Q2))+0.00238*LOG(1.+3.927*Q2) - ELSEIF(Q2.LT.1E4) THEN - RPIGG=AEMPI*(13.4955+3.*LOG(Q2))+0.00165+0.00299*LOG(1.+Q2) + ULANGL=0. + R=SQRT(X**2+Y**2) + IF(R.LT.1D-20) RETURN + IF(ABS(X)/R.LT.0.8) THEN + ULANGL=SIGN(ACOS(X/R),Y) ELSE - RPIGG=AEMPI*(13.4955+3.*LOG(Q2))+0.00221+0.00293*LOG(1.+Q2) + ULANGL=ASIN(Y/R) + IF(X.LT.0..AND.ULANGL.GE.0.) THEN + ULANGL=PARU(1)-ULANGL + ELSEIF(X.LT.0.) THEN + ULANGL=-PARU(1)-ULANGL + ENDIF ENDIF -C...Calculate running alpha_em. - ULALEM=PARU(101)/(1.-RPIGG) - PARU(108)=ULALEM - RETURN END C********************************************************************* -CDECK ID>, ULALPS - FUNCTION ULALPS(Q2) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to give the value of alpha_strong. - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - SAVE /LUDAT1/,/LUDAT2/ - -C...Constant alpha_strong trivial. - IF(MSTU(111).LE.0) THEN - ULALPS=PARU(111) - MSTU(118)=MSTU(112) - PARU(117)=0. - PARU(118)=PARU(111) - RETURN - ENDIF - -C...Find effective Q2, number of flavours and Lambda. - Q2EFF=Q2 - IF(MSTU(115).GE.2) Q2EFF=MAX(Q2,PARU(114)) - NF=MSTU(112) - ALAM2=PARU(112)**2 - 100 IF(NF.GT.MAX(2,MSTU(113))) THEN - Q2THR=PARU(113)*PMAS(NF,1)**2 - IF(Q2EFF.LT.Q2THR) THEN - NF=NF-1 - ALAM2=ALAM2*(Q2THR/ALAM2)**(2./(33.-2.*NF)) - GOTO 100 - ENDIF - ENDIF - 110 IF(NF.LT.MIN(8,MSTU(114))) THEN - Q2THR=PARU(113)*PMAS(NF+1,1)**2 - IF(Q2EFF.GT.Q2THR) THEN - NF=NF+1 - ALAM2=ALAM2*(ALAM2/Q2THR)**(2./(33.-2.*NF)) - GOTO 110 - ENDIF - ENDIF - IF(MSTU(115).EQ.1) Q2EFF=Q2EFF+ALAM2 - PARU(117)=SQRT(ALAM2) - -C...Evaluate first or second order alpha_strong. - B0=(33.-2.*NF)/6. - ALGQ=LOG(MAX(1.0001D0,Q2EFF/ALAM2)) - IF(MSTU(111).EQ.1) THEN - ULALPS=MIN(PARU(115),PARU(2)/(B0*ALGQ)) - ELSE - B1=(153.-19.*NF)/6. - ULALPS=MIN(PARU(115),PARU(2)/(B0*ALGQ)*(1.-B1*LOG(ALGQ)/ - & (B0**2*ALGQ))) - ENDIF - MSTU(118)=NF - PARU(118)=ULALPS - - RETURN - END - -C********************************************************************* - -CDECK ID>, ULANGL - FUNCTION ULANGL(X,Y) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to reconstruct an angle from given x and y coordinates. - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - SAVE /LUDAT1/ - - ULANGL=0. - R=SQRT(X**2+Y**2) - IF(R.LT.1D-20) RETURN - IF(ABS(X)/R.LT.0.8) THEN - ULANGL=SIGN(ACOS(X/R),Y) - ELSE - ULANGL=ASIN(Y/R) - IF(X.LT.0..AND.ULANGL.GE.0.) THEN - ULANGL=PARU(1)-ULANGL - ELSEIF(X.LT.0.) THEN - ULANGL=-PARU(1)-ULANGL - ENDIF - ENDIF - - RETURN - END - -C********************************************************************* - -CDECK ID>, RLU - FUNCTION RLU(IDUMMY) +CDECK ID>, RLU + FUNCTION RLU(IDUMMY) IMPLICIT DOUBLE PRECISION (A-H,O-Z) C...Purpose: to generate random numbers uniformly distributed between @@ -10253,80 +7985,7 @@ FUNCTION RLU(IDUMMY) RETURN END -C********************************************************************* - -CDECK ID>, RLUGET - SUBROUTINE RLUGET(LFN,MOVE) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to dump the state of the random number generator on a file -C...for subsequent startup from this state onwards. - COMMON/LUDATR/MRLU(6),RRLU(100) - SAVE /LUDATR/ - CHARACTER CHERR*8 - -C...Backspace required number of records (or as many as there are). - IF(MOVE.LT.0) THEN - NBCK=MIN(MRLU(6),-MOVE) - DO 100 IBCK=1,NBCK - BACKSPACE(LFN,ERR=110,IOSTAT=IERR) - 100 CONTINUE - MRLU(6)=MRLU(6)-NBCK - ENDIF - -C...Unformatted write on unit LFN. - WRITE(LFN,ERR=110,IOSTAT=IERR) (MRLU(I1),I1=1,5), - &(RRLU(I2),I2=1,100) - MRLU(6)=MRLU(6)+1 - RETURN - -C...Write error. - 110 WRITE(CHERR,'(I8)') IERR - CALL LUERRM(18,'(RLUGET:) error when accessing file, IOSTAT ='// - &CHERR) - - RETURN - END - -C********************************************************************* - -CDECK ID>, RLUSET - SUBROUTINE RLUSET(LFN,MOVE) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to read a state of the random number generator from a file -C...for subsequent generation from this state onwards. - COMMON/LUDATR/MRLU(6),RRLU(100) - SAVE /LUDATR/ - CHARACTER CHERR*8 - -C...Backspace required number of records (or as many as there are). - IF(MOVE.LT.0) THEN - NBCK=MIN(MRLU(6),-MOVE) - DO 100 IBCK=1,NBCK - BACKSPACE(LFN,ERR=120,IOSTAT=IERR) - 100 CONTINUE - MRLU(6)=MRLU(6)-NBCK - ENDIF - -C...Unformatted read from unit LFN. - NFOR=1+MAX(0,MOVE) - DO 110 IFOR=1,NFOR - READ(LFN,ERR=120,IOSTAT=IERR) (MRLU(I1),I1=1,5), - &(RRLU(I2),I2=1,100) - 110 CONTINUE - MRLU(6)=MRLU(6)+NFOR - RETURN - -C...Write error. - 120 WRITE(CHERR,'(I8)') IERR - CALL LUERRM(18,'(RLUSET:) error when accessing file, IOSTAT ='// - &CHERR) - - RETURN - END - -C********************************************************************* +C********************************************************************* CDECK ID>, LUROBO SUBROUTINE LUROBO(THE,PHI,BEX,BEY,BEZ) @@ -10339,7 +7998,7 @@ SUBROUTINE LUROBO(THE,PHI,BEX,BEY,BEZ) SAVE /LUJETS/,/LUDAT1/ DIMENSION ROT(3,3),PR(3),VR(3),DP(4),DV(4) -C...Find range of rotation/boost. Convert boost to double precision. +C...Find range of rotation/boost. Convert boost to DOUBLE PRECISION. IMIN=1 IF(MSTU(1).GT.0) IMIN=MSTU(1) IMAX=N @@ -10349,7 +8008,7 @@ SUBROUTINE LUROBO(THE,PHI,BEX,BEY,BEZ) DBZ=BEZ GOTO 120 -C...Entry for specific range and double precision boost. +C...Entry for specific range and DOUBLE PRECISION boost. ENTRY LUDBRB(IMI,IMA,THE,PHI,DBEX,DBEY,DBEZ) IMIN=IMI IF(IMIN.LE.0) IMIN=1 @@ -10619,7 +8278,7 @@ SUBROUTINE LUEDIT(MEDIT) IF(K(I,5).EQ.0) K(I,5)=K(I,4) 190 CONTINUE -C...Save top entries at bottom of LUJETS commonblock. +C...Save top entries at bottom of LUJETS COMMONblock. ELSEIF(MEDIT.EQ.21) THEN IF(2*N.GE.MSTU(4)) THEN CALL LUERRM(11,'(LUEDIT:) no more memory left in LUJETS') @@ -10634,7 +8293,7 @@ SUBROUTINE LUEDIT(MEDIT) 210 CONTINUE MSTU(32)=N -C...Restore bottom entries of commonblock LUJETS to top. +C...Restore bottom entries of COMMONblock LUJETS to top. ELSEIF(MEDIT.EQ.22) THEN DO 230 I=1,MSTU(32) DO 220 J=1,5 @@ -10645,7 +8304,7 @@ SUBROUTINE LUEDIT(MEDIT) 230 CONTINUE N=MSTU(32) -C...Mark primary entries at top of commonblock LUJETS as untreated. +C...Mark primary entries at top of COMMONblock LUJETS as untreated. ELSEIF(MEDIT.EQ.23) THEN I1=0 DO 240 I=1,N @@ -10710,710 +8369,15 @@ SUBROUTINE LUEDIT(MEDIT) ENDIF RETURN - END - -C********************************************************************* - -CDECK ID>, LULIST - SUBROUTINE LULIST(MLIST) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to give program heading, or list an event, or particle -C...data, or current parameter values. - COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - COMMON/LUDAT3/MDCY(500,3),MDME(2000,2),BRAT(2000),KFDP(2000,5) - SAVE /LUJETS/,/LUDAT1/,/LUDAT2/,/LUDAT3/ - CHARACTER CHAP*16,CHAC*16,CHAN*16,CHAD(5)*16,CHDL(7)*4 - DIMENSION PS(6) - DATA CHDL/'(())',' ','()','!!','<>','==','(==)'/ - -C...Initialization printout: version number and date of last change. - IF(MLIST.EQ.0.OR.MSTU(12).EQ.1) THEN - CALL LULOGO - MSTU(12)=0 - IF(MLIST.EQ.0) RETURN - ENDIF - -C...List event data, including additional lines after N. - IF(MLIST.GE.1.AND.MLIST.LE.3) THEN - IF(MLIST.EQ.1) WRITE(MSTU(11),5100) - IF(MLIST.EQ.2) WRITE(MSTU(11),5200) - IF(MLIST.EQ.3) WRITE(MSTU(11),5300) - LMX=12 - IF(MLIST.GE.2) LMX=16 - ISTR=0 - IMAX=N - IF(MSTU(2).GT.0) IMAX=MSTU(2) - DO 120 I=MAX(1,MSTU(1)),MAX(IMAX,N+MAX(0,MSTU(3))) - IF((I.GT.IMAX.AND.I.LE.N).OR.K(I,1).LT.0) GOTO 120 - -C...Get particle name, pad it and check it is not too long. - CALL LUNAME(K(I,2),CHAP) - LEN=0 - DO 100 LEM=1,16 - IF(CHAP(LEM:LEM).NE.' ') LEN=LEM - 100 CONTINUE - MDL=(K(I,1)+19)/10 - LDL=0 - IF(MDL.EQ.2.OR.MDL.GE.8) THEN - CHAC=CHAP - IF(LEN.GT.LMX) CHAC(LMX:LMX)='?' - ELSE - LDL=1 - IF(MDL.EQ.1.OR.MDL.EQ.7) LDL=2 - IF(LEN.EQ.0) THEN - CHAC=CHDL(MDL)(1:2*LDL)//' ' - ELSE - CHAC=CHDL(MDL)(1:LDL)//CHAP(1:MIN(LEN,LMX-2*LDL))// - & CHDL(MDL)(LDL+1:2*LDL)//' ' - IF(LEN+2*LDL.GT.LMX) CHAC(LMX:LMX)='?' - ENDIF - ENDIF - -C...Add information on string connection. - IF(K(I,1).EQ.1.OR.K(I,1).EQ.2.OR.K(I,1).EQ.11.OR.K(I,1).EQ.12) - & THEN - KC=LUCOMP(K(I,2)) - KCC=0 - IF(KC.NE.0) KCC=KCHG(KC,2) - IF(IABS(K(I,2)).EQ.39) THEN - IF(LEN+2*LDL+3.LE.LMX) CHAC(LMX-1:LMX-1)='X' - ELSEIF(KCC.NE.0.AND.ISTR.EQ.0) THEN - ISTR=1 - IF(LEN+2*LDL+3.LE.LMX) CHAC(LMX-1:LMX-1)='A' - ELSEIF(KCC.NE.0.AND.(K(I,1).EQ.2.OR.K(I,1).EQ.12)) THEN - IF(LEN+2*LDL+3.LE.LMX) CHAC(LMX-1:LMX-1)='I' - ELSEIF(KCC.NE.0) THEN - ISTR=0 - IF(LEN+2*LDL+3.LE.LMX) CHAC(LMX-1:LMX-1)='V' - ENDIF - ENDIF - -C...Write data for particle/jet. - IF(MLIST.EQ.1.AND.ABS(P(I,4)).LT.9999.) THEN - WRITE(MSTU(11),5400) I,CHAC(1:12),(K(I,J1),J1=1,3), - & (P(I,J2),J2=1,5) - ELSEIF(MLIST.EQ.1.AND.ABS(P(I,4)).LT.99999.) THEN - WRITE(MSTU(11),5500) I,CHAC(1:12),(K(I,J1),J1=1,3), - & (P(I,J2),J2=1,5) - ELSEIF(MLIST.EQ.1) THEN - WRITE(MSTU(11),5600) I,CHAC(1:12),(K(I,J1),J1=1,3), - & (P(I,J2),J2=1,5) - ELSEIF(MSTU(5).EQ.10000.AND.(K(I,1).EQ.3.OR.K(I,1).EQ.13.OR. - & K(I,1).EQ.14)) THEN - WRITE(MSTU(11),5700) I,CHAC,(K(I,J1),J1=1,3), - & K(I,4)/100000000,MOD(K(I,4)/10000,10000),MOD(K(I,4),10000), - & K(I,5)/100000000,MOD(K(I,5)/10000,10000),MOD(K(I,5),10000), - & (P(I,J2),J2=1,5) - ELSE - WRITE(MSTU(11),5800) I,CHAC,(K(I,J1),J1=1,5),(P(I,J2),J2=1,5) - ENDIF - IF(MLIST.EQ.3) WRITE(MSTU(11),5900) (V(I,J),J=1,5) - -C...Insert extra separator lines specified by user. - IF(MSTU(70).GE.1) THEN - ISEP=0 - DO 110 J=1,MIN(10,MSTU(70)) - IF(I.EQ.MSTU(70+J)) ISEP=1 - 110 CONTINUE - IF(ISEP.EQ.1.AND.MLIST.EQ.1) WRITE(MSTU(11),6000) - IF(ISEP.EQ.1.AND.MLIST.GE.2) WRITE(MSTU(11),6100) - ENDIF - 120 CONTINUE - -C...Sum of charges and momenta. - DO 130 J=1,6 - PS(J)=PLU(0,J) - 130 CONTINUE - IF(MLIST.EQ.1.AND.ABS(PS(4)).LT.9999.) THEN - WRITE(MSTU(11),6200) PS(6),(PS(J),J=1,5) - ELSEIF(MLIST.EQ.1.AND.ABS(PS(4)).LT.99999.) THEN - WRITE(MSTU(11),6300) PS(6),(PS(J),J=1,5) - ELSEIF(MLIST.EQ.1) THEN - WRITE(MSTU(11),6400) PS(6),(PS(J),J=1,5) - ELSE - WRITE(MSTU(11),6500) PS(6),(PS(J),J=1,5) - ENDIF - -C...Give simple list of KF codes defined in program. - ELSEIF(MLIST.EQ.11) THEN - WRITE(MSTU(11),6600) - DO 140 KF=1,40 - CALL LUNAME(KF,CHAP) - CALL LUNAME(-KF,CHAN) - IF(CHAP.NE.' '.AND.CHAN.EQ.' ') WRITE(MSTU(11),6700) KF,CHAP - IF(CHAN.NE.' ') WRITE(MSTU(11),6700) KF,CHAP,-KF,CHAN - 140 CONTINUE - DO 170 KFLS=1,3,2 - DO 160 KFLA=1,8 - DO 150 KFLB=1,KFLA-(3-KFLS)/2 - KF=1000*KFLA+100*KFLB+KFLS - CALL LUNAME(KF,CHAP) - CALL LUNAME(-KF,CHAN) - WRITE(MSTU(11),6700) KF,CHAP,-KF,CHAN - 150 CONTINUE - 160 CONTINUE - 170 CONTINUE - KF=130 - CALL LUNAME(KF,CHAP) - WRITE(MSTU(11),6700) KF,CHAP - KF=310 - CALL LUNAME(KF,CHAP) - WRITE(MSTU(11),6700) KF,CHAP - DO 200 KMUL=0,5 - KFLS=3 - IF(KMUL.EQ.0.OR.KMUL.EQ.3) KFLS=1 - IF(KMUL.EQ.5) KFLS=5 - KFLR=0 - IF(KMUL.EQ.2.OR.KMUL.EQ.3) KFLR=1 - IF(KMUL.EQ.4) KFLR=2 - DO 190 KFLB=1,8 - DO 180 KFLC=1,KFLB-1 - KF=10000*KFLR+100*KFLB+10*KFLC+KFLS - CALL LUNAME(KF,CHAP) - CALL LUNAME(-KF,CHAN) - WRITE(MSTU(11),6700) KF,CHAP,-KF,CHAN - 180 CONTINUE - KF=10000*KFLR+110*KFLB+KFLS - CALL LUNAME(KF,CHAP) - WRITE(MSTU(11),6700) KF,CHAP - 190 CONTINUE - 200 CONTINUE - KF=30443 - CALL LUNAME(KF,CHAP) - WRITE(MSTU(11),6700) KF,CHAP - KF=30553 - CALL LUNAME(KF,CHAP) - WRITE(MSTU(11),6700) KF,CHAP - DO 240 KFLSP=1,3 - KFLS=2+2*(KFLSP/3) - DO 230 KFLA=1,8 - DO 220 KFLB=1,KFLA - DO 210 KFLC=1,KFLB - IF(KFLSP.EQ.1.AND.(KFLA.EQ.KFLB.OR.KFLB.EQ.KFLC)) GOTO 210 - IF(KFLSP.EQ.2.AND.KFLA.EQ.KFLC) GOTO 210 - IF(KFLSP.EQ.1) KF=1000*KFLA+100*KFLC+10*KFLB+KFLS - IF(KFLSP.GE.2) KF=1000*KFLA+100*KFLB+10*KFLC+KFLS - CALL LUNAME(KF,CHAP) - CALL LUNAME(-KF,CHAN) - WRITE(MSTU(11),6700) KF,CHAP,-KF,CHAN - 210 CONTINUE - 220 CONTINUE - 230 CONTINUE - 240 CONTINUE - -C...List parton/particle data table. Check whether to be listed. - ELSEIF(MLIST.EQ.12) THEN - WRITE(MSTU(11),6800) - MSTJ24=MSTJ(24) - MSTJ(24)=0 - KFMAX=30553 - IF(MSTU(2).NE.0) KFMAX=MSTU(2) - DO 270 KF=MAX(1,MSTU(1)),KFMAX - KC=LUCOMP(KF) - IF(KC.EQ.0) GOTO 270 - IF(MSTU(14).EQ.0.AND.KF.GT.100.AND.KC.LE.100) GOTO 270 - IF(MSTU(14).GT.0.AND.KF.GT.100.AND.MAX(MOD(KF/1000,10), - & MOD(KF/100,10)).GT.MSTU(14)) GOTO 270 - IF(MSTU(14).GT.0.AND.KF.GT.100.AND.KC.EQ.90) GOTO 270 - -C...Find particle name and mass. Print information. - CALL LUNAME(KF,CHAP) - IF(KF.LE.100.AND.CHAP.EQ.' '.AND.MDCY(KC,2).EQ.0) GOTO 270 - CALL LUNAME(-KF,CHAN) - PM=ULMASS(KF) - WRITE(MSTU(11),6900) KF,KC,CHAP,CHAN,KCHG(KC,1),KCHG(KC,2), - & KCHG(KC,3),PM,PMAS(KC,2),PMAS(KC,3),PMAS(KC,4),MDCY(KC,1) - -C...Particle decay: channel number, branching ration, matrix element, -C...decay products. - IF(KF.GT.100.AND.KC.LE.100) GOTO 270 - DO 260 IDC=MDCY(KC,2),MDCY(KC,2)+MDCY(KC,3)-1 - DO 250 J=1,5 - CALL LUNAME(KFDP(IDC,J),CHAD(J)) - 250 CONTINUE - WRITE(MSTU(11),7000) IDC,MDME(IDC,1),MDME(IDC,2),BRAT(IDC), - & (CHAD(J),J=1,5) - 260 CONTINUE - 270 CONTINUE - MSTJ(24)=MSTJ24 - -C...List parameter value table. - ELSEIF(MLIST.EQ.13) THEN - WRITE(MSTU(11),7100) - DO 280 I=1,200 - WRITE(MSTU(11),7200) I,MSTU(I),PARU(I),MSTJ(I),PARJ(I),PARF(I) - 280 CONTINUE - ENDIF - -C...Format statements for output on unit MSTU(11) (by default 6). - 5100 FORMAT(///28X,'Event listing (summary)'//4X,'I particle/jet KS', - &5X,'KF orig p_x p_y p_z E m'/) - 5200 FORMAT(///28X,'Event listing (standard)'//4X,'I particle/jet', - &' K(I,1) K(I,2) K(I,3) K(I,4) K(I,5) P(I,1)', - &' P(I,2) P(I,3) P(I,4) P(I,5)'/) - 5300 FORMAT(///28X,'Event listing (with vertices)'//4X,'I particle/j', - &'et K(I,1) K(I,2) K(I,3) K(I,4) K(I,5) P(I,1)', - &' P(I,2) P(I,3) P(I,4) P(I,5)'/73X, - &'V(I,1) V(I,2) V(I,3) V(I,4) V(I,5)'/) - 5400 FORMAT(1X,I4,2X,A12,1X,I2,1X,I6,1X,I4,5F9.3) - 5500 FORMAT(1X,I4,2X,A12,1X,I2,1X,I6,1X,I4,5F9.2) - 5600 FORMAT(1X,I4,2X,A12,1X,I2,1X,I6,1X,I4,5F9.1) - 5700 FORMAT(1X,I4,2X,A16,1X,I3,1X,I8,2X,I4,2(3X,I1,2I4),5F13.5) - 5800 FORMAT(1X,I4,2X,A16,1X,I3,1X,I8,2X,I4,2(3X,I9),5F13.5) - 5900 FORMAT(66X,5(1X,F12.3)) - 6000 FORMAT(1X,78('=')) - 6100 FORMAT(1X,130('=')) - 6200 FORMAT(19X,'sum:',F6.2,5X,5F9.3) - 6300 FORMAT(19X,'sum:',F6.2,5X,5F9.2) - 6400 FORMAT(19X,'sum:',F6.2,5X,5F9.1) - 6500 FORMAT(19X,'sum charge:',F6.2,3X,'sum momentum and inv. mass:', - &5F13.5) - 6600 FORMAT(///20X,'List of KF codes in program'/) - 6700 FORMAT(4X,I6,4X,A16,6X,I6,4X,A16) - 6800 FORMAT(///30X,'Particle/parton data table'//5X,'KF',5X,'KC',4X, - &'particle',8X,'antiparticle',6X,'chg col anti',8X,'mass',7X, - &'width',7X,'w-cut',5X,'lifetime',1X,'decay'/11X,'IDC',1X,'on/off', - &1X,'ME',3X,'Br.rat.',4X,'decay products') - 6900 FORMAT(/1X,I6,3X,I4,4X,A16,A16,3I5,1X,F12.5,2(1X,F11.5), - &2X,F12.5,3X,I2) - 7000 FORMAT(10X,I4,2X,I3,2X,I3,2X,F8.5,4X,5A16) - 7100 FORMAT(///20X,'Parameter value table'//4X,'I',3X,'MSTU(I)', - &8X,'PARU(I)',3X,'MSTJ(I)',8X,'PARJ(I)',8X,'PARF(I)') - 7200 FORMAT(1X,I4,1X,I9,1X,F14.5,1X,I9,1X,F14.5,1X,F14.5) - - RETURN - END - -C********************************************************************* - -CDECK ID>, LULOGO - SUBROUTINE LULOGO - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to write logo for JETSET and PYTHIA programs. - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/PYPARS/MSTP(200),PARP(200),MSTI(200),PARI(200) - SAVE /LUDAT1/ - SAVE /PYPARS/ - CHARACTER MONTH(12)*3, LOGO(48)*32, REFER(22)*36, LINE*79, - &VERS*1, SUBV*3, DATE*2, YEAR*4 - -C...Data on months, logo, titles, and references. - DATA MONTH/'Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep', - &'Oct','Nov','Dec'/ - DATA (LOGO(J),J=1,10)/ - &'PPP Y Y TTTTT H H III A ', - &'P P Y Y T H H I A A ', - &'PPP Y T HHHHH I AAAAA', - &'P Y T H H I A A', - &'P Y T H H III A A', - &'JJJJ EEEE TTTTT SSS EEEE TTTTT', - &' J E T S E T ', - &' J EEE T SSS EEE T ', - &'J J E T S E T ', - &' JJ EEEE T SSS EEEE T '/ - DATA (LOGO(J),J=11,29)/ - &' *......* ', - &' *:::!!:::::::::::* ', - &' *::::::!!::::::::::::::* ', - &' *::::::::!!::::::::::::::::* ', - &' *:::::::::!!:::::::::::::::::* ', - &' *:::::::::!!:::::::::::::::::* ', - &' *::::::::!!::::::::::::::::*! ', - &' *::::::!!::::::::::::::* !! ', - &' !! *:::!!:::::::::::* !! ', - &' !! !* -><- * !! ', - &' !! !! !! ', - &' !! !! !! ', - &' !! !! ', - &' !! ep !! ', - &' !! !! ', - &' !! pp !! ', - &' !! e+e- !! ', - &' !! !! ', - &' !! '/ - DATA (LOGO(J),J=30,48)/ - &'Welcome to the Lund Monte Carlo!', - &' ', - &' This is PYTHIA version x.xxx ', - &'Last date of change: xx xxx 199x', - &' ', - &' This is JETSET version x.xxx ', - &'Last date of change: xx xxx 199x', - &' ', - &' Main author: ', - &' Torbjorn Sjostrand ', - &' Dept. of theoretical physics 2 ', - &' University of Lund ', - &' Solvegatan 14A ', - &' S-223 62 Lund, Sweden ', - &' phone: +46 - 46 - 222 48 16 ', - &' E-mail: torbjorn@thep.lu.se ', - &' ', - &' Copyright Torbjorn Sjostrand ', - &' and CERN, Geneva 1993 '/ - DATA (REFER(J),J=1,6)/ - &'The latest program versions and docu', - &'mentation is found on WWW address ', - &'http://thep.lu.se/tf2/staff/torbjorn', - &'/Welcome.html ', - &' ', - &' '/ - DATA (REFER(J),J=7,22)/ - &'When you cite these programs, priori', - &'ty should always be given to the ', - &'latest published description. Curren', - &'tly this is ', - &'T. Sjostrand, Computer Physics Commu', - &'n. 82 (1994) 74. ', - &'The most recent long description (un', - &'published) is ', - &'T. Sjostrand, LU TP 95-20 and CERN-T', - &'H.7112/93 (revised August 1995). ', - &'Also remember that the programs, to ', - &'a large extent, represent original ', - &'physics research. Other publications', - &' of special relevance to your ', - &'studies may therefore deserve separa', - &'te mention. '/ - -C...Check if PYTHIA linked. - IF(MSTP(183)/10.NE.199) THEN - LOGO(32)=' Warning: PYTHIA is not loaded! ' - LOGO(33)='Did you remember to link PYDATA?' - ELSE - WRITE(VERS,'(I1)') MSTP(181) - LOGO(32)(26:26)=VERS - WRITE(SUBV,'(I3)') MSTP(182) - LOGO(32)(28:30)=SUBV - WRITE(DATE,'(I2)') MSTP(185) - LOGO(33)(22:23)=DATE - LOGO(33)(25:27)=MONTH(MSTP(184)) - WRITE(YEAR,'(I4)') MSTP(183) - LOGO(33)(29:32)=YEAR - ENDIF - -C...Check if JETSET linked. - IF(MSTU(183)/10.NE.199) THEN - LOGO(35)=' Error: JETSET is not loaded! ' - LOGO(36)='Did you remember to link LUDATA?' - ELSE - WRITE(VERS,'(I1)') MSTU(181) - LOGO(35)(26:26)=VERS - WRITE(SUBV,'(I3)') MSTU(182) - LOGO(35)(28:30)=SUBV - WRITE(DATE,'(I2)') MSTU(185) - LOGO(36)(22:23)=DATE - LOGO(36)(25:27)=MONTH(MSTU(184)) - WRITE(YEAR,'(I4)') MSTU(183) - LOGO(36)(29:32)=YEAR - ENDIF - -C...Loop over lines in header. Define page feed and side borders. - DO 100 ILIN=1,48 - LINE=' ' - IF(ILIN.EQ.1) THEN - LINE(1:1)='1' - ELSE - LINE(2:3)='**' - LINE(78:79)='**' - ENDIF - -C...Separator lines and logos. - IF(ILIN.EQ.2.OR.ILIN.EQ.3.OR.ILIN.EQ.47.OR.ILIN.EQ.48) THEN - LINE(4:77)='***********************************************'// - & '***************************' - ELSEIF(ILIN.GE.6.AND.ILIN.LE.10) THEN - LINE(6:37)=LOGO(ILIN-5) - LINE(44:75)=LOGO(ILIN) - ELSEIF(ILIN.GE.13.AND.ILIN.LE.31) THEN - LINE(6:37)=LOGO(ILIN-2) - LINE(44:75)=LOGO(ILIN+17) - ELSEIF(ILIN.GE.34.AND.ILIN.LE.44) THEN - LINE(5:40)=REFER(2*ILIN-67) - LINE(41:76)=REFER(2*ILIN-66) - ENDIF - -C...Write lines to appropriate unit. - IF(MSTU(183)/10.EQ.199) THEN - WRITE(MSTU(11),'(A79)') LINE - ELSE - WRITE(*,'(A79)') LINE - ENDIF - 100 CONTINUE - -C...Check that matching subversions are linked. - IF(MSTU(183)/10.EQ.199.AND.MSTP(183)/10.EQ.199) THEN - IF(MSTU(182).LT.MSTP(186)) WRITE(MSTU(11), - & '(/'' Warning: JETSET subversion too old for PYTHIA''/)') - IF(MSTP(182).LT.MSTU(186)) WRITE(MSTU(11), - & '(/'' Warning: PYTHIA subversion too old for JETSET''/)') - ENDIF - - RETURN - END - -C********************************************************************* - -CDECK ID>, LUUPDA - SUBROUTINE LUUPDA(MUPDA,LFN) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to facilitate the updating of particle and decay data. - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - COMMON/LUDAT3/MDCY(500,3),MDME(2000,2),BRAT(2000),KFDP(2000,5) - COMMON/LUDAT4/CHAF(500) - CHARACTER CHAF*8 - SAVE /LUDAT1/,/LUDAT2/,/LUDAT3/,/LUDAT4/ - CHARACTER CHINL*80,CHKC*4,CHVAR(19)*9,CHLIN*72, - &CHBLK(20)*72,CHOLD*12,CHTMP*12,CHNEW*12,CHCOM*12 - DATA CHVAR/ 'KCHG(I,1)','KCHG(I,2)','KCHG(I,3)','PMAS(I,1)', - &'PMAS(I,2)','PMAS(I,3)','PMAS(I,4)','MDCY(I,1)','MDCY(I,2)', - &'MDCY(I,3)','MDME(I,1)','MDME(I,2)','BRAT(I) ','KFDP(I,1)', - &'KFDP(I,2)','KFDP(I,3)','KFDP(I,4)','KFDP(I,5)','CHAF(I) '/ - -C...Write information on file for editing. - IF(MSTU(12).GE.1) CALL LULIST(0) - IF(MUPDA.EQ.1) THEN - DO 110 KC=1,MSTU(6) - WRITE(LFN,5000) KC,CHAF(KC),(KCHG(KC,J1),J1=1,3), - & (PMAS(KC,J2),J2=1,4),MDCY(KC,1) - DO 100 IDC=MDCY(KC,2),MDCY(KC,2)+MDCY(KC,3)-1 - WRITE(LFN,5100) MDME(IDC,1),MDME(IDC,2),BRAT(IDC), - & (KFDP(IDC,J),J=1,5) - 100 CONTINUE - 110 CONTINUE - -C...Reset variables and read information from edited file. - ELSEIF(MUPDA.EQ.2) THEN - DO 130 I=1,MSTU(7) - MDME(I,1)=1 - MDME(I,2)=0 - BRAT(I)=0. - DO 120 J=1,5 - KFDP(I,J)=0 - 120 CONTINUE - 130 CONTINUE - KC=0 - IDC=0 - NDC=0 - 140 READ(LFN,5200,END=150) CHINL - IF(CHINL(2:5).NE.' ') THEN - CHKC=CHINL(2:5) - IF(KC.NE.0) THEN - MDCY(KC,2)=0 - IF(NDC.NE.0) MDCY(KC,2)=IDC+1-NDC - MDCY(KC,3)=NDC - ENDIF - READ(CHKC,5300) KC - IF(KC.LE.0.OR.KC.GT.MSTU(6)) CALL LUERRM(27, - & '(LUUPDA:) Read KC code illegal, KC ='//CHKC) - READ(CHINL,5000) KCR,CHAF(KC),(KCHG(KC,J1),J1=1,3), - & (PMAS(KC,J2),J2=1,4),MDCY(KC,1) - NDC=0 - ELSE - IDC=IDC+1 - NDC=NDC+1 - IF(IDC.GE.MSTU(7)) CALL LUERRM(27, - & '(LUUPDA:) Decay data arrays full by KC ='//CHKC) - READ(CHINL,5100) MDME(IDC,1),MDME(IDC,2),BRAT(IDC), - & (KFDP(IDC,J),J=1,5) - ENDIF - GOTO 140 - 150 MDCY(KC,2)=0 - IF(NDC.NE.0) MDCY(KC,2)=IDC+1-NDC - MDCY(KC,3)=NDC - -C...Perform possible tests that new information is consistent. - MSTJ24=MSTJ(24) - MSTJ(24)=0 - DO 180 KC=1,MSTU(6) - WRITE(CHKC,5300) KC - IF(MIN(PMAS(KC,1),PMAS(KC,2),PMAS(KC,3),PMAS(KC,1)-PMAS(KC,3), - & PMAS(KC,4)).LT.0..OR.MDCY(KC,3).LT.0) CALL LUERRM(17, - & '(LUUPDA:) Mass/width/life/(# channels) wrong for KC ='//CHKC) - BRSUM=0. - DO 170 IDC=MDCY(KC,2),MDCY(KC,2)+MDCY(KC,3)-1 - IF(MDME(IDC,2).GT.80) GOTO 170 - KQ=KCHG(KC,1) - PMS=PMAS(KC,1)-PMAS(KC,3)-PARJ(64) - MERR=0 - DO 160 J=1,5 - KP=KFDP(IDC,J) - IF(KP.EQ.0.OR.KP.EQ.81.OR.IABS(KP).EQ.82) THEN - ELSEIF(LUCOMP(KP).EQ.0) THEN - MERR=3 - ELSE - KQ=KQ-LUCHGE(KP) - PMS=PMS-ULMASS(KP) - ENDIF - 160 CONTINUE - IF(KQ.NE.0) MERR=MAX(2,MERR) - IF(KFDP(IDC,2).NE.0.AND.(KC.LE.20.OR.KC.GT.40).AND. - & (KC.LE.80.OR.KC.GT.100).AND.MDME(IDC,2).NE.34.AND. - & MDME(IDC,2).NE.61.AND.PMS.LT.0.) MERR=MAX(1,MERR) - IF(MERR.EQ.3) CALL LUERRM(17, - & '(LUUPDA:) Unknown particle code in decay of KC ='//CHKC) - IF(MERR.EQ.2) CALL LUERRM(17, - & '(LUUPDA:) Charge not conserved in decay of KC ='//CHKC) - IF(MERR.EQ.1) CALL LUERRM(7, - & '(LUUPDA:) Kinematically unallowed decay of KC ='//CHKC) - BRSUM=BRSUM+BRAT(IDC) - 170 CONTINUE - WRITE(CHTMP,5500) BRSUM - IF(ABS(BRSUM).GT.0.0005.AND.ABS(BRSUM-1.).GT.0.0005) CALL - & LUERRM(7,'(LUUPDA:) Sum of branching ratios is '//CHTMP(5:12)// - & ' for KC ='//CHKC) - 180 CONTINUE - MSTJ(24)=MSTJ24 - -C...Initialize writing of DATA statements for inclusion in program. - ELSEIF(MUPDA.EQ.3) THEN - DO 250 IVAR=1,19 - NDIM=MSTU(6) - IF(IVAR.GE.11.AND.IVAR.LE.18) NDIM=MSTU(7) - NLIN=1 - CHLIN=' ' - CHLIN(7:35)='DATA ('//CHVAR(IVAR)//',I= 1, )/' - LLIN=35 - CHOLD='START' - -C...Loop through variables for conversion to characters. - DO 230 IDIM=1,NDIM - IF(IVAR.EQ.1) WRITE(CHTMP,5400) KCHG(IDIM,1) - IF(IVAR.EQ.2) WRITE(CHTMP,5400) KCHG(IDIM,2) - IF(IVAR.EQ.3) WRITE(CHTMP,5400) KCHG(IDIM,3) - IF(IVAR.EQ.4) WRITE(CHTMP,5500) PMAS(IDIM,1) - IF(IVAR.EQ.5) WRITE(CHTMP,5500) PMAS(IDIM,2) - IF(IVAR.EQ.6) WRITE(CHTMP,5500) PMAS(IDIM,3) - IF(IVAR.EQ.7) WRITE(CHTMP,5500) PMAS(IDIM,4) - IF(IVAR.EQ.8) WRITE(CHTMP,5400) MDCY(IDIM,1) - IF(IVAR.EQ.9) WRITE(CHTMP,5400) MDCY(IDIM,2) - IF(IVAR.EQ.10) WRITE(CHTMP,5400) MDCY(IDIM,3) - IF(IVAR.EQ.11) WRITE(CHTMP,5400) MDME(IDIM,1) - IF(IVAR.EQ.12) WRITE(CHTMP,5400) MDME(IDIM,2) - IF(IVAR.EQ.13) WRITE(CHTMP,5500) BRAT(IDIM) - IF(IVAR.EQ.14) WRITE(CHTMP,5400) KFDP(IDIM,1) - IF(IVAR.EQ.15) WRITE(CHTMP,5400) KFDP(IDIM,2) - IF(IVAR.EQ.16) WRITE(CHTMP,5400) KFDP(IDIM,3) - IF(IVAR.EQ.17) WRITE(CHTMP,5400) KFDP(IDIM,4) - IF(IVAR.EQ.18) WRITE(CHTMP,5400) KFDP(IDIM,5) - IF(IVAR.EQ.19) CHTMP=CHAF(IDIM) - -C...Length of variable, trailing decimal zeros, quotation marks. - LLOW=1 - LHIG=1 - DO 190 LL=1,12 - IF(CHTMP(13-LL:13-LL).NE.' ') LLOW=13-LL - IF(CHTMP(LL:LL).NE.' ') LHIG=LL - 190 CONTINUE - CHNEW=CHTMP(LLOW:LHIG)//' ' - LNEW=1+LHIG-LLOW - IF((IVAR.GE.4.AND.IVAR.LE.7).OR.IVAR.EQ.13) THEN - LNEW=LNEW+1 - 200 LNEW=LNEW-1 - IF(CHNEW(LNEW:LNEW).EQ.'0') GOTO 200 - IF(LNEW.EQ.1) CHNEW(1:2)='0.' - IF(LNEW.EQ.1) LNEW=2 - ELSEIF(IVAR.EQ.19) THEN - DO 210 LL=LNEW,1,-1 - IF(CHNEW(LL:LL).EQ.'''') THEN - CHTMP=CHNEW - CHNEW=CHTMP(1:LL)//''''//CHTMP(LL+1:11) - LNEW=LNEW+1 - ENDIF - 210 CONTINUE - CHTMP=CHNEW - CHNEW(1:LNEW+2)=''''//CHTMP(1:LNEW)//'''' - LNEW=LNEW+2 - ENDIF - -C...Form composite character string, often including repetition counter. - IF(CHNEW.NE.CHOLD) THEN - NRPT=1 - CHOLD=CHNEW - CHCOM=CHNEW - LCOM=LNEW - ELSE - LRPT=LNEW+1 - IF(NRPT.GE.2) LRPT=LNEW+3 - IF(NRPT.GE.10) LRPT=LNEW+4 - IF(NRPT.GE.100) LRPT=LNEW+5 - IF(NRPT.GE.1000) LRPT=LNEW+6 - LLIN=LLIN-LRPT - NRPT=NRPT+1 - WRITE(CHTMP,5400) NRPT - LRPT=1 - IF(NRPT.GE.10) LRPT=2 - IF(NRPT.GE.100) LRPT=3 - IF(NRPT.GE.1000) LRPT=4 - CHCOM(1:LRPT+1+LNEW)=CHTMP(13-LRPT:12)//'*'//CHNEW(1:LNEW) - LCOM=LRPT+1+LNEW - ENDIF - -C...Add characters to end of line, to new line (after storing old line), -C...or to new block of lines (after writing old block). - IF(LLIN+LCOM.LE.70) THEN - CHLIN(LLIN+1:LLIN+LCOM+1)=CHCOM(1:LCOM)//',' - LLIN=LLIN+LCOM+1 - ELSEIF(NLIN.LE.19) THEN - CHLIN(LLIN+1:72)=' ' - CHBLK(NLIN)=CHLIN - NLIN=NLIN+1 - CHLIN(6:6+LCOM+1)='&'//CHCOM(1:LCOM)//',' - LLIN=6+LCOM+1 - ELSE - CHLIN(LLIN:72)='/'//' ' - CHBLK(NLIN)=CHLIN - WRITE(CHTMP,5400) IDIM-NRPT - CHBLK(1)(30:33)=CHTMP(9:12) - DO 220 ILIN=1,NLIN - WRITE(LFN,5600) CHBLK(ILIN) - 220 CONTINUE - NLIN=1 - CHLIN=' ' - CHLIN(7:35+LCOM+1)='DATA ('//CHVAR(IVAR)//',I= , )/'// - & CHCOM(1:LCOM)//',' - WRITE(CHTMP,5400) IDIM-NRPT+1 - CHLIN(25:28)=CHTMP(9:12) - LLIN=35+LCOM+1 - ENDIF - 230 CONTINUE - -C...Write final block of lines. - CHLIN(LLIN:72)='/'//' ' - CHBLK(NLIN)=CHLIN - WRITE(CHTMP,5400) NDIM - CHBLK(1)(30:33)=CHTMP(9:12) - DO 240 ILIN=1,NLIN - WRITE(LFN,5600) CHBLK(ILIN) - 240 CONTINUE - 250 CONTINUE - ENDIF - -C...Formats for reading and writing particle data. - 5000 FORMAT(1X,I4,2X,A8,3I3,3F12.5,2X,F12.5,I3) - 5100 FORMAT(5X,2I5,F12.5,5I8) - 5200 FORMAT(A80) - 5300 FORMAT(I4) - 5400 FORMAT(I12) - 5500 FORMAT(F12.5) - 5600 FORMAT(A72) - - RETURN - END + END SUBROUTINE LUEDIT -C********************************************************************* +C********************************************************************* CDECK ID>, KLU FUNCTION KLU(I,J) IMPLICIT DOUBLE PRECISION (A-H,O-Z) -C...Purpose: to provide various integer-valued event related data. +C...Purpose: to provide various INTEGER-valued event related data. COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) @@ -11614,3552 +8578,19 @@ FUNCTION PLU(I,J) RETURN END -C********************************************************************* +C********************************************************************* -CDECK ID>, LUSPHE - SUBROUTINE LUSPHE(SPH,APL) +CDECK ID>, LUDATA + BLOCK DATA LUDATA IMPLICIT DOUBLE PRECISION (A-H,O-Z) -C...Purpose: to perform sphericity tensor analysis to give sphericity, -C...aplanarity and the related event axes. - COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N +C...Purpose: to give default values to parameters and particle and +C...decay data. COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ - DIMENSION SM(3,3),SV(3,3) - -C...Calculate matrix to be diagonalized. - NP=0 - DO 110 J1=1,3 - DO 100 J2=J1,3 - SM(J1,J2)=0. - 100 CONTINUE - 110 CONTINUE - PS=0. - DO 140 I=1,N - IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 140 - IF(MSTU(41).GE.2) THEN - KC=LUCOMP(K(I,2)) - IF(KC.EQ.0.OR.KC.EQ.12.OR.KC.EQ.14.OR.KC.EQ.16.OR. - & KC.EQ.18) GOTO 140 - IF(MSTU(41).GE.3.AND.KCHG(KC,2).EQ.0.AND.LUCHGE(K(I,2)).EQ.0) - & GOTO 140 - ENDIF - NP=NP+1 - PA=SQRT(P(I,1)**2+P(I,2)**2+P(I,3)**2) - PWT=1. - IF(ABS(PARU(41)-2.).GT.0.001) PWT=MAX(1D-10,PA)**(PARU(41)-2.) - DO 130 J1=1,3 - DO 120 J2=J1,3 - SM(J1,J2)=SM(J1,J2)+PWT*P(I,J1)*P(I,J2) - 120 CONTINUE - 130 CONTINUE - PS=PS+PWT*PA**2 - 140 CONTINUE - -C...Very low multiplicities (0 or 1) not considered. - IF(NP.LE.1) THEN - CALL LUERRM(8,'(LUSPHE:) too few particles for analysis') - SPH=-1. - APL=-1. - RETURN - ENDIF - DO 160 J1=1,3 - DO 150 J2=J1,3 - SM(J1,J2)=SM(J1,J2)/PS - 150 CONTINUE - 160 CONTINUE - -C...Find eigenvalues to matrix (third degree equation). - SQ=(SM(1,1)*SM(2,2)+SM(1,1)*SM(3,3)+SM(2,2)*SM(3,3)-SM(1,2)**2- - &SM(1,3)**2-SM(2,3)**2)/3.-1./9. - SR=-0.5*(SQ+1./9.+SM(1,1)*SM(2,3)**2+SM(2,2)*SM(1,3)**2+SM(3,3)* - &SM(1,2)**2-SM(1,1)*SM(2,2)*SM(3,3))+SM(1,2)*SM(1,3)*SM(2,3)+1./27. - SP=COS(ACOS(MAX(MIN(SR/SQRT(-SQ**3),1.D0),-1.D0))/3.) - P(N+1,4)=1./3.+SQRT(-SQ)*MAX(2.*SP,SQRT(3.*(1.-SP**2))-SP) - P(N+3,4)=1./3.+SQRT(-SQ)*MIN(2.*SP,-SQRT(3.*(1.-SP**2))-SP) - P(N+2,4)=1.-P(N+1,4)-P(N+3,4) - IF(P(N+2,4).LT.1D-5) THEN - CALL LUERRM(8,'(LUSPHE:) all particles back-to-back') - SPH=-1. - APL=-1. - RETURN - ENDIF - -C...Find first and last eigenvector by solving equation system. - DO 240 I=1,3,2 - DO 180 J1=1,3 - SV(J1,J1)=SM(J1,J1)-P(N+I,4) - DO 170 J2=J1+1,3 - SV(J1,J2)=SM(J1,J2) - SV(J2,J1)=SM(J1,J2) - 170 CONTINUE - 180 CONTINUE - SMAX=0. - DO 200 J1=1,3 - DO 190 J2=1,3 - IF(ABS(SV(J1,J2)).LE.SMAX) GOTO 190 - JA=J1 - JB=J2 - SMAX=ABS(SV(J1,J2)) - 190 CONTINUE - 200 CONTINUE - SMAX=0. - DO 220 J3=JA+1,JA+2 - J1=J3-3*((J3-1)/3) - RL=SV(J1,JB)/SV(JA,JB) - DO 210 J2=1,3 - SV(J1,J2)=SV(J1,J2)-RL*SV(JA,J2) - IF(ABS(SV(J1,J2)).LE.SMAX) GOTO 210 - JC=J1 - SMAX=ABS(SV(J1,J2)) - 210 CONTINUE - 220 CONTINUE - JB1=JB+1-3*(JB/3) - JB2=JB+2-3*((JB+1)/3) - P(N+I,JB1)=-SV(JC,JB2) - P(N+I,JB2)=SV(JC,JB1) - P(N+I,JB)=-(SV(JA,JB1)*P(N+I,JB1)+SV(JA,JB2)*P(N+I,JB2))/ - &SV(JA,JB) - PA=SQRT(P(N+I,1)**2+P(N+I,2)**2+P(N+I,3)**2) - SGN=(-1.)**INT(RLU(0)+0.5) - DO 230 J=1,3 - P(N+I,J)=SGN*P(N+I,J)/PA - 230 CONTINUE - 240 CONTINUE - -C...Middle axis orthogonal to other two. Fill other codes. - SGN=(-1.)**INT(RLU(0)+0.5) - P(N+2,1)=SGN*(P(N+1,2)*P(N+3,3)-P(N+1,3)*P(N+3,2)) - P(N+2,2)=SGN*(P(N+1,3)*P(N+3,1)-P(N+1,1)*P(N+3,3)) - P(N+2,3)=SGN*(P(N+1,1)*P(N+3,2)-P(N+1,2)*P(N+3,1)) - DO 260 I=1,3 - K(N+I,1)=31 - K(N+I,2)=95 - K(N+I,3)=I - K(N+I,4)=0 - K(N+I,5)=0 - P(N+I,5)=0. - DO 250 J=1,5 - V(I,J)=0. - 250 CONTINUE - 260 CONTINUE - -C...Calculate sphericity and aplanarity. Select storing option. - SPH=1.5*(P(N+2,4)+P(N+3,4)) - APL=1.5*P(N+3,4) - MSTU(61)=N+1 - MSTU(62)=NP - IF(MSTU(43).LE.1) MSTU(3)=3 - IF(MSTU(43).GE.2) N=N+3 - - RETURN - END - -C********************************************************************* - -CDECK ID>, LUTHRU - SUBROUTINE LUTHRU(THR,OBL) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to perform thrust analysis to give thrust, oblateness -C...and the related event axes. - COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ - DIMENSION TDI(3),TPR(3) - -C...Take copy of particles that are to be considered in thrust analysis. - NP=0 - PS=0. - DO 100 I=1,N - IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 100 - IF(MSTU(41).GE.2) THEN - KC=LUCOMP(K(I,2)) - IF(KC.EQ.0.OR.KC.EQ.12.OR.KC.EQ.14.OR.KC.EQ.16.OR. - & KC.EQ.18) GOTO 100 - IF(MSTU(41).GE.3.AND.KCHG(KC,2).EQ.0.AND.LUCHGE(K(I,2)).EQ.0) - & GOTO 100 - ENDIF - IF(N+NP+MSTU(44)+15.GE.MSTU(4)-MSTU(32)-5) THEN - CALL LUERRM(11,'(LUTHRU:) no more memory left in LUJETS') - THR=-2. - OBL=-2. - RETURN - ENDIF - NP=NP+1 - K(N+NP,1)=23 - P(N+NP,1)=P(I,1) - P(N+NP,2)=P(I,2) - P(N+NP,3)=P(I,3) - P(N+NP,4)=SQRT(P(I,1)**2+P(I,2)**2+P(I,3)**2) - P(N+NP,5)=1. - IF(ABS(PARU(42)-1.).GT.0.001) P(N+NP,5)=P(N+NP,4)**(PARU(42)-1.) - PS=PS+P(N+NP,4)*P(N+NP,5) - 100 CONTINUE - -C...Very low multiplicities (0 or 1) not considered. - IF(NP.LE.1) THEN - CALL LUERRM(8,'(LUTHRU:) too few particles for analysis') - THR=-1. - OBL=-1. - RETURN - ENDIF - -C...Loop over thrust and major. T axis along z direction in latter case. - DO 320 ILD=1,2 - IF(ILD.EQ.2) THEN - K(N+NP+1,1)=31 - PHI=ULANGL(P(N+NP+1,1),P(N+NP+1,2)) - MSTU(33)=1 - CALL LUDBRB(N+1,N+NP+1,0.D0,-PHI,0D0,0D0,0D0) - THE=ULANGL(P(N+NP+1,3),P(N+NP+1,1)) - CALL LUDBRB(N+1,N+NP+1,-THE,0.D0,0D0,0D0,0D0) - ENDIF - -C...Find and order particles with highest p (pT for major). - DO 110 ILF=N+NP+4,N+NP+MSTU(44)+4 - P(ILF,4)=0. - 110 CONTINUE - DO 160 I=N+1,N+NP - IF(ILD.EQ.2) P(I,4)=SQRT(P(I,1)**2+P(I,2)**2) - DO 130 ILF=N+NP+MSTU(44)+3,N+NP+4,-1 - IF(P(I,4).LE.P(ILF,4)) GOTO 140 - DO 120 J=1,5 - P(ILF+1,J)=P(ILF,J) - 120 CONTINUE - 130 CONTINUE - ILF=N+NP+3 - 140 DO 150 J=1,5 - P(ILF+1,J)=P(I,J) - 150 CONTINUE - 160 CONTINUE - -C...Find and order initial axes with highest thrust (major). - DO 170 ILG=N+NP+MSTU(44)+5,N+NP+MSTU(44)+15 - P(ILG,4)=0. - 170 CONTINUE - NC=2**(MIN(MSTU(44),NP)-1) - DO 250 ILC=1,NC - DO 180 J=1,3 - TDI(J)=0. - 180 CONTINUE - DO 200 ILF=1,MIN(MSTU(44),NP) - SGN=P(N+NP+ILF+3,5) - IF(2**ILF*((ILC+2**(ILF-1)-1)/2**ILF).GE.ILC) SGN=-SGN - DO 190 J=1,4-ILD - TDI(J)=TDI(J)+SGN*P(N+NP+ILF+3,J) - 190 CONTINUE - 200 CONTINUE - TDS=TDI(1)**2+TDI(2)**2+TDI(3)**2 - DO 220 ILG=N+NP+MSTU(44)+MIN(ILC,10)+4,N+NP+MSTU(44)+5,-1 - IF(TDS.LE.P(ILG,4)) GOTO 230 - DO 210 J=1,4 - P(ILG+1,J)=P(ILG,J) - 210 CONTINUE - 220 CONTINUE - ILG=N+NP+MSTU(44)+4 - 230 DO 240 J=1,3 - P(ILG+1,J)=TDI(J) - 240 CONTINUE - P(ILG+1,4)=TDS - 250 CONTINUE - -C...Iterate direction of axis until stable maximum. - P(N+NP+ILD,4)=0. - ILG=0 - 260 ILG=ILG+1 - THP=0. - 270 THPS=THP - DO 280 J=1,3 - IF(THP.LE.1D-10) TDI(J)=P(N+NP+MSTU(44)+4+ILG,J) - IF(THP.GT.1D-10) TDI(J)=TPR(J) - TPR(J)=0. - 280 CONTINUE - DO 300 I=N+1,N+NP - SGN=SIGN(P(I,5),TDI(1)*P(I,1)+TDI(2)*P(I,2)+TDI(3)*P(I,3)) - DO 290 J=1,4-ILD - TPR(J)=TPR(J)+SGN*P(I,J) - 290 CONTINUE - 300 CONTINUE - THP=SQRT(TPR(1)**2+TPR(2)**2+TPR(3)**2)/PS - IF(THP.GE.THPS+PARU(48)) GOTO 270 - -C...Save good axis. Try new initial axis until a number of tries agree. - IF(THP.LT.P(N+NP+ILD,4)-PARU(48).AND.ILG.LT.MIN(10,NC)) GOTO 260 - IF(THP.GT.P(N+NP+ILD,4)+PARU(48)) THEN - IAGR=0 - SGN=(-1.)**INT(RLU(0)+0.5) - DO 310 J=1,3 - P(N+NP+ILD,J)=SGN*TPR(J)/(PS*THP) - 310 CONTINUE - P(N+NP+ILD,4)=THP - P(N+NP+ILD,5)=0. - ENDIF - IAGR=IAGR+1 - IF(IAGR.LT.MSTU(45).AND.ILG.LT.MIN(10,NC)) GOTO 260 - 320 CONTINUE - -C...Find minor axis and value by orthogonality. - SGN=(-1.)**INT(RLU(0)+0.5) - P(N+NP+3,1)=-SGN*P(N+NP+2,2) - P(N+NP+3,2)=SGN*P(N+NP+2,1) - P(N+NP+3,3)=0. - THP=0. - DO 330 I=N+1,N+NP - THP=THP+P(I,5)*ABS(P(N+NP+3,1)*P(I,1)+P(N+NP+3,2)*P(I,2)) - 330 CONTINUE - P(N+NP+3,4)=THP/PS - P(N+NP+3,5)=0. - -C...Fill axis information. Rotate back to original coordinate system. - DO 350 ILD=1,3 - K(N+ILD,1)=31 - K(N+ILD,2)=96 - K(N+ILD,3)=ILD - K(N+ILD,4)=0 - K(N+ILD,5)=0 - DO 340 J=1,5 - P(N+ILD,J)=P(N+NP+ILD,J) - V(N+ILD,J)=0. - 340 CONTINUE - 350 CONTINUE - CALL LUDBRB(N+1,N+3,THE,PHI,0D0,0D0,0D0) - -C...Calculate thrust and oblateness. Select storing option. - THR=P(N+1,4) - OBL=P(N+2,4)-P(N+3,4) - MSTU(61)=N+1 - MSTU(62)=NP - IF(MSTU(43).LE.1) MSTU(3)=3 - IF(MSTU(43).GE.2) N=N+3 - - RETURN - END - -C********************************************************************* - -CDECK ID>, LUCLUS - SUBROUTINE LUCLUS(NJET) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to subdivide the particle content of an event into -C...jets/clusters. - COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ - DIMENSION PS(5) - SAVE NSAV,NP,PS,PSS,RINIT,NPRE,NREM - -C...Functions: distance measure in pT or (pseudo)mass. - R2T(I1,I2)=(P(I1,5)*P(I2,5)-P(I1,1)*P(I2,1)-P(I1,2)*P(I2,2)- - &P(I1,3)*P(I2,3))*2.*P(I1,5)*P(I2,5)/(0.0001+P(I1,5)+P(I2,5))**2 - R2M(I1,I2)=2.*P(I1,4)*P(I2,4)*(1.-(P(I1,1)*P(I2,1)+P(I1,2)* - &P(I2,2)+P(I1,3)*P(I2,3))/(P(I1,5)*P(I2,5))) - -C...If first time, reset. If reentering, skip preliminaries. - IF(MSTU(48).LE.0) THEN - NP=0 - DO 100 J=1,5 - PS(J)=0. - 100 CONTINUE - PSS=0. - ELSE - NJET=NSAV - IF(MSTU(43).GE.2) N=N-NJET - DO 110 I=N+1,N+NJET - P(I,5)=SQRT(P(I,1)**2+P(I,2)**2+P(I,3)**2) - 110 CONTINUE - IF(MSTU(46).LE.3) R2ACC=PARU(44)**2 - IF(MSTU(46).GE.4) R2ACC=PARU(45)*PS(5)**2 - NLOOP=0 - GOTO 300 - ENDIF - -C...Find which particles are to be considered in cluster search. - DO 140 I=1,N - IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 140 - IF(MSTU(41).GE.2) THEN - KC=LUCOMP(K(I,2)) - IF(KC.EQ.0.OR.KC.EQ.12.OR.KC.EQ.14.OR.KC.EQ.16.OR. - & KC.EQ.18) GOTO 140 - IF(MSTU(41).GE.3.AND.KCHG(KC,2).EQ.0.AND.LUCHGE(K(I,2)).EQ.0) - & GOTO 140 - ENDIF - IF(N+2*NP.GE.MSTU(4)-MSTU(32)-5) THEN - CALL LUERRM(11,'(LUCLUS:) no more memory left in LUJETS') - NJET=-1 - RETURN - ENDIF - -C...Take copy of these particles, with space left for jets later on. - NP=NP+1 - K(N+NP,3)=I - DO 120 J=1,5 - P(N+NP,J)=P(I,J) - 120 CONTINUE - IF(MSTU(42).EQ.0) P(N+NP,5)=0. - IF(MSTU(42).EQ.1.AND.K(I,2).NE.22) P(N+NP,5)=PMAS(101,1) - P(N+NP,4)=SQRT(P(N+NP,5)**2+P(I,1)**2+P(I,2)**2+P(I,3)**2) - P(N+NP,5)=SQRT(P(I,1)**2+P(I,2)**2+P(I,3)**2) - DO 130 J=1,4 - PS(J)=PS(J)+P(N+NP,J) - 130 CONTINUE - PSS=PSS+P(N+NP,5) - 140 CONTINUE - DO 160 I=N+1,N+NP - K(I+NP,3)=K(I,3) - DO 150 J=1,5 - P(I+NP,J)=P(I,J) - 150 CONTINUE - 160 CONTINUE - PS(5)=SQRT(MAX(0.D0,PS(4)**2-PS(1)**2-PS(2)**2-PS(3)**2)) - -C...Very low multiplicities not considered. - IF(NP.LT.MSTU(47)) THEN - CALL LUERRM(8,'(LUCLUS:) too few particles for analysis') - NJET=-1 - RETURN - ENDIF - -C...Find precluster configuration. If too few jets, make harder cuts. - NLOOP=0 - IF(MSTU(46).LE.3) R2ACC=PARU(44)**2 - IF(MSTU(46).GE.4) R2ACC=PARU(45)*PS(5)**2 - RINIT=1.25*PARU(43) - IF(NP.LE.MSTU(47)+2) RINIT=0. - 170 RINIT=0.8*RINIT - NPRE=0 - NREM=NP - DO 180 I=N+NP+1,N+2*NP - K(I,4)=0 - 180 CONTINUE - -C...Sum up small momentum region. Jet if enough absolute momentum. - IF(MSTU(46).LE.2) THEN - DO 190 J=1,4 - P(N+1,J)=0. - 190 CONTINUE - DO 210 I=N+NP+1,N+2*NP - IF(P(I,5).GT.2.*RINIT) GOTO 210 - NREM=NREM-1 - K(I,4)=1 - DO 200 J=1,4 - P(N+1,J)=P(N+1,J)+P(I,J) - 200 CONTINUE - 210 CONTINUE - P(N+1,5)=SQRT(P(N+1,1)**2+P(N+1,2)**2+P(N+1,3)**2) - IF(P(N+1,5).GT.2.*RINIT) NPRE=1 - IF(RINIT.GE.0.2*PARU(43).AND.NPRE+NREM.LT.MSTU(47)) GOTO 170 - IF(NREM.EQ.0) GOTO 170 - ENDIF - -C...Find fastest remaining particle. - 220 NPRE=NPRE+1 - PMAX=0. - DO 230 I=N+NP+1,N+2*NP - IF(K(I,4).NE.0.OR.P(I,5).LE.PMAX) GOTO 230 - IMAX=I - PMAX=P(I,5) - 230 CONTINUE - DO 240 J=1,5 - P(N+NPRE,J)=P(IMAX,J) - 240 CONTINUE - NREM=NREM-1 - K(IMAX,4)=NPRE - -C...Sum up precluster around it according to pT separation. - IF(MSTU(46).LE.2) THEN - DO 260 I=N+NP+1,N+2*NP - IF(K(I,4).NE.0) GOTO 260 - R2=R2T(I,IMAX) - IF(R2.GT.RINIT**2) GOTO 260 - NREM=NREM-1 - K(I,4)=NPRE - DO 250 J=1,4 - P(N+NPRE,J)=P(N+NPRE,J)+P(I,J) - 250 CONTINUE - 260 CONTINUE - P(N+NPRE,5)=SQRT(P(N+NPRE,1)**2+P(N+NPRE,2)**2+P(N+NPRE,3)**2) - -C...Sum up precluster around it according to mass separation. - ELSE - 270 IMIN=0 - R2MIN=RINIT**2 - DO 280 I=N+NP+1,N+2*NP - IF(K(I,4).NE.0) GOTO 280 - R2=R2M(I,N+NPRE) - IF(R2.GE.R2MIN) GOTO 280 - IMIN=I - R2MIN=R2 - 280 CONTINUE - IF(IMIN.NE.0) THEN - DO 290 J=1,4 - P(N+NPRE,J)=P(N+NPRE,J)+P(IMIN,J) - 290 CONTINUE - P(N+NPRE,5)=SQRT(P(N+NPRE,1)**2+P(N+NPRE,2)**2+P(N+NPRE,3)**2) - NREM=NREM-1 - K(IMIN,4)=NPRE - GOTO 270 - ENDIF - ENDIF - -C...Check if more preclusters to be found. Start over if too few. - IF(RINIT.GE.0.2*PARU(43).AND.NPRE+NREM.LT.MSTU(47)) GOTO 170 - IF(NREM.GT.0) GOTO 220 - NJET=NPRE - -C...Reassign all particles to nearest jet. Sum up new jet momenta. - 300 TSAV=0. - PSJT=0. - 310 IF(MSTU(46).LE.1) THEN - DO 330 I=N+1,N+NJET - DO 320 J=1,4 - V(I,J)=0. - 320 CONTINUE - 330 CONTINUE - DO 360 I=N+NP+1,N+2*NP - R2MIN=PSS**2 - DO 340 IJET=N+1,N+NJET - IF(P(IJET,5).LT.RINIT) GOTO 340 - R2=R2T(I,IJET) - IF(R2.GE.R2MIN) GOTO 340 - IMIN=IJET - R2MIN=R2 - 340 CONTINUE - K(I,4)=IMIN-N - DO 350 J=1,4 - V(IMIN,J)=V(IMIN,J)+P(I,J) - 350 CONTINUE - 360 CONTINUE - PSJT=0. - DO 380 I=N+1,N+NJET - DO 370 J=1,4 - P(I,J)=V(I,J) - 370 CONTINUE - P(I,5)=SQRT(P(I,1)**2+P(I,2)**2+P(I,3)**2) - PSJT=PSJT+P(I,5) - 380 CONTINUE - ENDIF - -C...Find two closest jets. - R2MIN=2.*MAX(R2ACC,PS(5)**2) - DO 400 ITRY1=N+1,N+NJET-1 - DO 390 ITRY2=ITRY1+1,N+NJET - IF(MSTU(46).LE.2) R2=R2T(ITRY1,ITRY2) - IF(MSTU(46).GE.3) R2=R2M(ITRY1,ITRY2) - IF(R2.GE.R2MIN) GOTO 390 - IMIN1=ITRY1 - IMIN2=ITRY2 - R2MIN=R2 - 390 CONTINUE - 400 CONTINUE - -C...If allowed, join two closest jets and start over. - IF(NJET.GT.MSTU(47).AND.R2MIN.LT.R2ACC) THEN - IREC=MIN(IMIN1,IMIN2) - IDEL=MAX(IMIN1,IMIN2) - DO 410 J=1,4 - P(IREC,J)=P(IMIN1,J)+P(IMIN2,J) - 410 CONTINUE - P(IREC,5)=SQRT(P(IREC,1)**2+P(IREC,2)**2+P(IREC,3)**2) - DO 430 I=IDEL+1,N+NJET - DO 420 J=1,5 - P(I-1,J)=P(I,J) - 420 CONTINUE - 430 CONTINUE - IF(MSTU(46).GE.2) THEN - DO 440 I=N+NP+1,N+2*NP - IORI=N+K(I,4) - IF(IORI.EQ.IDEL) K(I,4)=IREC-N - IF(IORI.GT.IDEL) K(I,4)=K(I,4)-1 - 440 CONTINUE - ENDIF - NJET=NJET-1 - GOTO 300 - -C...Divide up broad jet if empty cluster in list of final ones. - ELSEIF(NJET.EQ.MSTU(47).AND.MSTU(46).LE.1.AND.NLOOP.LE.2) THEN - DO 450 I=N+1,N+NJET - K(I,5)=0 - 450 CONTINUE - DO 460 I=N+NP+1,N+2*NP - K(N+K(I,4),5)=K(N+K(I,4),5)+1 - 460 CONTINUE - IEMP=0 - DO 470 I=N+1,N+NJET - IF(K(I,5).EQ.0) IEMP=I - 470 CONTINUE - IF(IEMP.NE.0) THEN - NLOOP=NLOOP+1 - ISPL=0 - R2MAX=0. - DO 480 I=N+NP+1,N+2*NP - IF(K(N+K(I,4),5).LE.1.OR.P(I,5).LT.RINIT) GOTO 480 - IJET=N+K(I,4) - R2=R2T(I,IJET) - IF(R2.LE.R2MAX) GOTO 480 - ISPL=I - R2MAX=R2 - 480 CONTINUE - IF(ISPL.NE.0) THEN - IJET=N+K(ISPL,4) - DO 490 J=1,4 - P(IEMP,J)=P(ISPL,J) - P(IJET,J)=P(IJET,J)-P(ISPL,J) - 490 CONTINUE - P(IEMP,5)=P(ISPL,5) - P(IJET,5)=SQRT(P(IJET,1)**2+P(IJET,2)**2+P(IJET,3)**2) - IF(NLOOP.LE.2) GOTO 300 - ENDIF - ENDIF - ENDIF - -C...If generalized thrust has not yet converged, continue iteration. - IF(MSTU(46).LE.1.AND.NLOOP.LE.2.AND.PSJT/PSS.GT.TSAV+PARU(48)) - &THEN - TSAV=PSJT/PSS - GOTO 310 - ENDIF - -C...Reorder jets according to energy. - DO 510 I=N+1,N+NJET - DO 500 J=1,5 - V(I,J)=P(I,J) - 500 CONTINUE - 510 CONTINUE - DO 540 INEW=N+1,N+NJET - PEMAX=0. - DO 520 ITRY=N+1,N+NJET - IF(V(ITRY,4).LE.PEMAX) GOTO 520 - IMAX=ITRY - PEMAX=V(ITRY,4) - 520 CONTINUE - K(INEW,1)=31 - K(INEW,2)=97 - K(INEW,3)=INEW-N - K(INEW,4)=0 - DO 530 J=1,5 - P(INEW,J)=V(IMAX,J) - 530 CONTINUE - V(IMAX,4)=-1. - K(IMAX,5)=INEW - 540 CONTINUE - -C...Clean up particle-jet assignments and jet information. - DO 550 I=N+NP+1,N+2*NP - IORI=K(N+K(I,4),5) - K(I,4)=IORI-N - IF(K(K(I,3),1).NE.3) K(K(I,3),4)=IORI-N - K(IORI,4)=K(IORI,4)+1 - 550 CONTINUE - IEMP=0 - PSJT=0. - DO 570 I=N+1,N+NJET - K(I,5)=0 - PSJT=PSJT+P(I,5) - P(I,5)=SQRT(MAX(P(I,4)**2-P(I,5)**2,0.D0)) - DO 560 J=1,5 - V(I,J)=0. - 560 CONTINUE - IF(K(I,4).EQ.0) IEMP=I - 570 CONTINUE - -C...Select storing option. Output variables. Check for failure. - MSTU(61)=N+1 - MSTU(62)=NP - MSTU(63)=NPRE - PARU(61)=PS(5) - PARU(62)=PSJT/PSS - PARU(63)=SQRT(R2MIN) - IF(NJET.LE.1) PARU(63)=0. - IF(IEMP.NE.0) THEN - CALL LUERRM(8,'(LUCLUS:) failed to reconstruct as requested') - NJET=-1 - ENDIF - IF(MSTU(43).LE.1) MSTU(3)=NJET - IF(MSTU(43).GE.2) N=N+NJET - NSAV=NJET - - RETURN - END - -C********************************************************************* - -CDECK ID>, LUCELL - SUBROUTINE LUCELL(NJET) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to provide a simple way of jet finding in an eta-phi-ET -C...coordinate frame, as used for calorimeters at hadron colliders. - COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ - -C...Loop over all particles. Find cell that was hit by given particle. - PTLRAT=1./SINH(PARU(51))**2 - NP=0 - NC=N - DO 110 I=1,N - IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 110 - IF(P(I,1)**2+P(I,2)**2.LE.PTLRAT*P(I,3)**2) GOTO 110 - IF(MSTU(41).GE.2) THEN - KC=LUCOMP(K(I,2)) - IF(KC.EQ.0.OR.KC.EQ.12.OR.KC.EQ.14.OR.KC.EQ.16.OR. - & KC.EQ.18) GOTO 110 - IF(MSTU(41).GE.3.AND.KCHG(KC,2).EQ.0.AND.LUCHGE(K(I,2)).EQ.0) - & GOTO 110 - ENDIF - NP=NP+1 - PT=SQRT(P(I,1)**2+P(I,2)**2) - ETA=SIGN(LOG((SQRT(PT**2+P(I,3)**2)+ABS(P(I,3)))/PT),P(I,3)) - IETA=MAX(1,MIN(MSTU(51),1+INT(MSTU(51)*0.5*(ETA/PARU(51)+1.)))) - PHI=ULANGL(P(I,1),P(I,2)) - IPHI=MAX(1,MIN(MSTU(52),1+INT(MSTU(52)*0.5*(PHI/PARU(1)+1.)))) - IETPH=MSTU(52)*IETA+IPHI - -C...Add to cell already hit, or book new cell. - DO 100 IC=N+1,NC - IF(IETPH.EQ.K(IC,3)) THEN - K(IC,4)=K(IC,4)+1 - P(IC,5)=P(IC,5)+PT - GOTO 110 - ENDIF - 100 CONTINUE - IF(NC.GE.MSTU(4)-MSTU(32)-5) THEN - CALL LUERRM(11,'(LUCELL:) no more memory left in LUJETS') - NJET=-2 - RETURN - ENDIF - NC=NC+1 - K(NC,3)=IETPH - K(NC,4)=1 - K(NC,5)=2 - P(NC,1)=(PARU(51)/MSTU(51))*(2*IETA-1-MSTU(51)) - P(NC,2)=(PARU(1)/MSTU(52))*(2*IPHI-1-MSTU(52)) - P(NC,5)=PT - 110 CONTINUE - -C...Smear true bin content by calorimeter resolution. - IF(MSTU(53).GE.1) THEN - DO 130 IC=N+1,NC - PEI=P(IC,5) - IF(MSTU(53).EQ.2) PEI=P(IC,5)*COSH(P(IC,1)) - 120 PEF=PEI+PARU(55)*SQRT(-2.*LOG(MAX(1D-10,RLU(0)))*PEI)* - & COS(PARU(2)*RLU(0)) - IF(PEF.LT.0..OR.PEF.GT.PARU(56)*PEI) GOTO 120 - P(IC,5)=PEF - IF(MSTU(53).EQ.2) P(IC,5)=PEF/COSH(P(IC,1)) - 130 CONTINUE - ENDIF - -C...Remove cells below threshold. - IF(PARU(58).GT.0.) THEN - NCC=NC - NC=N - DO 140 IC=N+1,NCC - IF(P(IC,5).GT.PARU(58)) THEN - NC=NC+1 - K(NC,3)=K(IC,3) - K(NC,4)=K(IC,4) - K(NC,5)=K(IC,5) - P(NC,1)=P(IC,1) - P(NC,2)=P(IC,2) - P(NC,5)=P(IC,5) - ENDIF - 140 CONTINUE - ENDIF - -C...Find initiator cell: the one with highest pT of not yet used ones. - NJ=NC - 150 ETMAX=0. - DO 160 IC=N+1,NC - IF(K(IC,5).NE.2) GOTO 160 - IF(P(IC,5).LE.ETMAX) GOTO 160 - ICMAX=IC - ETA=P(IC,1) - PHI=P(IC,2) - ETMAX=P(IC,5) - 160 CONTINUE - IF(ETMAX.LT.PARU(52)) GOTO 220 - IF(NJ.GE.MSTU(4)-MSTU(32)-5) THEN - CALL LUERRM(11,'(LUCELL:) no more memory left in LUJETS') - NJET=-2 - RETURN - ENDIF - K(ICMAX,5)=1 - NJ=NJ+1 - K(NJ,4)=0 - K(NJ,5)=1 - P(NJ,1)=ETA - P(NJ,2)=PHI - P(NJ,3)=0. - P(NJ,4)=0. - P(NJ,5)=0. - -C...Sum up unused cells within required distance of initiator. - DO 170 IC=N+1,NC - IF(K(IC,5).EQ.0) GOTO 170 - IF(ABS(P(IC,1)-ETA).GT.PARU(54)) GOTO 170 - DPHIA=ABS(P(IC,2)-PHI) - IF(DPHIA.GT.PARU(54).AND.DPHIA.LT.PARU(2)-PARU(54)) GOTO 170 - PHIC=P(IC,2) - IF(DPHIA.GT.PARU(1)) PHIC=PHIC+SIGN(PARU(2),PHI) - IF((P(IC,1)-ETA)**2+(PHIC-PHI)**2.GT.PARU(54)**2) GOTO 170 - K(IC,5)=-K(IC,5) - K(NJ,4)=K(NJ,4)+K(IC,4) - P(NJ,3)=P(NJ,3)+P(IC,5)*P(IC,1) - P(NJ,4)=P(NJ,4)+P(IC,5)*PHIC - P(NJ,5)=P(NJ,5)+P(IC,5) - 170 CONTINUE - -C...Reject cluster below minimum ET, else accept. - IF(P(NJ,5).LT.PARU(53)) THEN - NJ=NJ-1 - DO 180 IC=N+1,NC - IF(K(IC,5).LT.0) K(IC,5)=-K(IC,5) - 180 CONTINUE - ELSEIF(MSTU(54).LE.2) THEN - P(NJ,3)=P(NJ,3)/P(NJ,5) - P(NJ,4)=P(NJ,4)/P(NJ,5) - IF(ABS(P(NJ,4)).GT.PARU(1)) P(NJ,4)=P(NJ,4)-SIGN(PARU(2), - & P(NJ,4)) - DO 190 IC=N+1,NC - IF(K(IC,5).LT.0) K(IC,5)=0 - 190 CONTINUE - ELSE - DO 200 J=1,4 - P(NJ,J)=0. - 200 CONTINUE - DO 210 IC=N+1,NC - IF(K(IC,5).GE.0) GOTO 210 - P(NJ,1)=P(NJ,1)+P(IC,5)*COS(P(IC,2)) - P(NJ,2)=P(NJ,2)+P(IC,5)*SIN(P(IC,2)) - P(NJ,3)=P(NJ,3)+P(IC,5)*SINH(P(IC,1)) - P(NJ,4)=P(NJ,4)+P(IC,5)*COSH(P(IC,1)) - K(IC,5)=0 - 210 CONTINUE - ENDIF - GOTO 150 - -C...Arrange clusters in falling ET sequence. - 220 DO 250 I=1,NJ-NC - ETMAX=0. - DO 230 IJ=NC+1,NJ - IF(K(IJ,5).EQ.0) GOTO 230 - IF(P(IJ,5).LT.ETMAX) GOTO 230 - IJMAX=IJ - ETMAX=P(IJ,5) - 230 CONTINUE - K(IJMAX,5)=0 - K(N+I,1)=31 - K(N+I,2)=98 - K(N+I,3)=I - K(N+I,4)=K(IJMAX,4) - K(N+I,5)=0 - DO 240 J=1,5 - P(N+I,J)=P(IJMAX,J) - V(N+I,J)=0. - 240 CONTINUE - 250 CONTINUE - NJET=NJ-NC - -C...Convert to massless or massive four-vectors. - IF(MSTU(54).EQ.2) THEN - DO 260 I=N+1,N+NJET - ETA=P(I,3) - P(I,1)=P(I,5)*COS(P(I,4)) - P(I,2)=P(I,5)*SIN(P(I,4)) - P(I,3)=P(I,5)*SINH(ETA) - P(I,4)=P(I,5)*COSH(ETA) - P(I,5)=0. - 260 CONTINUE - ELSEIF(MSTU(54).GE.3) THEN - DO 270 I=N+1,N+NJET - P(I,5)=SQRT(MAX(0.D0,P(I,4)**2-P(I,1)**2-P(I,2)**2-P(I,3)**2)) - 270 CONTINUE - ENDIF - -C...Information about storage. - MSTU(61)=N+1 - MSTU(62)=NP - MSTU(63)=NC-N - IF(MSTU(43).LE.1) MSTU(3)=NJET - IF(MSTU(43).GE.2) N=N+NJET - - RETURN - END - -C********************************************************************* - -CDECK ID>, LUJMAS - SUBROUTINE LUJMAS(PMH,PML) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to determine, approximately, the two jet masses that -C...minimize the sum m_H^2 + m_L^2, a la Clavelli and Wyler. - COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ - DIMENSION SM(3,3),SAX(3),PS(3,5) - -C...Reset. - NP=0 - DO 120 J1=1,3 - DO 100 J2=J1,3 - SM(J1,J2)=0. - 100 CONTINUE - DO 110 J2=1,4 - PS(J1,J2)=0. - 110 CONTINUE - 120 CONTINUE - PSS=0. - -C...Take copy of particles that are to be considered in mass analysis. - DO 170 I=1,N - IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 170 - IF(MSTU(41).GE.2) THEN - KC=LUCOMP(K(I,2)) - IF(KC.EQ.0.OR.KC.EQ.12.OR.KC.EQ.14.OR.KC.EQ.16.OR. - & KC.EQ.18) GOTO 170 - IF(MSTU(41).GE.3.AND.KCHG(KC,2).EQ.0.AND.LUCHGE(K(I,2)).EQ.0) - & GOTO 170 - ENDIF - IF(N+NP+1.GE.MSTU(4)-MSTU(32)-5) THEN - CALL LUERRM(11,'(LUJMAS:) no more memory left in LUJETS') - PMH=-2. - PML=-2. - RETURN - ENDIF - NP=NP+1 - DO 130 J=1,5 - P(N+NP,J)=P(I,J) - 130 CONTINUE - IF(MSTU(42).EQ.0) P(N+NP,5)=0. - IF(MSTU(42).EQ.1.AND.K(I,2).NE.22) P(N+NP,5)=PMAS(101,1) - P(N+NP,4)=SQRT(P(N+NP,5)**2+P(I,1)**2+P(I,2)**2+P(I,3)**2) - -C...Fill information in sphericity tensor and total momentum vector. - DO 150 J1=1,3 - DO 140 J2=J1,3 - SM(J1,J2)=SM(J1,J2)+P(I,J1)*P(I,J2) - 140 CONTINUE - 150 CONTINUE - PSS=PSS+(P(I,1)**2+P(I,2)**2+P(I,3)**2) - DO 160 J=1,4 - PS(3,J)=PS(3,J)+P(N+NP,J) - 160 CONTINUE - 170 CONTINUE - -C...Very low multiplicities (0 or 1) not considered. - IF(NP.LE.1) THEN - CALL LUERRM(8,'(LUJMAS:) too few particles for analysis') - PMH=-1. - PML=-1. - RETURN - ENDIF - PARU(61)= - &SQRT(MAX(0.D0,PS(3,4)**2-PS(3,1)**2-PS(3,2)**2-PS(3,3)**2)) - -C...Find largest eigenvalue to matrix (third degree equation). - DO 190 J1=1,3 - DO 180 J2=J1,3 - SM(J1,J2)=SM(J1,J2)/PSS - 180 CONTINUE - 190 CONTINUE - SQ=(SM(1,1)*SM(2,2)+SM(1,1)*SM(3,3)+SM(2,2)*SM(3,3)-SM(1,2)**2- - &SM(1,3)**2-SM(2,3)**2)/3.-1./9. - SR=-0.5*(SQ+1./9.+SM(1,1)*SM(2,3)**2+SM(2,2)*SM(1,3)**2+SM(3,3)* - &SM(1,2)**2-SM(1,1)*SM(2,2)*SM(3,3))+SM(1,2)*SM(1,3)*SM(2,3)+1./27. - SP=COS(ACOS(MAX(MIN(SR/SQRT(-SQ**3),1.D0),-1.D0))/3.) - SMA=1./3.+SQRT(-SQ)*MAX(2.*SP,SQRT(3.*(1.-SP**2))-SP) - -C...Find largest eigenvector by solving equation system. - DO 210 J1=1,3 - SM(J1,J1)=SM(J1,J1)-SMA - DO 200 J2=J1+1,3 - SM(J2,J1)=SM(J1,J2) - 200 CONTINUE - 210 CONTINUE - SMAX=0. - DO 230 J1=1,3 - DO 220 J2=1,3 - IF(ABS(SM(J1,J2)).LE.SMAX) GOTO 220 - JA=J1 - JB=J2 - SMAX=ABS(SM(J1,J2)) - 220 CONTINUE - 230 CONTINUE - SMAX=0. - DO 250 J3=JA+1,JA+2 - J1=J3-3*((J3-1)/3) - RL=SM(J1,JB)/SM(JA,JB) - DO 240 J2=1,3 - SM(J1,J2)=SM(J1,J2)-RL*SM(JA,J2) - IF(ABS(SM(J1,J2)).LE.SMAX) GOTO 240 - JC=J1 - SMAX=ABS(SM(J1,J2)) - 240 CONTINUE - 250 CONTINUE - JB1=JB+1-3*(JB/3) - JB2=JB+2-3*((JB+1)/3) - SAX(JB1)=-SM(JC,JB2) - SAX(JB2)=SM(JC,JB1) - SAX(JB)=-(SM(JA,JB1)*SAX(JB1)+SM(JA,JB2)*SAX(JB2))/SM(JA,JB) - -C...Divide particles into two initial clusters by hemisphere. - DO 270 I=N+1,N+NP - PSAX=P(I,1)*SAX(1)+P(I,2)*SAX(2)+P(I,3)*SAX(3) - IS=1 - IF(PSAX.LT.0.) IS=2 - K(I,3)=IS - DO 260 J=1,4 - PS(IS,J)=PS(IS,J)+P(I,J) - 260 CONTINUE - 270 CONTINUE - PMS=MAX(1D-10,PS(1,4)**2-PS(1,1)**2-PS(1,2)**2-PS(1,3)**2)+ - &MAX(1D-10,PS(2,4)**2-PS(2,1)**2-PS(2,2)**2-PS(2,3)**2) - -C...Reassign one particle at a time; find maximum decrease of m^2 sum. - 280 PMD=0. - IM=0 - DO 290 J=1,4 - PS(3,J)=PS(1,J)-PS(2,J) - 290 CONTINUE - DO 300 I=N+1,N+NP - PPS=P(I,4)*PS(3,4)-P(I,1)*PS(3,1)-P(I,2)*PS(3,2)-P(I,3)*PS(3,3) - IF(K(I,3).EQ.1) PMDI=2.*(P(I,5)**2-PPS) - IF(K(I,3).EQ.2) PMDI=2.*(P(I,5)**2+PPS) - IF(PMDI.LT.PMD) THEN - PMD=PMDI - IM=I - ENDIF - 300 CONTINUE - -C...Loop back if significant reduction in sum of m^2. - IF(PMD.LT.-PARU(48)*PMS) THEN - PMS=PMS+PMD - IS=K(IM,3) - DO 310 J=1,4 - PS(IS,J)=PS(IS,J)-P(IM,J) - PS(3-IS,J)=PS(3-IS,J)+P(IM,J) - 310 CONTINUE - K(IM,3)=3-IS - GOTO 280 - ENDIF - -C...Final masses and output. - MSTU(61)=N+1 - MSTU(62)=NP - PS(1,5)= - &SQRT(MAX(0.D0,PS(1,4)**2-PS(1,1)**2-PS(1,2)**2-PS(1,3)**2)) - PS(2,5)= - &SQRT(MAX(0.D0,PS(2,4)**2-PS(2,1)**2-PS(2,2)**2-PS(2,3)**2)) - PMH=MAX(PS(1,5),PS(2,5)) - PML=MIN(PS(1,5),PS(2,5)) - - RETURN - END - -C********************************************************************* - -CDECK ID>, LUFOWO - SUBROUTINE LUFOWO(H10,H20,H30,H40) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to calculate the first few Fox-Wolfram moments. - COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ - -C...Copy momenta for particles and calculate H0. - NP=0 - H0=0. - HD=0. - DO 110 I=1,N - IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 110 - IF(MSTU(41).GE.2) THEN - KC=LUCOMP(K(I,2)) - IF(KC.EQ.0.OR.KC.EQ.12.OR.KC.EQ.14.OR.KC.EQ.16.OR. - & KC.EQ.18) GOTO 110 - IF(MSTU(41).GE.3.AND.KCHG(KC,2).EQ.0.AND.LUCHGE(K(I,2)).EQ.0) - & GOTO 110 - ENDIF - IF(N+NP.GE.MSTU(4)-MSTU(32)-5) THEN - CALL LUERRM(11,'(LUFOWO:) no more memory left in LUJETS') - H10=-1. - H20=-1. - H30=-1. - H40=-1. - RETURN - ENDIF - NP=NP+1 - DO 100 J=1,3 - P(N+NP,J)=P(I,J) - 100 CONTINUE - P(N+NP,4)=SQRT(P(I,1)**2+P(I,2)**2+P(I,3)**2) - H0=H0+P(N+NP,4) - HD=HD+P(N+NP,4)**2 - 110 CONTINUE - H0=H0**2 - -C...Very low multiplicities (0 or 1) not considered. - IF(NP.LE.1) THEN - CALL LUERRM(8,'(LUFOWO:) too few particles for analysis') - H10=-1. - H20=-1. - H30=-1. - H40=-1. - RETURN - ENDIF - -C...Calculate H1 - H4. - H10=0. - H20=0. - H30=0. - H40=0. - DO 130 I1=N+1,N+NP - DO 120 I2=I1+1,N+NP - CTHE=(P(I1,1)*P(I2,1)+P(I1,2)*P(I2,2)+P(I1,3)*P(I2,3))/ - &(P(I1,4)*P(I2,4)) - H10=H10+P(I1,4)*P(I2,4)*CTHE - H20=H20+P(I1,4)*P(I2,4)*(1.5*CTHE**2-0.5) - H30=H30+P(I1,4)*P(I2,4)*(2.5*CTHE**3-1.5*CTHE) - H40=H40+P(I1,4)*P(I2,4)*(4.375*CTHE**4-3.75*CTHE**2+0.375) - 120 CONTINUE - 130 CONTINUE - -C...Calculate H1/H0 - H4/H0. Output. - MSTU(61)=N+1 - MSTU(62)=NP - H10=(HD+2.*H10)/H0 - H20=(HD+2.*H20)/H0 - H30=(HD+2.*H30)/H0 - H40=(HD+2.*H40)/H0 - - RETURN - END - -C********************************************************************* - -CDECK ID>, LUTABU - SUBROUTINE LUTABU(MTABU) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to evaluate various properties of an event, with -C...statistics accumulated during the course of the run and -C...printed at the end. - COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - COMMON/LUDAT3/MDCY(500,3),MDME(2000,2),BRAT(2000),KFDP(2000,5) - SAVE /LUJETS/,/LUDAT1/,/LUDAT2/,/LUDAT3/ - DIMENSION KFIS(100,2),NPIS(100,0:10),KFFS(400),NPFS(400,4), - &FEVFM(10,4),FM1FM(3,10,4),FM2FM(3,10,4),FMOMA(4),FMOMS(4), - &FEVEE(50),FE1EC(50),FE2EC(50),FE1EA(25),FE2EA(25), - &KFDM(8),KFDC(200,0:8),NPDC(200) - SAVE NEVIS,NKFIS,KFIS,NPIS,NEVFS,NPRFS,NFIFS,NCHFS,NKFFS, - &KFFS,NPFS,NEVFM,NMUFM,FM1FM,FM2FM,NEVEE,FE1EC,FE2EC,FE1EA, - &FE2EA,NEVDC,NKFDC,NREDC,KFDC,NPDC - CHARACTER CHAU*16,CHIS(2)*12,CHDC(8)*12 - DATA NEVIS/0/,NKFIS/0/,NEVFS/0/,NPRFS/0/,NFIFS/0/,NCHFS/0/, - &NKFFS/0/,NEVFM/0/,NMUFM/0/,FM1FM/120*0./,FM2FM/120*0./, - &NEVEE/0/,FE1EC/50*0./,FE2EC/50*0./,FE1EA/25*0./,FE2EA/25*0./, - &NEVDC/0/,NKFDC/0/,NREDC/0/ - -C...Reset statistics on initial parton state. - IF(MTABU.EQ.10) THEN - NEVIS=0 - NKFIS=0 - -C...Identify and order flavour content of initial state. - ELSEIF(MTABU.EQ.11) THEN - NEVIS=NEVIS+1 - KFM1=2*IABS(MSTU(161)) - IF(MSTU(161).GT.0) KFM1=KFM1-1 - KFM2=2*IABS(MSTU(162)) - IF(MSTU(162).GT.0) KFM2=KFM2-1 - KFMN=MIN(KFM1,KFM2) - KFMX=MAX(KFM1,KFM2) - DO 100 I=1,NKFIS - IF(KFMN.EQ.KFIS(I,1).AND.KFMX.EQ.KFIS(I,2)) THEN - IKFIS=-I - GOTO 110 - ELSEIF(KFMN.LT.KFIS(I,1).OR.(KFMN.EQ.KFIS(I,1).AND. - & KFMX.LT.KFIS(I,2))) THEN - IKFIS=I - GOTO 110 - ENDIF - 100 CONTINUE - IKFIS=NKFIS+1 - 110 IF(IKFIS.LT.0) THEN - IKFIS=-IKFIS - ELSE - IF(NKFIS.GE.100) RETURN - DO 130 I=NKFIS,IKFIS,-1 - KFIS(I+1,1)=KFIS(I,1) - KFIS(I+1,2)=KFIS(I,2) - DO 120 J=0,10 - NPIS(I+1,J)=NPIS(I,J) - 120 CONTINUE - 130 CONTINUE - NKFIS=NKFIS+1 - KFIS(IKFIS,1)=KFMN - KFIS(IKFIS,2)=KFMX - DO 140 J=0,10 - NPIS(IKFIS,J)=0 - 140 CONTINUE - ENDIF - NPIS(IKFIS,0)=NPIS(IKFIS,0)+1 - -C...Count number of partons in initial state. - NP=0 - DO 160 I=1,N - IF(K(I,1).LE.0.OR.K(I,1).GT.12) THEN - ELSEIF(IABS(K(I,2)).GT.80.AND.IABS(K(I,2)).LE.100) THEN - ELSEIF(IABS(K(I,2)).GT.100.AND.MOD(IABS(K(I,2))/10,10).NE.0) - & THEN - ELSE - IM=I - 150 IM=K(IM,3) - IF(IM.LE.0.OR.IM.GT.N) THEN - NP=NP+1 - ELSEIF(K(IM,1).LE.0.OR.K(IM,1).GT.20) THEN - NP=NP+1 - ELSEIF(IABS(K(IM,2)).GT.80.AND.IABS(K(IM,2)).LE.100) THEN - ELSEIF(IABS(K(IM,2)).GT.100.AND.MOD(IABS(K(IM,2))/10,10).NE.0) - & THEN - ELSE - GOTO 150 - ENDIF - ENDIF - 160 CONTINUE - NPCO=MAX(NP,1) - IF(NP.GE.6) NPCO=6 - IF(NP.GE.8) NPCO=7 - IF(NP.GE.11) NPCO=8 - IF(NP.GE.16) NPCO=9 - IF(NP.GE.26) NPCO=10 - NPIS(IKFIS,NPCO)=NPIS(IKFIS,NPCO)+1 - MSTU(62)=NP - -C...Write statistics on initial parton state. - ELSEIF(MTABU.EQ.12) THEN - FAC=1./MAX(1,NEVIS) - WRITE(MSTU(11),5000) NEVIS - DO 170 I=1,NKFIS - KFMN=KFIS(I,1) - IF(KFMN.EQ.0) KFMN=KFIS(I,2) - KFM1=(KFMN+1)/2 - IF(2*KFM1.EQ.KFMN) KFM1=-KFM1 - CALL LUNAME(KFM1,CHAU) - CHIS(1)=CHAU(1:12) - IF(CHAU(13:13).NE.' ') CHIS(1)(12:12)='?' - KFMX=KFIS(I,2) - IF(KFIS(I,1).EQ.0) KFMX=0 - KFM2=(KFMX+1)/2 - IF(2*KFM2.EQ.KFMX) KFM2=-KFM2 - CALL LUNAME(KFM2,CHAU) - CHIS(2)=CHAU(1:12) - IF(CHAU(13:13).NE.' ') CHIS(2)(12:12)='?' - WRITE(MSTU(11),5100) CHIS(1),CHIS(2),FAC*NPIS(I,0), - & (NPIS(I,J)/ DBLE(NPIS(I,0)),J=1,10) - 170 CONTINUE - -C...Copy statistics on initial parton state into /LUJETS/. - ELSEIF(MTABU.EQ.13) THEN - FAC=1./MAX(1,NEVIS) - DO 190 I=1,NKFIS - KFMN=KFIS(I,1) - IF(KFMN.EQ.0) KFMN=KFIS(I,2) - KFM1=(KFMN+1)/2 - IF(2*KFM1.EQ.KFMN) KFM1=-KFM1 - KFMX=KFIS(I,2) - IF(KFIS(I,1).EQ.0) KFMX=0 - KFM2=(KFMX+1)/2 - IF(2*KFM2.EQ.KFMX) KFM2=-KFM2 - K(I,1)=32 - K(I,2)=99 - K(I,3)=KFM1 - K(I,4)=KFM2 - K(I,5)=NPIS(I,0) - DO 180 J=1,5 - P(I,J)=FAC*NPIS(I,J) - V(I,J)=FAC*NPIS(I,J+5) - 180 CONTINUE - 190 CONTINUE - N=NKFIS - DO 200 J=1,5 - K(N+1,J)=0 - P(N+1,J)=0. - V(N+1,J)=0. - 200 CONTINUE - K(N+1,1)=32 - K(N+1,2)=99 - K(N+1,5)=NEVIS - MSTU(3)=1 - -C...Reset statistics on number of particles/partons. - ELSEIF(MTABU.EQ.20) THEN - NEVFS=0 - NPRFS=0 - NFIFS=0 - NCHFS=0 - NKFFS=0 - -C...Identify whether particle/parton is primary or not. - ELSEIF(MTABU.EQ.21) THEN - NEVFS=NEVFS+1 - MSTU(62)=0 - DO 260 I=1,N - IF(K(I,1).LE.0.OR.K(I,1).GT.20.OR.K(I,1).EQ.13) GOTO 260 - MSTU(62)=MSTU(62)+1 - KC=LUCOMP(K(I,2)) - MPRI=0 - IF(K(I,3).LE.0.OR.K(I,3).GT.N) THEN - MPRI=1 - ELSEIF(K(K(I,3),1).LE.0.OR.K(K(I,3),1).GT.20) THEN - MPRI=1 - ELSEIF(K(K(I,3),2).GE.91.AND.K(K(I,3),2).LE.93) THEN - MPRI=1 - ELSEIF(KC.EQ.0) THEN - ELSEIF(K(K(I,3),1).EQ.13) THEN - IM=K(K(I,3),3) - IF(IM.LE.0.OR.IM.GT.N) THEN - MPRI=1 - ELSEIF(K(IM,1).LE.0.OR.K(IM,1).GT.20) THEN - MPRI=1 - ENDIF - ELSEIF(KCHG(KC,2).EQ.0) THEN - KCM=LUCOMP(K(K(I,3),2)) - IF(KCM.NE.0) THEN - IF(KCHG(KCM,2).NE.0) MPRI=1 - ENDIF - ENDIF - IF(KC.NE.0.AND.MPRI.EQ.1) THEN - IF(KCHG(KC,2).EQ.0) NPRFS=NPRFS+1 - ENDIF - IF(K(I,1).LE.10) THEN - NFIFS=NFIFS+1 - IF(LUCHGE(K(I,2)).NE.0) NCHFS=NCHFS+1 - ENDIF - -C...Fill statistics on number of particles/partons in event. - KFA=IABS(K(I,2)) - KFS=3-ISIGN(1,K(I,2))-MPRI - DO 210 IP=1,NKFFS - IF(KFA.EQ.KFFS(IP)) THEN - IKFFS=-IP - GOTO 220 - ELSEIF(KFA.LT.KFFS(IP)) THEN - IKFFS=IP - GOTO 220 - ENDIF - 210 CONTINUE - IKFFS=NKFFS+1 - 220 IF(IKFFS.LT.0) THEN - IKFFS=-IKFFS - ELSE - IF(NKFFS.GE.400) RETURN - DO 240 IP=NKFFS,IKFFS,-1 - KFFS(IP+1)=KFFS(IP) - DO 230 J=1,4 - NPFS(IP+1,J)=NPFS(IP,J) - 230 CONTINUE - 240 CONTINUE - NKFFS=NKFFS+1 - KFFS(IKFFS)=KFA - DO 250 J=1,4 - NPFS(IKFFS,J)=0 - 250 CONTINUE - ENDIF - NPFS(IKFFS,KFS)=NPFS(IKFFS,KFS)+1 - 260 CONTINUE - -C...Write statistics on particle/parton composition of events. - ELSEIF(MTABU.EQ.22) THEN - FAC=1./MAX(1,NEVFS) - WRITE(MSTU(11),5200) NEVFS,FAC*NPRFS,FAC*NFIFS,FAC*NCHFS - DO 270 I=1,NKFFS - CALL LUNAME(KFFS(I),CHAU) - KC=LUCOMP(KFFS(I)) - MDCYF=0 - IF(KC.NE.0) MDCYF=MDCY(KC,1) - WRITE(MSTU(11),5300) KFFS(I),CHAU,MDCYF,(FAC*NPFS(I,J),J=1,4), - & FAC*(NPFS(I,1)+NPFS(I,2)+NPFS(I,3)+NPFS(I,4)) - 270 CONTINUE - -C...Copy particle/parton composition information into /LUJETS/. - ELSEIF(MTABU.EQ.23) THEN - FAC=1./MAX(1,NEVFS) - DO 290 I=1,NKFFS - K(I,1)=32 - K(I,2)=99 - K(I,3)=KFFS(I) - K(I,4)=0 - K(I,5)=NPFS(I,1)+NPFS(I,2)+NPFS(I,3)+NPFS(I,4) - DO 280 J=1,4 - P(I,J)=FAC*NPFS(I,J) - V(I,J)=0. - 280 CONTINUE - P(I,5)=FAC*K(I,5) - V(I,5)=0. - 290 CONTINUE - N=NKFFS - DO 300 J=1,5 - K(N+1,J)=0 - P(N+1,J)=0. - V(N+1,J)=0. - 300 CONTINUE - K(N+1,1)=32 - K(N+1,2)=99 - K(N+1,5)=NEVFS - P(N+1,1)=FAC*NPRFS - P(N+1,2)=FAC*NFIFS - P(N+1,3)=FAC*NCHFS - MSTU(3)=1 - -C...Reset factorial moments statistics. - ELSEIF(MTABU.EQ.30) THEN - NEVFM=0 - NMUFM=0 - DO 330 IM=1,3 - DO 320 IB=1,10 - DO 310 IP=1,4 - FM1FM(IM,IB,IP)=0. - FM2FM(IM,IB,IP)=0. - 310 CONTINUE - 320 CONTINUE - 330 CONTINUE - -C...Find particles to include, with (pion,pseudo)rapidity and azimuth. - ELSEIF(MTABU.EQ.31) THEN - NEVFM=NEVFM+1 - NLOW=N+MSTU(3) - NUPP=NLOW - DO 410 I=1,N - IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 410 - IF(MSTU(41).GE.2) THEN - KC=LUCOMP(K(I,2)) - IF(KC.EQ.0.OR.KC.EQ.12.OR.KC.EQ.14.OR.KC.EQ.16.OR. - & KC.EQ.18) GOTO 410 - IF(MSTU(41).GE.3.AND.KCHG(KC,2).EQ.0.AND.LUCHGE(K(I,2)).EQ.0) - & GOTO 410 - ENDIF - PMR=0. - IF(MSTU(42).EQ.1.AND.K(I,2).NE.22) PMR=ULMASS(211) - IF(MSTU(42).GE.2) PMR=P(I,5) - PR=MAX(1D-20,PMR**2+P(I,1)**2+P(I,2)**2) - YETA=SIGN(LOG(MIN((SQRT(PR+P(I,3)**2)+ABS(P(I,3)))/SQRT(PR), - & 1D20)),P(I,3)) - IF(ABS(YETA).GT.PARU(57)) GOTO 410 - PHI=ULANGL(P(I,1),P(I,2)) - IYETA=512.*(YETA+PARU(57))/(2.*PARU(57)) - IYETA=MAX(0,MIN(511,IYETA)) - IPHI=512.*(PHI+PARU(1))/PARU(2) - IPHI=MAX(0,MIN(511,IPHI)) - IYEP=0 - DO 340 IB=0,9 - IYEP=IYEP+4**IB*(2*MOD(IYETA/2**IB,2)+MOD(IPHI/2**IB,2)) - 340 CONTINUE - -C...Order particles in (pseudo)rapidity and/or azimuth. - IF(NUPP.GT.MSTU(4)-5-MSTU(32)) THEN - CALL LUERRM(11,'(LUTABU:) no more memory left in LUJETS') - RETURN - ENDIF - NUPP=NUPP+1 - IF(NUPP.EQ.NLOW+1) THEN - K(NUPP,1)=IYETA - K(NUPP,2)=IPHI - K(NUPP,3)=IYEP - ELSE - DO 350 I1=NUPP-1,NLOW+1,-1 - IF(IYETA.GE.K(I1,1)) GOTO 360 - K(I1+1,1)=K(I1,1) - 350 CONTINUE - 360 K(I1+1,1)=IYETA - DO 370 I1=NUPP-1,NLOW+1,-1 - IF(IPHI.GE.K(I1,2)) GOTO 380 - K(I1+1,2)=K(I1,2) - 370 CONTINUE - 380 K(I1+1,2)=IPHI - DO 390 I1=NUPP-1,NLOW+1,-1 - IF(IYEP.GE.K(I1,3)) GOTO 400 - K(I1+1,3)=K(I1,3) - 390 CONTINUE - 400 K(I1+1,3)=IYEP - ENDIF - 410 CONTINUE - K(NUPP+1,1)=2**10 - K(NUPP+1,2)=2**10 - K(NUPP+1,3)=4**10 - -C...Calculate sum of factorial moments in event. - DO 480 IM=1,3 - DO 430 IB=1,10 - DO 420 IP=1,4 - FEVFM(IB,IP)=0. - 420 CONTINUE - 430 CONTINUE - DO 450 IB=1,10 - IF(IM.LE.2) IBIN=2**(10-IB) - IF(IM.EQ.3) IBIN=4**(10-IB) - IAGR=K(NLOW+1,IM)/IBIN - NAGR=1 - DO 440 I=NLOW+2,NUPP+1 - ICUT=K(I,IM)/IBIN - IF(ICUT.EQ.IAGR) THEN - NAGR=NAGR+1 - ELSE - IF(NAGR.EQ.1) THEN - ELSEIF(NAGR.EQ.2) THEN - FEVFM(IB,1)=FEVFM(IB,1)+2. - ELSEIF(NAGR.EQ.3) THEN - FEVFM(IB,1)=FEVFM(IB,1)+6. - FEVFM(IB,2)=FEVFM(IB,2)+6. - ELSEIF(NAGR.EQ.4) THEN - FEVFM(IB,1)=FEVFM(IB,1)+12. - FEVFM(IB,2)=FEVFM(IB,2)+24. - FEVFM(IB,3)=FEVFM(IB,3)+24. - ELSE - FEVFM(IB,1)=FEVFM(IB,1)+NAGR*(NAGR-1.) - FEVFM(IB,2)=FEVFM(IB,2)+NAGR*(NAGR-1.)*(NAGR-2.) - FEVFM(IB,3)=FEVFM(IB,3)+NAGR*(NAGR-1.)*(NAGR-2.)*(NAGR-3.) - FEVFM(IB,4)=FEVFM(IB,4)+NAGR*(NAGR-1.)*(NAGR-2.)*(NAGR-3.)* - & (NAGR-4.) - ENDIF - IAGR=ICUT - NAGR=1 - ENDIF - 440 CONTINUE - 450 CONTINUE - -C...Add results to total statistics. - DO 470 IB=10,1,-1 - DO 460 IP=1,4 - IF(FEVFM(1,IP).LT.0.5) THEN - FEVFM(IB,IP)=0. - ELSEIF(IM.LE.2) THEN - FEVFM(IB,IP)=2.**((IB-1)*IP)*FEVFM(IB,IP)/FEVFM(1,IP) - ELSE - FEVFM(IB,IP)=4.**((IB-1)*IP)*FEVFM(IB,IP)/FEVFM(1,IP) - ENDIF - FM1FM(IM,IB,IP)=FM1FM(IM,IB,IP)+FEVFM(IB,IP) - FM2FM(IM,IB,IP)=FM2FM(IM,IB,IP)+FEVFM(IB,IP)**2 - 460 CONTINUE - 470 CONTINUE - 480 CONTINUE - NMUFM=NMUFM+(NUPP-NLOW) - MSTU(62)=NUPP-NLOW - -C...Write accumulated statistics on factorial moments. - ELSEIF(MTABU.EQ.32) THEN - FAC=1./MAX(1,NEVFM) - IF(MSTU(42).LE.0) WRITE(MSTU(11),5400) NEVFM,'eta' - IF(MSTU(42).EQ.1) WRITE(MSTU(11),5400) NEVFM,'ypi' - IF(MSTU(42).GE.2) WRITE(MSTU(11),5400) NEVFM,'y ' - DO 510 IM=1,3 - WRITE(MSTU(11),5500) - DO 500 IB=1,10 - BYETA=2.*PARU(57) - IF(IM.NE.2) BYETA=BYETA/2**(IB-1) - BPHI=PARU(2) - IF(IM.NE.1) BPHI=BPHI/2**(IB-1) - IF(IM.LE.2) BNAVE=FAC*NMUFM/ DBLE(2**(IB-1)) - IF(IM.EQ.3) BNAVE=FAC*NMUFM/ DBLE(4**(IB-1)) - DO 490 IP=1,4 - FMOMA(IP)=FAC*FM1FM(IM,IB,IP) - FMOMS(IP)=SQRT(MAX(0.D0,FAC*(FAC*FM2FM(IM,IB,IP)-FMOMA(IP)**2))) - 490 CONTINUE - WRITE(MSTU(11),5600) BYETA,BPHI,BNAVE,(FMOMA(IP),FMOMS(IP), - & IP=1,4) - 500 CONTINUE - 510 CONTINUE - -C...Copy statistics on factorial moments into /LUJETS/. - ELSEIF(MTABU.EQ.33) THEN - FAC=1./MAX(1,NEVFM) - DO 540 IM=1,3 - DO 530 IB=1,10 - I=10*(IM-1)+IB - K(I,1)=32 - K(I,2)=99 - K(I,3)=1 - IF(IM.NE.2) K(I,3)=2**(IB-1) - K(I,4)=1 - IF(IM.NE.1) K(I,4)=2**(IB-1) - K(I,5)=0 - P(I,1)=2.*PARU(57)/K(I,3) - V(I,1)=PARU(2)/K(I,4) - DO 520 IP=1,4 - P(I,IP+1)=FAC*FM1FM(IM,IB,IP) - V(I,IP+1)=SQRT(MAX(0.D0,FAC*(FAC*FM2FM(IM,IB,IP)-P(I,IP+1)**2))) - 520 CONTINUE - 530 CONTINUE - 540 CONTINUE - N=30 - DO 550 J=1,5 - K(N+1,J)=0 - P(N+1,J)=0. - V(N+1,J)=0. - 550 CONTINUE - K(N+1,1)=32 - K(N+1,2)=99 - K(N+1,5)=NEVFM - MSTU(3)=1 - -C...Reset statistics on Energy-Energy Correlation. - ELSEIF(MTABU.EQ.40) THEN - NEVEE=0 - DO 560 J=1,25 - FE1EC(J)=0. - FE2EC(J)=0. - FE1EC(51-J)=0. - FE2EC(51-J)=0. - FE1EA(J)=0. - FE2EA(J)=0. - 560 CONTINUE - -C...Find particles to include, with proper assumed mass. - ELSEIF(MTABU.EQ.41) THEN - NEVEE=NEVEE+1 - NLOW=N+MSTU(3) - NUPP=NLOW - ECM=0. - DO 570 I=1,N - IF(K(I,1).LE.0.OR.K(I,1).GT.10) GOTO 570 - IF(MSTU(41).GE.2) THEN - KC=LUCOMP(K(I,2)) - IF(KC.EQ.0.OR.KC.EQ.12.OR.KC.EQ.14.OR.KC.EQ.16.OR. - & KC.EQ.18) GOTO 570 - IF(MSTU(41).GE.3.AND.KCHG(KC,2).EQ.0.AND.LUCHGE(K(I,2)).EQ.0) - & GOTO 570 - ENDIF - PMR=0. - IF(MSTU(42).EQ.1.AND.K(I,2).NE.22) PMR=ULMASS(211) - IF(MSTU(42).GE.2) PMR=P(I,5) - IF(NUPP.GT.MSTU(4)-5-MSTU(32)) THEN - CALL LUERRM(11,'(LUTABU:) no more memory left in LUJETS') - RETURN - ENDIF - NUPP=NUPP+1 - P(NUPP,1)=P(I,1) - P(NUPP,2)=P(I,2) - P(NUPP,3)=P(I,3) - P(NUPP,4)=SQRT(PMR**2+P(I,1)**2+P(I,2)**2+P(I,3)**2) - P(NUPP,5)=MAX(1D-10,SQRT(P(I,1)**2+P(I,2)**2+P(I,3)**2)) - ECM=ECM+P(NUPP,4) - 570 CONTINUE - IF(NUPP.EQ.NLOW) RETURN - -C...Analyze Energy-Energy Correlation in event. - FAC=(2./ECM**2)*50./PARU(1) - DO 580 J=1,50 - FEVEE(J)=0. - 580 CONTINUE - DO 600 I1=NLOW+2,NUPP - DO 590 I2=NLOW+1,I1-1 - CTHE=(P(I1,1)*P(I2,1)+P(I1,2)*P(I2,2)+P(I1,3)*P(I2,3))/ - & (P(I1,5)*P(I2,5)) - THE=ACOS(MAX(-1.D0,MIN(1.D0,CTHE))) - ITHE=MAX(1,MIN(50,1+INT(50.*THE/PARU(1)))) - FEVEE(ITHE)=FEVEE(ITHE)+FAC*P(I1,4)*P(I2,4) - 590 CONTINUE - 600 CONTINUE - DO 610 J=1,25 - FE1EC(J)=FE1EC(J)+FEVEE(J) - FE2EC(J)=FE2EC(J)+FEVEE(J)**2 - FE1EC(51-J)=FE1EC(51-J)+FEVEE(51-J) - FE2EC(51-J)=FE2EC(51-J)+FEVEE(51-J)**2 - FE1EA(J)=FE1EA(J)+(FEVEE(51-J)-FEVEE(J)) - FE2EA(J)=FE2EA(J)+(FEVEE(51-J)-FEVEE(J))**2 - 610 CONTINUE - MSTU(62)=NUPP-NLOW - -C...Write statistics on Energy-Energy Correlation. - ELSEIF(MTABU.EQ.42) THEN - FAC=1./MAX(1,NEVEE) - WRITE(MSTU(11),5700) NEVEE - DO 620 J=1,25 - FEEC1=FAC*FE1EC(J) - FEES1=SQRT(MAX(0.D0,FAC*(FAC*FE2EC(J)-FEEC1**2))) - FEEC2=FAC*FE1EC(51-J) - FEES2=SQRT(MAX(0.D0,FAC*(FAC*FE2EC(51-J)-FEEC2**2))) - FEECA=FAC*FE1EA(J) - FEESA=SQRT(MAX(0.D0,FAC*(FAC*FE2EA(J)-FEECA**2))) - WRITE(MSTU(11),5800) 3.6*(J-1),3.6*J,FEEC1,FEES1,FEEC2,FEES2, - & FEECA,FEESA - 620 CONTINUE - -C...Copy statistics on Energy-Energy Correlation into /LUJETS/. - ELSEIF(MTABU.EQ.43) THEN - FAC=1./MAX(1,NEVEE) - DO 630 I=1,25 - K(I,1)=32 - K(I,2)=99 - K(I,3)=0 - K(I,4)=0 - K(I,5)=0 - P(I,1)=FAC*FE1EC(I) - V(I,1)=SQRT(MAX(0.D0,FAC*(FAC*FE2EC(I)-P(I,1)**2))) - P(I,2)=FAC*FE1EC(51-I) - V(I,2)=SQRT(MAX(0.D0,FAC*(FAC*FE2EC(51-I)-P(I,2)**2))) - P(I,3)=FAC*FE1EA(I) - V(I,3)=SQRT(MAX(0.D0,FAC*(FAC*FE2EA(I)-P(I,3)**2))) - P(I,4)=PARU(1)*(I-1)/50. - P(I,5)=PARU(1)*I/50. - V(I,4)=3.6*(I-1) - V(I,5)=3.6*I - 630 CONTINUE - N=25 - DO 640 J=1,5 - K(N+1,J)=0 - P(N+1,J)=0. - V(N+1,J)=0. - 640 CONTINUE - K(N+1,1)=32 - K(N+1,2)=99 - K(N+1,5)=NEVEE - MSTU(3)=1 - -C...Reset statistics on decay channels. - ELSEIF(MTABU.EQ.50) THEN - NEVDC=0 - NKFDC=0 - NREDC=0 - -C...Identify and order flavour content of final state. - ELSEIF(MTABU.EQ.51) THEN - NEVDC=NEVDC+1 - NDS=0 - DO 670 I=1,N - IF(K(I,1).LE.0.OR.K(I,1).GE.6) GOTO 670 - NDS=NDS+1 - IF(NDS.GT.8) THEN - NREDC=NREDC+1 - RETURN - ENDIF - KFM=2*IABS(K(I,2)) - IF(K(I,2).LT.0) KFM=KFM-1 - DO 650 IDS=NDS-1,1,-1 - IIN=IDS+1 - IF(KFM.LT.KFDM(IDS)) GOTO 660 - KFDM(IDS+1)=KFDM(IDS) - 650 CONTINUE - IIN=1 - 660 KFDM(IIN)=KFM - 670 CONTINUE - -C...Find whether old or new final state. - DO 690 IDC=1,NKFDC - IF(NDS.LT.KFDC(IDC,0)) THEN - IKFDC=IDC - GOTO 700 - ELSEIF(NDS.EQ.KFDC(IDC,0)) THEN - DO 680 I=1,NDS - IF(KFDM(I).LT.KFDC(IDC,I)) THEN - IKFDC=IDC - GOTO 700 - ELSEIF(KFDM(I).GT.KFDC(IDC,I)) THEN - GOTO 690 - ENDIF - 680 CONTINUE - IKFDC=-IDC - GOTO 700 - ENDIF - 690 CONTINUE - IKFDC=NKFDC+1 - 700 IF(IKFDC.LT.0) THEN - IKFDC=-IKFDC - ELSEIF(NKFDC.GE.200) THEN - NREDC=NREDC+1 - RETURN - ELSE - DO 720 IDC=NKFDC,IKFDC,-1 - NPDC(IDC+1)=NPDC(IDC) - DO 710 I=0,8 - KFDC(IDC+1,I)=KFDC(IDC,I) - 710 CONTINUE - 720 CONTINUE - NKFDC=NKFDC+1 - KFDC(IKFDC,0)=NDS - DO 730 I=1,NDS - KFDC(IKFDC,I)=KFDM(I) - 730 CONTINUE - NPDC(IKFDC)=0 - ENDIF - NPDC(IKFDC)=NPDC(IKFDC)+1 - -C...Write statistics on decay channels. - ELSEIF(MTABU.EQ.52) THEN - FAC=1./MAX(1,NEVDC) - WRITE(MSTU(11),5900) NEVDC - DO 750 IDC=1,NKFDC - DO 740 I=1,KFDC(IDC,0) - KFM=KFDC(IDC,I) - KF=(KFM+1)/2 - IF(2*KF.NE.KFM) KF=-KF - CALL LUNAME(KF,CHAU) - CHDC(I)=CHAU(1:12) - IF(CHAU(13:13).NE.' ') CHDC(I)(12:12)='?' - 740 CONTINUE - WRITE(MSTU(11),6000) FAC*NPDC(IDC),(CHDC(I),I=1,KFDC(IDC,0)) - 750 CONTINUE - IF(NREDC.NE.0) WRITE(MSTU(11),6100) FAC*NREDC - -C...Copy statistics on decay channels into /LUJETS/. - ELSEIF(MTABU.EQ.53) THEN - FAC=1./MAX(1,NEVDC) - DO 780 IDC=1,NKFDC - K(IDC,1)=32 - K(IDC,2)=99 - K(IDC,3)=0 - K(IDC,4)=0 - K(IDC,5)=KFDC(IDC,0) - DO 760 J=1,5 - P(IDC,J)=0. - V(IDC,J)=0. - 760 CONTINUE - DO 770 I=1,KFDC(IDC,0) - KFM=KFDC(IDC,I) - KF=(KFM+1)/2 - IF(2*KF.NE.KFM) KF=-KF - IF(I.LE.5) P(IDC,I)=KF - IF(I.GE.6) V(IDC,I-5)=KF - 770 CONTINUE - V(IDC,5)=FAC*NPDC(IDC) - 780 CONTINUE - N=NKFDC - DO 790 J=1,5 - K(N+1,J)=0 - P(N+1,J)=0. - V(N+1,J)=0. - 790 CONTINUE - K(N+1,1)=32 - K(N+1,2)=99 - K(N+1,5)=NEVDC - V(N+1,5)=FAC*NREDC - MSTU(3)=1 - ENDIF - -C...Format statements for output on unit MSTU(11) (default 6). - 5000 FORMAT(///20X,'Event statistics - initial state'/ - &20X,'based on an analysis of ',I6,' events'// - &3X,'Main flavours after',8X,'Fraction',4X,'Subfractions ', - &'according to fragmenting system multiplicity'/ - &4X,'hard interaction',24X,'1',7X,'2',7X,'3',7X,'4',7X,'5', - &6X,'6-7',5X,'8-10',3X,'11-15',3X,'16-25',4X,'>25'/) - 5100 FORMAT(3X,A12,1X,A12,F10.5,1X,10F8.4) - 5200 FORMAT(///20X,'Event statistics - final state'/ - &20X,'based on an analysis of ',I7,' events'// - &5X,'Mean primary multiplicity =',F10.4/ - &5X,'Mean final multiplicity =',F10.4/ - &5X,'Mean charged multiplicity =',F10.4// - &5X,'Number of particles produced per event (directly and via ', - &'decays/branchings)'/ - &5X,'KF Particle/jet MDCY',10X,'Particles',13X,'Antiparticles', - &8X,'Total'/35X,'prim seco prim seco'/) - 5300 FORMAT(1X,I6,4X,A16,I2,5(1X,F11.6)) - 5400 FORMAT(///20X,'Factorial moments analysis of multiplicity'/ - &20X,'based on an analysis of ',I6,' events'// - &3X,'delta-',A3,' delta-phi /bin',10X,'',18X,'', - &18X,'',18X,''/35X,4(' value error ')) - 5500 FORMAT(10X) - 5600 FORMAT(2X,2F10.4,F12.4,4(F12.4,F10.4)) - 5700 FORMAT(///20X,'Energy-Energy Correlation and Asymmetry'/ - &20X,'based on an analysis of ',I6,' events'// - &2X,'theta range',8X,'EEC(theta)',8X,'EEC(180-theta)',7X, - &'EECA(theta)'/2X,'in degrees ',3(' value error')/) - 5800 FORMAT(2X,F4.1,' - ',F4.1,3(F11.4,F9.4)) - 5900 FORMAT(///20X,'Decay channel analysis - final state'/ - &20X,'based on an analysis of ',I6,' events'// - &2X,'Probability',10X,'Complete final state'/) - 6000 FORMAT(2X,F9.5,5X,8(A12,1X)) - 6100 FORMAT(2X,F9.5,5X,'into other channels (more than 8 particles ', - &'or table overflow)') - - RETURN - END - -C********************************************************************* - -CDECK ID>, LUEEVT - SUBROUTINE LUEEVT(KFL,ECM) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to handle the generation of an e+e- annihilation jet event. -C IMPLICIT DOUBLE PRECISION(D) - COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ - -C...Check input parameters. - IF(MSTU(12).GE.1) CALL LULIST(0) - IF(KFL.LT.0.OR.KFL.GT.8) THEN - CALL LUERRM(16,'(LUEEVT:) called with unknown flavour code') - IF(MSTU(21).GE.1) RETURN - ENDIF - IF(KFL.LE.5) ECMMIN=PARJ(127)+2.02*PARF(100+MAX(1,KFL)) - IF(KFL.GE.6) ECMMIN=PARJ(127)+2.02*PMAS(KFL,1) - IF(ECM.LT.ECMMIN) THEN - CALL LUERRM(16,'(LUEEVT:) called with too small CM energy') - IF(MSTU(21).GE.1) RETURN - ENDIF - -C...Check consistency of MSTJ options set. - IF(MSTJ(109).EQ.2.AND.MSTJ(110).NE.1) THEN - CALL LUERRM(6, - & '(LUEEVT:) MSTJ(109) value requires MSTJ(110) = 1') - MSTJ(110)=1 - ENDIF - IF(MSTJ(109).EQ.2.AND.MSTJ(111).NE.0) THEN - CALL LUERRM(6, - & '(LUEEVT:) MSTJ(109) value requires MSTJ(111) = 0') - MSTJ(111)=0 - ENDIF - -C...Initialize alpha_strong and total cross-section. - MSTU(111)=MSTJ(108) - IF(MSTJ(108).EQ.2.AND.(MSTJ(101).EQ.0.OR.MSTJ(101).EQ.1)) - &MSTU(111)=1 - PARU(112)=PARJ(121) - IF(MSTU(111).EQ.2) PARU(112)=PARJ(122) - IF(MSTJ(116).GT.0.AND.(MSTJ(116).GE.2.OR.ABS(ECM-PARJ(151)).GE. - &PARJ(139).OR.10*MSTJ(102)+KFL.NE.MSTJ(119))) CALL LUXTOT(KFL,ECM, - &XTOT) - IF(MSTJ(116).GE.3) MSTJ(116)=1 - PARJ(171)=0. - -C...Add initial e+e- to event record (documentation only). - NTRY=0 - 100 NTRY=NTRY+1 - IF(NTRY.GT.100) THEN - CALL LUERRM(14,'(LUEEVT:) caught in an infinite loop') - RETURN - ENDIF - MSTU(24)=0 - NC=0 - IF(MSTJ(115).GE.2) THEN - NC=NC+2 - CALL LU1ENT(NC-1,11,0.5*ECM,0.D0,0.D0) - K(NC-1,1)=21 - CALL LU1ENT(NC,-11,0.5*ECM,PARU(1),0.D0) - K(NC,1)=21 - ENDIF - -C...Radiative photon (in initial state). - MK=0 - ECMC=ECM - IF(MSTJ(107).GE.1.AND.MSTJ(116).GE.1) CALL LURADK(ECM,MK,PAK, - &THEK,PHIK,ALPK) - IF(MK.EQ.1) ECMC=SQRT(ECM*(ECM-2.*PAK)) - IF(MSTJ(115).GE.1.AND.MK.EQ.1) THEN - NC=NC+1 - CALL LU1ENT(NC,22,PAK,THEK,PHIK) - K(NC,3)=MIN(MSTJ(115)/2,1) - ENDIF - -C...Virtual exchange boson (gamma or Z0). - IF(MSTJ(115).GE.3) THEN - NC=NC+1 - KF=22 - IF(MSTJ(102).EQ.2) KF=23 - MSTU10=MSTU(10) - MSTU(10)=1 - P(NC,5)=ECMC - CALL LU1ENT(NC,KF,ECMC,0.D0,0.D0) - K(NC,1)=21 - K(NC,3)=1 - MSTU(10)=MSTU10 - ENDIF - -C...Choice of flavour and jet configuration. - CALL LUXKFL(KFL,ECM,ECMC,KFLC) - IF(KFLC.EQ.0) GOTO 100 - CALL LUXJET(ECMC,NJET,CUT) - KFLN=21 - IF(NJET.EQ.4) CALL LUX4JT(NJET,CUT,KFLC,ECMC,KFLN,X1,X2,X4, - &X12,X14) - IF(NJET.EQ.3) CALL LUX3JT(NJET,CUT,KFLC,ECMC,X1,X3) - IF(NJET.EQ.2) MSTJ(120)=1 - -C...Fill jet configuration and origin. - IF(NJET.EQ.2.AND.MSTJ(101).NE.5) CALL LU2ENT(NC+1,KFLC,-KFLC,ECMC) - IF(NJET.EQ.2.AND.MSTJ(101).EQ.5) CALL LU2ENT(-(NC+1),KFLC,-KFLC, - &ECMC) - IF(NJET.EQ.3) CALL LU3ENT(NC+1,KFLC,21,-KFLC,ECMC,X1,X3) - IF(NJET.EQ.4.AND.KFLN.EQ.21) CALL LU4ENT(NC+1,KFLC,KFLN,KFLN, - &-KFLC,ECMC,X1,X2,X4,X12,X14) - IF(NJET.EQ.4.AND.KFLN.NE.21) CALL LU4ENT(NC+1,KFLC,-KFLN,KFLN, - &-KFLC,ECMC,X1,X2,X4,X12,X14) - IF(MSTU(24).NE.0) GOTO 100 - DO 110 IP=NC+1,N - K(IP,3)=K(IP,3)+MIN(MSTJ(115)/2,1)+(MSTJ(115)/3)*(NC-1) - 110 CONTINUE - -C...Angular orientation according to matrix element. - IF(MSTJ(106).EQ.1) THEN - CALL LUXDIF(NC,NJET,KFLC,ECMC,CHI,THE,PHI) - CALL LUDBRB(NC+1,N,0.D0,CHI,0D0,0D0,0D0) - CALL LUDBRB(NC+1,N,THE,PHI,0D0,0D0,0D0) - ENDIF - -C...Rotation and boost from radiative photon. - IF(MK.EQ.1) THEN - DBEK=-PAK/(ECM-PAK) - NMIN=NC+1-MSTJ(115)/3 - CALL LUDBRB(NMIN,N,0.D0,-PHIK,0D0,0D0,0D0) - CALL LUDBRB(NMIN,N,ALPK,0.D0,DBEK*SIN(THEK),0D0,DBEK*COS(THEK)) - CALL LUDBRB(NMIN,N,0.D0,PHIK,0D0,0D0,0D0) - ENDIF - -C...Generate parton shower. Rearrange along strings and check. - IF(MSTJ(101).EQ.5) THEN - CALL LUSHOW(N-1,N,ECMC) - MSTJ14=MSTJ(14) - IF(MSTJ(105).EQ.-1) MSTJ(14)=-1 - IF(MSTJ(105).GE.0) MSTU(28)=0 - CALL LUPREP(0) - MSTJ(14)=MSTJ14 - IF(MSTJ(105).GE.0.AND.MSTU(28).NE.0) GOTO 100 - ENDIF - -C...Fragmentation/decay generation. Information for LUTABU. - IF(MSTJ(105).EQ.1) CALL LUEXEC - MSTU(161)=KFLC - MSTU(162)=-KFLC - - RETURN - END - -C********************************************************************* - -CDECK ID>, LUXTOT - SUBROUTINE LUXTOT(KFL,ECM,XTOT) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to calculate total cross-section, including initial -C...state radiation effects. - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - SAVE /LUDAT1/,/LUDAT2/ - -C...Status, (optimized) Q^2 scale, alpha_strong. - PARJ(151)=ECM - MSTJ(119)=10*MSTJ(102)+KFL - IF(MSTJ(111).EQ.0) THEN - Q2R=ECM**2 - ELSEIF(MSTU(111).EQ.0) THEN - PARJ(168)=MIN(1.D0,MAX(PARJ(128),EXP(-12.*PARU(1)/ - & ((33.-2.*MSTU(112))*PARU(111))))) - Q2R=PARJ(168)*ECM**2 - ELSE - PARJ(168)=MIN(1.D0,MAX(PARJ(128),PARU(112)/ECM, - & (2.*PARU(112)/ECM)**2)) - Q2R=PARJ(168)*ECM**2 - ENDIF - ALSPI=ULALPS(Q2R)/PARU(1) - -C...QCD corrections factor in R. - IF(MSTJ(101).EQ.0.OR.MSTJ(109).EQ.1) THEN - RQCD=1. - ELSEIF(IABS(MSTJ(101)).EQ.1.AND.MSTJ(109).EQ.0) THEN - RQCD=1.+ALSPI - ELSEIF(MSTJ(109).EQ.0) THEN - RQCD=1.+ALSPI+(1.986-0.115*MSTU(118))*ALSPI**2 - IF(MSTJ(111).EQ.1) RQCD=MAX(1.D0,RQCD+(33.-2.*MSTU(112))/12.* - & LOG(PARJ(168))*ALSPI**2) - ELSEIF(IABS(MSTJ(101)).EQ.1) THEN - RQCD=1.+(3./4.)*ALSPI - ELSE - RQCD=1.+(3./4.)*ALSPI-(3./32.+0.519*MSTU(118))*ALSPI**2 - ENDIF - -C...Calculate Z0 width if default value not acceptable. - IF(MSTJ(102).GE.3) THEN - RVA=3.*(3.+(4.*PARU(102)-1.)**2)+6.*RQCD*(2.+(1.-8.*PARU(102)/ - & 3.)**2+(4.*PARU(102)/3.-1.)**2) - DO 100 KFLC=5,6 - VQ=1. - IF(MOD(MSTJ(103),2).EQ.1) VQ=SQRT(MAX(0.D0,1.-(2.*ULMASS(KFLC)/ - & ECM)**2)) - IF(KFLC.EQ.5) VF=4.*PARU(102)/3.-1. - IF(KFLC.EQ.6) VF=1.-8.*PARU(102)/3. - RVA=RVA+3.*RQCD*(0.5*VQ*(3.-VQ**2)*VF**2+VQ**3) - 100 CONTINUE - PARJ(124)=PARU(101)*PARJ(123)*RVA/(48.*PARU(102)*(1.-PARU(102))) - ENDIF - -C...Calculate propagator and related constants for QFD case. - POLL=1.-PARJ(131)*PARJ(132) - IF(MSTJ(102).GE.2) THEN - SFF=1./(16.*PARU(102)*(1.-PARU(102))) - SFW=ECM**4/((ECM**2-PARJ(123)**2)**2+(PARJ(123)*PARJ(124))**2) - SFI=SFW*(1.-(PARJ(123)/ECM)**2) - VE=4.*PARU(102)-1. - SF1I=SFF*(VE*POLL+PARJ(132)-PARJ(131)) - SF1W=SFF**2*((VE**2+1.)*POLL+2.*VE*(PARJ(132)-PARJ(131))) - HF1I=SFI*SF1I - HF1W=SFW*SF1W - ENDIF - -C...Loop over different flavours: charge, velocity. - RTOT=0. - RQQ=0. - RQV=0. - RVA=0. - DO 110 KFLC=1,MAX(MSTJ(104),KFL) - IF(KFL.GT.0.AND.KFLC.NE.KFL) GOTO 110 - MSTJ(93)=1 - PMQ=ULMASS(KFLC) - IF(ECM.LT.2.*PMQ+PARJ(127)) GOTO 110 - QF=KCHG(KFLC,1)/3. - VQ=1. - IF(MOD(MSTJ(103),2).EQ.1) VQ=SQRT(1.-(2.*PMQ/ECM)**2) - -C...Calculate R and sum of charges for QED or QFD case. - RQQ=RQQ+3.*QF**2*POLL - IF(MSTJ(102).LE.1) THEN - RTOT=RTOT+3.*0.5*VQ*(3.-VQ**2)*QF**2*POLL - ELSE - VF=SIGN(1.D0,QF)-4.*QF*PARU(102) - RQV=RQV-6.*QF*VF*SF1I - RVA=RVA+3.*(VF**2+1.)*SF1W - RTOT=RTOT+3.*(0.5*VQ*(3.-VQ**2)*(QF**2*POLL-2.*QF*VF*HF1I+ - & VF**2*HF1W)+VQ**3*HF1W) - ENDIF - 110 CONTINUE - RSUM=RQQ - IF(MSTJ(102).GE.2) RSUM=RQQ+SFI*RQV+SFW*RVA - -C...Calculate cross-section, including QCD corrections. - PARJ(141)=RQQ - PARJ(142)=RTOT - PARJ(143)=RTOT*RQCD - PARJ(144)=PARJ(143) - PARJ(145)=PARJ(141)*86.8/ECM**2 - PARJ(146)=PARJ(142)*86.8/ECM**2 - PARJ(147)=PARJ(143)*86.8/ECM**2 - PARJ(148)=PARJ(147) - PARJ(157)=RSUM*RQCD - PARJ(158)=0. - PARJ(159)=0. - XTOT=PARJ(147) - IF(MSTJ(107).LE.0) RETURN - -C...Virtual cross-section. - XKL=PARJ(135) - XKU=MIN(PARJ(136),1.-(2.*PARJ(127)/ECM)**2) - ALE=2.*LOG(ECM/ULMASS(11))-1. - SIGV=ALE/3.+2.*LOG(ECM**2/(ULMASS(13)*ULMASS(15)))/3.-4./3.+ - &1.526*LOG(ECM**2/0.932) - -C...Soft and hard radiative cross-section in QED case. - IF(MSTJ(102).LE.1) THEN - SIGV=1.5*ALE-0.5+PARU(1)**2/3.+2.*SIGV - SIGS=ALE*(2.*LOG(XKL)-LOG(1.-XKL)-XKL) - SIGH=ALE*(2.*LOG(XKU/XKL)-LOG((1.-XKU)/(1.-XKL))-(XKU-XKL)) - -C...Soft and hard radiative cross-section in QFD case. - ELSE - SZM=1.-(PARJ(123)/ECM)**2 - SZW=PARJ(123)*PARJ(124)/ECM**2 - PARJ(161)=-RQQ/RSUM - PARJ(162)=-(RQQ+RQV+RVA)/RSUM - PARJ(163)=(RQV*(1.-0.5*SZM-SFI)+RVA*(1.5-SZM-SFW))/RSUM - PARJ(164)=(RQV*SZW**2*(1.-2.*SFW)+RVA*(2.*SFI+SZW**2-4.+3.*SZM- - & SZM**2))/(SZW*RSUM) - SIGV=1.5*ALE-0.5+PARU(1)**2/3.+((2.*RQQ+SFI*RQV)/RSUM)*SIGV+ - & (SZW*SFW*RQV/RSUM)*PARU(1)*20./9. - SIGS=ALE*(2.*LOG(XKL)+PARJ(161)*LOG(1.-XKL)+PARJ(162)*XKL+ - & PARJ(163)*LOG(((XKL-SZM)**2+SZW**2)/(SZM**2+SZW**2))+ - & PARJ(164)*(ATAN((XKL-SZM)/SZW)-ATAN(-SZM/SZW))) - SIGH=ALE*(2.*LOG(XKU/XKL)+PARJ(161)*LOG((1.-XKU)/(1.-XKL))+ - & PARJ(162)*(XKU-XKL)+PARJ(163)*LOG(((XKU-SZM)**2+SZW**2)/ - & ((XKL-SZM)**2+SZW**2))+PARJ(164)*(ATAN((XKU-SZM)/SZW)- - & ATAN((XKL-SZM)/SZW))) - ENDIF - -C...Total cross-section and fraction of hard photon events. - PARJ(160)=SIGH/(PARU(1)/PARU(101)+SIGV+SIGS+SIGH) - PARJ(157)=RSUM*(1.+(PARU(101)/PARU(1))*(SIGV+SIGS+SIGH))*RQCD - PARJ(144)=PARJ(157) - PARJ(148)=PARJ(144)*86.8/ECM**2 - XTOT=PARJ(148) - - RETURN - END - -C********************************************************************* - -CDECK ID>, LURADK - SUBROUTINE LURADK(ECM,MK,PAK,THEK,PHIK,ALPK) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to generate initial state photon radiation. - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - SAVE /LUDAT1/ - -C...Function: cumulative hard photon spectrum in QFD case. - FXK(XX)=2.*LOG(XX)+PARJ(161)*LOG(1.-XX)+PARJ(162)*XX+ - &PARJ(163)*LOG((XX-SZM)**2+SZW**2)+PARJ(164)*ATAN((XX-SZM)/SZW) - -C...Determine whether radiative photon or not. - MK=0 - PAK=0. - IF(PARJ(160).LT.RLU(0)) RETURN - MK=1 - -C...Photon energy range. Find photon momentum in QED case. - XKL=PARJ(135) - XKU=MIN(PARJ(136),1.-(2.*PARJ(127)/ECM)**2) - IF(MSTJ(102).LE.1) THEN - 100 XK=1./(1.+(1./XKL-1.)*((1./XKU-1.)/(1./XKL-1.))**RLU(0)) - IF(1.+(1.-XK)**2.LT.2.*RLU(0)) GOTO 100 - -C...Ditto in QFD case, by numerical inversion of integrated spectrum. - ELSE - SZM=1.-(PARJ(123)/ECM)**2 - SZW=PARJ(123)*PARJ(124)/ECM**2 - FXKL=FXK(XKL) - FXKU=FXK(XKU) - FXKD=1D-4*(FXKU-FXKL) - FXKR=FXKL+RLU(0)*(FXKU-FXKL) - NXK=0 - 110 NXK=NXK+1 - XK=0.5*(XKL+XKU) - FXKV=FXK(XK) - IF(FXKV.GT.FXKR) THEN - XKU=XK - FXKU=FXKV - ELSE - XKL=XK - FXKL=FXKV - ENDIF - IF(NXK.LT.15.AND.FXKU-FXKL.GT.FXKD) GOTO 110 - XK=XKL+(XKU-XKL)*(FXKR-FXKL)/(FXKU-FXKL) - ENDIF - PAK=0.5*ECM*XK - -C...Photon polar and azimuthal angle. - PME=2.*(ULMASS(11)/ECM)**2 - 120 CTHM=PME*(2./PME)**RLU(0) - IF(1.-(XK**2*CTHM*(1.-0.5*CTHM)+2.*(1.-XK)*PME/MAX(PME, - &CTHM*(1.-0.5*CTHM)))/(1.+(1.-XK)**2).LT.RLU(0)) GOTO 120 - CTHE=1.-CTHM - IF(RLU(0).GT.0.5) CTHE=-CTHE - STHE=SQRT(MAX(0.D0,(CTHM-PME)*(2.-CTHM))) - THEK=ULANGL(CTHE,STHE) - PHIK=PARU(2)*RLU(0) - -C...Rotation angle for hadronic system. - SGN=1. - IF(0.5*(2.-XK*(1.-CTHE))**2/((2.-XK)**2+(XK*CTHE)**2).GT. - &RLU(0)) SGN=-1. - ALPK=ASIN(SGN*STHE*(XK-SGN*(2.*SQRT(1.-XK)-2.+XK)*CTHE)/ - &(2.-XK*(1.-SGN*CTHE))) - - RETURN - END - -C********************************************************************* - -CDECK ID>, LUXKFL - SUBROUTINE LUXKFL(KFL,ECM,ECMC,KFLC) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to select flavour for produced qqbar pair. - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - SAVE /LUDAT1/,/LUDAT2/ - -C...Calculate maximum weight in QED or QFD case. - IF(MSTJ(102).LE.1) THEN - RFMAX=4./9. - ELSE - POLL=1.-PARJ(131)*PARJ(132) - SFF=1./(16.*PARU(102)*(1.-PARU(102))) - SFW=ECMC**4/((ECMC**2-PARJ(123)**2)**2+(PARJ(123)*PARJ(124))**2) - SFI=SFW*(1.-(PARJ(123)/ECMC)**2) - VE=4.*PARU(102)-1. - HF1I=SFI*SFF*(VE*POLL+PARJ(132)-PARJ(131)) - HF1W=SFW*SFF**2*((VE**2+1.)*POLL+2.*VE*(PARJ(132)-PARJ(131))) - RFMAX=MAX(4./9.*POLL-4./3.*(1.-8.*PARU(102)/3.)*HF1I+ - & ((1.-8.*PARU(102)/3.)**2+1.)*HF1W,1./9.*POLL+2./3.* - & (-1.+4.*PARU(102)/3.)*HF1I+((-1.+4.*PARU(102)/3.)**2+1.)*HF1W) - ENDIF - -C...Choose flavour. Gives charge and velocity. - NTRY=0 - 100 NTRY=NTRY+1 - IF(NTRY.GT.100) THEN - CALL LUERRM(14,'(LUXKFL:) caught in an infinite loop') - KFLC=0 - RETURN - ENDIF - KFLC=KFL - IF(KFL.LE.0) KFLC=1+INT(MSTJ(104)*RLU(0)) - MSTJ(93)=1 - PMQ=ULMASS(KFLC) - IF(ECM.LT.2.*PMQ+PARJ(127)) GOTO 100 - QF=KCHG(KFLC,1)/3. - VQ=1. - IF(MOD(MSTJ(103),2).EQ.1) VQ=SQRT(MAX(0.D0,1.-(2.*PMQ/ECMC)**2)) - -C...Calculate weight in QED or QFD case. - IF(MSTJ(102).LE.1) THEN - RF=QF**2 - RFV=0.5*VQ*(3.-VQ**2)*QF**2 - ELSE - VF=SIGN(1.D0,QF)-4.*QF*PARU(102) - RF=QF**2*POLL-2.*QF*VF*HF1I+(VF**2+1.)*HF1W - RFV=0.5*VQ*(3.-VQ**2)*(QF**2*POLL-2.*QF*VF*HF1I+VF**2*HF1W)+ - & VQ**3*HF1W - IF(RFV.GT.0.) PARJ(171)=MIN(1.D0,VQ**3*HF1W/RFV) - ENDIF - -C...Weighting or new event (radiative photon). Cross-section update. - IF(KFL.LE.0.AND.RF.LT.RLU(0)*RFMAX) GOTO 100 - PARJ(158)=PARJ(158)+1. - IF(ECMC.LT.2.*PMQ+PARJ(127).OR.RFV.LT.RLU(0)*RF) KFLC=0 - IF(MSTJ(107).LE.0.AND.KFLC.EQ.0) GOTO 100 - IF(KFLC.NE.0) PARJ(159)=PARJ(159)+1. - PARJ(144)=PARJ(157)*PARJ(159)/PARJ(158) - PARJ(148)=PARJ(144)*86.8/ECM**2 - - RETURN - END - -C********************************************************************* - -CDECK ID>, LUXJET - SUBROUTINE LUXJET(ECM,NJET,CUT) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to select number of jets in matrix element approach. - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - SAVE /LUDAT1/ - DIMENSION ZHUT(5) - -C...Relative three-jet rate in Zhu second order parametrization. - DATA ZHUT/3.0922, 6.2291, 7.4782, 7.8440, 8.2560/ - -C...Trivial result for two-jets only, including parton shower. - IF(MSTJ(101).EQ.0.OR.MSTJ(101).EQ.5) THEN - CUT=0. - -C...QCD and Abelian vector gluon theory: Q^2 for jet rate and R. - ELSEIF(MSTJ(109).EQ.0.OR.MSTJ(109).EQ.2) THEN - CF=4./3. - IF(MSTJ(109).EQ.2) CF=1. - IF(MSTJ(111).EQ.0) THEN - Q2=ECM**2 - Q2R=ECM**2 - ELSEIF(MSTU(111).EQ.0) THEN - PARJ(169)=MIN(1.D0,PARJ(129)) - Q2=PARJ(169)*ECM**2 - PARJ(168)=MIN(1.D0,MAX(PARJ(128),EXP(-12.*PARU(1)/ - & ((33.-2.*MSTU(112))*PARU(111))))) - Q2R=PARJ(168)*ECM**2 - ELSE - PARJ(169)=MIN(1.D0,MAX(PARJ(129),(2.*PARU(112)/ECM)**2)) - Q2=PARJ(169)*ECM**2 - PARJ(168)=MIN(1.D0,MAX(PARJ(128),PARU(112)/ECM, - & (2.*PARU(112)/ECM)**2)) - Q2R=PARJ(168)*ECM**2 - ENDIF - -C...alpha_strong for R and R itself. - ALSPI=(3./4.)*CF*ULALPS(Q2R)/PARU(1) - IF(IABS(MSTJ(101)).EQ.1) THEN - RQCD=1.+ALSPI - ELSEIF(MSTJ(109).EQ.0) THEN - RQCD=1.+ALSPI+(1.986-0.115*MSTU(118))*ALSPI**2 - IF(MSTJ(111).EQ.1) RQCD=MAX(1.D0,RQCD+(33.-2.*MSTU(112))/12.* - & LOG(PARJ(168))*ALSPI**2) - ELSE - RQCD=1.+ALSPI-(3./32.+0.519*MSTU(118))*(4.*ALSPI/3.)**2 - ENDIF - -C...alpha_strong for jet rate. Initial value for y cut. - ALSPI=(3./4.)*CF*ULALPS(Q2)/PARU(1) - CUT=MAX(0.001D0,PARJ(125),(PARJ(126)/ECM)**2) - IF(IABS(MSTJ(101)).LE.1.OR.(MSTJ(109).EQ.0.AND.MSTJ(111).EQ.0)) - & CUT=MAX(CUT,EXP(-SQRT(0.75/ALSPI))/2.) - IF(MSTJ(110).EQ.2) CUT=MAX(0.01D0,MIN(0.05D0,CUT)) - -C...Parametrization of first order three-jet cross-section. - 100 IF(MSTJ(101).EQ.0.OR.CUT.GE.0.25) THEN - PARJ(152)=0. - ELSE - PARJ(152)=(2.*ALSPI/3.)*((3.-6.*CUT+2.*LOG(CUT))* - & LOG(CUT/(1.-2.*CUT))+(2.5+1.5*CUT-6.571)*(1.-3.*CUT)+ - & 5.833*(1.-3.*CUT)**2-3.894*(1.-3.*CUT)**3+ - & 1.342*(1.-3.*CUT)**4)/RQCD - IF(MSTJ(109).EQ.2.AND.(MSTJ(101).EQ.2.OR.MSTJ(101).LE.-2)) - & PARJ(152)=0. - ENDIF - -C...Parametrization of second order three-jet cross-section. - IF(IABS(MSTJ(101)).LE.1.OR.MSTJ(101).EQ.3.OR.MSTJ(109).EQ.2.OR. - & CUT.GE.0.25) THEN - PARJ(153)=0. - ELSEIF(MSTJ(110).LE.1) THEN - CT=LOG(1./CUT-2.) - PARJ(153)=ALSPI**2*CT**2*(2.419+0.5989*CT+0.6782*CT**2- - & 0.2661*CT**3+0.01159*CT**4)/RQCD - -C...Interpolation in second/first order ratio for Zhu parametrization. - ELSEIF(MSTJ(110).EQ.2) THEN - IZA=0 - DO 110 IY=1,5 - IF(ABS(CUT-0.01*IY).LT.0.0001) IZA=IY - 110 CONTINUE - IF(IZA.NE.0) THEN - ZHURAT=ZHUT(IZA) - ELSE - IZ=100.*CUT - ZHURAT=ZHUT(IZ)+(100.*CUT-IZ)*(ZHUT(IZ+1)-ZHUT(IZ)) - ENDIF - PARJ(153)=ALSPI*PARJ(152)*ZHURAT - ENDIF - -C...Shift in second order three-jet cross-section with optimized Q^2. - IF(MSTJ(111).EQ.1.AND.IABS(MSTJ(101)).GE.2.AND.MSTJ(101).NE.3. - & AND.CUT.LT.0.25) PARJ(153)=PARJ(153)+(33.-2.*MSTU(112))/12.* - & LOG(PARJ(169))*ALSPI*PARJ(152) - -C...Parametrization of second order four-jet cross-section. - IF(IABS(MSTJ(101)).LE.1.OR.CUT.GE.0.125) THEN - PARJ(154)=0. - ELSE - CT=LOG(1./CUT-5.) - IF(CUT.LE.0.018) THEN - XQQGG=6.349-4.330*CT+0.8304*CT**2 - IF(MSTJ(109).EQ.2) XQQGG=(4./3.)**2*(3.035-2.091*CT+ - & 0.4059*CT**2) - XQQQQ=1.25*(-0.1080+0.01486*CT+0.009364*CT**2) - IF(MSTJ(109).EQ.2) XQQQQ=8.*XQQQQ - ELSE - XQQGG=-0.09773+0.2959*CT-0.2764*CT**2+0.08832*CT**3 - IF(MSTJ(109).EQ.2) XQQGG=(4./3.)**2*(-0.04079+0.1340*CT- - & 0.1326*CT**2+0.04365*CT**3) - XQQQQ=1.25*(0.003661-0.004888*CT-0.001081*CT**2+0.002093* - & CT**3) - IF(MSTJ(109).EQ.2) XQQQQ=8.*XQQQQ - ENDIF - PARJ(154)=ALSPI**2*CT**2*(XQQGG+XQQQQ)/RQCD - PARJ(155)=XQQQQ/(XQQGG+XQQQQ) - ENDIF - -C...If negative three-jet rate, change y' optimization parameter. - IF(MSTJ(111).EQ.1.AND.PARJ(152)+PARJ(153).LT.0..AND. - & PARJ(169).LT.0.99) THEN - PARJ(169)=MIN(1.D0,1.2*PARJ(169)) - Q2=PARJ(169)*ECM**2 - ALSPI=(3./4.)*CF*ULALPS(Q2)/PARU(1) - GOTO 100 - ENDIF - -C...If too high cross-section, use harder cuts, or fail. - IF(PARJ(152)+PARJ(153)+PARJ(154).GE.1) THEN - IF(MSTJ(110).EQ.2.AND.CUT.GT.0.0499.AND.MSTJ(111).EQ.1.AND. - & PARJ(169).LT.0.99) THEN - PARJ(169)=MIN(1.D0,1.2*PARJ(169)) - Q2=PARJ(169)*ECM**2 - ALSPI=(3./4.)*CF*ULALPS(Q2)/PARU(1) - GOTO 100 - ELSEIF(MSTJ(110).EQ.2.AND.CUT.GT.0.0499) THEN - CALL LUERRM(26, - & '(LUXJET:) no allowed y cut value for Zhu parametrization') - ENDIF - CUT=0.26*(4.*CUT)**(PARJ(152)+PARJ(153)+PARJ(154))**(-1./3.) - IF(MSTJ(110).EQ.2) CUT=MAX(0.01D0,MIN(0.05D0,CUT)) - GOTO 100 - ENDIF - -C...Scalar gluon (first order only). - ELSE - ALSPI=ULALPS(ECM**2)/PARU(1) - CUT=MAX(0.001D0,PARJ(125),(PARJ(126)/ECM)**2,EXP(-3./ALSPI)) - PARJ(152)=0. - IF(CUT.LT.0.25) PARJ(152)=(ALSPI/3.)*((1.-2.*CUT)* - & LOG((1.-2.*CUT)/CUT)+0.5*(9.*CUT**2-1.)) - PARJ(153)=0. - PARJ(154)=0. - ENDIF - -C...Select number of jets. - PARJ(150)=CUT - IF(MSTJ(101).EQ.0.OR.MSTJ(101).EQ.5) THEN - NJET=2 - ELSEIF(MSTJ(101).LE.0) THEN - NJET=MIN(4,2-MSTJ(101)) - ELSE - RNJ=RLU(0) - NJET=2 - IF(PARJ(152)+PARJ(153)+PARJ(154).GT.RNJ) NJET=3 - IF(PARJ(154).GT.RNJ) NJET=4 - ENDIF - - RETURN - END - -C********************************************************************* - -CDECK ID>, LUX3JT - SUBROUTINE LUX3JT(NJET,CUT,KFL,ECM,X1,X2) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to select the kinematical variables of three-jet events. - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - SAVE /LUDAT1/ - DIMENSION ZHUP(5,12) - -C...Coefficients of Zhu second order parametrization. - DATA ((ZHUP(IC1,IC2),IC2=1,12),IC1=1,5)/ - & 18.29, 89.56, 4.541, -52.09, -109.8, 24.90, - & 11.63, 3.683, 17.50, 0.002440, -1.362, -0.3537, - & 11.42, 6.299, -22.55, -8.915, 59.25, -5.855, - & -32.85, -1.054, -16.90, 0.006489, -0.8156, 0.01095, - & 7.847, -3.964, -35.83, 1.178, 29.39, 0.2806, - & 47.82, -12.36, -56.72, 0.04054, -0.4365, 0.6062, - & 5.441, -56.89, -50.27, 15.13, 114.3, -18.19, - & 97.05, -1.890, -139.9, 0.08153, -0.4984, 0.9439, - & -17.65, 51.44, -58.32, 70.95, -255.7, -78.99, - & 476.9, 29.65, -239.3, 0.4745, -1.174, 6.081/ - -C...Dilogarithm of x for x<0.5 (x>0.5 obtained by analytic trick). - DILOG(X)=X+X**2/4.+X**3/9.+X**4/16.+X**5/25.+X**6/36.+X**7/49. - -C...Event type. Mass effect factors and other common constants. - MSTJ(120)=2 - MSTJ(121)=0 - PMQ=ULMASS(KFL) - QME=(2.*PMQ/ECM)**2 - IF(MSTJ(109).NE.1) THEN - CUTL=LOG(CUT) - CUTD=LOG(1./CUT-2.) - IF(MSTJ(109).EQ.0) THEN - CF=4./3. - CN=3. - TR=2. - WTMX=MIN(20.D0,37.-6.*CUTD) - IF(MSTJ(110).EQ.2) WTMX=2.*(7.5+80.*CUT) - ELSE - CF=1. - CN=0. - TR=12. - WTMX=0. - ENDIF - -C...Alpha_strong and effects of optimized Q^2 scale. Maximum weight. - ALS2PI=PARU(118)/PARU(2) - WTOPT=0. - IF(MSTJ(111).EQ.1) WTOPT=(33.-2.*MSTU(112))/6.*LOG(PARJ(169))* - & ALS2PI - WTMAX=MAX(0.D0,1.+WTOPT+ALS2PI*WTMX) - -C...Choose three-jet events in allowed region. - 100 NJET=3 - 110 Y13L=CUTL+CUTD*RLU(0) - Y23L=CUTL+CUTD*RLU(0) - Y13=EXP(Y13L) - Y23=EXP(Y23L) - Y12=1.-Y13-Y23 - IF(Y12.LE.CUT) GOTO 110 - IF(Y13**2+Y23**2+2.*Y12.LE.2.*RLU(0)) GOTO 110 - -C...Second order corrections. - IF(MSTJ(101).EQ.2.AND.MSTJ(110).LE.1) THEN - Y12L=LOG(Y12) - Y13M=LOG(1.-Y13) - Y23M=LOG(1.-Y23) - Y12M=LOG(1.-Y12) - IF(Y13.LE.0.5) Y13I=DILOG(Y13) - IF(Y13.GE.0.5) Y13I=1.644934-Y13L*Y13M-DILOG(1.-Y13) - IF(Y23.LE.0.5) Y23I=DILOG(Y23) - IF(Y23.GE.0.5) Y23I=1.644934-Y23L*Y23M-DILOG(1.-Y23) - IF(Y12.LE.0.5) Y12I=DILOG(Y12) - IF(Y12.GE.0.5) Y12I=1.644934-Y12L*Y12M-DILOG(1.-Y12) - WT1=(Y13**2+Y23**2+2.*Y12)/(Y13*Y23) - WT2=CF*(-2.*(CUTL-Y12L)**2-3.*CUTL-1.+3.289868+ - & 2.*(2.*CUTL-Y12L)*CUT/Y12)+ - & CN*((CUTL-Y12L)**2-(CUTL-Y13L)**2-(CUTL-Y23L)**2-11.*CUTL/6.+ - & 67./18.+1.644934-(2.*CUTL-Y12L)*CUT/Y12+(2.*CUTL-Y13L)* - & CUT/Y13+(2.*CUTL-Y23L)*CUT/Y23)+ - & TR*(2.*CUTL/3.-10./9.)+ - & CF*(Y12/(Y12+Y13)+Y12/(Y12+Y23)+(Y12+Y23)/Y13+(Y12+Y13)/Y23+ - & Y13L*(4.*Y12**2+2.*Y12*Y13+4.*Y12*Y23+Y13*Y23)/(Y12+Y23)**2+ - & Y23L*(4.*Y12**2+2.*Y12*Y23+4.*Y12*Y13+Y13*Y23)/(Y12+Y13)**2)/ - & WT1+ - & CN*(Y13L*Y13/(Y12+Y23)+Y23L*Y23/(Y12+Y13))/WT1+ - & (CN-2.*CF)*((Y12**2+(Y12+Y13)**2)*(Y12L*Y23L-Y12L*Y12M-Y23L* - & Y23M+1.644934-Y12I-Y23I)/(Y13*Y23)+(Y12**2+(Y12+Y23)**2)* - & (Y12L*Y13L-Y12L*Y12M-Y13L*Y13M+1.644934-Y12I-Y13I)/ - & (Y13*Y23)+(Y13**2+Y23**2)/(Y13*Y23*(Y13+Y23))- - & 2.*Y12L*Y12**2/(Y13+Y23)**2-4.*Y12L*Y12/(Y13+Y23))/WT1- - & CN*(Y13L*Y23L-Y13L*Y13M-Y23L*Y23M+1.644934-Y13I-Y23I) - IF(1.+WTOPT+ALS2PI*WT2.LE.0.) MSTJ(121)=1 - IF(1.+WTOPT+ALS2PI*WT2.LE.WTMAX*RLU(0)) GOTO 110 - PARJ(156)=(WTOPT+ALS2PI*WT2)/(1.+WTOPT+ALS2PI*WT2) - - ELSEIF(MSTJ(101).EQ.2.AND.MSTJ(110).EQ.2) THEN -C...Second order corrections; Zhu parametrization of ERT. - ZX=(Y23-Y13)**2 - ZY=1.-Y12 - IZA=0 - DO 120 IY=1,5 - IF(ABS(CUT-0.01*IY).LT.0.0001) IZA=IY - 120 CONTINUE - IF(IZA.NE.0) THEN - IZ=IZA - WT2=ZHUP(IZ,1)+ZHUP(IZ,2)*ZX+ZHUP(IZ,3)*ZX**2+(ZHUP(IZ,4)+ - & ZHUP(IZ,5)*ZX)*ZY+(ZHUP(IZ,6)+ZHUP(IZ,7)*ZX)*ZY**2+ - & (ZHUP(IZ,8)+ZHUP(IZ,9)*ZX)*ZY**3+ZHUP(IZ,10)/(ZX-ZY**2)+ - & ZHUP(IZ,11)/(1.-ZY)+ZHUP(IZ,12)/ZY - ELSE - IZ=100.*CUT - WTL=ZHUP(IZ,1)+ZHUP(IZ,2)*ZX+ZHUP(IZ,3)*ZX**2+(ZHUP(IZ,4)+ - & ZHUP(IZ,5)*ZX)*ZY+(ZHUP(IZ,6)+ZHUP(IZ,7)*ZX)*ZY**2+ - & (ZHUP(IZ,8)+ZHUP(IZ,9)*ZX)*ZY**3+ZHUP(IZ,10)/(ZX-ZY**2)+ - & ZHUP(IZ,11)/(1.-ZY)+ZHUP(IZ,12)/ZY - IZ=IZ+1 - WTU=ZHUP(IZ,1)+ZHUP(IZ,2)*ZX+ZHUP(IZ,3)*ZX**2+(ZHUP(IZ,4)+ - & ZHUP(IZ,5)*ZX)*ZY+(ZHUP(IZ,6)+ZHUP(IZ,7)*ZX)*ZY**2+ - & (ZHUP(IZ,8)+ZHUP(IZ,9)*ZX)*ZY**3+ZHUP(IZ,10)/(ZX-ZY**2)+ - & ZHUP(IZ,11)/(1.-ZY)+ZHUP(IZ,12)/ZY - WT2=WTL+(WTU-WTL)*(100.*CUT+1.-IZ) - ENDIF - IF(1.+WTOPT+2.*ALS2PI*WT2.LE.0.) MSTJ(121)=1 - IF(1.+WTOPT+2.*ALS2PI*WT2.LE.WTMAX*RLU(0)) GOTO 110 - PARJ(156)=(WTOPT+2.*ALS2PI*WT2)/(1.+WTOPT+2.*ALS2PI*WT2) - ENDIF - -C...Impose mass cuts (gives two jets). For fixed jet number new try. - X1=1.-Y23 - X2=1.-Y13 - X3=1.-Y12 - IF(4.*Y23*Y13*Y12/X3**2.LE.QME) NJET=2 - IF(MOD(MSTJ(103),4).GE.2.AND.IABS(MSTJ(101)).LE.1.AND.QME*X3+ - & 0.5*QME**2+(0.5*QME+0.25*QME**2)*((1.-X2)/(1.-X1)+ - & (1.-X1)/(1.-X2)).GT.(X1**2+X2**2)*RLU(0)) NJET=2 - IF(MSTJ(101).EQ.-1.AND.NJET.EQ.2) GOTO 100 - -C...Scalar gluon model (first order only, no mass effects). - ELSE - 130 NJET=3 - 140 X3=SQRT(4.*CUT**2+RLU(0)*((1.-CUT)**2-4.*CUT**2)) - IF(LOG((X3-CUT)/CUT).LE.RLU(0)*LOG((1.-2.*CUT)/CUT)) GOTO 140 - YD=SIGN(2.*CUT*((X3-CUT)/CUT)**RLU(0)-X3,RLU(0)-0.5) - X1=1.-0.5*(X3+YD) - X2=1.-0.5*(X3-YD) - IF(4.*(1.-X1)*(1.-X2)*(1.-X3)/X3**2.LE.QME) NJET=2 - IF(MSTJ(102).GE.2) THEN - IF(X3**2-2.*(1.+X3)*(1.-X1)*(1.-X2)*PARJ(171).LT. - & X3**2*RLU(0)) NJET=2 - ENDIF - IF(MSTJ(101).EQ.-1.AND.NJET.EQ.2) GOTO 130 - ENDIF - - RETURN - END - -C********************************************************************* - -CDECK ID>, LUX4JT - SUBROUTINE LUX4JT(NJET,CUT,KFL,ECM,KFLN,X1,X2,X4,X12,X14) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to select the kinematical variables of four-jet events. - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - SAVE /LUDAT1/ - DIMENSION WTA(4),WTB(4),WTC(4),WTD(4),WTE(4) - -C...Common constants. Colour factors for QCD and Abelian gluon theory. - PMQ=ULMASS(KFL) - QME=(2.*PMQ/ECM)**2 - CT=LOG(1./CUT-5.) - IF(MSTJ(109).EQ.0) THEN - CF=4./3. - CN=3. - TR=2.5 - ELSE - CF=1. - CN=0. - TR=15. - ENDIF - -C...Choice of process (qqbargg or qqbarqqbar). - 100 NJET=4 - IT=1 - IF(PARJ(155).GT.RLU(0)) IT=2 - IF(MSTJ(101).LE.-3) IT=-MSTJ(101)-2 - IF(IT.EQ.1) WTMX=0.7/CUT**2 - IF(IT.EQ.1.AND.MSTJ(109).EQ.2) WTMX=0.6/CUT**2 - IF(IT.EQ.2) WTMX=0.1125*CF*TR/CUT**2 - ID=1 - -C...Sample the five kinematical variables (for qqgg preweighted in y34). - 110 Y134=3.*CUT+(1.-6.*CUT)*RLU(0) - Y234=3.*CUT+(1.-6.*CUT)*RLU(0) - IF(IT.EQ.1) Y34=(1.-5.*CUT)*EXP(-CT*RLU(0)) - IF(IT.EQ.2) Y34=CUT+(1.-6.*CUT)*RLU(0) - IF(Y34.LE.Y134+Y234-1..OR.Y34.GE.Y134*Y234) GOTO 110 - VT=RLU(0) - CP=COS(PARU(1)*RLU(0)) - Y14=(Y134-Y34)*VT - Y13=Y134-Y14-Y34 - VB=Y34*(1.-Y134-Y234+Y34)/((Y134-Y34)*(Y234-Y34)) - Y24=0.5*(Y234-Y34)*(1.-4.*SQRT(MAX(0.D0,VT*(1.-VT)*VB*(1.-VB)))* - &CP-(1.-2.*VT)*(1.-2.*VB)) - Y23=Y234-Y34-Y24 - Y12=1.-Y134-Y23-Y24 - IF(MIN(Y12,Y13,Y14,Y23,Y24).LE.CUT) GOTO 110 - Y123=Y12+Y13+Y23 - Y124=Y12+Y14+Y24 - -C...Calculate matrix elements for qqgg or qqqq process. - IC=0 - WTTOT=0. - 120 IC=IC+1 - IF(IT.EQ.1) THEN - WTA(IC)=(Y12*Y34**2-Y13*Y24*Y34+Y14*Y23*Y34+3.*Y12*Y23*Y34+ - & 3.*Y12*Y14*Y34+4.*Y12**2*Y34-Y13*Y23*Y24+2.*Y12*Y23*Y24- - & Y13*Y14*Y24-2.*Y12*Y13*Y24+2.*Y12**2*Y24+Y14*Y23**2+2.*Y12* - & Y23**2+Y14**2*Y23+4.*Y12*Y14*Y23+4.*Y12**2*Y23+2.*Y12*Y14**2+ - & 2.*Y12*Y13*Y14+4.*Y12**2*Y14+2.*Y12**2*Y13+2.*Y12**3)/(2.*Y13* - & Y134*Y234*Y24)+(Y24*Y34+Y12*Y34+Y13*Y24-Y14*Y23+Y12*Y13)/(Y13* - & Y134**2)+2.*Y23*(1.-Y13)/(Y13*Y134*Y24)+Y34/(2.*Y13*Y24) - WTB(IC)=(Y12*Y24*Y34+Y12*Y14*Y34-Y13*Y24**2+Y13*Y14*Y24+2.*Y12* - & Y14*Y24)/(Y13*Y134*Y23*Y14)+Y12*(1.+Y34)*Y124/(Y134*Y234*Y14* - & Y24)-(2.*Y13*Y24+Y14**2+Y13*Y23+2.*Y12*Y13)/(Y13*Y134*Y14)+ - & Y12*Y123*Y124/(2.*Y13*Y14*Y23*Y24) - WTC(IC)=-(5.*Y12*Y34**2+2.*Y12*Y24*Y34+2.*Y12*Y23*Y34+2.*Y12* - & Y14*Y34+2.*Y12*Y13*Y34+4.*Y12**2*Y34-Y13*Y24**2+Y14*Y23*Y24+ - & Y13*Y23*Y24+Y13*Y14*Y24-Y12*Y14*Y24-Y13**2*Y24-3.*Y12*Y13*Y24- - & Y14*Y23**2-Y14**2*Y23+Y13*Y14*Y23-3.*Y12*Y14*Y23-Y12*Y13*Y23)/ - & (4.*Y134*Y234*Y34**2)+(3.*Y12*Y34**2-3.*Y13*Y24*Y34+3.*Y12*Y24* - & Y34+3.*Y14*Y23*Y34-Y13*Y24**2-Y12*Y23*Y34+6.*Y12*Y14*Y34+2.*Y12* - & Y13*Y34-2.*Y12**2*Y34+Y14*Y23*Y24-3.*Y13*Y23*Y24-2.*Y13*Y14* - & Y24+4.*Y12*Y14*Y24+2.*Y12*Y13*Y24+3.*Y14*Y23**2+2.*Y14**2*Y23+ - & 2.*Y14**2*Y12+2.*Y12**2*Y14+6.*Y12*Y14*Y23-2.*Y12*Y13**2- - & 2.*Y12**2*Y13)/(4.*Y13*Y134*Y234*Y34) - WTC(IC)=WTC(IC)+(2.*Y12*Y34**2-2.*Y13*Y24*Y34+Y12*Y24*Y34+ - & 4.*Y13*Y23*Y34+4.*Y12*Y14*Y34+2.*Y12*Y13*Y34+2.*Y12**2*Y34- - & Y13*Y24**2+3.*Y14*Y23*Y24+4.*Y13*Y23*Y24-2.*Y13*Y14*Y24+ - & 4.*Y12*Y14*Y24+2.*Y12*Y13*Y24+2.*Y14*Y23**2+4.*Y13*Y23**2+ - & 2.*Y13*Y14*Y23+2.*Y12*Y14*Y23+4.*Y12*Y13*Y23+2.*Y12*Y14**2+4.* - & Y12**2*Y13+4.*Y12*Y13*Y14+2.*Y12**2*Y14)/(4.*Y13*Y134*Y24*Y34)- - & (Y12*Y34**2-2.*Y14*Y24*Y34-2.*Y13*Y24*Y34-Y14*Y23*Y34+Y13*Y23* - & Y34+Y12*Y14*Y34+2.*Y12*Y13*Y34-2.*Y14**2*Y24-4.*Y13*Y14*Y24- - & 4.*Y13**2*Y24-Y14**2*Y23-Y13**2*Y23+Y12*Y13*Y14-Y12*Y13**2)/ - & (2.*Y13*Y34*Y134**2)+(Y12*Y34**2-4.*Y14*Y24*Y34-2.*Y13*Y24*Y34- - & 2.*Y14*Y23*Y34-4.*Y13*Y23*Y34-4.*Y12*Y14*Y34-4.*Y12*Y13*Y34- - & 2.*Y13*Y14*Y24+2.*Y13**2*Y24+2.*Y14**2*Y23-2.*Y13*Y14*Y23- - & Y12*Y14**2-6.*Y12*Y13*Y14-Y12*Y13**2)/(4.*Y34**2*Y134**2) - WTTOT=WTTOT+Y34*CF*(CF*WTA(IC)+(CF-0.5*CN)*WTB(IC)+CN*WTC(IC))/ - & 8. - ELSE - WTD(IC)=(Y13*Y23*Y34+Y12*Y23*Y34-Y12**2*Y34+Y13*Y23*Y24+2.*Y12* - & Y23*Y24-Y14*Y23**2+Y12*Y13*Y24+Y12*Y14*Y23+Y12*Y13*Y14)/(Y13**2* - & Y123**2)-(Y12*Y34**2-Y13*Y24*Y34+Y12*Y24*Y34-Y14*Y23*Y34-Y12* - & Y23*Y34-Y13*Y24**2+Y14*Y23*Y24-Y13*Y23*Y24-Y13**2*Y24+Y14* - & Y23**2)/(Y13**2*Y123*Y134)+(Y13*Y14*Y12+Y34*Y14*Y12-Y34**2*Y12+ - & Y13*Y14*Y24+2.*Y34*Y14*Y24-Y23*Y14**2+Y34*Y13*Y24+Y34*Y23*Y14+ - & Y34*Y13*Y23)/(Y13**2*Y134**2)-(Y34*Y12**2-Y13*Y24*Y12+Y34*Y24* - & Y12-Y23*Y14*Y12-Y34*Y14*Y12-Y13*Y24**2+Y23*Y14*Y24-Y13*Y14*Y24- - & Y13**2*Y24+Y23*Y14**2)/(Y13**2*Y134*Y123) - WTE(IC)=(Y12*Y34*(Y23-Y24+Y14+Y13)+Y13*Y24**2-Y14*Y23*Y24+Y13* - & Y23*Y24+Y13*Y14*Y24+Y13**2*Y24-Y14*Y23*(Y14+Y23+Y13))/(Y13*Y23* - & Y123*Y134)-Y12*(Y12*Y34-Y23*Y24-Y13*Y24-Y14*Y23-Y14*Y13)/(Y13* - & Y23*Y123**2)-(Y14+Y13)*(Y24+Y23)*Y34/(Y13*Y23*Y134*Y234)+ - & (Y12*Y34*(Y14-Y24+Y23+Y13)+Y13*Y24**2-Y23*Y14*Y24+Y13*Y14*Y24+ - & Y13*Y23*Y24+Y13**2*Y24-Y23*Y14*(Y14+Y23+Y13))/(Y13*Y14*Y134* - & Y123)-Y34*(Y34*Y12-Y14*Y24-Y13*Y24-Y23*Y14-Y23*Y13)/(Y13*Y14* - & Y134**2)-(Y23+Y13)*(Y24+Y14)*Y12/(Y13*Y14*Y123*Y124) - WTTOT=WTTOT+CF*(TR*WTD(IC)+(CF-0.5*CN)*WTE(IC))/16. - ENDIF - -C...Permutations of momenta in matrix element. Weighting. - 130 IF(IC.EQ.1.OR.IC.EQ.3.OR.ID.EQ.2.OR.ID.EQ.3) THEN - YSAV=Y13 - Y13=Y14 - Y14=YSAV - YSAV=Y23 - Y23=Y24 - Y24=YSAV - YSAV=Y123 - Y123=Y124 - Y124=YSAV - ENDIF - IF(IC.EQ.2.OR.IC.EQ.4.OR.ID.EQ.3.OR.ID.EQ.4) THEN - YSAV=Y13 - Y13=Y23 - Y23=YSAV - YSAV=Y14 - Y14=Y24 - Y24=YSAV - YSAV=Y134 - Y134=Y234 - Y234=YSAV - ENDIF - IF(IC.LE.3) GOTO 120 - IF(ID.EQ.1.AND.WTTOT.LT.RLU(0)*WTMX) GOTO 110 - IC=5 - -C...qqgg events: string configuration and event type. - IF(IT.EQ.1) THEN - IF(MSTJ(109).EQ.0.AND.ID.EQ.1) THEN - PARJ(156)=Y34*(2.*(WTA(1)+WTA(2)+WTA(3)+WTA(4))+4.*(WTC(1)+ - & WTC(2)+WTC(3)+WTC(4)))/(9.*WTTOT) - IF(WTA(2)+WTA(4)+2.*(WTC(2)+WTC(4)).GT.RLU(0)*(WTA(1)+WTA(2)+ - & WTA(3)+WTA(4)+2.*(WTC(1)+WTC(2)+WTC(3)+WTC(4)))) ID=2 - IF(ID.EQ.2) GOTO 130 - ELSEIF(MSTJ(109).EQ.2.AND.ID.EQ.1) THEN - PARJ(156)=Y34*(WTA(1)+WTA(2)+WTA(3)+WTA(4))/(8.*WTTOT) - IF(WTA(2)+WTA(4).GT.RLU(0)*(WTA(1)+WTA(2)+WTA(3)+WTA(4))) ID=2 - IF(ID.EQ.2) GOTO 130 - ENDIF - MSTJ(120)=3 - IF(MSTJ(109).EQ.0.AND.0.5*Y34*(WTC(1)+WTC(2)+WTC(3)+WTC(4)).GT. - & RLU(0)*WTTOT) MSTJ(120)=4 - KFLN=21 - -C...Mass cuts. Kinematical variables out. - IF(Y12.LE.CUT+QME) NJET=2 - IF(NJET.EQ.2) GOTO 150 - Q12=0.5*(1.-SQRT(1.-QME/Y12)) - X1=1.-(1.-Q12)*Y234-Q12*Y134 - X4=1.-(1.-Q12)*Y134-Q12*Y234 - X2=1.-Y124 - X12=(1.-Q12)*Y13+Q12*Y23 - X14=Y12-0.5*QME - IF(Y134*Y234/((1.-X1)*(1.-X4)).LE.RLU(0)) NJET=2 - -C...qqbarqqbar events: string configuration, choose new flavour. - ELSE - IF(ID.EQ.1) THEN - WTR=RLU(0)*(WTD(1)+WTD(2)+WTD(3)+WTD(4)) - IF(WTR.LT.WTD(2)+WTD(3)+WTD(4)) ID=2 - IF(WTR.LT.WTD(3)+WTD(4)) ID=3 - IF(WTR.LT.WTD(4)) ID=4 - IF(ID.GE.2) GOTO 130 - ENDIF - MSTJ(120)=5 - PARJ(156)=CF*TR*(WTD(1)+WTD(2)+WTD(3)+WTD(4))/(16.*WTTOT) - 140 KFLN=1+INT(5.*RLU(0)) - IF(KFLN.NE.KFL.AND.0.2*PARJ(156).LE.RLU(0)) GOTO 140 - IF(KFLN.EQ.KFL.AND.1.-0.8*PARJ(156).LE.RLU(0)) GOTO 140 - IF(KFLN.GT.MSTJ(104)) NJET=2 - PMQN=ULMASS(KFLN) - QMEN=(2.*PMQN/ECM)**2 - -C...Mass cuts. Kinematical variables out. - IF(Y24.LE.CUT+QME.OR.Y13.LE.1.1*QMEN) NJET=2 - IF(NJET.EQ.2) GOTO 150 - Q24=0.5*(1.-SQRT(1.-QME/Y24)) - Q13=0.5*(1.-SQRT(1.-QMEN/Y13)) - X1=1.-(1.-Q24)*Y123-Q24*Y134 - X4=1.-(1.-Q24)*Y134-Q24*Y123 - X2=1.-(1.-Q13)*Y234-Q13*Y124 - X12=(1.-Q24)*((1.-Q13)*Y14+Q13*Y34)+Q24*((1.-Q13)*Y12+Q13*Y23) - X14=Y24-0.5*QME - X34=(1.-Q24)*((1.-Q13)*Y23+Q13*Y12)+Q24*((1.-Q13)*Y34+Q13*Y14) - IF(PMQ**2+PMQN**2+MIN(X12,X34)*ECM**2.LE. - & (PARJ(127)+PMQ+PMQN)**2) NJET=2 - IF(Y123*Y134/((1.-X1)*(1.-X4)).LE.RLU(0)) NJET=2 - ENDIF - 150 IF(MSTJ(101).LE.-2.AND.NJET.EQ.2) GOTO 100 - - RETURN - END - -C********************************************************************* - -CDECK ID>, LUXDIF - SUBROUTINE LUXDIF(NC,NJET,KFL,ECM,CHI,THE,PHI) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to give the angular orientation of events. - COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ - -C...Charge. Factors depending on polarization for QED case. - QF=KCHG(KFL,1)/3. - POLL=1.-PARJ(131)*PARJ(132) - POLD=PARJ(132)-PARJ(131) - IF(MSTJ(102).LE.1.OR.MSTJ(109).EQ.1) THEN - HF1=POLL - HF2=0. - HF3=PARJ(133)**2 - HF4=0. - -C...Factors depending on flavour, energy and polarization for QFD case. - ELSE - SFF=1./(16.*PARU(102)*(1.-PARU(102))) - SFW=ECM**4/((ECM**2-PARJ(123)**2)**2+(PARJ(123)*PARJ(124))**2) - SFI=SFW*(1.-(PARJ(123)/ECM)**2) - AE=-1. - VE=4.*PARU(102)-1. - AF=SIGN(1.D0,QF) - VF=AF-4.*QF*PARU(102) - HF1=QF**2*POLL-2.*QF*VF*SFI*SFF*(VE*POLL-AE*POLD)+ - & (VF**2+AF**2)*SFW*SFF**2*((VE**2+AE**2)*POLL-2.*VE*AE*POLD) - HF2=-2.*QF*AF*SFI*SFF*(AE*POLL-VE*POLD)+2.*VF*AF*SFW*SFF**2* - & (2.*VE*AE*POLL-(VE**2+AE**2)*POLD) - HF3=PARJ(133)**2*(QF**2-2.*QF*VF*SFI*SFF*VE+(VF**2+AF**2)* - & SFW*SFF**2*(VE**2-AE**2)) - HF4=-PARJ(133)**2*2.*QF*VF*SFW*(PARJ(123)*PARJ(124)/ECM**2)* - & SFF*AE - ENDIF - -C...Mass factor. Differential cross-sections for two-jet events. - SQ2=SQRT(2.) - QME=0. - IF(MSTJ(103).GE.4.AND.IABS(MSTJ(101)).LE.1.AND.MSTJ(102).LE.1.AND. - &MSTJ(109).NE.1) QME=(2.*ULMASS(KFL)/ECM)**2 - IF(NJET.EQ.2) THEN - SIGU=4.*SQRT(1.-QME) - SIGL=2.*QME*SQRT(1.-QME) - SIGT=0. - SIGI=0. - SIGA=0. - SIGP=4. - -C...Kinematical variables. Reduce four-jet event to three-jet one. - ELSE - IF(NJET.EQ.3) THEN - X1=2.*P(NC+1,4)/ECM - X2=2.*P(NC+3,4)/ECM - ELSE - ECMR=P(NC+1,4)+P(NC+4,4)+SQRT((P(NC+2,1)+P(NC+3,1))**2+ - & (P(NC+2,2)+P(NC+3,2))**2+(P(NC+2,3)+P(NC+3,3))**2) - X1=2.*P(NC+1,4)/ECMR - X2=2.*P(NC+4,4)/ECMR - ENDIF - -C...Differential cross-sections for three-jet (or reduced four-jet). - XQ=(1.-X1)/(1.-X2) - CT12=(X1*X2-2.*X1-2.*X2+2.+QME)/SQRT((X1**2-QME)*(X2**2-QME)) - ST12=SQRT(1.-CT12**2) - IF(MSTJ(109).NE.1) THEN - SIGU=2.*X1**2+X2**2*(1.+CT12**2)-QME*(3.+CT12**2-X1-X2)- - & QME*X1/XQ+0.5*QME*((X2**2-QME)*ST12**2-2.*X2)*XQ - SIGL=(X2*ST12)**2-QME*(3.-CT12**2-2.5*(X1+X2)+X1*X2+QME)+ - & 0.5*QME*(X1**2-X1-QME)/XQ+0.5*QME*((X2**2-QME)*CT12**2-X2)*XQ - SIGT=0.5*(X2**2-QME-0.5*QME*(X2**2-QME)/XQ)*ST12**2 - SIGI=((1.-0.5*QME*XQ)*(X2**2-QME)*ST12*CT12+QME*(1.-X1-X2+ - & 0.5*X1*X2+0.5*QME)*ST12/CT12)/SQ2 - SIGA=X2**2*ST12/SQ2 - SIGP=2.*(X1**2-X2**2*CT12) - -C...Differential cross-sect for scalar gluons (no mass effects). - ELSE - X3=2.-X1-X2 - XT=X2*ST12 - CT13=SQRT(MAX(0.D0,1.-(XT/X3)**2)) - SIGU=(1.-PARJ(171))*(X3**2-0.5*XT**2)+ - & PARJ(171)*(X3**2-0.5*XT**2-4.*(1.-X1)*(1.-X2)**2/X1) - SIGL=(1.-PARJ(171))*0.5*XT**2+ - & PARJ(171)*0.5*(1.-X1)**2*XT**2 - SIGT=(1.-PARJ(171))*0.25*XT**2+ - & PARJ(171)*0.25*XT**2*(1.-2.*X1) - SIGI=-(0.5/SQ2)*((1.-PARJ(171))*XT*X3*CT13+ - & PARJ(171)*XT*((1.-2.*X1)*X3*CT13-X1*(X1-X2))) - SIGA=(0.25/SQ2)*XT*(2.*(1.-X1)-X1*X3) - SIGP=X3**2-2.*(1.-X1)*(1.-X2)/X1 - ENDIF - ENDIF - -C...Upper bounds for differential cross-section. - HF1A=ABS(HF1) - HF2A=ABS(HF2) - HF3A=ABS(HF3) - HF4A=ABS(HF4) - SIGMAX=(2.*HF1A+HF3A+HF4A)*ABS(SIGU)+2.*(HF1A+HF3A+HF4A)* - &ABS(SIGL)+2.*(HF1A+2.*HF3A+2.*HF4A)*ABS(SIGT)+2.*SQ2* - &(HF1A+2.*HF3A+2.*HF4A)*ABS(SIGI)+4.*SQ2*HF2A*ABS(SIGA)+ - &2.*HF2A*ABS(SIGP) - -C...Generate angular orientation according to differential cross-sect. - 100 CHI=PARU(2)*RLU(0) - CTHE=2.*RLU(0)-1. - PHI=PARU(2)*RLU(0) - CCHI=COS(CHI) - SCHI=SIN(CHI) - C2CHI=COS(2.*CHI) - S2CHI=SIN(2.*CHI) - THE=ACOS(CTHE) - STHE=SIN(THE) - C2PHI=COS(2.*(PHI-PARJ(134))) - S2PHI=SIN(2.*(PHI-PARJ(134))) - SIG=((1.+CTHE**2)*HF1+STHE**2*(C2PHI*HF3-S2PHI*HF4))*SIGU+ - &2.*(STHE**2*HF1-STHE**2*(C2PHI*HF3-S2PHI*HF4))*SIGL+ - &2.*(STHE**2*C2CHI*HF1+((1.+CTHE**2)*C2CHI*C2PHI-2.*CTHE*S2CHI* - &S2PHI)*HF3-((1.+CTHE**2)*C2CHI*S2PHI+2.*CTHE*S2CHI*C2PHI)*HF4)* - &SIGT-2.*SQ2*(2.*STHE*CTHE*CCHI*HF1-2.*STHE*(CTHE*CCHI*C2PHI- - &SCHI*S2PHI)*HF3+2.*STHE*(CTHE*CCHI*S2PHI+SCHI*C2PHI)*HF4)*SIGI+ - &4.*SQ2*STHE*CCHI*HF2*SIGA+2.*CTHE*HF2*SIGP - IF(SIG.LT.SIGMAX*RLU(0)) GOTO 100 - - RETURN - END - -C********************************************************************* - -CDECK ID>, LUONIA - SUBROUTINE LUONIA(KFL,ECM) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to generate Upsilon and toponium decays into three -C...gluons or two gluons and a photon. - COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ - -C...Printout. Check input parameters. - IF(MSTU(12).GE.1) CALL LULIST(0) - IF(KFL.LT.0.OR.KFL.GT.8) THEN - CALL LUERRM(16,'(LUONIA:) called with unknown flavour code') - IF(MSTU(21).GE.1) RETURN - ENDIF - IF(ECM.LT.PARJ(127)+2.02*PARF(101)) THEN - CALL LUERRM(16,'(LUONIA:) called with too small CM energy') - IF(MSTU(21).GE.1) RETURN - ENDIF - -C...Initial e+e- and onium state (optional). - NC=0 - IF(MSTJ(115).GE.2) THEN - NC=NC+2 - CALL LU1ENT(NC-1,11,0.5*ECM,0.D0,0.D0) - K(NC-1,1)=21 - CALL LU1ENT(NC,-11,0.5*ECM,PARU(1),0.D0) - K(NC,1)=21 - ENDIF - KFLC=IABS(KFL) - IF(MSTJ(115).GE.3.AND.KFLC.GE.5) THEN - NC=NC+1 - KF=110*KFLC+3 - MSTU10=MSTU(10) - MSTU(10)=1 - P(NC,5)=ECM - CALL LU1ENT(NC,KF,ECM,0.D0,0.D0) - K(NC,1)=21 - K(NC,3)=1 - MSTU(10)=MSTU10 - ENDIF - -C...Choose x1 and x2 according to matrix element. - NTRY=0 - 100 X1=RLU(0) - X2=RLU(0) - X3=2.-X1-X2 - IF(X3.GE.1..OR.((1.-X1)/(X2*X3))**2+((1.-X2)/(X1*X3))**2+ - &((1.-X3)/(X1*X2))**2.LE.2.*RLU(0)) GOTO 100 - NTRY=NTRY+1 - NJET=3 - IF(MSTJ(101).LE.4) CALL LU3ENT(NC+1,21,21,21,ECM,X1,X3) - IF(MSTJ(101).GE.5) CALL LU3ENT(-(NC+1),21,21,21,ECM,X1,X3) - -C...Photon-gluon-gluon events. Small system modifications. Jet origin. - MSTU(111)=MSTJ(108) - IF(MSTJ(108).EQ.2.AND.(MSTJ(101).EQ.0.OR.MSTJ(101).EQ.1)) - &MSTU(111)=1 - PARU(112)=PARJ(121) - IF(MSTU(111).EQ.2) PARU(112)=PARJ(122) - QF=0. - IF(KFLC.NE.0) QF=KCHG(KFLC,1)/3. - RGAM=7.2*QF**2*PARU(101)/ULALPS(ECM**2) - MK=0 - ECMC=ECM - IF(RLU(0).GT.RGAM/(1.+RGAM)) THEN - IF(1.-MAX(X1,X2,X3).LE.MAX((PARJ(126)/ECM)**2,PARJ(125))) - & NJET=2 - IF(NJET.EQ.2.AND.MSTJ(101).LE.4) CALL LU2ENT(NC+1,21,21,ECM) - IF(NJET.EQ.2.AND.MSTJ(101).GE.5) CALL LU2ENT(-(NC+1),21,21,ECM) - ELSE - MK=1 - ECMC=SQRT(1.-X1)*ECM - IF(ECMC.LT.2.*PARJ(127)) GOTO 100 - K(NC+1,1)=1 - K(NC+1,2)=22 - K(NC+1,4)=0 - K(NC+1,5)=0 - IF(MSTJ(101).GE.5) K(NC+2,4)=MSTU(5)*(NC+3) - IF(MSTJ(101).GE.5) K(NC+2,5)=MSTU(5)*(NC+3) - IF(MSTJ(101).GE.5) K(NC+3,4)=MSTU(5)*(NC+2) - IF(MSTJ(101).GE.5) K(NC+3,5)=MSTU(5)*(NC+2) - NJET=2 - IF(ECMC.LT.4.*PARJ(127)) THEN - MSTU10=MSTU(10) - MSTU(10)=1 - P(NC+2,5)=ECMC - CALL LU1ENT(NC+2,83,0.5*(X2+X3)*ECM,PARU(1),0.D0) - MSTU(10)=MSTU10 - NJET=0 - ENDIF - ENDIF - DO 110 IP=NC+1,N - K(IP,3)=K(IP,3)+(MSTJ(115)/2)+(KFLC/5)*(MSTJ(115)/3)*(NC-1) - 110 CONTINUE - -C...Differential cross-sections. Upper limit for cross-section. - IF(MSTJ(106).EQ.1) THEN - SQ2=SQRT(2.) - HF1=1.-PARJ(131)*PARJ(132) - HF3=PARJ(133)**2 - CT13=(X1*X3-2.*X1-2.*X3+2.)/(X1*X3) - ST13=SQRT(1.-CT13**2) - SIGL=0.5*X3**2*((1.-X2)**2+(1.-X3)**2)*ST13**2 - SIGU=(X1*(1.-X1))**2+(X2*(1.-X2))**2+(X3*(1.-X3))**2-SIGL - SIGT=0.5*SIGL - SIGI=(SIGL*CT13/ST13+0.5*X1*X3*(1.-X2)**2*ST13)/SQ2 - SIGMAX=(2.*HF1+HF3)*ABS(SIGU)+2.*(HF1+HF3)*ABS(SIGL)+2.*(HF1+ - & 2.*HF3)*ABS(SIGT)+2.*SQ2*(HF1+2.*HF3)*ABS(SIGI) - -C...Angular orientation of event. - 120 CHI=PARU(2)*RLU(0) - CTHE=2.*RLU(0)-1. - PHI=PARU(2)*RLU(0) - CCHI=COS(CHI) - SCHI=SIN(CHI) - C2CHI=COS(2.*CHI) - S2CHI=SIN(2.*CHI) - THE=ACOS(CTHE) - STHE=SIN(THE) - C2PHI=COS(2.*(PHI-PARJ(134))) - S2PHI=SIN(2.*(PHI-PARJ(134))) - SIG=((1.+CTHE**2)*HF1+STHE**2*C2PHI*HF3)*SIGU+2.*(STHE**2*HF1- - & STHE**2*C2PHI*HF3)*SIGL+2.*(STHE**2*C2CHI*HF1+((1.+CTHE**2)* - & C2CHI*C2PHI-2.*CTHE*S2CHI*S2PHI)*HF3)*SIGT-2.*SQ2*(2.*STHE*CTHE* - & CCHI*HF1-2.*STHE*(CTHE*CCHI*C2PHI-SCHI*S2PHI)*HF3)*SIGI - IF(SIG.LT.SIGMAX*RLU(0)) GOTO 120 - CALL LUDBRB(NC+1,N,0.D0,CHI,0D0,0D0,0D0) - CALL LUDBRB(NC+1,N,THE,PHI,0D0,0D0,0D0) - ENDIF - -C...Generate parton shower. Rearrange along strings and check. - IF(MSTJ(101).GE.5.AND.NJET.GE.2) THEN - CALL LUSHOW(NC+MK+1,-NJET,ECMC) - MSTJ14=MSTJ(14) - IF(MSTJ(105).EQ.-1) MSTJ(14)=-1 - IF(MSTJ(105).GE.0) MSTU(28)=0 - CALL LUPREP(0) - MSTJ(14)=MSTJ14 - IF(MSTJ(105).GE.0.AND.MSTU(28).NE.0) GOTO 100 - ENDIF - -C...Generate fragmentation. Information for LUTABU: - IF(MSTJ(105).EQ.1) CALL LUEXEC - MSTU(161)=110*KFLC+3 - MSTU(162)=0 - - RETURN - END - -C********************************************************************* - -CDECK ID>, LUHEPC - SUBROUTINE LUHEPC(MCONV) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to convert JETSET event record contents to or from -C...the standard event record commonblock. -C...Note that HEPEVT is in double precision according to LEP 2 standard. - PARAMETER (NMXHEP=2000) - COMMON/HEPEVT/NEVHEP,NHEP,ISTHEP(NMXHEP),IDHEP(NMXHEP), - &JMOHEP(2,NMXHEP),JDAHEP(2,NMXHEP),PHEP(5,NMXHEP),VHEP(4,NMXHEP) -C DOUBLE PRECISION PHEP,VHEP - COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - SAVE /HEPEVT/ - SAVE /LUJETS/,/LUDAT1/,/LUDAT2/ - -C...Conversion from JETSET to standard, the easy part. - IF(MCONV.EQ.1) THEN - NEVHEP=0 - IF(N.GT.NMXHEP) CALL LUERRM(8, - & '(LUHEPC:) no more space in /HEPEVT/') - NHEP=MIN(N,NMXHEP) - DO 140 I=1,NHEP - ISTHEP(I)=0 - IF(K(I,1).GE.1.AND.K(I,1).LE.10) ISTHEP(I)=1 - IF(K(I,1).GE.11.AND.K(I,1).LE.20) ISTHEP(I)=2 - IF(K(I,1).GE.21.AND.K(I,1).LE.30) ISTHEP(I)=3 - IF(K(I,1).GE.31.AND.K(I,1).LE.100) ISTHEP(I)=K(I,1) - IDHEP(I)=K(I,2) - JMOHEP(1,I)=K(I,3) - JMOHEP(2,I)=0 - IF(K(I,1).NE.3.AND.K(I,1).NE.13.AND.K(I,1).NE.14) THEN - JDAHEP(1,I)=K(I,4) - JDAHEP(2,I)=K(I,5) - ELSE - JDAHEP(1,I)=0 - JDAHEP(2,I)=0 - ENDIF - DO 100 J=1,5 - PHEP(J,I)=P(I,J) - 100 CONTINUE - DO 110 J=1,4 - VHEP(J,I)=V(I,J) - 110 CONTINUE - -C...Check if new event (from pileup). - IF(I.EQ.1) THEN - INEW=1 - ELSE - IF(K(I,1).EQ.21.AND.K(I-1,1).NE.21) INEW=I - ENDIF - -C...Fill in missing mother information. - IF(I.GE.INEW+2.AND.K(I,1).EQ.21.AND.K(I,3).EQ.0) THEN - IMO1=I-2 - IF(I.GE.INEW+3.AND.K(I-1,1).EQ.21.AND.K(I-1,3).EQ.0) - & IMO1=IMO1-1 - JMOHEP(1,I)=IMO1 - JMOHEP(2,I)=IMO1+1 - ELSEIF(K(I,2).GE.91.AND.K(I,2).LE.93) THEN - I1=K(I,3)-1 - 120 I1=I1+1 - IF(I1.GE.I) CALL LUERRM(8, - & '(LUHEPC:) translation of inconsistent event history') - IF(I1.LT.I.AND.K(I1,1).NE.1.AND.K(I1,1).NE.11) GOTO 120 - KC=LUCOMP(K(I1,2)) - IF(I1.LT.I.AND.KC.EQ.0) GOTO 120 - IF(I1.LT.I.AND.KCHG(KC,2).EQ.0) GOTO 120 - JMOHEP(2,I)=I1 - ELSEIF(K(I,2).EQ.94) THEN - NJET=2 - IF(NHEP.GE.I+3.AND.K(I+3,3).LE.I) NJET=3 - IF(NHEP.GE.I+4.AND.K(I+4,3).LE.I) NJET=4 - JMOHEP(2,I)=MOD(K(I+NJET,4)/MSTU(5),MSTU(5)) - IF(JMOHEP(2,I).EQ.JMOHEP(1,I)) JMOHEP(2,I)= - & MOD(K(I+1,4)/MSTU(5),MSTU(5)) - ENDIF - -C...Fill in missing daughter information. - IF(K(I,2).EQ.94.AND.MSTU(16).NE.2) THEN - DO 130 I1=JDAHEP(1,I),JDAHEP(2,I) - I2=MOD(K(I1,4)/MSTU(5),MSTU(5)) - JDAHEP(1,I2)=I - 130 CONTINUE - ENDIF - IF(K(I,2).GE.91.AND.K(I,2).LE.94) GOTO 140 - I1=JMOHEP(1,I) - IF(I1.LE.0.OR.I1.GT.NHEP) GOTO 140 - IF(K(I1,1).NE.13.AND.K(I1,1).NE.14) GOTO 140 - IF(JDAHEP(1,I1).EQ.0) THEN - JDAHEP(1,I1)=I - ELSE - JDAHEP(2,I1)=I - ENDIF - 140 CONTINUE - DO 150 I=1,NHEP - IF(K(I,1).NE.13.AND.K(I,1).NE.14) GOTO 150 - IF(JDAHEP(2,I).EQ.0) JDAHEP(2,I)=JDAHEP(1,I) - 150 CONTINUE - -C...Conversion from standard to JETSET, the easy part. - ELSE - IF(NHEP.GT.MSTU(4)) CALL LUERRM(8, - & '(LUHEPC:) no more space in /LUJETS/') - N=MIN(NHEP,MSTU(4)) - NKQ=0 - KQSUM=0 - DO 180 I=1,N - K(I,1)=0 - IF(ISTHEP(I).EQ.1) K(I,1)=1 - IF(ISTHEP(I).EQ.2) K(I,1)=11 - IF(ISTHEP(I).EQ.3) K(I,1)=21 - K(I,2)=IDHEP(I) - K(I,3)=JMOHEP(1,I) - K(I,4)=JDAHEP(1,I) - K(I,5)=JDAHEP(2,I) - DO 160 J=1,5 - P(I,J)=PHEP(J,I) - 160 CONTINUE - DO 170 J=1,4 - V(I,J)=VHEP(J,I) - 170 CONTINUE - V(I,5)=0. - IF(ISTHEP(I).EQ.2.AND.PHEP(4,I).GT.PHEP(5,I)) THEN - I1=JDAHEP(1,I) - IF(I1.GT.0.AND.I1.LE.NHEP) V(I,5)=(VHEP(4,I1)-VHEP(4,I))* - & PHEP(5,I)/PHEP(4,I) - ENDIF - -C...Fill in missing information on colour connection in jet systems. - IF(ISTHEP(I).EQ.1) THEN - KC=LUCOMP(K(I,2)) - KQ=0 - IF(KC.NE.0) KQ=KCHG(KC,2)*ISIGN(1,K(I,2)) - IF(KQ.NE.0) NKQ=NKQ+1 - IF(KQ.NE.2) KQSUM=KQSUM+KQ - IF(KQ.NE.0.AND.KQSUM.NE.0) THEN - K(I,1)=2 - ELSEIF(KQ.EQ.2.AND.I.LT.N) THEN - IF(K(I+1,2).EQ.21) K(I,1)=2 - ENDIF - ENDIF - 180 CONTINUE - IF(NKQ.EQ.1.OR.KQSUM.NE.0) CALL LUERRM(8, - & '(LUHEPC:) input parton configuration not colour singlet') - ENDIF - - END - -C********************************************************************* - -CDECK ID>, LUTEST - SUBROUTINE LUTEST(MTEST) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to provide a simple program (disguised as subroutine) to -C...run at installation as a check that the program works as intended. - COMMON/LUJETS/K(4000,5),P(4000,5),V(4000,5),N - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - SAVE /LUJETS/,/LUDAT1/ - DIMENSION PSUM(5),PINI(6),PFIN(6) - -C...Loop over events to be generated. - IF(MTEST.GE.1) CALL LUTABU(20) - NERR=0 - DO 180 IEV=1,600 - -C...Reset parameter values. Switch on some nonstandard features. - MSTJ(1)=1 - MSTJ(3)=0 - MSTJ(11)=1 - MSTJ(42)=2 - MSTJ(43)=4 - MSTJ(44)=2 - PARJ(17)=0.1 - PARJ(22)=1.5 - PARJ(43)=1. - PARJ(54)=-0.05 - MSTJ(101)=5 - MSTJ(104)=5 - MSTJ(105)=0 - MSTJ(107)=1 - IF(IEV.EQ.301.OR.IEV.EQ.351.OR.IEV.EQ.401) MSTJ(116)=3 - -C...Ten events each for some single jets configurations. - IF(IEV.LE.50) THEN - ITY=(IEV+9)/10 - MSTJ(3)=-1 - IF(ITY.EQ.3.OR.ITY.EQ.4) MSTJ(11)=2 - IF(ITY.EQ.1) CALL LU1ENT(1,1,15.D0,0.D0,0.D0) - IF(ITY.EQ.2) CALL LU1ENT(1,3101,15.D0,0.D0,0.D0) - IF(ITY.EQ.3) CALL LU1ENT(1,-2203,15.D0,0.D0,0.D0) - IF(ITY.EQ.4) CALL LU1ENT(1,-4,30.D0,0.D0,0.D0) - IF(ITY.EQ.5) CALL LU1ENT(1,21,15.D0,0.D0,0.D0) - -C...Ten events each for some simple jet systems; string fragmentation. - ELSEIF(IEV.LE.130) THEN - ITY=(IEV-41)/10 - IF(ITY.EQ.1) CALL LU2ENT(1,1,-1,40.D0) - IF(ITY.EQ.2) CALL LU2ENT(1,4,-4,30.D0) - IF(ITY.EQ.3) CALL LU2ENT(1,2,2103,100.D0) - IF(ITY.EQ.4) CALL LU2ENT(1,21,21,40.D0) - IF(ITY.EQ.5) CALL LU3ENT(1,2101,21,-3203,30.D0,0.6D0,0.8D0) - IF(ITY.EQ.6) CALL LU3ENT(1,5,21,-5,40.D0,0.9D0,0.8D0) - IF(ITY.EQ.7) CALL LU3ENT(1,21,21,21,60.D0,0.7D0,0.5D0) - IF(ITY.EQ.8) - & CALL LU4ENT(1,2,21,21,-2,40.D0,0.4D0,0.64D0,0.6D0,0.12D0,0.2D0) - -C...Seventy events with independent fragmentation and momentum cons. - ELSEIF(IEV.LE.200) THEN - ITY=1+(IEV-131)/16 - MSTJ(2)=1+MOD(IEV-131,4) - MSTJ(3)=1+MOD((IEV-131)/4,4) - IF(ITY.EQ.1) CALL LU2ENT(1,4,-5,40.D0) - IF(ITY.EQ.2) CALL LU3ENT(1,3,21,-3,40.D0,0.9D0,0.4D0) - IF(ITY.EQ.3) - & CALL LU4ENT(1,2,21,21,-2,40.D0,0.4D0,0.64D0,0.6D0,0.12D0,0.2D0) - IF(ITY.GE.4) - & CALL LU4ENT(1,2,-3,3,-2,40.D0,0.4D0,0.64D0,0.6D0,0.12D0,0.2D0) - -C...A hundred events with random jets (check invariant mass). - ELSEIF(IEV.LE.300) THEN - 100 DO 110 J=1,5 - PSUM(J)=0. - 110 CONTINUE - NJET=2.+6.*RLU(0) - DO 130 I=1,NJET - KFL=21 - IF(I.EQ.1) KFL=INT(1.+4.*RLU(0)) - IF(I.EQ.NJET) KFL=-INT(1.+4.*RLU(0)) - EJET=5.+20.*RLU(0) - THETA=ACOS(2.*RLU(0)-1.) - PHI=6.2832*RLU(0) - IF(I.LT.NJET) CALL LU1ENT(-I,KFL,EJET,THETA,PHI) - IF(I.EQ.NJET) CALL LU1ENT(I,KFL,EJET,THETA,PHI) - IF(I.EQ.1.OR.I.EQ.NJET) MSTJ(93)=1 - IF(I.EQ.1.OR.I.EQ.NJET) PSUM(5)=PSUM(5)+ULMASS(KFL) - DO 120 J=1,4 - PSUM(J)=PSUM(J)+P(I,J) - 120 CONTINUE - 130 CONTINUE - IF(PSUM(4)**2-PSUM(1)**2-PSUM(2)**2-PSUM(3)**2.LT. - & (PSUM(5)+PARJ(32))**2) GOTO 100 - -C...Fifty e+e- continuum events with matrix elements. - ELSEIF(IEV.LE.350) THEN - MSTJ(101)=2 - CALL LUEEVT(0,40.D0) - -C...Fifty e+e- continuum event with varying shower options. - ELSEIF(IEV.LE.400) THEN - MSTJ(42)=1+MOD(IEV,2) - MSTJ(43)=1+MOD(IEV/2,4) - MSTJ(44)=MOD(IEV/8,3) - CALL LUEEVT(0,90.D0) - -C...Fifty e+e- continuum events with coherent shower, including top. - ELSEIF(IEV.LE.450) THEN - MSTJ(104)=6 - CALL LUEEVT(0,500.D0) - -C...Fifty Upsilon decays to ggg or gammagg with coherent shower. - ELSEIF(IEV.LE.500) THEN - CALL LUONIA(5,9.46D0) - -C...One decay each for some heavy mesons. - ELSEIF(IEV.LE.560) THEN - ITY=IEV-501 - KFLS=2*(ITY/20)+1 - KFLB=8-MOD(ITY/5,4) - KFLC=KFLB-MOD(ITY,5) - CALL LU1ENT(1,100*KFLB+10*KFLC+KFLS,0.D0,0.D0,0.D0) - -C...One decay each for some heavy baryons. - ELSEIF(IEV.LE.600) THEN - ITY=IEV-561 - KFLS=2*(ITY/20)+2 - KFLA=8-MOD(ITY/5,4) - KFLB=KFLA-MOD(ITY,5) - KFLC=MAX(1,KFLB-1) - CALL LU1ENT(1,1000*KFLA+100*KFLB+10*KFLC+KFLS,0.D0,0.D0,0.D0) - ENDIF - -C...Generate event. Find total momentum, energy and charge. - DO 140 J=1,4 - PINI(J)=PLU(0,J) - 140 CONTINUE - PINI(6)=PLU(0,6) - CALL LUEXEC - DO 150 J=1,4 - PFIN(J)=PLU(0,J) - 150 CONTINUE - PFIN(6)=PLU(0,6) - -C...Check conservation of energy, momentum and charge; -C...usually exact, but only approximate for single jets. - MERR=0 - IF(IEV.LE.50) THEN - IF((PFIN(1)-PINI(1))**2+(PFIN(2)-PINI(2))**2.GE.4.) MERR=MERR+1 - EPZREM=PINI(4)+PINI(3)-PFIN(4)-PFIN(3) - IF(EPZREM.LT.0..OR.EPZREM.GT.2.*PARJ(31)) MERR=MERR+1 - IF(ABS(PFIN(6)-PINI(6)).GT.2.1) MERR=MERR+1 - ELSE - DO 160 J=1,4 - IF(ABS(PFIN(J)-PINI(J)).GT.0.0001*PINI(4)) MERR=MERR+1 - 160 CONTINUE - IF(ABS(PFIN(6)-PINI(6)).GT.0.1) MERR=MERR+1 - ENDIF - IF(MERR.NE.0) WRITE(MSTU(11),5000) (PINI(J),J=1,4),PINI(6), - &(PFIN(J),J=1,4),PFIN(6) - -C...Check that all KF codes are known ones, and that partons/particles -C...satisfy energy-momentum-mass relation. Store particle statistics. - DO 170 I=1,N - IF(K(I,1).GT.20) GOTO 170 - IF(LUCOMP(K(I,2)).EQ.0) THEN - WRITE(MSTU(11),5100) I - MERR=MERR+1 - ENDIF - PD=P(I,4)**2-P(I,1)**2-P(I,2)**2-P(I,3)**2-P(I,5)**2 - IF(ABS(PD).GT.MAX(0.1D0,0.001*P(I,4)**2).OR.P(I,4).LT.0.) THEN - WRITE(MSTU(11),5200) I - MERR=MERR+1 - ENDIF - 170 CONTINUE - IF(MTEST.GE.1) CALL LUTABU(21) - -C...List all erroneous events and some normal ones. - IF(MERR.NE.0.OR.MSTU(24).NE.0.OR.MSTU(28).NE.0) THEN - CALL LULIST(2) - ELSEIF(MTEST.GE.1.AND.MOD(IEV-5,100).EQ.0) THEN - CALL LULIST(1) - ENDIF - -C...Stop execution if too many errors. - IF(MERR.NE.0) NERR=NERR+1 - IF(NERR.GE.10) THEN - WRITE(MSTU(11),5300) IEV - STOP - ENDIF - 180 CONTINUE - -C...Summarize result of run. - IF(MTEST.GE.1) CALL LUTABU(22) - IF(NERR.EQ.0) WRITE(MSTU(11),5400) - IF(NERR.GT.0) WRITE(MSTU(11),5500) NERR - -C...Reset commonblock variables changed during run. - MSTJ(2)=3 - PARJ(17)=0. - PARJ(22)=1. - PARJ(43)=0.5 - PARJ(54)=0. - MSTJ(105)=1 - MSTJ(107)=0 - -C...Format statements for output. - 5000 FORMAT(/' Momentum, energy and/or charge were not conserved ', - &'in following event'/' sum of',9X,'px',11X,'py',11X,'pz',11X, - &'E',8X,'charge'/' before',2X,4(1X,F12.5),1X,F8.2/' after',3X, - &4(1X,F12.5),1X,F8.2) - 5100 FORMAT(/5X,'Entry no.',I4,' in following event not known code') - 5200 FORMAT(/5X,'Entry no.',I4,' in following event has faulty ', - &'kinematics') - 5300 FORMAT(/5X,'Ten errors experienced by event ',I3/ - &5X,'Something is seriously wrong! Execution stopped now!') - 5400 FORMAT(//5X,'End result of LUTEST: no errors detected.') - 5500 FORMAT(//5X,'End result of LUTEST:',I2,' errors detected.'/ - &5X,'This should not have happened!') - - RETURN - END - -C********************************************************************* - -CDECK ID>, LUDATA - BLOCK DATA LUDATA - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - -C...Purpose: to give default values to parameters and particle and -C...decay data. - COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) - COMMON/LUDAT2/KCHG(500,3),PMAS(500,4),PARF(2000),VCKM(4,4) - COMMON/LUDAT3/MDCY(500,3),MDME(2000,2),BRAT(2000),KFDP(2000,5) - COMMON/LUDAT4/CHAF(500) - CHARACTER CHAF*8 - COMMON/LUDATR/MRLU(6),RRLU(100) - SAVE /LUDAT1/,/LUDAT2/,/LUDAT3/,/LUDAT4/,/LUDATR/ + COMMON/LUDAT3/MDCY(500,3),MDME(2000,2),BRAT(2000),KFDP(2000,5) + COMMON/LUDATR/MRLU(6),RRLU(100) + SAVE /LUDAT1/,/LUDAT2/,/LUDAT3/,/LUDATR/ C...LUDAT1, containing status codes and most parameters. DATA MSTU/ @@ -15559,36 +8990,7 @@ BLOCK DATA LUDATA DATA (KFDP(I,5),I= 1,2000)/90*0,111,16*0,111,7*0,111,0,2*111, &303*0,-211,2*111,-211,111,-211,111,54*0,111,-211,3*111,-211,111, &1510*0/ - -C...LUDAT4, with character strings. - DATA (CHAF(I) ,I= 1, 281)/'d','u','s','c','b','t','l','h', - &2*' ','e','nu_e','mu','nu_mu','tau','nu_tau','chi','nu_chi', - &2*' ','g','gamma','Z','W','H',2*' ','reggeon','pomeron',2*' ', - &'Z''','Z"','W''','H''','A','H','eta_tech','LQ_ue','R',40*' ', - &'specflav','rndmflav','phasespa','c-hadron','b-hadron', - &'t-hadron','l-hadron','h-hadron','Wvirt','diquark','cluster', - &'string','indep.','CMshower','SPHEaxis','THRUaxis','CLUSjet', - &'CELLjet','table',' ','pi',2*'K',2*'D','D_s',2*'B','B_s','B_c', - &'pi','eta','eta''','eta_c','eta_b','eta_t','eta_l','eta_h',2*' ', - &'rho',2*'K*',2*'D*','D*_s',2*'B*','B*_s','B*_c','rho','omega', - &'phi','J/psi','Upsilon','Theta','Theta_l','Theta_h',2*' ','b_1', - &2*'K_1',2*'D_1','D_1s',2*'B_1','B_1s','B_1c','b_1','h_1','h''_1', - &'h_1c','h_1b','h_1t','h_1l','h_1h',2*' ','a_0',2*'K*_0',2*'D*_0', - &'D*_0s',2*'B*_0','B*_0s','B*_0c','a_0','f_0','f''_0','chi_0c', - &'chi_0b','chi_0t','chi_0l','chi_0h',2*' ','a_1',2*'K*_1', - &2*'D*_1','D*_1s',2*'B*_1','B*_1s','B*_1c','a_1','f_1','f''_1', - &'chi_1c','chi_1b','chi_1t','chi_1l','chi_1h',2*' ','a_2', - &2*'K*_2',2*'D*_2','D*_2s',2*'B*_2','B*_2s','B*_2c','a_2','f_2', - &'f''_2','chi_2c','chi_2b','chi_2t','chi_2l','chi_2h',2*' ','K_L', - &'K_S',8*' ','psi''',3*' ','Upsilon''',45*' ','pi_diffr'/ - DATA (CHAF(I) ,I= 282, 500)/'n_diffr','p_diffr','rho_diff', - &'omega_di','phi_diff','J/psi_di',18*' ','Lambda',5*' ', - &'Lambda_c',' ',2*'Xi_c',6*' ','Lambda_b',' ',2*'Xi_b',6*' ','n', - &'p',' ',3*'Sigma',2*'Xi',' ',3*'Sigma_c',2*'Xi''_c','Omega_c', - &4*' ',3*'Sigma_b',2*'Xi''_b','Omega_b',4*' ',4*'Delta', - &3*'Sigma*',2*'Xi*','Omega',3*'Sigma*_c',2*'Xi*_c','Omega*_c', - &4*' ',3*'Sigma*_b',2*'Xi*_b','Omega*_b',114*' '/ - + C...LUDATR, with initial values for the random number generator. DATA MRLU/19780503,0,0,97,33,0/ @@ -15613,7 +9015,7 @@ SUBROUTINE LUTAUD(ITAU,IORIG,KFORIG,NDECAY) C... is not explicitly stored but the W code is still unambiguous. C...Output: C...NDECAY is the number of decay products in the current tau decay. -C...These decay products should be added to the /LUJETS/ common block, +C...These decay products should be added to the /LUJETS/ COMMON block, C...in positions N+1 through N+NDECAY. For each product I you must C...give the flavour codes K(I,2) and the five-momenta P(I,1), P(I,2), C...P(I,3), P(I,4) and P(I,5). The rest will be stored automatically. @@ -15622,16 +9024,16 @@ SUBROUTINE LUTAUD(ITAU,IORIG,KFORIG,NDECAY) COMMON/LUDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200) SAVE /LUJETS/,/LUDAT1/ -C...Stop program if this routine is ever called. +C...STOP program if this routine is ever called. C...You should not copy these lines to your own routine. NDECAY=ITAU+IORIG+KFORIG WRITE(MSTU(11),5000) IF(RLU(0).LT.10.) STOP -C...Format for error printout. +C...Format for error PRINTout. 5000 FORMAT(1X,'Error: you did not link your LUTAUD routine ', &'correctly.'/1X,'Dummy routine in JETSET file called instead.'/ - &1X,'Execution stopped!') + &1X,'Execution STOPped!') RETURN @@ -15709,52 +9111,32 @@ DOUBLE PRECISION FUNCTION RNDM(IDUMMY) RNDM=RUNI RETURN END -c***************************************************************************** -c**!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*** -c**!! IF YOU USE THIS PROGRAM, PLEASE CITE: !!*** -c**!! A.M"ucke, Ralph Engel, J.P.Rachen, R.J.Protheroe and Todor Stanev, !!*** -c**!! 1999, astro-ph/9903478, to appear in Comp.Phys.Commun. !!*** -c**!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*** -c***************************************************************************** -c** Further SOPHIA related papers: *** -c** (1) M"ucke A., et al 1999, astro-ph/9808279, to appear in PASA. *** -c** (2) M"ucke A., et al 1999, to appear in: Proc. of the *** -c** 19th Texas Symposium on Relativistic Astrophysics, Paris, France, *** -c** Dec. 1998. Eds.: J.~Paul, T.~Montmerle \& E.~Aubourg (CEA Saclay) *** -c** (3) M"ucke A., et al 1999, astro-ph/9905153, to appear in: Proc. of *** -c** 19th Texas Symposium on Relativistic Astrophysics, Paris, France, *** -c** Dec. 1998. Eds.: J.~Paul, T.~Montmerle \& E.~Aubourg (CEA Saclay) *** -c** (4) M"ucke A., et al 1999, to appear in: Proc. of 26th Int.Cosmic Ray *** -c** Conf. (Salt Lake City, Utah) *** -c***************************************************************************** + +C######################################################## +C This is the end of JETSET v 7.4 - Now SOPHIA resumes. # +C######################################################## + c********************************************** c** Routines/functions related to sampling *** -c** photon energy and squared CMF energy: *** c********************************************** - - subroutine sample_s(s,eps) - + SUBROUTINE sample_s(s,eps) c*********************************************************************** c samples distribution of s: p(s) = (s-mp^2)sigma_Ngamma c rejection for s=[sth,s0], analyt.inversion for s=[s0,smax] -c*********************************************************************** -c** Date: 20/01/98 ** -c** author: A.Muecke ** -c********************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) - SAVE +c*********************************************************************** + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + IMPLICIT INTEGER (I-N) + SAVE - common/input/ tbb,E0,alpha1,alpha2, - & epsm1,epsm2,epsb,L0 - COMMON /S_MASS1/ AM(49), AM2(49) + COMMON /input/ E0,L0 + COMMON /S_MASS1/ AM(49), AM2(49) - external functs,gauss,rndm - double precision functs,gauss,rndm + EXTERNAL functs,gauss,rndm + DOUBLE PRECISION functs,gauss,rndm c*** calculate smin,smax : ************************ xmpi = AM(7) @@ -15763,8 +9145,8 @@ subroutine sample_s(s,eps) smin = 1.1646D0 smax = max(smin,xmp*xmp+2.D0*eps*(E0+Pp)) if ((smax-smin).le.1.D-8) then - s = smin+rndm(0)*1.d-6 - RETURN + s = smin+rndm(0)*1.d-6 + RETURN endif s0 = 10.D0 c*** determine which method applies: rejection or analyt.inversion: ** @@ -15772,958 +9154,99 @@ subroutine sample_s(s,eps) sintegr2 = gauss(functs,s0,smax) if (smax.le.s0) then c rejection method: - nmethod=1 - goto 41 + nmethod=1 + goto 41 endif r1 = rndm(0) quo = sintegr1/(sintegr1+sintegr2) if (r1.le.quo) then c rejection method: - nmethod=1 + nmethod=1 else c analyt. inversion: - nmethod=2 + nmethod=2 endif - 41 continue - + 41 CONTINUE c*** rejection method: ************************ if (nmethod.eq.1) then - i_rept = 0 - 10 continue + i_rept = 0 + 10 CONTINUE c*** sample s random between smin ... s0 ** - if (i_rept.ge.100000) RETURN !LM - r2 = rndm(0) - s = smin+r2*(smax-smin) + if (i_rept.ge.100000) RETURN !LM + r2 = rndm(0) + s = smin+r2*(smax-smin) c*** calculate p(s) = pes ********************** - ps = functs(s) + ps = functs(s) c*** rejection method to sample s ********************* - r3 = rndm(1) + r3 = rndm(1) c pmax is roughly p(s) at s=s0 - pmax = 1300.D0/sintegr1 - i_rept = i_rept+1 - if (r3*pmax.le.ps/sintegr1) then - RETURN - else - goto 10 - endif + pmax = 1300.D0/sintegr1 + i_rept = i_rept+1 + if (r3*pmax.le.ps/sintegr1) then + RETURN + else + goto 10 + endif endif c*** analyt. inversion method: ******************* if (nmethod.eq.2) then - r4 = rndm(0) - beta = 2.04D0 - betai = 1.D0/beta - term1 = r4*(smax**beta) - term2 = (r4-1.D0)*(s0**beta) - s = (term1-term2)**betai - RETURN + r4 = rndm(0) + beta = 2.04D0 + betai = 1.D0/beta + term1 = r4*(smax**beta) + term2 = (r4-1.D0)*(s0**beta) + s = (term1-term2)**betai + RETURN endif - RETURN - END - + RETURN + END SUBROUTINE sample_s - subroutine sample_ir_eps(eps,epsmin,epsmax) -c**************************************************************************** -c samples distribution of n(epsilon)/epsilon^2 for ir background using -c rejection technique -c**************************************************************************** -c** Date: Aug '05 ** -c** author: G.Sigl ** -c********************** + DOUBLE PRECISION FUNCTION functs(s) +c Returns (s-pm^2)*sigma_Nucleon/gamma +c calling program is SAMPLE_S & sample_eps_blackbody IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) SAVE - - common/input/ tbb,E0,alpha1,alpha2, - & epsm1,epsm2,epsb,L0 - common/PLindex/ alphaxx - COMMON /S_MASS1/ AM(49), AM2(49) - - external photd_ir,rndm - double precision prob_epskt,prob_epspl,rndm,gauss - double precision functs,probint_pl - - xmpi = AM(7) - xmp = AM(L0) - Pp = sqrt(E0*E0-xmp*xmp) - epsm1 = max(epsmin,1.D9*(1.1646D0-xmp*xmp)/2.D0/(E0+Pp)) - - if (epsmax.gt.epsm1) then - i_max=idint(10.d0*dlog(epsmax/epsm1))+1 - de=dlog(epsmax/epsm1)/dble(i_max) - rmax=0.d0 - do i=0,i_max - eps_dum=epsm1*dexp(dble(i)*de) - dum=eps_dum**2*PHOTD_IR(eps_dum) - if (dum.gt.rmax) rmax=dum - enddo - beta=4.d0 - e1=epsm1**(1.d0-beta) - e2=epsmax**(1.d0-beta) - i_try=1 - i_rep = 0 - do while(i_try.eq.1) - if (i_rep.ge.100000) then - i_try = 0 - result = 0. - endif - r1 = rndm(0) - result=(r1*(e1-e2)+e2)**(1.d0/(1.d0-beta)) - r1 = rndm(1) - i_rep = i_rep + 1 - if (r1.lt.result**2*PHOTD_IR(result)/rmax) i_try=0 - enddo - else - result=0. - endif - eps=result - RETURN - END - - subroutine sample_eps(eps,epsmin,epsmax) - -c**************************************************************************** -c samples distribution of epsilon p(epsilon) for blackbody spectrum if tbb>0 -c and power law \sim eps^-alpha, epsm1 [eV] < eps [eV] < epsm2 [eV], -c eps in LAB frame if tbb \leq 0 -c**************************************************************************** -c** Date: 20/01/98 ** -c** author: A.Muecke ** -c********************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) - SAVE - - common/input/ tbb,E0,alpha1,alpha2, - & epsm1,epsm2,epsb,L0 - common/PLindex/ alphaxx - COMMON /S_MASS1/ AM(49), AM2(49) - - external prob_epskt,prob_epspl,rndm,gauss,functs,probint_pl - double precision prob_epskt,prob_epspl,rndm,gauss - double precision functs,probint_pl - - xmpi = AM(7) - xmp = AM(L0) - gammap = E0/xmp - betap = sqrt(1.-1./gammap/gammap) - Pp = sqrt(E0*E0-xmp*xmp) - 1 continue - facpmax = 1.6D0 -c*** for tbb<=0: power law photon spectrum n(eps) ~ eps^-alpha ********* - if (tbb.gt.0.D0) then - epsm1 = (1.1646D0-xmp*xmp)/2.D0/(E0+Pp) - epsm1 = epsm1*1.D9 - epsm2 = 0.007D0*tbb - epskt = 8.619D-5*tbb - epspmax = (3.D-3*((E0*epskt*1.D-9)**(-0.97D0)) - & +0.047D0)/3.9D2*tbb - if (epsm1.gt.epsm2) then - print*, - & 'CMF energy is below threshold for nucleon energy ' - & ,E0,' GeV !' - eps = 0.D0 - RETURN - endif - cnorm = gauss(prob_epskt,epsm1,epsm2) - pmaxc = prob_epskt(epspmax)/cnorm - pmax = facpmax*pmaxc - - else -c*** determine distribution: - epsth = (1.1646D0-xmp*xmp)/2.D0/(E0+Pp) - epsth = epsth*1.D9 - epsm1 = max(epsmin,epsth) - epsm2 = epsmax - if (epsm1.ge.epsm2) then - eps = 0. - RETURN - endif - endif - - epsmx1 = epsm1 - epsmx2 = epsm2 - epsbx = epsb - epsdelta = 0.159368/E0*1.d9 - epsxx = 126.D0/E0*1.d9 - alpha12 = alpha2-alpha1 - a1 = 1.D0 - 10 continue -c*** sample eps randomly between epsmin ... epsmax ** - r1 = rndm(0) -c*** calculate p(eps) = peps *************************************** - if (tbb.le.0.D0) then - rn = rndm(0) -c******************************************************************* -c... sample from straight power law (alpha = alpha2, epsb < epsm1): - if (alpha12.eq.0.D0.or.epsm1.ge.epsb) then - if (epsxx.ge.epsm2) then - alphaxx = alpha2 - else if (epsxx.le.epsm1) then - alphaxx = (alpha2+2.D0) - else if (epsm1.lt.epsxx.and.epsxx.lt.epsm2) then - a2 = epxx*epsxx - alphaxx = alpha2 - pintegr1 = a1*probint_pl(epsm1,epsxx,alphaxx) - alphaxx = (alpha2+2.D0) - pintegr2 = a2*probint_pl(epsxx,epsm2,alphaxx) - pintegr1 = pintegr1/(pintegr1+pintegr2) - if (rn.lt.pintegr1) then - alphaxx = alpha2 - epsm2 = epsxx - ampl = a1 - else if (pintegr1.le.rn.and.rn.lt.1.D0) then - alphaxx = alpha2+2.D0 - epsm1 = epsxx - ampl = a2 - endif - endif - endif -c... sample from broken power law: input always epsm1 < epsb < epsm2 - if (epsm1.lt.epsb) then -c... determine where epsb,epsxx lies: - if (epsm1.lt.epsxx.and.epsxx.lt.epsb) then - a2 = epxx*epsxx - a3 = a2*(epsb**(alpha2-alpha1)) - alphaxx = alpha1 - pintegr1 = a1*probint_pl(epsm1,epsxx,alphaxx) - alphaxx = (alpha1+2.D0) - pintegr2 = a2*probint_pl(epsxx,epsb,alphaxx) - alphaxx = (alpha2+2.D0) - pintegr3 = a3*probint_pl(epsb,epsm2,alphaxx) - pintegr1 = pintegr1/(pintegr1+pintegr2+pintegr3) - pintegr2 = (pintegr1+pintegr2)/(pintegr1+pintegr2+pintegr3) - pintegr3 = 1.D0 - if (rn.lt.pintegr1) then - alphaxx = alpha1 - epsm2 = epsxx - ampl = a1 - else if (pintegr1.le.rn.and.rn.lt.pintegr2) then - alphaxx = alpha1+2.D0 - epsm1 = epsxx - epsm2 = epsb - ampl = a2 - else if (pintegr2.le.rn.and.rn.le.pintegr3) then - alphaxx = alpha2+2.D0 - epsm1 = epsb - ampl = a3 - else - print*,'error in sampling broken power law: SAMPLE_EPS (1)!' - STOP - endif - - else if (epsb.le.epsxx.and.epsxx.lt.epsm2) then - a2 = epsb**(alpha2-alpha1) - a3 = a2*epsxx*epsxx - alphaxx = alpha1 - pintegr1 = a1*probint_pl(epsm1,epsb,alphaxx) - alphaxx = alpha2 - pintegr2 = a2*probint_pl(epsb,epsxx,alphaxx) - alphaxx = (alpha2+2.D0) - pintegr3 = a3*probint_pl(epsxx,epsm2,alphaxx) - pintegr1 = pintegr1/(pintegr1+pintegr2+pintegr3) - pintegr2 = (pintegr1+pintegr2)/(pintegr1+pintegr2+pintegr3) - pintegr3 = 1.D0 - if (rn.lt.pintegr1) then - alphaxx = alpha1 - epsm2 = epsb - ampl = a1 - else if (pintegr1.le.rn.and.rn.lt.pintegr2) then - alphaxx = alpha2 - epsm1 = epsb - epsm2 = epsxx - ampl = a2 - else if (pintegr2.le.rn.and.rn.le.pintegr3) then - alphaxx = alpha2+2.D0 - epsm1 = epsxx - ampl = a3 - else - print*,'error in sampling broken power law: SAMPLE_EPS (2)!' - STOP - endif - - else if (epsxx.ge.epsm2) then - a2 = epsb**(alpha2-alpha1) - a3 = 0.D0 - alphaxx = alpha1 - pintegr1 = a1*probint_pl(epsm1,epsb,alphaxx) - alphaxx = alpha2 - pintegr2 = a2*probint_pl(epsb,epsm2,alphaxx) - pintegr1 = pintegr1/(pintegr1+pintegr2) - pintegr2 = 1.D0 - if (rn.lt.pintegr1) then - alphaxx = alpha1 - epsm2 = epsb - ampl = a1 - else if (pintegr1.le.rn.and.rn.le.pintegr2) then - alphaxx = alpha2 - epsm1 = epsb - ampl = a2 - else - print*,'error in sampling broken power law: SAMPLE_EPS (3)!' - STOP - endif - - else if (epsxx.le.epsm1) then - a2 = epsb**(alpha2-alpha1) - a3 = 0.D0 - alphaxx = (alpha1+2.D0) - pintegr1 = a1*probint_pl(epsm1,epsb,alphaxx) - alphaxx = (alpha2+2.D0) - pintegr2 = a2*probint_pl(epsb,epsm2,alphaxx) - pintegr1 = pintegr1/(pintegr1+pintegr2) - pintegr2 = 1.D0 - if (rn.lt.pintegr1) then - alphaxx = alpha1+2.D0 - epsm2 = epsb - ampl = a1 - else if (pintegr1.le.rn.and.rn.le.pintegr2) then - alphaxx = alpha2+2.D0 - epsm1 = epsb - ampl = a2 - else - print*,'error in sampling broken power law: SAMPLE_EPS (4)!' - STOP - endif - - endif -cxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -c... END: sample from broken power law: - endif -c***************************************************** - if (alphaxx.eq.1.D0) then - term1 = r1*log(epsm2/epsm1) - eps = epsm1*exp(term1) - else - beta = 1.D0-alphaxx - betai = 1.D0/beta - term1 = r1*(epsm2**beta) - term2 = (r1-1.D0)*(epsm1**beta) - eps = (term1-term2)**betai - endif - - -c****************************************************** -c*** for thermal spectrum: *** - else - eps = epsm1+r1*(epsm2-epsm1) - peps = prob_epskt(eps)/cnorm -c endif -c*** rejection method to sample eps ********************* - r2 = rndm(0) - if (r2*pmax.gt.peps) then - goto 10 - endif - - endif - - epsm1 = epsmx1 - epsm2 = epsmx2 - epsb = epsbx - -c... check maximum of epsilon distribution: - if (pmax.lt.peps) then - facpmax = facpmax + 0.1D0 - goto 1 - endif - - RETURN - END - - - DOUBLE PRECISION function prob_epskt(eps) - -c*** calculates probability distribution for thermal photon field *** -c*** with temerature tbb (in K), eps (in eV) ************* -c** Date: 20/01/98 ** -c** author: A.Muecke ** -c********************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) - - SAVE - - common/input/ tbb,E0,alpha1,alpha2, - & epsm1,epsm2,epsb,L0 - - external functs,photd,gauss - double precision functs,photd,gauss - - xmpi = 0.135D0 - xmp = 0.93827D0 - Pp = sqrt(E0*E0-xmp*xmp) - gammap = E0/xmp - betap = sqrt(1.D0-1.D0/gammap/gammap) - deps = photd(eps,tbb) - if (deps.eq.0.D0) then - prob_epskt = 0.D0 - RETURN - else -c*** calculate \int_sth^smax ds (s-mp^2) sigma_pg ******* -c*** smin is for head-on collision ********************** - smin = 1.1646D0 - smax = max(smin,xmp*xmp+2.D0*eps/1.D9*E0*(1.D0+betap)) - sintegr = gauss(functs,smin,smax) - - prob_epskt = deps/eps/eps*sintegr/ - & 8.D0/betap/E0/E0*1.D18*1.D6 - endif - - RETURN - - END - - DOUBLE PRECISION function prob_epspl(eps) - -c*** calculates probability distribution for power law photon field *** -c*** n = anorm*eps^-alpha, eps=[epsm1,epsm2], eps in eV ************* -c** Date: 20/01/98 ** -c** author: A.Muecke ** -c********************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) - - SAVE - - common/input/ tbb,E0,alpha1,alpha2, - & epsm1,epsm2,epsb,L0 - - external functs,gauss - double precision functs,gauss - - xmpi = 0.135D0 - xmp = 0.93827D0 - Pp = sqrt(E0*E0-xmp*xmp) - gammap = E0/xmp - betap = sqrt(1.D0-1.D0/gammap/gammap) - alpha12 = alpha2-alpha1 - ampl = epsb**alpha12 - if (eps.lt.epsb) then - deps = eps**(-alpha1) - else - deps = ampl*(eps**(-alpha2)) - endif - -c*** calculate \int_sth^smax ds (s-mp^2) sigma_pg ******* -c*** smin is for head-on collision ********************** - smin = 1.1646D0 - smax = max(smin,xmp*xmp+2.D0*eps/1.D9*(E0+Pp)) - - sintegr = gauss(functs,smin,smax) - - prob_epspl = deps/eps/eps*sintegr/ - & 8.D0/betap/E0/E0*1.D18*1.D6 - - RETURN - - END - - DOUBLE PRECISION function probint_pl(epsi,epsf,p) - -c*** returns \int_epsi^epsf eps^-p ************** -c*** calling program is SAMPLE_EPS **************** -c** Date: 03/03/99 ** -c** author: A.Muecke ** -c********************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) - - SAVE - - if (p.eq.1.D0) then - probint_pl = log(epsf/epsi) - else - p1 = 1.D0-p - probint_pl = ((epsf**p1)-(epsi**p1))/p1 - endif - - RETURN - - END - - - DOUBLE PRECISION function functs(s) - -c*** returns (s-pm^2)*sigma_Ngamma ************** -c*** calling program is SAMPLE_S **************** -c** Date: 20/01/98 ** -c** author: A.Muecke ** -c********************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) - - SAVE - - common/input/ tbb,E0,alpha1,alpha2, - & epsm1,epsm2,epsb,L0 - - external crossection - double precision crossection - - - pm = 0.93827D0 - factor = (s-pm*pm) - epsprime = factor/2.D0/pm - sigma_pg = crossection(epsprime,3,L0) - functs = factor*sigma_pg - - RETURN - - END - - DOUBLE PRECISION FUNCTION PHOTD(EPS,TBB) -C ************************************************************** -C RETURNS THE DENSITY OF BLACKBODY RADIATION OF TEMPERATURE * -C "TBB" DEGREES (DENS1). EPS IN eV, PHOTD IN #/(cm^3.eV) * -C TSS, May '92 * -C ************************************************************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - SAVE -C CONVERT TEMPERATURE TO eV - EPH = EPS - EKT = 8.619D-5*TBB - EPHKT = EPS/EKT - IF (EPHKT .GT. 80.D0) GO TO 10 - IF (EPHKT .LT. 1.D-4) GO TO 11 - FEE = DEXP(EPHKT) - 1.D0 - GO TO 12 - 11 FEE = EPHKT - 12 BB = 1.318D13*EPH*EPH/FEE - GO TO 15 - 10 BB = 0.D0 - 15 PHOTD = BB - END - - DOUBLE PRECISION FUNCTION PHOTD_IR(EPS) -C ************************************************************** -C RETURNS THE DENSITY OF IR background at redshift Z* -C EPS IN eV, PHOTD_IR IN #/(cm^3.eV) * -C G.Sigl, Aug '05 * -C At the moment, redshift is a dummy variable within the program -C IR background from Primack et al. (1999) -C ************************************************************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) - SAVE -c NN put the following line up from some line below (f77 error) - COMMON /REDSHIFT/ Z,ZMAX_IR - PARAMETER (FLUX_CONVERSION = 3.82182d3) - - DIMENSION XData(15), YData(15) - DATA (XData(I),I=1,15)/ -1., -0.75, -0.5, -0.25, 0., -c COMMON /REDSHIFT/ Z,ZMAX_IR - & 0.25, 0.5, 0.75, 1., 1.25, 1.5, 1.75, 2., 2.25, 2.5/ -c DATA (YData(I),I=1,15)/ 0.8, 1.1, 1.15, 1.2, 1.3, -c & 1.2, 1.05, 0.7, 0.4, 0.3, 0.5, 0.8, 1.1, 1.3, 1./ -c Kneiske background - DATA (YData(I),I=1,15)/-0.214401, 0.349313, 0.720354, 0.890389, - & 1.16042, 1.24692, 1.06525, 0.668659, 0.536312, 0.595859, - & 0.457456, 0.623521, 1.20208, 1.33657, 1.04461/ -c Redshift evolution as for CMB. (added Dec.'05) -c conversion from nW/cm^3/sr to eV/cm^3 -c FLUX_CONVERSION = -c & 2.9979e10/4./dacos(-1.d0)*1.602e-19*1.e9*1.e4 -c PARAMETER (FLUX_CONVERSION = 3.82182d3) - -c print*,Z - -c conversion from eV to micrometers - X = 1.2398d0*(1.+Z)/EPS - if (X.gt.500.) then - RESULT=0. - else - if (dlog10(X).ge.XData(15)) then - RESULT = (YData(15) - YData(14))/(XData(15) - XData(14))* - & (dlog10(X) - XData(14)) + YData(14) - RESULT = 10.d0**RESULT - endif - endif - if (dlog10(X).le.XData(1)) RESULT=0. - if ((dlog10(X).lt.XData(15)).and.(dlog10(X).gt.XData(1))) then - INDEX = 2 - do while (XData(INDEX).lt.dlog10(X)) - INDEX = INDEX+1 - enddo - RESULT = (YData(INDEX) - YData(INDEX-1))/ - & (XData(INDEX) - XData(INDEX-1))*(dlog10(X) - XData(INDEX-1))+ - & YData(INDEX-1) - RESULT = 10.d0**RESULT - endif - PHOTD_IR = RESULT*(1.+Z)**2/(EPS/(1.+Z))**2/FLUX_CONVERSION - - if (Z.gt.ZMAX_IR) then - PHOTD_IR = 0.d0 - endif - - RETURN - END - - DOUBLE PRECISION function plinterpol(alpha) - -c*** interpolates p(Ep) to give the max. probability p(eps) for *** -c*** a given initial proton energy *** -c** Date: 20/01/98 ** -c** author: A.Muecke ** -c********************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) - SAVE - - DIMENSION AINDEX(4), A(4) - DATA A / 0.D0,1.D0,2.D0,3.D0/ - DATA AINDEX / 8.D8,5.D8,5.D8,1.D9/ - - plinterpol = 0.D0 - - do 1 ni=1,3 - p1 = A(ni) - p2 = A(ni+1) - if (alpha.le.p2.and.alpha.gt.p1) then - tang = (log10(AINDEX(ni+1))-log10(AINDEX(ni)))/(p2-p1) - plinterpol = log10(AINDEX(ni))+(alpha-p1)*tang - plinterpol = 10.D0**plinterpol - endif - 1 continue - - if (alpha.eq.0.D0) plinterpol = 5.D8 - - if (plinterpol.eq.0.D0) then - print*,'interpolation not sucessful !' -C pause - endif - - END - - DOUBLE PRECISION function f_epspl(eps) - -c*** gives energy density law of power law photon field *** -c*** f(epsilon) = eps^-alpha, eps=[epsm1,epsm2], eps in eV ************* -c** Date: 14/03/99 ** -c** author: A.Muecke ** -c********************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) - - SAVE - - common/input/ tbb,E0,alpha1,alpha2, - & epsm1,epsm2,epsb,L0 - - - alpha12 = alpha2-alpha1 - ampl = epsb**alpha12 - if (eps.lt.epsb) then - f_epspl = eps*(eps**(-alpha1)) - else - f_epspl = eps*ampl*(eps**(-alpha2)) - endif - - RETURN - - END - - - - -C ************************************************************** -C integrand for Total_rate_ir -C G.Sigl, Aug '05 * -C ************************************************************** - DOUBLE PRECISION function functs_int_ir(eps_ln) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) - - SAVE - common/input/ tbb,E0,alpha1,alpha2, - & epsm1,epsm2,epsb,L0 - COMMON /S_MASS1/ AM(49), AM2(49) - COMMON /REDSHIFT/ Z,ZMAX_IR - external functs,gauss - - eps=dexp(eps_ln) - xmpi = AM(7) - xmp = AM(L0) - Pp = sqrt(E0*E0-xmp*xmp) - smin = 1.1646D0 - smax = xmp*xmp+2.D0*eps*1.d-9*(E0+Pp) - s0 = 10.D0 - if (smax.lt.smin) result=0.d0 - if (smax.gt.smin) then - if (smax.le.s0) result=gauss(functs,smin,smax) - if (smax.gt.s0) result=gauss(functs,smin,s0)+ - & gauss(functs,s0,smax) - endif - functs_int_ir=photd_ir(eps)/eps*result - RETURN - END - -C ************************************************************** -C RETURNS interaction rate with IRB in Mpc^-1 -C G.Sigl, Aug '05 * -C ************************************************************** - DOUBLE PRECISION function Total_rate_ir(epsmin,epsmax) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) - - SAVE - common/input/ tbb,E0,alpha1,alpha2, - & epsm1,epsm2,epsb,L0 - COMMON /S_MASS1/ AM(49), AM2(49) - COMMON /REDSHIFT/ Z,ZMAX_IR - external functs_int_ir,gauss - - pm = 0.93827D0 - xmpi = AM(7) - xmp = AM(L0) - Pp = sqrt(E0*E0-xmp*xmp) - epsm1 = max(epsmin,1.D9*(1.1646D0-xmp*xmp)/2.D0/(E0+Pp)) - if (epsmax.gt.epsm1) then - result=2.d0*xmp*gauss(functs_int_ir,dlog(epsm1),dlog(epsmax)) - else - result=0.d0 - endif - Total_rate_ir=1.d18/8.d0/E0/Pp*result*1.d-30*3.0856d24 - - RETURN - END - -C ************************************************************** -C integrand for Total_rate_cmb -C G.Sigl, Aug '05 * -C ************************************************************** - DOUBLE PRECISION function functs_int_cmb(eps_ln) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) - - SAVE - common/input/ tbb,E0,alpha1,alpha2, - & epsm1,epsm2,epsb,L0 - COMMON /S_MASS1/ AM(49), AM2(49) - COMMON /REDSHIFT/ Z,ZMAX_IR - external functs,gauss - - eps=dexp(eps_ln) - xmpi = AM(7) - xmp = AM(L0) - Pp = sqrt(E0*E0-xmp*xmp) - smin = 1.1646D0 - smax = xmp*xmp+2.D0*eps*1.d-9*(E0+Pp) - s0 = 10.D0 - if (smax.lt.smin) result=0.d0 - if (smax.gt.smin) then - if (smax.le.s0) result=gauss(functs,smin,smax) - if (smax.gt.s0) result=gauss(functs,smin,s0)+ - & gauss(functs,s0,smax) - endif - functs_int_cmb=photd(eps,(1.d0+Z)*2.75)/eps*result - RETURN - END - -C ************************************************************** -C RETURNS total interaction rate with CMB in Mpc^-1 -C G.Sigl, Aug '05 * -C ************************************************************** - DOUBLE PRECISION function Total_rate_cmb(epsmin,epsmax) - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) - - SAVE - common/input/ tbb,E0,alpha1,alpha2, - & epsm1,epsm2,epsb,L0 - COMMON /S_MASS1/ AM(49), AM2(49) - COMMON /REDSHIFT/ Z,ZMAX_IR - external functs_int_cmb,gauss - - pm = 0.93827D0 - xmpi = AM(7) - xmp = AM(L0) - Pp = sqrt(E0*E0-xmp*xmp) - epsm1 = max(epsmin,1.D9*(1.1646D0-xmp*xmp)/2.D0/(E0+Pp)) - if (epsmax.gt.epsm1) then - result=2.d0*xmp*gauss(functs_int_cmb,dlog(epsm1),dlog(epsmax)) - else - result=0.d0 - endif - Total_rate_cmb=1.d18/8.d0/E0/Pp*result*1.d-30*3.0856d24 - - RETURN - END -c**************************************************************************** -c -c SOPHIAEVENT -c -c interface between Sophia and CRPropa -c simulate an interaction between p/n of given energy and the CMB -c -c Eric Armengaud, 2005 -c******************************* -c add Sept 2005 : redshift effect and interactions on IRB (from Primack 1999) -c**************************************************************************** - -c subroutine sophiaevent(nature,Ein,OutPart,OutPartType,NbOutPart, -c & z_particle,bgFlag,Zmax_IRB) - -c********************************** -c nature, Ein = input nature and energy of the nucleon -c nature = 0 -> p ; 1 -> n -c Ein : in GeV (SOPHIA standard energy unit) -c OutPart,OutPartType,NbOutPart = output data: -c P(2000,5) list of 4-momenta + masses of output particles -c LList(2000) list of output particle IDs -c NP nb of output particles -c Added Sept. 2005 : -c z_particle : needed to estimate the CMB temperature (no redshift -c evolution of IRB at the moment) -c bgFlag = 1 for CMB, 2 for Primack et al. (1999) IRB -c Added Dec. 2005 : -c zmax : now there is a "standard" IRB evolution which requires to -c know the redshift and z_max of the irb. -c********************************** -c IMPLICIT DOUBLE PRECISION (A-H,O-Z) -c IMPLICIT INTEGER (I-N) -c SAVE - -c COMMON/input/ tbb,E0,alpha1,alpha2, -c & epsm1,epsm2,epsb,L0cc - -c COMMON /REDSHIFT/ Z, ZMAX_IR - -c COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb -c COMMON /S_MASS1/ AM(49), AM2(49) -c COMMON /S_CHP/ S_LIFE(49), ICHP(49), ISTR(49), IBAR(49) -c COMMON /S_CSYDEC/ CBR(102), IDB(49), KDEC(612), LBARP(49) -c -c CHARACTER*6 NAMPRES -c COMMON /RES_PROP/ AMRES(9), SIG0(9),WIDTH(9), -c + NAMPRES(0:9) - -c CHARACTER*6 NAMPRESp -c COMMON /RES_PROPp/ AMRESp(9), BGAMMAp(9),WIDTHp(9), -c + RATIOJp(9),NAMPRESp(0:9) + COMMON /input/ E0,L0 -c CHARACTER*6 NAMPRESn -c COMMON /RES_PROPn/ AMRESn(9), BGAMMAn(9),WIDTHn(9), -c + RATIOJn(9),NAMPRESn(0:9) + EXTERNAL crossection + DOUBLE PRECISION crossection + pm = 0.93827D0 + factor = (s-pm*pm) + epsprime = factor/2.D0/pm + sigma_pg = crossection(epsprime,3,L0) + functs = factor*sigma_pg -c external sample_eps,sample_s,eventgen,initial,prob_epskt, -c & sample_ir_eps - -c integer nature -c integer bgFlag -c double precision Ein -c double precision z_particle -c double precision OutPart(2000,5) -c integer OutPartType(2000) -c integer NbOutPart - -c double precision epsmin,epsmax - -c DATA pi /3.141593D0/ - -c if (nature.eq.0) then -c L0=13 -c else if (nature.eq.1) then -c L0=14 -c else -c print*,'sophiaevent: incoming particle incorrectly specified' -c stop -c endif - -c$$$ call initial(L0) -c$$$ E0 = Ein -c$$$ pm = AM(L0) -c$$$ -c$$$ tbb=2.73*(1.D0+z_particle) -c$$$ Z = z_particle -c$$$ ZMAX_IR = Zmax_IRB -c$$$ -c$$$ if (bgFlag.eq.1) then -c$$$ epsmin = 0. -c$$$ epsmax = 0. -c$$$ call sample_eps(epseV,epsmin,epsmax) -c$$$ else if (bgFlag.eq.2) then -c$$$c Choice for epsmin/epsmax : the Primack data is for -1 p ; 1 -> n c Ein : in GeV (SOPHIA standard energy unit) +C eps : in eV c OutPart,OutPartType,NbOutPart = output data: c P(2000,5) list of 4-momenta + masses of output particles c LList(2000) list of output particle IDs c NP nb of output particles -c Added Sept. 2005 : -c z_particle : needed to estimate the CMB temperature (no redshift -c evolution of IRB at the moment) -c bgFlag = 1 for CMB, 2 for Primack et al. (1999) IRB -c Added Dec. 2005 : -c zmax : now there is a "standard" IRB evolution which requires to -c know the redshift and z_max of the irb. +C Removed Jun. 2018 : All eps-sampling and photon fields because this is bullshit. c********************************** - IMPLICIT DOUBLE PRECISION (A-H,O-Z) IMPLICIT INTEGER (I-N) SAVE - COMMON/input/ tbb,E0,alpha1,alpha2, - & epsm1,epsm2,epsb,L0 - - COMMON /REDSHIFT/ Z, ZMAX_IR + COMMON /input/ E0,L0 COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb COMMON /S_MASS1/ AM(49), AM2(49) @@ -16742,426 +9265,56 @@ subroutine sophiaevent(nature,Ein,OutPart,OutPartType,NbOut COMMON /RES_PROPn/ AMRESn(9), BGAMMAn(9),WIDTHn(9), + RATIOJn(9),NAMPRESn(0:9) + EXTERNAL sample_s - external sample_eps,sample_s,eventgen,initial,prob_epskt, - & sample_ir_eps - - integer nature - integer bgFlag - double precision Ein,Pp - double precision z_particle - double precision OutPart(2000,5) - integer OutPartType(2000) - integer NbOutPart - - double precision epsmin,epsmax + INTEGER nature + DOUBLE PRECISION Ein,Pp,eps +C DOUBLE PRECISION OutPart(2000,5) + DOUBLE PRECISION OutPart(2000) + INTEGER OutPartType(2000) + INTEGER NbOutPart DATA pi /3.141593D0/ - - -cc 15.09.2009 - integer idatamax - double precision en_data(idatamax),flux_data(idatamax) ! eV, eV/cm3 cc if (nature.eq.0) then - L0=13 + L0=13 else if (nature.eq.1) then - L0=14 + L0=14 else - print*,'sophiaevent: incoming particle incorrectly specified' - stop + PRINT*,'sophiaevent: incoming particle incorrectly specified' + STOP endif - call initial(L0) + CALL initial(L0) E0 = Ein pm = AM(L0) + eps = eps/1.D9 - tbb=2.73*(1.D0+z_particle) - Z = z_particle - ZMAX_IR = Zmax_IRB - -* check -c return -*** - if (bgFlag.eq.1) then - epsmin = 0. - epsmax = 0. - call sample_eps(epseV,epsmin,epsmax) - else if (bgFlag.eq.2) then -c Choice for epsmin/epsmax : the Primack data is for -1 1.D0: ', theta - theta = 0.D0 + PRINT*,'sophiaevent: theta > 1.D0: ', theta + theta = 0.D0 else if (theta.lt.-1.D0) then - print*,'sophiaevent: theta < -1.D0: ', theta - theta = 180.D0 + PRINT*,'sophiaevent: theta < -1.D0: ', theta + theta = 180.D0 else - theta = acos(theta)*180.D0/pi + theta = acos(theta)*180.D0/pi endif - call eventgen(L0,E0,eps,theta,Imode) + CALL eventgen(L0,E0,eps,theta,Imode) do i=1,2000 - do j=1,5 - OutPart(i,j)=P(i,j) - end do - OutPartType(i)=LLIST(i) +C do j=1,5 +C OutPart(i,j)=P(i,j) +C end do + OutPart(i)=P(i,4) + OutPartType(i)=LLIST(i) end do NbOutPart=NP - return - end - - -ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc - - subroutine sample_ir_eps2(eps,epsmin,epsmax - $ ,idatamax,en_data,flux_data) - - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) - SAVE - - common/input/ tbb,E0,alpha1,alpha2, - & epsm1,epsm2,epsb,L0 - common/PLindex/ alphaxx - COMMON /S_MASS1/ AM(49), AM2(49) - -cc 15.09.2009 - integer idatamax - double precision en_data(idatamax),flux_data(idatamax) ! eV, eV/cm3 - double precision prob_ir(idatamax) -ccc - - - xmpi = AM(7) ! Mpion (GeV) - xmp = AM(L0) ! Mp (GeV) - smin = 1.1646D0 ! (xmpi+xmp)**2 -c gammap = E0/xmp -c betap = sqrt(1.d0-1.d0/gammap/gammap) - Pp = sqrt(E0*E0-xmp*xmp) - - epsth = (smin-xmp*xmp)/2.D0/(E0+Pp) - epsth = epsth*1.D9 - epsm1 = max(epsmin,epsth) - - - factor = 2.d0 - - if (epsm1.ge.epsmax) then - eps = 0.d0 - - else -c find the maximum of E**2*prob_eps_ir -> calculation of alpha - e2prob_max = -1d100 - do i = 1,idatamax - eps = en_data(i) ! eV - prob_ir(i) = prob_eps_ir(eps - $ ,idatamax,en_data,flux_data) - - - if(eps**2*prob_ir(i) .gt. e2prob_max) then - eps_max = eps - e2prob_max = eps**2*prob_ir(i) - endif - enddo - alpha = e2prob_max - -c loop -> acceptance-rejection method, comparison function alpha*E^(-2) - do - r1 = rndm(0) - - eps = 1.d0/epsm1 - r1*(1.d0/epsm1 - 1.d0/epsmax) - eps = 1.d0/eps - - f_comp = factor*alpha*eps**(-2.d0) - - r2 = rndm(1) - Prob = divdif(prob_ir,en_data,idatamax,eps,1) - - if(Prob .gt. f_comp*r2) exit - enddo - endif - -*** check -c write(14,*)eps,Prob,f_comp -* 5 format(5E16.6) -*** - - - return - end - - -c.... - - double precision function prob_eps_ir(eps - $ ,idatamax,en_data,flux_data) ! eps (eV) - implicit none - - integer L0 - double precision tbb,E0,alpha1,alpha2,epsm1,epsm2,epsb,am - $ ,am2 - - common/input/ tbb,E0,alpha1,alpha2, - & epsm1,epsm2,epsb,L0 - COMMON /S_MASS1/ AM(49), AM2(49) - - external functs,photd,gauss - double precision functs,photd,gauss - - external n_ir - double precision n_ir - - double precision xmpi,xmp,Pp,gammap,betap,deps,eps - double precision smin,smax,sintegr - -c - integer idatamax - double precision en_data(idatamax),flux_data(idatamax) ! eV, eV/cm3 -c - - xmpi = 0.135D0 - xmp = am(l0) - Pp = sqrt(E0*E0-xmp*xmp) - gammap = E0/xmp - betap = sqrt(1.D0-1.D0/gammap/gammap) - deps = n_ir(eps,idatamax,en_data,flux_data) ! n_photon(eps) 1/(cm^3 eV) - - if (deps.eq.0.D0) then - prob_eps_ir = 0.D0 - RETURN - else -c*** calculate \int_sth^smax ds (s-mp^2) sigma_pg ******* -c*** smin is for head-on collision ********************** - smin = (xmpi+xmp)**2 ! GeV^2 - -c isotropy - smax = xmp*xmp+2.D0*eps/1.D9*E0*(1.D0+betap) - - endif - - - if(smax .gt. smin)then -c isotropy - sintegr = gauss(functs,smin,smax) ! GeV^4 microbn - - prob_eps_ir = deps/eps/eps*sintegr/ - & 8.D0/betap/E0/E0*1.D-12 ! 1/(cm^3 eV)*1/eV^2*GeV^4*microbn/GeV^2 -> 1/(cm*eV) - - else - prob_eps_ir = 0.d0 - endif - - return - end - - -c........ - - double precision function n_ir(eps,idatamax,en_data,flux_data)! 1/(eV cm3) - implicit none - - integer idatairmax - integer idatamax - double precision en_data(idatamax),flux_data(idatamax) ! eV, eV/cm3 - - double precision eps - external divdif - double precision divdif - - n_ir = divdif(flux_data,en_data,idatamax,eps,1) ! eV/cm^3 - n_ir = n_ir/eps**2 - - if(n_ir .lt. 0.d0)n_ir = 0.d0 - - return - end - - -c.............................................................................. -c Performs polynomial interpolation. The first term F(NN) contains the values. -c of the function to interpolate, A(NN) contains the corresponding x-values, . -c x is the point at which we want to evaluate the function and the last -c parameter MM corresponds to the order of the polynomial -c interpolation 1 p ; 14 -> n -c Ein : in GeV (SOPHIA standard energy unit) -c Nsec_arg : flag to request the total cross section -c crosssection : output. Total cross section (mub) -c********************************** - - IMPLICIT DOUBLE PRECISION (A-H,O-Z) - IMPLICIT INTEGER (I-N) - SAVE - - COMMON/input/ tbb,E0,alpha1,alpha2, - & epsm1,epsm2,epsb,L0 - - COMMON /REDSHIFT/ Z, ZMAX_IR - - COMMON /S_PLIST/ P(2000,5), LLIST(2000), NP, Ideb - COMMON /S_MASS1/ AM(49), AM2(49) - COMMON /S_CHP/ S_LIFE(49), ICHP(49), ISTR(49), IBAR(49) - COMMON /S_CSYDEC/ CBR(102), IDB(49), KDEC(612), LBARP(49) - - CHARACTER*6 NAMPRES - COMMON /RES_PROP/ AMRES(9), SIG0(9),WIDTH(9), - + NAMPRES(0:9) - - CHARACTER*6 NAMPRESp - COMMON /RES_PROPp/ AMRESp(9), BGAMMAp(9),WIDTHp(9), - + RATIOJp(9),NAMPRESp(0:9) - - CHARACTER*6 NAMPRESn - COMMON /RES_PROPn/ AMRESn(9), BGAMMAn(9),WIDTHn(9), - + RATIOJn(9),NAMPRESn(0:9) - - - external sample_eps,sample_s,eventgen,initial,prob_epskt, - & sample_ir_eps, crossection - - integer Npartid - integer Nsec_arg - double precision Ein - double precision crosssection - double precision epsprime - - DATA pi /3.141593D0/ - - L0=Npartid - - call initial(L0) - - E0 = Ein - pm = AM(L0) - tbb=2.73*(1.D0) - Z = 0 - - ZMAX_IR = 0 - - crosssection = crossection(epsprime, Nsec_arg, Npartid) - return - END + END SUBROUTINE sophiaevent From 6376344c161cb9e10f596a0e4edc61a96ad4153a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 18:02:30 +0100 Subject: [PATCH 05/81] implement ScalarGrid4d --- python/2_headers.i | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/python/2_headers.i b/python/2_headers.i index 5bd8e8163..194f2d573 100644 --- a/python/2_headers.i +++ b/python/2_headers.i @@ -285,10 +285,6 @@ %template(AdvectionFieldRefPtr) crpropa::ref_ptr; %include "crpropa/advectionField/AdvectionField.h" -%implicitconv crpropa::ref_ptr; -%template(DensityRefPtr) crpropa::ref_ptr; -%include "crpropa/massDistribution/Density.h" - %include "crpropa/Grid.h" %include "crpropa/GridTools.h" @@ -300,6 +296,10 @@ %template(ScalarGridRefPtr) crpropa::ref_ptr >; %template(ScalarGrid) crpropa::Grid; +%implicitconv crpropa::ref_ptr >; +%template(ScalarGrid4dRefPtr) crpropa::ref_ptr >; +%template(ScalarGrid4d) crpropa::Grid; + %include "crpropa/EmissionMap.h" %implicitconv crpropa::ref_ptr; %template(EmissionMapRefPtr) crpropa::ref_ptr; @@ -311,7 +311,6 @@ %include "crpropa/magneticField/QuimbyMagneticField.h" %include "crpropa/magneticField/AMRMagneticField.h" %include "crpropa/magneticField/JF12Field.h" -%include "crpropa/magneticField/JF12FieldSolenoidal.h" %include "crpropa/magneticField/PT11Field.h" %include "crpropa/magneticField/ArchimedeanSpiralField.h" %include "crpropa/module/BreakCondition.h" @@ -539,11 +538,3 @@ class ParticleCollectorIterator { }; %include "crpropa/module/ParticleCollector.h" - -%include "crpropa/massDistribution/Density.h" -%include "crpropa/massDistribution/Nakanishi.h" -%include "crpropa/massDistribution/Cordes.h" -%include "crpropa/massDistribution/Ferriere.h" -%include "crpropa/massDistribution/Massdistribution.h" -%include "crpropa/massDistribution/ConstantDensity.h" - From 47ef026ed16df5b33bec0172a424425dc60d0ed3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 18:11:58 +0100 Subject: [PATCH 06/81] - implement custom photon field - add geometry & time dependence of photon field --- include/crpropa/module/EMDoublePairProduction.h | 2 ++ include/crpropa/module/EMInverseComptonScattering.h | 2 ++ include/crpropa/module/EMPairProduction.h | 2 ++ include/crpropa/module/EMTripletPairProduction.h | 2 ++ include/crpropa/module/ElasticScattering.h | 4 +++- include/crpropa/module/ElectronPairProduction.h | 9 ++++++--- include/crpropa/module/PhotoDisintegration.h | 6 +++++- 7 files changed, 22 insertions(+), 5 deletions(-) diff --git a/include/crpropa/module/EMDoublePairProduction.h b/include/crpropa/module/EMDoublePairProduction.h index 0a8025512..343823c5f 100644 --- a/include/crpropa/module/EMDoublePairProduction.h +++ b/include/crpropa/module/EMDoublePairProduction.h @@ -18,6 +18,7 @@ namespace crpropa { class EMDoublePairProduction: public Module { private: PhotonField photonField; + ScalarGrid4d geometryGrid; bool haveElectrons; double limit; @@ -28,6 +29,7 @@ class EMDoublePairProduction: public Module { public: EMDoublePairProduction( PhotonField photonField = CMB, //!< target photon background + ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, 1.,1.), //!< spacial and temporal dependence of photon field bool haveElectrons = false, //!< switch to create the secondary electron pair double limit = 0.1 //!< step size limit as fraction of mean free path ); diff --git a/include/crpropa/module/EMInverseComptonScattering.h b/include/crpropa/module/EMInverseComptonScattering.h index 954f6a2ec..71d691d3f 100644 --- a/include/crpropa/module/EMInverseComptonScattering.h +++ b/include/crpropa/module/EMInverseComptonScattering.h @@ -18,6 +18,7 @@ namespace crpropa { class EMInverseComptonScattering: public Module { private: PhotonField photonField; + ScalarGrid4d geometryGrid; bool havePhotons; double limit; @@ -33,6 +34,7 @@ class EMInverseComptonScattering: public Module { public: EMInverseComptonScattering( PhotonField photonField = CMB, //!< target photon background + ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, 1.,1.), bool havePhotons = false, //!< switch to create secondary photon double limit = 0.1 //!< step size limit as fraction of mean free path ); diff --git a/include/crpropa/module/EMPairProduction.h b/include/crpropa/module/EMPairProduction.h index dc157f84c..e366404b8 100644 --- a/include/crpropa/module/EMPairProduction.h +++ b/include/crpropa/module/EMPairProduction.h @@ -19,6 +19,7 @@ namespace crpropa { class EMPairProduction: public Module { private: PhotonField photonField; + ScalarGrid4d geometryGrid; bool haveElectrons; double limit; @@ -34,6 +35,7 @@ class EMPairProduction: public Module { public: EMPairProduction( PhotonField photonField = CMB, //!< target photon background + ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, 1.,1.), bool haveElectrons = false, //!< switch to create secondary electron pair double limit = 0.1 //!< step size limit as fraction of mean free path ); diff --git a/include/crpropa/module/EMTripletPairProduction.h b/include/crpropa/module/EMTripletPairProduction.h index d30e4a827..845c4ac70 100644 --- a/include/crpropa/module/EMTripletPairProduction.h +++ b/include/crpropa/module/EMTripletPairProduction.h @@ -22,6 +22,7 @@ namespace crpropa { class EMTripletPairProduction: public Module { private: PhotonField photonField; + ScalarGrid4d geometryGrid; bool haveElectrons; double limit; @@ -37,6 +38,7 @@ class EMTripletPairProduction: public Module { public: EMTripletPairProduction( PhotonField photonField = CMB, //!< target photon background + ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, 1.,1.), bool haveElectrons = false, //!< switch to create secondary electron pair double limit = 0.1 //!< step size limit as fraction of mean free path ); diff --git a/include/crpropa/module/ElasticScattering.h b/include/crpropa/module/ElasticScattering.h index 01194ad1b..2eb4e4bc3 100644 --- a/include/crpropa/module/ElasticScattering.h +++ b/include/crpropa/module/ElasticScattering.h @@ -15,6 +15,7 @@ namespace crpropa { class ElasticScattering: public Module { private: PhotonField photonField; + ScalarGrid4d geometryGrid; std::vector tabRate; // elastic scattering rate std::vector > tabCDF; // CDF as function of background photon energy @@ -27,7 +28,8 @@ class ElasticScattering: public Module { static const size_t neps; // number of eps steps public: - ElasticScattering(PhotonField photonField = CMB); + ElasticScattering(PhotonField photonField = CMB, + ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, 1.,1.) ); void initRate(std::string filename); void initCDF(std::string filename); void setPhotonField(PhotonField photonField); diff --git a/include/crpropa/module/ElectronPairProduction.h b/include/crpropa/module/ElectronPairProduction.h index 2978ed4f9..8c590b753 100644 --- a/include/crpropa/module/ElectronPairProduction.h +++ b/include/crpropa/module/ElectronPairProduction.h @@ -23,6 +23,7 @@ namespace crpropa { class ElectronPairProduction: public Module { private: PhotonField photonField; + ScalarGrid4d geometryGrid; std::vector tabLossRate; /*< tabulated energy loss rate in [J/m] for protons at z = 0 */ std::vector tabLorentzFactor; /*< tabulated Lorentz factor */ std::vector > tabSpectrum; /*< electron/positron cdf(Ee|log10(gamma)) for log10(Ee/eV)=7-24 in 170 steps and log10(gamma)=6-13 in 70 steps and*/ @@ -30,8 +31,10 @@ class ElectronPairProduction: public Module { bool haveElectrons; public: - ElectronPairProduction(PhotonField photonField = CMB, bool haveElectrons = - false, double limit = 0.1); + ElectronPairProduction(PhotonField photonField = CMB, + ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, 1.,1.), + bool haveElectrons = false, + double limit = 0.1); void setPhotonField(PhotonField photonField); void setHaveElectrons(bool haveElectrons); @@ -53,7 +56,7 @@ class ElectronPairProduction: public Module { beta_A,Z(E) = Z^2 / A * beta_p(E/A) beta(E,z) = (1+z)^3 beta((1+z)E). */ - double lossLength(int id, double lf, double z=0) const; + double lossLength(int id, double lf, double z, Vector3d pos, double time) const; }; /** @}*/ diff --git a/include/crpropa/module/PhotoDisintegration.h b/include/crpropa/module/PhotoDisintegration.h index 4684faefc..e510a81e3 100644 --- a/include/crpropa/module/PhotoDisintegration.h +++ b/include/crpropa/module/PhotoDisintegration.h @@ -20,6 +20,7 @@ namespace crpropa { class PhotoDisintegration: public Module { private: PhotonField photonField; + ScalarGrid4d geometryGrid; double limit; // fraction of mean free path for limiting the next step bool havePhotons; @@ -42,7 +43,10 @@ class PhotoDisintegration: public Module { static const size_t nlg; // number of Lorentz-factor steps public: - PhotoDisintegration(PhotonField photonField = CMB, bool havePhotons = false, double limit = 0.1); + PhotoDisintegration(PhotonField photonField = CMB, + ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, 1.,1.), + bool havePhotons = false, + double limit = 0.1); void setPhotonField(PhotonField photonField); void setHavePhotons(bool havePhotons); From e550ef460c805f31761849c117f979b224179fd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 18:14:52 +0100 Subject: [PATCH 07/81] implement ScalarGrid4d --- include/crpropa/GridTools.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/crpropa/GridTools.h b/include/crpropa/GridTools.h index d1c081d4e..05f669ee7 100644 --- a/include/crpropa/GridTools.h +++ b/include/crpropa/GridTools.h @@ -81,6 +81,10 @@ void dumpGrid(ref_ptr grid, std::string filename, void dumpGrid(ref_ptr grid, std::string filename, double conversion = 1); +/** Load a VectorGrid grid from a plain text file */ +void loadGridFromTxt(ref_ptr grid, std::string filename, + double conversion = 1); + /** Load a VectorGrid grid from a plain text file */ void loadGridFromTxt(ref_ptr grid, std::string filename, double conversion = 1); From 30e88b590cbe238ef498d08e0e3042e7be547363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 18:15:31 +0100 Subject: [PATCH 08/81] - implement ScalarGrid4d - implement interpolation routine for ScalarGrid4d --- include/crpropa/Grid.h | 178 +++++++++++++++++++++++++++++++++++------ 1 file changed, 155 insertions(+), 23 deletions(-) diff --git a/include/crpropa/Grid.h b/include/crpropa/Grid.h index 3765d7451..cbbf3b4cb 100644 --- a/include/crpropa/Grid.h +++ b/include/crpropa/Grid.h @@ -34,7 +34,7 @@ inline double round(double r) { @class Grid @brief Template class for fields on a periodic grid with trilinear interpolation - The grid spacing is constant with diffrent resulution along all three axes. + The grid spacing is constant and equal along all three axes. Values are calculated by trilinear interpolation of the surrounding 8 grid points. The grid is periodically (default) or reflectively extended. The grid sample positions are at 1/2 * size/N, 3/2 * size/N ... (2N-1)/2 * size/N. @@ -42,13 +42,20 @@ inline double round(double r) { template class Grid: public Referenced { std::vector grid; - size_t Nx, Ny, Nz; /**< Number of grid points */ + size_t Nx, Ny, Nz, Nt; /**< Number of grid points (x,y,z) and number of time points (t) */ Vector3d origin; /**< Origin of the volume that is represented by the grid. */ Vector3d gridOrigin; /**< Grid origin */ - Vector3d spacing; /**< Distance between grid points, determines the extension of the grid */ + double spacing; /**< Distance between grid points, determines the spatial extension of the grid */ + double timing; /**< Time between grid points, determines the temporal extension of the grid */ + double startTime; /**< Point of time from which the grid starts */ bool reflective; /**< If set to true, the grid is repeated reflectively instead of periodically */ + public: + Grid() { + // empty constructor for initialization in some modules + } + /** Constructor for cubic grid @param origin Position of the lower left front corner of the volume @param N Number of grid points in one direction @@ -56,8 +63,10 @@ class Grid: public Referenced { */ Grid(Vector3d origin, size_t N, double spacing) { setOrigin(origin); - setGridSize(N, N, N); - setSpacing(Vector3d(spacing)); + setGridSize(N, N, N, 1); + setSpacing(spacing); + setTiming(1.); + setStartTime(0.); setReflective(false); } @@ -70,44 +79,64 @@ class Grid: public Referenced { */ Grid(Vector3d origin, size_t Nx, size_t Ny, size_t Nz, double spacing) { setOrigin(origin); - setGridSize(Nx, Ny, Nz); - setSpacing(Vector3d(spacing)); + setGridSize(Nx, Ny, Nz, 1); + setSpacing(spacing); + setTiming(1.); + setStartTime(0.); setReflective(false); } - - /** Constructor for non-cubic grid with spacing vector - @param origin Position of the lower left front corner of the volume + + // ScalarGrid4d + /** Constructor for 4-dimensional grid (space + time) + @param origin Position of the lower left front corner of the volume + @param start Starting point of time @param Nx Number of grid points in x-direction @param Ny Number of grid points in y-direction @param Nz Number of grid points in z-direction - @param spacing Spacing vector between grid points - */ - Grid(Vector3d origin, size_t Nx, size_t Ny, size_t Nz, Vector3d spacing) { - setOrigin(origin); - setGridSize(Nx, Ny, Nz); - setSpacing(spacing); - setReflective(false); - } + @param Nt Number of grid points in t-direction (set 1 for time-independent) + @param spacing Spacing between grid points + @param timing Amount of time between grid points in t-direction + */ + Grid(Vector3d origin, double start, size_t Nx, size_t Ny, size_t Nz, size_t Nt, double spacing, double timing) { + setOrigin(origin); + setGridSize(Nx, Ny, Nz, Nt); + setSpacing(spacing); + setTiming(timing); + setStartTime(start); + setReflective(false); + } void setOrigin(Vector3d origin) { this->origin = origin; - this->gridOrigin = origin + spacing/2; + this->gridOrigin = origin + Vector3d(spacing/2); } + // ScalarGrid4d + void setStartTime(double start) { + this->startTime = start; + } + + // ScalarGrid4d /** Resize grid, also enlarges the volume as the spacing stays constant */ - void setGridSize(size_t Nx, size_t Ny, size_t Nz) { + void setGridSize(size_t Nx, size_t Ny, size_t Nz, size_t Nt) { this->Nx = Nx; this->Ny = Ny; this->Nz = Nz; - grid.resize(Nx * Ny * Nz); + this->Nt = Nt; + grid.resize(Nx * Ny * Nz * Nt); setOrigin(origin); } - void setSpacing(Vector3d spacing) { + void setSpacing(double spacing) { this->spacing = spacing; setOrigin(origin); } + // ScalarGrid4d + void setTiming(double timing) { + this->timing = timing; + } + void setReflective(bool b) { reflective = b; } @@ -115,6 +144,12 @@ class Grid: public Referenced { Vector3d getOrigin() const { return origin; } + + // ScalarGrid4d + double getStartTime() const { + return startTime; + } + size_t getNx() const { return Nx; } @@ -127,10 +162,20 @@ class Grid: public Referenced { return Nz; } - Vector3d getSpacing() const { + // ScalarGrid4d + size_t getNt() const { + return Nt; + } + + double getSpacing() const { return spacing; } + // ScalarGrid4d + double getTiming() const { + return timing; + } + bool isReflective() const { return reflective; } @@ -145,10 +190,28 @@ class Grid: public Referenced { return grid[ix * Ny * Nz + iy * Nz + iz]; } + // ScalarGrid4d + /** Inspector & Mutator */ + T &get(size_t ix, size_t iy, size_t iz, size_t it) { + return grid[ix * Ny * Nz * Nt + iy * Nz * Nt + iz * Nt + it]; + } + + // ScalarGrid4d + /** Inspector & Mutator */ + const T &get(size_t ix, size_t iy, size_t iz, size_t it) const { + return grid[ix * Ny * Nz * Nt + iy * Nz * Nt + iz * Nt + it]; + } + T getValue(size_t ix, size_t iy, size_t iz) { return grid[ix * Ny * Nz + iy * Nz + iz]; } + // ScalarGrid4d + /** Inspector */ + T getValue(size_t ix, size_t iy, size_t iz, size_t it) { + return grid[ix * Ny * Nz * Nt + iy * Nz * Nt + iz * Nt + it]; + } + void setValue(size_t ix, size_t iy, size_t iz, T value) { grid[ix * Ny * Nz + iy * Nz + iz] = value; } @@ -233,8 +296,77 @@ class Grid: public Referenced { return b; } + + /** Interpolate the grid at a given position and point of time */ + T interpolate(const Vector3d &position, const double time) const { + // position on a unit grid + Vector3d r = (position - gridOrigin) / spacing; + double t = (time - startTime) / timing; + + // indices of lower and upper neighbors + int ix, iX, iy, iY, iz, iZ, it, iT; + if (reflective) { + reflectiveClamp(r.x, Nx, ix, iX); + reflectiveClamp(r.y, Ny, iy, iY); + reflectiveClamp(r.z, Nz, iz, iZ); + reflectiveClamp(t, Nt, it, iT); + } else { + periodicClamp(r.x, Nx, ix, iX); + periodicClamp(r.y, Ny, iy, iY); + periodicClamp(r.z, Nz, iz, iZ); + periodicClamp(t, Nt, it, iT); + } + + // linear fraction to lower and upper neighbors + double fx = r.x - floor(r.x); + double fX = 1 - fx; + double fy = r.y - floor(r.y); + double fY = 1 - fy; + double fz = r.z - floor(r.z); + double fZ = 1 - fz; + double ft = t - floor(t); + double fT = 1 - ft; + + // quadrilinear interpolation (generalized from: see http://paulbourke.net/miscellaneous/interpolation) + T b(0.); + //V0000 (1 - x) (1 - y) (1 - z) (1 - t) + + b += get(ix, iy, iz, it) * fX * fY * fZ * fT; + //V0001 (1 - x) (1 - y) (1 - z) t + + b += get(ix, iy, iz, iT) * fX * fY * fZ * ft; + //V1000 x (1 - y) (1 - z) (1 - t) + + b += get(iX, iy, iz, it) * fx * fY * fZ * fT; + //V1001 x (1 - y) (1 - z) t + + b += get(iX, iy, iz, iT) * fx * fY * fZ * ft; + //V0100 (1 - x) y (1 - z) (1 - t) + + b += get(ix, iY, iz, it) * fX * fy * fZ * fT; + //V0101 (1 - x) y (1 - z) t + + b += get(ix, iY, iz, iT) * fX * fy * fZ * ft; + //V0010 (1 - x) (1 - y) z (1 - t) + + b += get(ix, iy, iZ, it) * fX * fY * fz * fT; + //V0011 (1 - x) (1 - y) z t + + b += get(ix, iy, iZ, iT) * fX * fY * fz * ft; + //V1010 x (1 - y) z (1 - t) + + b += get(iX, iy, iZ, it) * fx * fY * fz * fT; + //V1011 x (1 - y) z t + + b += get(iX, iy, iZ, iT) * fx * fY * fz * ft; + //V0110 (1 - x) y z (1 - t) + + b += get(ix, iY, iZ, it) * fX * fy * fz * fT; + //V0111 (1 - x) y z t + + b += get(ix, iY, iZ, iT) * fX * fy * fz * ft; + //V1100 x y (1 - z) (1 - t) + + b += get(iX, iY, iz, it) * fx * fy * fZ * fT; + //V1101 x y (1 - z) t + + b += get(iX, iY, iz, iT) * fx * fy * fZ * ft; + //V1110 x y z (1 - t) + + b += get(iX, iY, iZ, it) * fx * fy * fz * fT; + //V1111 x y z t + b += get(iX, iY, iZ, iT) * fx * fy * fz * ft; + + return b; + } }; +typedef Grid ScalarGrid4d; typedef Grid VectorGrid; typedef Grid ScalarGrid; /** @}*/ From bb59f33ee7368eb5b2f3182a26b881298497ae7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 18:16:14 +0100 Subject: [PATCH 09/81] implement custom photon fields --- include/crpropa/PhotonBackground.h | 42 +++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/include/crpropa/PhotonBackground.h b/include/crpropa/PhotonBackground.h index 55b0302a8..457a08b29 100644 --- a/include/crpropa/PhotonBackground.h +++ b/include/crpropa/PhotonBackground.h @@ -1,7 +1,16 @@ #ifndef CRPROPA_PHOTONBACKGROUND_H #define CRPROPA_PHOTONBACKGROUND_H +#include +#include + +#include // cout, endl +#include // sqrt, pow #include +#include // write to file +#include // max_element +#include // for ::max +#include namespace crpropa { @@ -11,6 +20,7 @@ namespace crpropa { */ // Photon fields // The default IRB model is that of Kneiske et al. 2004 +// The slots PF1 to PF8 may be used for custom photon fields enum PhotonField { CMB, IRB, // same as IRB_Kneiske04 @@ -22,7 +32,9 @@ enum PhotonField { IRB_Gilmore12, IRB_Stecker16_upper, IRB_Stecker16_lower, - URB_Protheroe96 + URB_Protheroe96, + PF1, PF2, PF3, PF4, // customizable + PF5, PF6, PF7, PF8, // field slots }; // Returns overall comoving scaling factor @@ -31,6 +43,34 @@ double photonFieldScaling(PhotonField photonField, double z); // Returns a string representation of the field std::string photonFieldName(PhotonField photonField); + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// custom photon field methods +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class Photon_Field { + public: + explicit Photon_Field(std::string fieldPath); + Photon_Field(); + double sample_eps(bool onProton, double E_in, double z_in) const; + + private: + void init(std::string fieldPath); + std::vector energy; + std::vector< std::vector > dn_deps; + std::vector redshift; + double get_photonDensity(double eps, int z_pos) const; + double gaussInt(std::string type, double lowerLimit, double upperLimit, bool onProton, double E_in, int z_pos) const; + double functs(double s, bool onProton) const; + double prob_eps(double eps, bool onProton, double E_in, int z_pos) const; + double crossection(double eps, bool onProton) const; + double Pl(double, double, double, double) const; + double Ef(double, double, double) const; + double breitwigner(double, double, double, double, bool onProton) const; + double singleback(double) const; + double twoback(double) const; +}; + /** @}*/ } // namespace crpropa From 04e1fc76b5791f327fb7f71b0dd44d90f16aefc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 18:19:37 +0100 Subject: [PATCH 10/81] add higher time units {day, year, kyr, Myr, Gyr} --- include/crpropa/Units.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/crpropa/Units.h b/include/crpropa/Units.h index 4cffe2213..30e2f7261 100644 --- a/include/crpropa/Units.h +++ b/include/crpropa/Units.h @@ -124,6 +124,11 @@ static const double microsecond = 1e-6 * second; static const double millisecond = 1e-3 * second; static const double minute = 60 * second; static const double hour = 3600 * second; +static const double day = 24 * hour; +static const double year = 365.25636 * day; +static const double kyr = 1000 * year; +static const double Myr = 1000 * kyr; +static const double Gyr = 1000 * Myr; static const double ns = nanosecond; static const double mus = microsecond; static const double ms = millisecond; From 5623604ca3c7c53406f6c6b9c4d718256c15b0a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 18:20:33 +0100 Subject: [PATCH 11/81] - implement custom photon fields - remove option for non-redshift dependence - implement histogram version of SOPHIA --- include/crpropa/module/PhotoPionProduction.h | 33 ++++++++++++++------ 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/include/crpropa/module/PhotoPionProduction.h b/include/crpropa/module/PhotoPionProduction.h index 4175989e8..04c52a19e 100644 --- a/include/crpropa/module/PhotoPionProduction.h +++ b/include/crpropa/module/PhotoPionProduction.h @@ -1,10 +1,13 @@ #ifndef CRPROPA_PHOTOPIONPRODUCTION_H #define CRPROPA_PHOTOPIONPRODUCTION_H +// #include // ! c++11 and above only +#include +#include + #include "crpropa/Module.h" #include "crpropa/PhotonBackground.h" -#include namespace crpropa { /** @@ -19,8 +22,13 @@ namespace crpropa { class PhotoPionProduction: public Module { protected: PhotonField photonField; + ScalarGrid4d geometryGrid; + Photon_Field phtnfld; + std::vector hashMap; // contains histogram hashtags (workaround until c++11) + std::vector< std::vector > histData; // contains histogram data (workaround until c++11) + // std::unordered_map > particleMap; // if c++11 std::vector tabLorentz; ///< Lorentz factor of nucleus - std::vector tabRedshifts; ///< redshifts (optional for haveRedshiftDependence) + std::vector tabRedshifts; ///< redshifts std::vector tabProtonRate; ///< interaction rate in [1/m] for protons std::vector tabNeutronRate; ///< interaction rate in [1/m] for neutrons double limit; ///< fraction of mean free path to limit the next step @@ -28,30 +36,37 @@ class PhotoPionProduction: public Module { bool haveNeutrinos; bool haveElectrons; bool haveAntiNucleons; - bool haveRedshiftDependence; + bool useTabulatedData; public: PhotoPionProduction( PhotonField photonField = CMB, + ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, 1.,1.), bool photons = false, bool neutrinos = false, bool electrons = false, bool antiNucleons = false, - double limit = 0.1, - bool haveRedshiftDependence = false); + bool useTabulatedData = false, + double limit = 0.1); void setPhotonField(PhotonField photonField); void setHavePhotons(bool b); void setHaveNeutrinos(bool b); void setHaveElectrons(bool b); void setHaveAntiNucleons(bool b); - void setHaveRedshiftDependence(bool b); + void setUseTabulatedData(bool b); void setLimit(double limit); void initRate(std::string filename); - double nucleonMFP(double gamma, double z, bool onProton) const; + double nucleonMFP(double gamma, double z, bool onProton, Vector3d pos, double time) const; double nucleiModification(int A, int X) const; void process(Candidate *candidate) const; void performInteraction(Candidate *candidate, bool onProton) const; - + // related to histogram version of SOPHIA + void initHistogram(std::string filename); + std::string hashTag(int nature, double Ein, double eps, int ID, int multiplicity) const; + int produce(const std::vector &particle) const; + double drawEnergy(const std::vector &data) const; + double snapToHalfLog(double x) const; + std::vector sophiaEvent(bool onProton, double E, double e) const; /** Calculates the loss length E dx/dE in [m]. This is not used in the simulation. @@ -59,7 +74,7 @@ class PhotoPionProduction: public Module { @param gamma Lorentz factor of particle @param z redshift */ - double lossLength(int id, double gamma, double z = 0); + // double lossLength(int id, double gamma, double z = 0); }; /** @}*/ From b93bf1b69205d7a1443b35aa390a324d510365ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 18:24:06 +0100 Subject: [PATCH 12/81] - implement custom photon field - implement geometry and time dependence --- src/module/EMInverseComptonScattering.cpp | 27 +++++++++-- src/module/EMPairProduction.cpp | 31 ++++++++++-- src/module/EMTripletPairProduction.cpp | 37 +++++++++++--- src/module/ElasticScattering.cpp | 12 ++++- src/module/ElectronPairProduction.cpp | 22 ++++++--- src/module/PhotoDisintegration.cpp | 59 +++++++++++------------ 6 files changed, 135 insertions(+), 53 deletions(-) diff --git a/src/module/EMInverseComptonScattering.cpp b/src/module/EMInverseComptonScattering.cpp index f9b2c7545..465cd3898 100644 --- a/src/module/EMInverseComptonScattering.cpp +++ b/src/module/EMInverseComptonScattering.cpp @@ -11,8 +11,12 @@ namespace crpropa { static const double mec2 = mass_electron * c_squared; -EMInverseComptonScattering::EMInverseComptonScattering(PhotonField photonField, bool havePhotons, double limit) { +EMInverseComptonScattering::EMInverseComptonScattering(PhotonField photonField, + ScalarGrid4d geometryGrid, + bool havePhotons, + double limit) { setPhotonField(photonField); + this->geometryGrid = geometryGrid; this->havePhotons = havePhotons; this->limit = limit; } @@ -175,7 +179,16 @@ void EMInverseComptonScattering::performInteraction(Candidate *candidate) const // sample the value of s Random &random = Random::instance(); size_t i = closestIndex(E, tabE); - size_t j = random.randBin(tabCDF[i]); + Vector3d pos = candidate->current.getPosition(); + double time = candidate->getTrajectoryLength()/c_light; + double geometricScaling = geometryGrid.interpolate(pos, time); + if (geometricScaling == 0.) + return; + std::vector tabCDF_geoScaled; + for (int j = 0; j < tabCDF[i].size(); ++j) { + tabCDF_geoScaled.push_back(tabCDF[i][j]*geometricScaling); + } + size_t j = random.randBin(tabCDF_geoScaled); double s_kin = pow(10, log10(tabs[j]) + (random.rand() - 0.5) * 0.1); double s = s_kin + mec2 * mec2; @@ -208,8 +221,14 @@ void EMInverseComptonScattering::process(Candidate *candidate) const { return; // interaction rate - double rate = interpolate(E, tabEnergy, tabRate); - rate *= pow(1 + z, 2) * photonFieldScaling(photonField, z); + // geometric scaling + Vector3d pos = candidate->current.getPosition(); + double time = candidate->getTrajectoryLength()/c_light; + double rate = geometryGrid.interpolate(pos, time); + if (rate == 0.) + return; + rate *= interpolate(E, tabEnergy, tabRate); + rate *= pow(1 + z, 2) * photonFieldScaling(photonField, z); // check for interaction Random &random = Random::instance(); diff --git a/src/module/EMPairProduction.cpp b/src/module/EMPairProduction.cpp index f446424cd..9cb571754 100644 --- a/src/module/EMPairProduction.cpp +++ b/src/module/EMPairProduction.cpp @@ -11,8 +11,13 @@ namespace crpropa { static const double mec2 = mass_electron * c_squared; -EMPairProduction::EMPairProduction(PhotonField photonField, bool haveElectrons, double limit) : haveElectrons(haveElectrons), limit(limit) { +EMPairProduction::EMPairProduction(PhotonField photonField, + ScalarGrid4d geometryGrid, + bool haveElectrons, + double limit) : haveElectrons(haveElectrons), + limit(limit) { setPhotonField(photonField); + this->geometryGrid = geometryGrid; } void EMPairProduction::setPhotonField(PhotonField photonField) { @@ -181,7 +186,19 @@ void EMPairProduction::performInteraction(Candidate *candidate) const { // sample the value of s Random &random = Random::instance(); size_t i = closestIndex(E, tabE); // find closest tabulation point - size_t j = random.randBin(tabCDF[i]); + + // geometric scaling + Vector3d pos = candidate->current.getPosition(); + double time = candidate->getTrajectoryLength()/c_light; + double geometricScaling = geometryGrid.interpolate(pos, time); + if (geometricScaling == 0.) + return; + + std::vector tabCDF_geoScaled; + for (int j = 0; j < tabCDF[i].size(); ++j) { + tabCDF_geoScaled.push_back(tabCDF[i][j]*geometricScaling); + } + size_t j = random.randBin(tabCDF_geoScaled); double lo = std::max(4 * mec2 * mec2, tabs[j-1]); // first s-tabulation point below min(s_kin) = (2 me c^2)^2; ensure physical value double hi = tabs[j]; double s = lo + random.rand() * (hi - lo); @@ -192,7 +209,7 @@ void EMPairProduction::performInteraction(Candidate *candidate) const { double Ep = E - Ee; // sample random position along current step - Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition()); + pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition()); candidate->addSecondary(-11, Ee / (1 + z), pos); candidate->addSecondary(11, Ep / (1 + z), pos); } @@ -211,7 +228,13 @@ void EMPairProduction::process(Candidate *candidate) const { return; // interaction rate - double rate = interpolate(E, tabEnergy, tabRate); + // geometric scaling + Vector3d pos = candidate->current.getPosition(); + double time = candidate->getTrajectoryLength()/c_light; + double rate = geometryGrid.interpolate(pos, time); + if (rate == 0.) + return; + rate *= interpolate(E, tabEnergy, tabRate); rate *= pow(1 + z, 2) * photonFieldScaling(photonField, z); // check for interaction diff --git a/src/module/EMTripletPairProduction.cpp b/src/module/EMTripletPairProduction.cpp index beee907f1..5d20f7089 100644 --- a/src/module/EMTripletPairProduction.cpp +++ b/src/module/EMTripletPairProduction.cpp @@ -10,8 +10,12 @@ namespace crpropa { static const double mec2 = mass_electron * c_squared; -EMTripletPairProduction::EMTripletPairProduction(PhotonField photonField, bool haveElectrons, double limit) { +EMTripletPairProduction::EMTripletPairProduction(PhotonField photonField, + ScalarGrid4d geometryGrid, + bool haveElectrons, + double limit) { setPhotonField(photonField); + this->geometryGrid = geometryGrid; this->haveElectrons = haveElectrons; this->limit = limit; } @@ -107,13 +111,25 @@ void EMTripletPairProduction::performInteraction(Candidate *candidate) const { // sample the value of eps Random &random = Random::instance(); size_t i = closestIndex(E, tabE); - size_t j = random.randBin(tabCDF[i]); + + // geometric scaling + Vector3d pos = candidate->current.getPosition(); + double time = candidate->getTrajectoryLength()/c_light; + double geometricScaling = geometryGrid.interpolate(pos, time); + if (geometricScaling == 0.) + return; + + std::vector tabCDF_geoScaled; + for (int j = 0; j < tabCDF[i].size(); ++j) { + tabCDF_geoScaled.push_back(tabCDF[i][j]*geometricScaling); + } + size_t j = random.randBin(tabCDF_geoScaled); double s_kin = pow(10, log10(tabs[j]) + (random.rand() - 0.5) * 0.1); double eps = s_kin / 4 / E; // random background photon energy // Use approximation from A. Mastichiadis et al., Astroph. Journ. 300:178-189 (1986), eq. 30. // This approx is valid only for alpha >=100 where alpha = p0*eps*costheta - E0*eps - // For our purposes, me << E0 --> p0~E0 --> alpha = E0*eps*(costheta - 1) >= 100 + // For our purposes, me << E0 --> p0~E0 --> alpha = E0*eps*(costheta - 1) >= 100 <= Note by Mario: How is this even supposed to be >0? double Epp = 5.7e-1 * pow(eps/mec2, -0.56) * pow(E/mec2, 0.44) * mec2; if (haveElectrons) { @@ -123,7 +139,7 @@ void EMTripletPairProduction::performInteraction(Candidate *candidate) const { } // update the primary particle energy; do this after adding the secondaries to correctly set the secondaries parent - candidate->current.setEnergy((E - 2 * Epp)); + candidate->current.setEnergy(E - 2 * Epp); } void EMTripletPairProduction::process(Candidate *candidate) const { @@ -135,14 +151,21 @@ void EMTripletPairProduction::process(Candidate *candidate) const { // scale the particle energy instead of background photons double z = candidate->getRedshift(); double E = (1 + z) * candidate->current.getEnergy(); - + // check if in tabulated energy range if (E < tabEnergy.front() or (E > tabEnergy.back())) return; + // geometric scaling + Vector3d pos = candidate->current.getPosition(); + double time = candidate->getTrajectoryLength()/c_light; + double rate = geometryGrid.interpolate(pos, time); + if (rate == 0.) + return; + + rate *= interpolate(E, tabEnergy, tabRate); // cosmological scaling of interaction distance (comoving) - double scaling = pow(1 + z, 2) * photonFieldScaling(photonField, z); - double rate = scaling * interpolate(E, tabEnergy, tabRate); + rate *= pow(1 + z, 2) * photonFieldScaling(photonField, z); // check for interaction Random &random = Random::instance(); diff --git a/src/module/ElasticScattering.cpp b/src/module/ElasticScattering.cpp index ea56727e7..ef1ba9a4a 100644 --- a/src/module/ElasticScattering.cpp +++ b/src/module/ElasticScattering.cpp @@ -19,8 +19,9 @@ const double ElasticScattering::epsmin = log10(2 * eV) + 3; // log10 minimum const double ElasticScattering::epsmax = log10(2 * eV) + 8.12; // log10 maximum photon background energy in nucleus rest frame for elastic scattering const size_t ElasticScattering::neps = 513; // number of photon background energies in nucleus rest frame -ElasticScattering::ElasticScattering(PhotonField f) { +ElasticScattering::ElasticScattering(PhotonField f, ScalarGrid4d geometryGrid) { setPhotonField(f); + this->geometryGrid = geometryGrid; } void ElasticScattering::setPhotonField(PhotonField photonField) { @@ -82,6 +83,8 @@ void ElasticScattering::initCDF(std::string filename) { void ElasticScattering::process(Candidate *candidate) const { int id = candidate->current.getId(); double z = candidate->getRedshift(); + Vector3d pos = candidate->current.getPosition(); + double time = candidate->getTrajectoryLength()/c_light; if (not isNucleus(id)) return; @@ -97,7 +100,12 @@ void ElasticScattering::process(Candidate *candidate) const { double step = candidate->getCurrentStep(); while (step > 0) { - double rate = interpolateEquidistant(lg, lgmin, lgmax, tabRate); + // geometric scaling + double rate = geometryGrid.interpolate(pos, time); + if (rate == 0.) + return; + + rate *= interpolateEquidistant(lg, lgmin, lgmax, tabRate); rate *= Z * N / double(A); // TRK scaling rate *= pow(1 + z, 2) * photonFieldScaling(photonField, z); // cosmological scaling diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index d6e0f7cc1..0b1f00ccc 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -11,8 +11,11 @@ namespace crpropa { ElectronPairProduction::ElectronPairProduction(PhotonField photonField, - bool haveElectrons, double limit) { + ScalarGrid4d geometryGrid, + bool haveElectrons, + double limit) { setPhotonField(photonField); + this->geometryGrid = geometryGrid; this->haveElectrons = haveElectrons; this->limit = limit; } @@ -77,16 +80,19 @@ void ElectronPairProduction::initSpectrum(std::string filename) { infile.close(); } -double ElectronPairProduction::lossLength(int id, double lf, double z) const { +double ElectronPairProduction::lossLength(int id, double lf, double z, Vector3d pos, double time) const { double Z = chargeNumber(id); if (Z == 0) return std::numeric_limits::max(); // no pair production on uncharged particles - lf *= (1 + z); if (lf < tabLorentzFactor.front()) return std::numeric_limits::max(); // below energy threshold - double rate; + // geometric scaling + double rate = geometryGrid.interpolate(pos, time); + if (rate == 0.) + return std::numeric_limits::max(); + if (lf < tabLorentzFactor.back()) rate = interpolate(lf, tabLorentzFactor, tabLossRate); // interpolation else @@ -94,6 +100,7 @@ double ElectronPairProduction::lossLength(int id, double lf, double z) const { double A = nuclearMass(id) / mass_proton; // more accurate than massNumber(Id) rate *= Z * Z / A * pow(1 + z, 3) * photonFieldScaling(photonField, z); + return 1. / rate; } @@ -104,10 +111,13 @@ void ElectronPairProduction::process(Candidate *c) const { double lf = c->current.getLorentzFactor(); double z = c->getRedshift(); - double losslen = lossLength(id, lf, z); // energy loss length + Vector3d pos = c->current.getPosition(); + double time = c->getTrajectoryLength()/c_light; + + double losslen = lossLength(id, lf, z, pos, time); // energy loss length + // check if interaction does not happen if (losslen >= std::numeric_limits::max()) return; - double step = c->getCurrentStep() / (1 + z); // step size in local frame double loss = step / losslen; // relative energy loss diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index efc27b89c..0cf1efefd 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -3,7 +3,6 @@ #include "crpropa/ParticleID.h" #include "crpropa/ParticleMass.h" #include "crpropa/Random.h" -#include #include #include @@ -17,8 +16,12 @@ const double PhotoDisintegration::lgmin = 6; // minimum log10(Lorentz-factor) const double PhotoDisintegration::lgmax = 14; // maximum log10(Lorentz-factor) const size_t PhotoDisintegration::nlg = 201; // number of Lorentz-factor steps -PhotoDisintegration::PhotoDisintegration(PhotonField f, bool havePhotons, double limit) { +PhotoDisintegration::PhotoDisintegration(PhotonField f, + ScalarGrid4d geometryGrid, + bool havePhotons, + double limit) { setPhotonField(f); + this->geometryGrid = geometryGrid; this->havePhotons = havePhotons; this->limit = limit; } @@ -148,6 +151,9 @@ void PhotoDisintegration::initPhotonEmission(std::string filename) { void PhotoDisintegration::process(Candidate *candidate) const { // execute the loop at least once for limiting the next step double step = candidate->getCurrentStep(); + Vector3d pos = candidate->current.getPosition(); + double time = candidate->getTrajectoryLength()/c_light; + do { // check if nucleus int id = candidate->current.getId(); @@ -171,7 +177,11 @@ void PhotoDisintegration::process(Candidate *candidate) const { if ((lg <= lgmin) or (lg >= lgmax)) return; - double rate = interpolateEquidistant(lg, lgmin, lgmax, pdRate[idx]); + // geometrical scaling + double rate = geometryGrid.interpolate(pos, time); + if (rate == 0) + return; + rate *= interpolateEquidistant(lg, lgmin, lgmax, pdRate[idx]); rate *= pow(1 + z, 2) * photonFieldScaling(photonField, z); // cosmological scaling, rate per comoving distance // check if interaction occurs in this step @@ -200,7 +210,6 @@ void PhotoDisintegration::process(Candidate *candidate) const { } void PhotoDisintegration::performInteraction(Candidate *candidate, int channel) const { - KISS_LOG_DEBUG << "Photodisintegration::performInteraction. Channel " << channel << " on candidate " << candidate->getDescription(); // parse disintegration channel int nNeutron = digit(channel, 100000); int nProton = digit(channel, 10000); @@ -217,35 +226,25 @@ void PhotoDisintegration::performInteraction(Candidate *candidate, int channel) int Z = chargeNumber(id); double EpA = candidate->current.getEnergy() / A; + // update particle + candidate->current.setId(nucleusId(A + dA, Z + dZ)); + candidate->current.setEnergy(EpA * (A + dA)); + // create secondaries Random &random = Random::instance(); Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition()); - try - { - for (size_t i = 0; i < nNeutron; i++) - candidate->addSecondary(nucleusId(1, 0), EpA, pos); - for (size_t i = 0; i < nProton; i++) - candidate->addSecondary(nucleusId(1, 1), EpA, pos); - for (size_t i = 0; i < nH2; i++) - candidate->addSecondary(nucleusId(2, 1), EpA * 2, pos); - for (size_t i = 0; i < nH3; i++) - candidate->addSecondary(nucleusId(3, 1), EpA * 3, pos); - for (size_t i = 0; i < nHe3; i++) - candidate->addSecondary(nucleusId(3, 2), EpA * 3, pos); - for (size_t i = 0; i < nHe4; i++) - candidate->addSecondary(nucleusId(4, 2), EpA * 4, pos); - - - // update particle - candidate->created = candidate->current; - candidate->current.setId(nucleusId(A + dA, Z + dZ)); - candidate->current.setEnergy(EpA * (A + dA)); - } - catch (std::runtime_error &e) - { - KISS_LOG_ERROR << "Something went wrong in the PhotoDisentigration\n" << "Please report this error on https://github.com/CRPropa/CRPropa3/issues including your simulation setup and the following random seed:\n" << Random::instance().getSeed_base64(); - throw; - } + for (size_t i = 0; i < nNeutron; i++) + candidate->addSecondary(nucleusId(1, 0), EpA, pos); + for (size_t i = 0; i < nProton; i++) + candidate->addSecondary(nucleusId(1, 1), EpA, pos); + for (size_t i = 0; i < nH2; i++) + candidate->addSecondary(nucleusId(2, 1), EpA * 2, pos); + for (size_t i = 0; i < nH3; i++) + candidate->addSecondary(nucleusId(3, 1), EpA * 3, pos); + for (size_t i = 0; i < nHe3; i++) + candidate->addSecondary(nucleusId(3, 2), EpA * 3, pos); + for (size_t i = 0; i < nHe4; i++) + candidate->addSecondary(nucleusId(4, 2), EpA * 4, pos); if (not havePhotons) return; From 1509133c2bc6fa705e6ecba8ceb33eeaf417ba74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 18:25:00 +0100 Subject: [PATCH 13/81] - implement custom photon fields - remove option for non-redshift dependence - implement geometry and time-dependence - implement histogram version of SOPHIA --- src/module/PhotoPionProduction.cpp | 832 +++++++++++++++++++---------- 1 file changed, 555 insertions(+), 277 deletions(-) diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 03b5e4898..548f512e3 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -2,11 +2,14 @@ #include "crpropa/Units.h" #include "crpropa/ParticleID.h" #include "crpropa/Random.h" +#include "crpropa/PhotonBackground.h" #include -#include #include "sophia.h" +#include // srand, rand, abs ! +#include // log10 ! +#include // std::find #include #include #include @@ -15,324 +18,599 @@ namespace crpropa { -PhotoPionProduction::PhotoPionProduction(PhotonField field, bool photons, bool neutrinos, bool electrons, bool antiNucleons, double l, bool redshift) { - havePhotons = photons; - haveNeutrinos = neutrinos; - haveElectrons = electrons; - haveAntiNucleons = antiNucleons; - haveRedshiftDependence = redshift; - limit = l; - setPhotonField(field); + +PhotoPionProduction::PhotoPionProduction( PhotonField field, + ScalarGrid4d geometryGrid, + bool photons, + bool neutrinos, + bool electrons, + bool antiNucleons, + bool useTabData, + double l) { + havePhotons = photons; + haveNeutrinos = neutrinos; + haveElectrons = electrons; + haveAntiNucleons = antiNucleons; + useTabulatedData = useTabData; + limit = l; + setPhotonField(field); + this->geometryGrid = geometryGrid; + geometryGrid.setOrigin(Vector3d(-geometryGrid.getSpacing()/2.)); // correct for weird interpolation convention in CRPropa + this->phtnfld = Photon_Field(getDataPath("Scaling/" + photonFieldName(field) + ".txt")); + if (useTabData) initHistogram(getDataPath("PhotoPionProduction/SOPHIA_histogram.txt")); } + void PhotoPionProduction::setPhotonField(PhotonField field) { - photonField = field; - if (haveRedshiftDependence) { - std::cout << "PhotoPionProduction: tabulated redshift dependence not needed for CMB, switching off" << std::endl; - haveRedshiftDependence = false; - } - std::string fname = photonFieldName(field); - setDescription("PhotoPionProduction: " + fname); - if (haveRedshiftDependence) - initRate(getDataPath("PhotoPionProduction/rate_" + fname.replace(0, 3, "IRBz") + ".txt")); - else - initRate(getDataPath("PhotoPionProduction/rate_" + fname + ".txt")); + photonField = field; + std::string fname = photonFieldName(field); + setDescription("PhotoPionProduction: " + fname); + initRate(getDataPath("PhotoPionProduction/rate_" + fname + ".txt")); } void PhotoPionProduction::setHavePhotons(bool b) { - havePhotons = b; + havePhotons = b; } - + void PhotoPionProduction::setHaveElectrons(bool b) { - haveElectrons = b; + haveElectrons = b; } void PhotoPionProduction::setHaveNeutrinos(bool b) { - haveNeutrinos = b; + haveNeutrinos = b; } void PhotoPionProduction::setHaveAntiNucleons(bool b) { - haveAntiNucleons = b; + haveAntiNucleons = b; } -void PhotoPionProduction::setHaveRedshiftDependence(bool b) { - haveRedshiftDependence = b; - setPhotonField(photonField); +void PhotoPionProduction::setUseTabulatedData(bool b) { + useTabulatedData = b; } void PhotoPionProduction::setLimit(double l) { - limit = l; + limit = l; } void PhotoPionProduction::initRate(std::string filename) { - // clear previously loaded tables - tabLorentz.clear(); - tabRedshifts.clear(); - tabProtonRate.clear(); - tabNeutronRate.clear(); - - std::ifstream infile(filename.c_str()); - if (!infile.good()) - throw std::runtime_error("PhotoPionProduction: could not open file " + filename); - - if (haveRedshiftDependence) { - double zOld = -1, aOld = -1; - while (infile.good()) { - if (infile.peek() == '#') { - infile.ignore(std::numeric_limits::max(), '\n'); - continue; - } - double z, a, b, c; - infile >> z >> a >> b >> c; - if (!infile) - break; - if (z > zOld) { - tabRedshifts.push_back(z); - zOld = z; - } - if (a > aOld) { - tabLorentz.push_back(pow(10, a)); - aOld = a; - } - tabProtonRate.push_back(b / Mpc); - tabNeutronRate.push_back(c / Mpc); - } - } else { - while (infile.good()) { - if (infile.peek() == '#') { - infile.ignore(std::numeric_limits::max(), '\n'); - continue; - } - double a, b, c; - infile >> a >> b >> c; - if (!infile) - break; - tabLorentz.push_back(pow(10, a)); - tabProtonRate.push_back(b / Mpc); - tabNeutronRate.push_back(c / Mpc); - } - } - - infile.close(); + // clear previously loaded tables + tabLorentz.clear(); + tabRedshifts.clear(); + tabProtonRate.clear(); + tabNeutronRate.clear(); + + std::ifstream infile(filename.c_str()); + if (!infile.good()) + throw std::runtime_error("PhotoPionProduction: could not open file " + filename); + + double zOld = -1, aOld = -1; + while (infile.good()) { + if (infile.peek() == '#') { + infile.ignore(std::numeric_limits::max(), '\n'); + continue; + } + double z, a, b, c; + infile >> z >> a >> b >> c; + if (!infile) + break; + if (z > zOld) { + tabRedshifts.push_back(z); + zOld = z; + } + if (a > aOld) { + tabLorentz.push_back(pow(10, a)); + aOld = a; + } + tabProtonRate.push_back(b / Mpc); + tabNeutronRate.push_back(c / Mpc); + } + + infile.close(); +} + +/* + related to histogram version of SOPHIA: + - initHistogram + - hashTag + - produce + - drawEnergy + - snapToHalfLog + - sophiaEvent +*/ + +void PhotoPionProduction::initHistogram(std::string filename) { + // read in histogram file + hashMap.clear(); + histData.clear(); + std::ifstream infile(filename.c_str()); + if (!infile.good()) + throw std::runtime_error("PhotoPionProduction: Could not open file " + filename); + + std::string line; + while ( std::getline(infile, line) ) { + std::istringstream ss(line); + std::string hash; + ss >> hash; + std::vector vec; + double n; + while (ss >> n) vec.push_back(n); + // input.insert({ hash, vec }); // with C++11 + hashMap.push_back(hash); + histData.push_back(vec); + } + infile.close(); +} + + +std::string PhotoPionProduction::hashTag(int n, // nucleon type + double E, // primary Energy + double e, // photon energy + int ID, // particle to be produced + int m = 0 // amount of particles produced in this event + ) const { + // method to generate hash tags for navigation in std::unordered_map + std::stringstream hash; + int exp = std::floor(log10(E)); + int pre = E/pow(10, exp); + hash << "#" << n << "_" << pre << "e"; + (exp >= 0)? hash << "+" : hash << "-"; + if (exp < 10) hash << "0"; + hash << std::abs(exp) << "_"; + exp = std::floor(log10(e)); + pre = e/pow(10, exp); + hash << pre << "e"; + (exp >= 0)? hash << "+" : hash << "-"; + if (exp < 10) hash << "0"; + hash << std::abs(exp) << "_" << ID; + if (m > 0) hash << "_x" << m; + return hash.str(); } -double PhotoPionProduction::nucleonMFP(double gamma, double z, bool onProton) const { - const std::vector &tabRate = (onProton)? tabProtonRate : tabNeutronRate; - // scale nucleus energy instead of background photon energy - gamma *= (1 + z); - if (gamma < tabLorentz.front() or (gamma > tabLorentz.back())) - return std::numeric_limits::max(); +int PhotoPionProduction::produce(const std::vector &particle) const { +/* + - input: probability vector with chances to produce: [0,1,...n] particles + - output: number of particles being produced +*/ + if (particle.size() == 0) + return 0; + Random &random = Random::instance(); + double r = random.rand(); + int index = 0; + while ((r >= 0) && (index < particle.size())) { + r -= particle[index]; + index++; + } + return index-1; +} + - double rate; - if (haveRedshiftDependence) - rate = interpolate2d(z, gamma, tabRedshifts, tabLorentz, tabRate); - else - rate = interpolate(gamma, tabLorentz, tabRate) * photonFieldScaling(photonField, z); +double PhotoPionProduction::drawEnergy(const std::vector &data) const { + /* + input format: first half of vector contains probabilities to draw + a certain energy contained in the second half + output: energy + */ + if (data.size() == 0) + return 0.; + std::vector p, E; + for (int i = 0; i < data.size(); ++i) { + p.push_back(data[i]); + E.push_back(data[i+data.size()/2]); + } + int pos = produce(p); + if (pos == 0) + return E[pos]; + // interpolation + Random &random = Random::instance(); + double r = random.rand(); + return E[pos-1]*(1.-r) + r*E[pos]; +} - // cosmological scaling - rate *= pow(1 + z, 2); - return 1. / rate; +double PhotoPionProduction::snapToHalfLog(double x) const { + /* + method to aid the hashTag function + selects the closest value where histogram data is available + */ + int exp = std::floor(log10(x)); + double pre = x/pow(10, exp); + if (pre == 1.0) + return x; + double result = pow(10, std::ceil(log10(x))); + if (pre < 2.5) + return result / 10.; + if (pre >= 7.5) + return result; + return result / 2.; +} + + +std::vector PhotoPionProduction::sophiaEvent(bool onProton, // 0=p, 1=n + double E, // primary nucleon's energy / GeV + double e // target photon's energy / eV + ) const { + /* + Histogram version of SOPHIA. + */ + const double nature = 1 - static_cast(onProton); + const double E_in = snapToHalfLog(E); + const double eps = snapToHalfLog(e); + std::vector output; + std::string hash; + ptrdiff_t whereHash; + + hash = hashTag(nature, E_in, eps, 13); + whereHash = std::find(hashMap.begin(), hashMap.end(), hash) - hashMap.begin(); + const std::vector proton = histData[whereHash]; + + hash = hashTag(nature, E_in, eps, 14); + whereHash = std::find(hashMap.begin(), hashMap.end(), hash) - hashMap.begin(); + const std::vector neutron = histData[whereHash]; + + // return primary if no histogram for E and e is available + if (proton.size() == 0 && neutron.size() == 0) { + int id = (onProton)? 13 : 14; + output.push_back(id); + output.push_back(E_in); + return output; + } + + hash = hashTag(nature, E_in, eps, 1); + whereHash = std::find(hashMap.begin(), hashMap.end(), hash) - hashMap.begin(); + const std::vector photon = histData[whereHash]; + + hash = hashTag(nature, E_in, eps, 2); + whereHash = std::find(hashMap.begin(), hashMap.end(), hash) - hashMap.begin(); + const std::vector positron = histData[whereHash]; + + hash = hashTag(nature, E_in, eps, 3); + whereHash = std::find(hashMap.begin(), hashMap.end(), hash) - hashMap.begin(); + const std::vector electron = histData[whereHash]; + + hash = hashTag(nature, E_in, eps, -13); + whereHash = std::find(hashMap.begin(), hashMap.end(), hash) - hashMap.begin(); + const std::vector antiProton = histData[whereHash]; + + hash = hashTag(nature, E_in, eps, -14); + whereHash = std::find(hashMap.begin(), hashMap.end(), hash) - hashMap.begin(); + const std::vector antiNeutron = histData[whereHash]; + + hash = hashTag(nature, E_in, eps, 15); + whereHash = std::find(hashMap.begin(), hashMap.end(), hash) - hashMap.begin(); + const std::vector nu_e = histData[whereHash]; + + hash = hashTag(nature, E_in, eps, 16); + whereHash = std::find(hashMap.begin(), hashMap.end(), hash) - hashMap.begin(); + const std::vector antiNu_e = histData[whereHash]; + + hash = hashTag(nature, E_in, eps, 17); + whereHash = std::find(hashMap.begin(), hashMap.end(), hash) - hashMap.begin(); + const std::vector nu_mu = histData[whereHash]; + + const std::vector antiNu_mu = nu_mu; + +// ######################################################## +// ### particle production (without energy) +// ######################################################## + const int Le_in = 0; + const int charge_in = 1 - nature; + const int Nnuc_in = 1; + + int Le = 0, charge = 0, Nnuc = 0; + int N_electron = 0, N_positron = 0, + N_antiNu_e = 0, N_nu_e = 0, + N_proton = 0, N_neutron = 0, + N_antiProton = 0, N_antiNeutron = 0, + N_photon = 0, N_nu_mu = 0, N_antiNu_mu = 0; + + // looped particle production (preserves quantum numbers) + do { // lepton loop + do { // charge loop + do { // nucleon loop + // reset particles for new production loop + Le = 0; + charge = 0; + Nnuc = 0; + N_electron = 0; + N_positron = 0; + N_antiNu_e = 0; + N_nu_e = 0; + N_proton = 0; + N_neutron = 0; + N_antiProton = 0; + N_antiNeutron = 0; + + N_proton += produce(proton); + charge += N_proton; + Nnuc += N_proton; + + N_neutron += produce(neutron); + Nnuc += N_neutron; + + N_nu_e += produce(nu_e); + Le += N_nu_e; + + N_antiNu_e += produce(antiNu_e); + Le -= N_antiNu_e; + + N_electron += produce(electron); + charge -= N_electron; + Le += N_electron; + + N_positron += produce(positron); + charge += N_positron; + Le -= N_positron; + + N_antiProton += produce(antiProton); + charge -= N_antiProton; + Nnuc -= N_antiProton; + + N_antiNeutron += produce(antiNeutron); + Nnuc -= N_antiNeutron; + } while ( Nnuc != Nnuc_in ); + } while ( charge != charge_in ); + } while ( Le != Le_in ); + do { + N_nu_mu = 0; + N_antiNu_mu = 0; + N_nu_mu += produce(nu_mu); + N_antiNu_mu += N_nu_mu; // antiNu_mu equals nu_mu + } while ( N_nu_mu != (N_nu_e + N_antiNu_e) ); + + // experimental setup + // N_nu_mu = N_nu_e + N_antiNu_e; + // N_antiNu_mu = N_nu_mu; // antiNu_mu equals nu_mu + + N_photon = produce(photon); + + // std::cout << "[" << N_electron << "e-," << N_positron << "e+," << N_nu_e << "ne," << N_antiNu_e << "~ne," << N_proton << "p," + // << N_neutron << "n," << N_nu_mu << "nm," << N_antiNu_mu << "~nm," + // << N_photon << "ph," << N_antiProton << "~p," << N_antiNeutron << "~n]@[" + // << Le << "L," << charge << "C," << Nnuc << "N] " << std::endl; + +// ######################################################## +// ### draw energy of produced particles +// ######################################################## + double availableEnergy = E; + std::vector outE; + double E_part; + const int pCount[] = {N_antiNeutron, N_antiProton, N_photon, + N_positron, N_electron, N_proton, + N_neutron, N_nu_e, N_antiNu_e, + N_nu_mu, N_antiNu_mu}; + const int partID[] = {-14, -13, 1, 2, 3, 13, 14, 15, 16, 17, 18}; + for (int j = 0; j < 11; ++j) { + for (int k = 0; k < pCount[j]; ++k) { + output.push_back(partID[j]); + int id = (partID[j] == 18)? 17 : partID[j]; // ~nu_mu=nu_mu + hash = hashTag(nature, E_in, eps, id, pCount[j]); + whereHash = std::find(hashMap.begin(), hashMap.end(), hash) - hashMap.begin(); + E_part = drawEnergy(histData[whereHash]); + availableEnergy -= E_part; + outE.push_back(E_part); + } + } + // preserve energy + double weight = E / (E - availableEnergy); + int nOutPart = output.size(); + for (int j = 0; j < nOutPart; ++j) { + output.push_back(outE[j]*weight); + } + return output; +} + + +double PhotoPionProduction::nucleonMFP(double gamma, double z, bool onProton, Vector3d pos, double time) const { + const std::vector &tabRate = (onProton)? tabProtonRate : tabNeutronRate; + + // scale nucleus energy instead of background photon energy + gamma *= (1 + z); + if (gamma < tabLorentz.front() or (gamma > tabLorentz.back())) + return std::numeric_limits::max(); + + // geometric scaling + double rate = geometryGrid.interpolate(pos, time); + if (rate == 0.) + return std::numeric_limits::max(); + + rate *= interpolate2d(z, gamma, tabRedshifts, tabLorentz, tabRate); + + // cosmological scaling + rate *= pow(1 + z, 2); + + return 1. / rate; } double PhotoPionProduction::nucleiModification(int A, int X) const { - if (A == 1) - return 1.; - if (A <= 8) - return 0.85 * pow(X, 2. / 3.); - return 0.85 * X; + if (A == 1) + return 1.; + if (A <= 8) + return 0.85 * pow(X, 2. / 3.); + return 0.85 * X; } void PhotoPionProduction::process(Candidate *candidate) const { - double step = candidate->getCurrentStep(); - double z = candidate->getRedshift(); - // the loop is processed at least once for limiting the next step - do { - // check if nucleus - int id = candidate->current.getId(); - if (!isNucleus(id)) - return; - - // find interaction with minimum random distance - Random &random = Random::instance(); - double randDistance = std::numeric_limits::max(); - double meanFreePath; - double totalRate = 0; - bool onProton = true; // interacting particle: proton or neutron - - int A = massNumber(id); - int Z = chargeNumber(id); - int N = A - Z; - double gamma = candidate->current.getLorentzFactor(); - - // check for interaction on protons - if (Z > 0) { - meanFreePath = nucleonMFP(gamma, z, true) / nucleiModification(A, Z); - randDistance = -log(random.rand()) * meanFreePath; - totalRate += 1. / meanFreePath; - } - // check for interaction on neutrons - if (N > 0) { - meanFreePath = nucleonMFP(gamma, z, false) / nucleiModification(A, N); - totalRate += 1. / meanFreePath; - double d = -log(random.rand()) * meanFreePath; - if (d < randDistance) { - randDistance = d; - onProton = false; - } - } - - // check if interaction does not happen - if (step < randDistance) { - if (totalRate > 0.) - candidate->limitNextStep(limit / totalRate); - return; - } - - // interact and repeat with remaining step - performInteraction(candidate, onProton); - step -= randDistance; - } while (step > 0); + double step = candidate->getCurrentStep(); + double z = candidate->getRedshift(); + Vector3d pos = candidate->current.getPosition(); + double time = candidate->getTrajectoryLength()/c_light; + // the loop is processed at least once for limiting the next step + do { + // check if nucleus + int id = candidate->current.getId(); + if (!isNucleus(id)) + return; + + // find interaction with minimum random distance + Random &random = Random::instance(); + double randDistance = std::numeric_limits::max(); + double meanFreePath; + double totalRate = 0; + bool onProton = true; // interacting particle: proton or neutron + + int A = massNumber(id); + int Z = chargeNumber(id); + int N = A - Z; + double gamma = candidate->current.getLorentzFactor(); + + // check for interaction on protons + if (Z > 0) { + meanFreePath = nucleonMFP(gamma, z, true, pos, time) / nucleiModification(A, Z); + randDistance = -log(random.rand()) * meanFreePath; + totalRate += 1. / meanFreePath; + } + // check for interaction on neutrons + if (N > 0) { + meanFreePath = nucleonMFP(gamma, z, false, pos, time) / nucleiModification(A, N); + totalRate += 1. / meanFreePath; + double d = -log(random.rand()) * meanFreePath; + if (d < randDistance) { + randDistance = d; + onProton = false; + } + } + // check if interaction does not happen + if ( meanFreePath == std::numeric_limits::max()) + return; + if (step < randDistance) { + if (totalRate > 0.) + candidate->limitNextStep(limit / totalRate); + return; + } + // interact and repeat with remaining step + performInteraction(candidate, onProton); + step -= randDistance; + } while (step > 0); } void PhotoPionProduction::performInteraction(Candidate *candidate, bool onProton) const { - int id = candidate->current.getId(); - int A = massNumber(id); - int Z = chargeNumber(id); - double E = candidate->current.getEnergy(); - double EpA = E / A; - double z = candidate->getRedshift(); - - // SOPHIA simulates interactions only for protons / neutrons - // for anti-protons / neutrons assume charge symmetry and change all - // interaction products from particle <--> anti-particle - int sign = (id > 0) ? 1 : -1; - - // arguments for SOPHIA - int nature = 1 - int(onProton); // interacting particle: 0 for proton, 1 for neutron - double Ein = EpA / GeV; // energy of in-going nucleon in GeV - double momentaList[5][2000]; // momentum list, what are the five components? - int particleList[2000]; // particle id list - int nParticles; // number of outgoing particles - double maxRedshift = 100; // IR photon density is zero above this redshift - int dummy1; // not needed - double dummy2[2]; // not needed - int background = (photonField == CMB) ? 1 : 2; // photon background: 1 for CMB, 2 for Kneiske IRB - - // check if below SOPHIA's energy threshold - double E_threshold = (photonField == CMB) ? 3.72e18 * eV : 5.83e15 * eV; - if (EpA * (1 + z) < E_threshold) - return; - -#pragma omp critical - { - sophiaevent_(nature, Ein, momentaList, particleList, nParticles, z, background, maxRedshift, dummy1, dummy2, dummy2); - } - - Random &random = Random::instance(); - Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition()); - for (int i = 0; i < nParticles; i++) { // loop over out-going particles - double Eout = momentaList[3][i] * GeV; // only the energy is used; could be changed for more detail - int pType = particleList[i]; - switch (pType) { - case 13: // proton - case 14: // neutron - if (A == 1) { - // single interacting nucleon - candidate->current.setEnergy(Eout); - try - { - candidate->current.setId(sign * nucleusId(1, 14 - pType)); - } - catch (std::runtime_error &e) - { - KISS_LOG_ERROR<< "Something went wrong in the PhotoPionProduction\n" << "Please report this error on https://github.com/CRPropa/CRPropa3/issues including your simulation setup and the following random seed:\n" << Random::instance().getSeed_base64(); - throw; - } - } else { - // interacting nucleon is part of nucleus: it is emitted from the nucleus - candidate->current.setEnergy(E - EpA); - try - { - candidate->current.setId(sign * nucleusId(A - 1, Z - int(onProton))); - candidate->addSecondary(sign * nucleusId(1, 14 - pType), Eout, pos); - } - catch (std::runtime_error &e) - { - KISS_LOG_ERROR<< "Something went wrong in the PhotoPionProduction\n" << "Please report this error on https://github.com/CRPropa/CRPropa3/issues including your simulation setup and the following random seed:\n" << Random::instance().getSeed_base64(); - throw; - } - } - break; - case -13: // anti-proton - case -14: // anti-neutron - if (haveAntiNucleons) - try - { - candidate->addSecondary(-sign * nucleusId(1, 14 + pType), Eout, pos); - } - catch (std::runtime_error &e) - { - KISS_LOG_ERROR<< "Something went wrong in the PhotoPionProduction\n" << "Something went wrong in the PhotoPionProduction\n"<< "Please report this error on https://github.com/CRPropa/CRPropa3/issues including your simulation setup and the following random seed:\n" << Random::instance().getSeed_base64(); - throw; - } - break; - case 1: // photon - if (havePhotons) - candidate->addSecondary(22, Eout, pos); - break; - case 2: // positron - if (haveElectrons) - candidate->addSecondary(sign * -11, Eout, pos); - break; - case 3: // electron - if (haveElectrons) - candidate->addSecondary(sign * 11, Eout, pos); - break; - case 15: // nu_e - if (haveNeutrinos) - candidate->addSecondary(sign * 12, Eout, pos); - break; - case 16: // antinu_e - if (haveNeutrinos) - candidate->addSecondary(sign * -12, Eout, pos); - break; - case 17: // nu_muon - if (haveNeutrinos) - candidate->addSecondary(sign * 14, Eout, pos); - break; - case 18: // antinu_muon - if (haveNeutrinos) - candidate->addSecondary(sign * -14, Eout, pos); - break; - default: - throw std::runtime_error("PhotoPionProduction: unexpected particle " + kiss::str(pType)); - } - } + int id = candidate->current.getId(); + int A = massNumber(id); + int Z = chargeNumber(id); + double E = candidate->current.getEnergy(); + double EpA = E / A; + double z = candidate->getRedshift(); + + // SOPHIA simulates interactions only for protons / neutrons + // for anti-protons / neutrons assume charge symmetry and change all + // interaction products from particle <--> anti-particle + int sign = (id > 0) ? 1 : -1; + + // SOPHIA - input: + int nature = 1 - static_cast(onProton); // 0=proton, 1=neutron + double Ein = EpA / GeV; + double eps = phtnfld.sample_eps(onProton, Ein, z); + + // SOPHIA - output: + double outputEnergy[2000]; + int outPartID[2000]; + int nOutPart; + + if (useTabulatedData) { + std::vector outVec = sophiaEvent(onProton, Ein, eps); + nOutPart = outVec.size() / 2; + for (int i = 0; i < nOutPart; ++i) { + outPartID[i] = outVec[i]; + outputEnergy[i] = outVec[i+nOutPart]; + } + } else { + #pragma omp critical + { + sophiaevent_(nature, Ein, eps, outputEnergy, outPartID, nOutPart); + } + } + + // output particle treatment + Random &random = Random::instance(); + Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition()); + bool isPrimary = true; // the first hadron in output is declared the primary + for (int i = 0; i < nOutPart; i++) { // loop over out-going particles + double Eout = outputEnergy[i] * GeV; // only the energy is used; could be changed for more detail + int pType = outPartID[i]; + switch (pType) { + case 13: // proton + // pType = 13 -> 14 - 13 = charge = 1 + case 14: // neutron + if (isPrimary) { + if (A == 1) { + // single interacting nucleon + candidate->current.setEnergy(Eout); + candidate->current.setId(sign * nucleusId(1, 14 - pType)); + } else { + // interacting nucleon is part of nucleus: it is emitted from the nucleus + candidate->current.setEnergy(E - EpA); + candidate->current.setId(sign * nucleusId(A - 1, Z - int(onProton))); + candidate->addSecondary(sign * nucleusId(1, 14 - pType), Eout, pos); + } + isPrimary = false; + } else { + candidate->addSecondary(sign * nucleusId(1, 14 - pType), Eout, pos); + } + break; + case -13: // anti-proton + if (haveAntiNucleons) + candidate->addSecondary(-sign * nucleusId(1, 1), Eout, pos); + break; + case -14: // anti-neutron + if (haveAntiNucleons) + candidate->addSecondary(-sign * nucleusId(1, 0), Eout, pos); + break; + case 1: // photon + if (havePhotons) + candidate->addSecondary(22, Eout, pos); + break; + case 2: // positron + if (haveElectrons) // if this is havePhotons, this works with PPP + candidate->addSecondary(sign * -11, Eout, pos); + break; + case 3: // electron + if (haveElectrons) // if this is havePhotons, this works with PPP + candidate->addSecondary(sign * 11, Eout, pos); + break; + case 15: // nu_e + if (haveNeutrinos) + candidate->addSecondary(sign * 12, Eout, pos); + break; + case 16: // antinu_e + if (haveNeutrinos) + candidate->addSecondary(sign * -12, Eout, pos); + break; + case 17: // nu_muon + if (haveNeutrinos) + candidate->addSecondary(sign * 14, Eout, pos); + break; + case 18: // antinu_muon + if (haveNeutrinos) + candidate->addSecondary(sign * -14, Eout, pos); + break; + default: + throw std::runtime_error("PhotoPionProduction: unexpected particle " + kiss::str(pType)); + } + } } -double PhotoPionProduction::lossLength(int id, double gamma, double z) { - int A = massNumber(id); - int Z = chargeNumber(id); - int N = A - Z; +// double PhotoPionProduction::lossLength(int id, double gamma, double z) { +// int A = massNumber(id); +// int Z = chargeNumber(id); +// int N = A - Z; - double lossRate = 0; - if (Z > 0) - lossRate += 1 / nucleonMFP(gamma, z, true) * nucleiModification(A, Z); - if (N > 0) - lossRate += 1 / nucleonMFP(gamma, z, false) * nucleiModification(A, N); +// double lossRate = 0; +// if (Z > 0) +// lossRate += 1 / nucleonMFP(gamma, z, true) * nucleiModification(A, Z); +// if (N > 0) +// lossRate += 1 / nucleonMFP(gamma, z, false) * nucleiModification(A, N); - // approximate the relative energy loss - // - nucleons keep the fraction of mass to delta-resonance mass - // - nuclei lose the energy 1/A the interacting nucleon is carrying - double relativeEnergyLoss = (A == 1) ? 1 - 938. / 1232. : 1. / A; - lossRate *= relativeEnergyLoss; +// // approximate the relative energy loss +// // - nucleons keep the fraction of mass to delta-resonance mass +// // - nuclei lose the energy 1/A the interacting nucleon is carrying +// double relativeEnergyLoss = (A == 1) ? 1 - 938. / 1232. : 1. / A; +// lossRate *= relativeEnergyLoss; - // scaling factor: interaction rate --> energy loss rate - lossRate *= (1 + z); +// // scaling factor: interaction rate --> energy loss rate +// lossRate *= (1 + z); - return 1. / lossRate; -} +// return 1. / lossRate; +// } } // namespace crpropa From 5d2b326c88fdcf8ebe4381c20673d1934f2750b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 18:26:24 +0100 Subject: [PATCH 14/81] implement ScalarGrid4d --- src/GridTools.cpp | 46 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/src/GridTools.cpp b/src/GridTools.cpp index 95c2ebb56..c9aaefd20 100644 --- a/src/GridTools.cpp +++ b/src/GridTools.cpp @@ -89,16 +89,13 @@ void initTurbulence(ref_ptr grid, double Brms, double lMin, double l size_t Nz = grid->getNz(); if ((Nx != Ny) or (Ny != Nz)) throw std::runtime_error("turbulentField: only cubic grid supported"); - - Vector3d spacing = grid->getSpacing(); - if ((spacing.x != spacing.y) or (spacing.y != spacing.z)) - throw std::runtime_error("turbulentField: only equal spacing suported"); - - if (lMin < 2 * spacing.x) + + double spacing = grid->getSpacing(); + if (lMin < 2 * spacing) throw std::runtime_error("turbulentField: lMin < 2 * spacing"); if (lMin >= lMax) throw std::runtime_error("turbulentField: lMin >= lMax"); - if (lMax > Nx * spacing.x / 2) + if (lMax > Nx * spacing / 2) throw std::runtime_error("turbulentField: lMax > size / 2"); size_t n = Nx; // size of array @@ -130,8 +127,8 @@ void initTurbulence(ref_ptr grid, double Brms, double lMin, double l // parameters goes for non helical calculations double theta, phase, cosPhase, sinPhase; - double kMin = spacing.x / lMax; - double kMax = spacing.x / lMin; + double kMin = spacing / lMax; + double kMax = spacing / lMin; Vector3f b; // real b-field vector Vector3f ek, e1, e2; // orthogonal base Vector3f n0(1, 1, 1); // arbitrary vector to construct orthogonal base @@ -269,7 +266,7 @@ void initTurbulence(ref_ptr grid, double Brms, double lMin, double l void fromMagneticField(ref_ptr grid, ref_ptr field) { Vector3d origin = grid->getOrigin(); - Vector3d spacing = grid->getSpacing(); + double spacing = grid->getSpacing(); size_t Nx = grid->getNx(); size_t Ny = grid->getNy(); size_t Nz = grid->getNz(); @@ -284,7 +281,7 @@ void fromMagneticField(ref_ptr grid, ref_ptr field) { void fromMagneticFieldStrength(ref_ptr grid, ref_ptr field) { Vector3d origin = grid->getOrigin(); - Vector3d spacing = grid->getSpacing(); + double spacing = grid->getSpacing(); size_t Nx = grid->getNx(); size_t Ny = grid->getNy(); size_t Nz = grid->getNz(); @@ -407,6 +404,33 @@ void dumpGrid(ref_ptr grid, std::string filename, double c) { fout.close(); } +void loadGridFromTxt(ref_ptr grid, std::string filename, double c) { + std::ifstream fin(filename.c_str()); + if (!fin) { + std::stringstream ss; + ss << "load ScalarGrid4d: " << filename << " not found"; + throw std::runtime_error(ss.str()); + } + // skip header lines + while (fin.peek() == '#') + fin.ignore(std::numeric_limits::max(), '\n'); + + for (int ix = 0; ix < grid->getNx(); ix++) { + for (int iy = 0; iy < grid->getNy(); iy++) { + for (int iz = 0; iz < grid->getNz(); iz++) { + for (int it = 0; it < grid->getNt(); it++) { + double &b = grid->get(ix,iy,iz,it); + fin >> b; + b *= c; + if (fin.eof()) + throw std::runtime_error("load ScalarGrid4d: file too short"); + } + } + } + } + fin.close(); +} + void loadGridFromTxt(ref_ptr grid, std::string filename, double c) { std::ifstream fin(filename.c_str()); if (!fin) { From c25fad895bb5aca5dfbb5de0f57e94a36556b763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 18:26:45 +0100 Subject: [PATCH 15/81] - implement custom photon fields - implement a generalized version of SOPHIA's background photon sampling routine --- src/PhotonBackground.cpp | 468 ++++++++++++++++++++++++++++++++++----- 1 file changed, 413 insertions(+), 55 deletions(-) diff --git a/src/PhotonBackground.cpp b/src/PhotonBackground.cpp index 8743719ea..f0fed2202 100644 --- a/src/PhotonBackground.cpp +++ b/src/PhotonBackground.cpp @@ -1,11 +1,14 @@ #include "crpropa/PhotonBackground.h" #include "crpropa/Common.h" +#include "crpropa/Random.h" +#include "crpropa/Units.h" #include #include #include #include #include +#include namespace crpropa { @@ -63,64 +66,419 @@ static PhotonFieldScaling scalingStecker16_upper("IRB_Stecker16_upper"); static PhotonFieldScaling scalingStecker16_lower("IRB_Stecker16_lower"); double photonFieldScaling(PhotonField photonField, double z) { - switch (photonField) { - case CMB: - return 1; // constant comoving photon number density - case IRB: - case IRB_Kneiske04: - return scalingKneiske04.scalingFactor(z); - case IRB_Stecker05: - return scalingStecker05.scalingFactor(z); - case IRB_Franceschini08: - return scalingFranceschini08.scalingFactor(z); - case IRB_Finke10: - return scalingFinke10.scalingFactor(z); - case IRB_Dominguez11: - return scalingDominguez11.scalingFactor(z); - case IRB_Gilmore12: - return scalingGilmore12.scalingFactor(z); - case IRB_Stecker16_upper: - return scalingStecker16_upper.scalingFactor(z); - case IRB_Stecker16_lower: - return scalingStecker16_lower.scalingFactor(z); - case URB_Protheroe96: - if (z < 0.8) - return 1; - if (z < 6) - return pow((1 + 0.8) / (1 + z), 4); - else - return 0; - default: - throw std::runtime_error("PhotonField: unknown photon background"); - } + switch (photonField) { + case CMB: // constant comoving photon number density + case PF1: case PF2: case PF3: case PF4: + case PF5: case PF6: case PF7: case PF8: + return 1; + case IRB: + case IRB_Kneiske04: + return scalingKneiske04.scalingFactor(z); + case IRB_Stecker05: + return scalingStecker05.scalingFactor(z); + case IRB_Franceschini08: + return scalingFranceschini08.scalingFactor(z); + case IRB_Finke10: + return scalingFinke10.scalingFactor(z); + case IRB_Dominguez11: + return scalingDominguez11.scalingFactor(z); + case IRB_Gilmore12: + return scalingGilmore12.scalingFactor(z); + case IRB_Stecker16_upper: + return scalingStecker16_upper.scalingFactor(z); + case IRB_Stecker16_lower: + return scalingStecker16_lower.scalingFactor(z); + case URB_Protheroe96: + if (z < 0.8) { return 1; } + if (z < 6) { return pow((1 + 0.8) / (1 + z), 4); } + else { return 0; } + default: + throw std::runtime_error("PhotonField: unknown photon background"); + } } std::string photonFieldName(PhotonField photonField) { - switch (photonField) { - case CMB: - return "CMB"; - case IRB: - case IRB_Kneiske04: - return "IRB_Kneiske04"; - case IRB_Stecker05: - return "IRB_Stecker05"; - case IRB_Franceschini08: - return "IRB_Franceschini08"; - case IRB_Finke10: - return "IRB_Finke10"; - case IRB_Dominguez11: - return "IRB_Dominguez11"; - case IRB_Gilmore12: - return "IRB_Gilmore12"; - case IRB_Stecker16_upper: - return "IRB_Stecker16_upper"; - case IRB_Stecker16_lower: - return "IRB_Stecker16_lower"; - case URB_Protheroe96: - return "URB_Protheroe96"; - default: - throw std::runtime_error("PhotonField: unknown photon background"); - } + switch (photonField) { + case CMB: return "CMB"; + case PF1: return "PF1"; + case PF2: return "PF2"; + case PF3: return "PF3"; + case PF4: return "PF4"; + case PF5: return "PF5"; + case PF6: return "PF6"; + case PF7: return "PF7"; + case PF8: return "PF8"; + case IRB: + case IRB_Kneiske04: return "IRB_Kneiske04"; + case IRB_Stecker05: return "IRB_Stecker05"; + case IRB_Franceschini08: return "IRB_Franceschini08"; + case IRB_Finke10: return "IRB_Finke10"; + case IRB_Dominguez11: return "IRB_Dominguez11"; + case IRB_Gilmore12: return "IRB_Gilmore12"; + case IRB_Stecker16_upper: return "IRB_Stecker16_upper"; + case IRB_Stecker16_lower: return "IRB_Stecker16_lower"; + case URB_Protheroe96: return "URB_Protheroe96"; + default: + throw std::runtime_error("PhotonField: unknown photon background"); + } +} + + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// custom photon field methods related to SAMPLING +// These methods are taken from SOPHIA. +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +Photon_Field::Photon_Field(std::string fieldPath) { + // constructor + init(fieldPath); +} + + +Photon_Field::Photon_Field() { + // constructor 2 } + +double Photon_Field::sample_eps(bool onProton, double E_in, double z_in) const { +/* + - input: particle type 0=neutron, 1=proton, its energy [GeV], its redshift + - output: photon energy [eV] of random photon of photon field + - samples distribution of n(epsilon)/epsilon^2 +*/ + const double mass = onProton? 0.93827 : 0.93947; // Gev/c^2 + const double z_max = redshift[redshift.size()-1]; + if (z_in > z_max) { return 0.; } + double z_pos; + double smallestDiff = z_max; + for (int i = 0; i < redshift.size(); ++i) { + double diff = std::abs(z_in-redshift[i]); + if (diff < smallestDiff) { + smallestDiff = diff; + z_pos = i; + } + } + + const double epsMin = energy[0]; + const double epsMax = energy[energy.size()-1]; + double eps; + double p = std::sqrt(E_in*E_in-mass*mass); + double peps; + double cnorm = gaussInt("prob_eps", epsMin, epsMax, onProton, E_in, z_pos); + + // calculate pMax + double highest = 0.; + int closestPos; + for (int i = 0; i < energy.size(); ++i) { + if (dn_deps[i][z_pos] > highest) { + highest = dn_deps[i][z_pos]; + closestPos = i; + } + } + double eps_pMax = energy[closestPos]; + double pMax = prob_eps(eps_pMax, onProton, E_in, z_pos)/cnorm; + if ( (pMax < 0.01) || (pMax > 1.) ) { pMax = 1.; } + + // sample eps randomly between epsMin ... epsMax + Random &random = Random::instance(); + do { + eps = epsMin+random.rand()*(epsMax-epsMin); + peps = prob_eps(eps, onProton, E_in, z_pos)/cnorm; + } while (random.rand()*pMax > peps); + return eps; +} // end sample_eps + + +void Photon_Field::init(std::string filename) { + std::ifstream infile(filename.c_str()); + if (!infile.good()) { + throw std::runtime_error("PhotoPionProduction @ Photon_Field::init : could not open file " + filename); + } + std::string line; + int i = 0; + while ( std::getline(infile, line) ) { + if (line.find('#') == 0 ) continue; + std::istringstream ss(line); + std::vector vec; + double n; + while (ss >> n) vec.push_back(n); + if (i == 0) { energy = vec; i++; continue; } + if (i == 1) { redshift = vec; i++; continue; } + dn_deps.push_back(vec); + } + infile.close(); +} // end init + + +double Photon_Field::prob_eps(double eps, bool onProton, double E_in, int z_pos) const { +/* + - input: eps [eV] + - output: probability to encounter photon of energy eps + - called by: sample_eps, gaussInt +*/ + const double mass = onProton? 0.93827 : 0.93947; // Gev/c^2 + double gamma = E_in/mass; + double beta = std::sqrt(1.-1./gamma/gamma); + double photonDensity = get_photonDensity(eps, z_pos); + if (photonDensity == 0.) { + return 0.; + } else { + double smin = 1.1646; // head-on collision + double smax = std::max(smin, mass*mass+2.*eps/1.e9*E_in*(1.+beta)); + double sintegr = gaussInt("functs", smin, smax, onProton, E_in, z_pos); + return photonDensity/eps/eps*sintegr/8./beta/E_in/E_in*1.e18*1.e6; + } +} // end prob_eps + + +double Photon_Field::get_photonDensity(double eps, int z_pos) const { +/* + - input: photon energy [eV], redshift + - output: dn_deps(e,z) [#/(eV cm^3)] from input file + - called by: sample_eps +*/ + // find closest dn_deps + double smallestDiff = energy[energy.size()-1]; + int closestPos; + for (int i = 0; i < energy.size(); ++i) { + double diff = std::abs(eps-energy[i]); + if (diff < smallestDiff) { + smallestDiff = diff; + closestPos = i; + } + } + // linear interpolation of energy + double realDiff = eps-energy[closestPos]; + double rho; + if (realDiff >= 0.) { + rho = realDiff / (energy[closestPos+1] - energy[closestPos]); + return (1.-rho)*dn_deps[closestPos][z_pos] + + rho*dn_deps[closestPos+1][z_pos]; + } else { + rho = 1. - (std::abs(realDiff)/energy[closestPos-1]); + return (1.-rho)*dn_deps[closestPos-1][z_pos] + + rho*dn_deps[closestPos][z_pos]; + } +} // end get_photonDensity + + +double Photon_Field::crossection(double x, bool onProton) const { +/* + - input: photon energy [eV], specifier: 0=neutron, 1=proton + - output: crossection of nucleon-photon-interaction [area] + - called by: functs +*/ + const double mass = onProton? 0.93827 : 0.93947; // Gev/c^2 + double sth = 1.1646; + double s = mass*mass + 2.*mass*x; + if (s < sth) { return 0.; } + double cross_res = 0.; + double cross_dir = 0.; + double cross_dir1 = 0.; + double cross_dir2 = 0.; + double sig_res[9]; + + // upper: ppppppppp + // lower: nnnnnnnnn + const double AMRES[18] = { 1.231, 1.440, 1.515, 1.525, 1.675, 1.680, 1.690, 1.895, 1.950, + 1.231, 1.440, 1.515, 1.525, 1.675, 1.675, 1.690, 1.895, 1.950 }; + const double BGAMMA[18] = { 5.6, .5, 4.6, 2.5, 1., 2.1, 2., .2, 1., + 6.1, .3, 4., 2.5, 0.0, .2, 2., .2, 1.}; + const double WIDTH[18] = { .11, .35, .11, .1, .16, .125, .29, .35, .3, + .11, .35, .11, .1, .16, .15, .29, .35, .3}; + const double RATIOJ[18] = { 1., .5, 1., .5, .5, 1.5, 1., 1.5, 2., + 1., .5, 1., .5, .5, 1.5, 1., 1.5, 2.}; + const double AM2[2] = { 0.882792, 0.880351 }; + + // int idx = (onProton == 0)? 9:0; // neutron = 0, proton = 1 + int idx = onProton? 0:9; // neutron = 0, proton = 1 + double SIG0[9]; + for (int i = 0; i < 9; ++i) { + SIG0[i] = 4.893089117/AM2[int(onProton)]*RATIOJ[i+idx]*BGAMMA[i+idx]; + } + + if (x <= 10.) { + cross_res = breitwigner(SIG0[0], WIDTH[0+idx], AMRES[0+idx], x, onProton) + * Ef(x, 0.152, 0.17); + sig_res[0] = cross_res; + for (int i = 1; i < 9; ++i) { + sig_res[i] = breitwigner(SIG0[i], WIDTH[i+idx], AMRES[i+idx], x, onProton) + * Ef(x, 0.15, 0.38); + cross_res += sig_res[i]; + } + // direct channel + if ( (x > 0.1) && (x < 0.6) ) { + cross_dir1 = singleback(x) + + 40.*std::exp(-(x-0.29)*(x-0.29) / 0.002) + - 15.*std::exp(-(x-0.37)*(x-0.37) / 0.002); + } else { + cross_dir1 = singleback(x); + } + cross_dir2 = twoback(x); + cross_dir = cross_dir1 + cross_dir2; + } + // fragmentation 2: + double cross_frag2; + if (onProton) { + cross_frag2 = 80.3*Ef(x, 0.5, 0.1) * std::pow(s, -0.34); + } else { + cross_frag2 = 60.2*Ef(x, 0.5, 0.1) * std::pow(s, -0.34); + } + // multipion production/fragmentation 1 cross section + double cs_multidiff; + double cs_multi; + double cross_diffr1; + double cross_diffr2; + double cross_diffr; + if (x > 0.85) { + double ss1 = (x-0.85)/.69; + double ss2; + if (onProton) { + ss2 = 29.3*std::pow(s, -0.34) + 59.3*std::pow(s, 0.095); + } else { + ss2 = 26.4*std::pow(s, -0.34) + 59.3*std::pow(s, 0.095); + } + cs_multidiff = (1.-std::exp(-ss1))*ss2; + cs_multi = 0.89*cs_multidiff; + // diffractive scattering: + cross_diffr1 = .099*cs_multidiff; + cross_diffr2 = .011*cs_multidiff; + cross_diffr = .11*cs_multidiff; + // ************************************** + ss1 = std::pow((x-.85), .75)/.64; + ss2 = 74.1*std::pow(x, -0.44) + 62.*std::pow(s, 0.08); + double cs_tmp = 0.96*(1.-std::exp(-ss1))*ss2; + cross_diffr1 = 0.14*cs_tmp; + cross_diffr2 = 0.013*cs_tmp; + double cs_delta = cross_frag2 + - (cross_diffr1+cross_diffr2-cross_diffr); + if (cs_delta < 0.) { + cross_frag2 = 0.; + cs_multi += cs_delta; + } else { + cross_frag2 = cs_delta; + } + cross_diffr = cross_diffr1 + cross_diffr2; + cs_multidiff = cs_multi + cross_diffr; + // ***************************************** + } else { + cross_diffr = 0.; + cross_diffr1 = 0.; + cross_diffr2 = 0.; + cs_multidiff = 0.; + cs_multi = 0.; + } + // in the original SOPHIA code, this is a switch. + // Here, only one case (NDIR=3) is needed. + return cross_res+cross_dir+cs_multidiff+cross_frag2; +} // end crossection + + +double Photon_Field::Pl(double x, double xth, double xmax, double alpha) const { +/* + - input: photon energy [eV], unknown, unknown, unknown + - output: unknown. + - called by: crossection +*/ + if (xth > x) { return 0.; } + double a = alpha*xmax/xth; + double prod1 = std::pow((x-xth)/(xmax-xth), (a-alpha)); + double prod2 = std::pow(x/xmax, -a); + return prod1*prod2; +} // end Pl + + +double Photon_Field::Ef(double x, double th, double w) const { +/* + - input: photon energy [eV], unknown, unknown + - output: unknown + - called by: crossection +*/ + double wth = w+th; + if (x <= th) { + return 0.; + } else if ( (x > th) && (x < wth) ) { + return (x-th)/w; + } else if (x >= wth) { + return 1.; + } else { + throw std::runtime_error("error in function Ef"); + } +} // end Ef + + +double Photon_Field::breitwigner(double sigma_0, double Gamma, double DMM, double eps_prime, bool onProton) const { +/* + - input: cross section [µbarn], width [GeV], mass [GeV/c^2] + - output: Breit-Wigner crossection of a resonance widh width Gamma + - called by: crossection +*/ + const double mass = onProton? 0.93827 : 0.93947; // Gev/c^2 + double s = mass*mass + 2.*mass*eps_prime; + double gam2s = Gamma*Gamma*s; + return sigma_0 * (s/eps_prime/eps_prime)*gam2s + / ((s-DMM*DMM)*(s-DMM*DMM)+gam2s); +} // end breitwigner + + +double Photon_Field::singleback(double x) const { +/* + - single pion channel + - called by: crossection +*/ + return 92.7 * Pl(x, .152, .25, 2.); +} // end singleback + + +double Photon_Field::twoback(double x) const { +/* + - two pion production + - called by: crossection +*/ + return 37.7 * Pl(x, .4, .6, 2.); +} // end twoback + + +double Photon_Field::functs(double s, bool onProton) const { +/* + - input: s [GeV^2] + - output: (s-p^2)*sigma_(nucleon/gamma) [GeV^2*area] + - called by: sample_eps +*/ + const double mass = onProton? 0.93827 : 0.93947; // Gev/c^2 + double factor = s - mass*mass; + double epsprime = factor/2./mass; + double sigma_pg = crossection(epsprime, onProton); + return factor*sigma_pg; +} // end functs + + +double Photon_Field::gaussInt(std::string type, double A, double B, bool onProton, double E_in, int z_pos) const { +/* + - input: type: specifier of function over which to integrate, + integration limits A and B + - output: 8-points gauss-Legendre integral + - called by: sample_eps, prob_eps +*/ + const double X[8] = { .0950125098, .2816035507, .4580167776, .6178762444, + .7554044083, .8656312023, .9445750230, .9894009349 }; + const double W[8] = { .1894506104, .1826034150, .1691565193, .1495959888, + .1246289712, .0951585116, .0622535239, .0271524594 }; + double XM = 0.5*(B+A); + double XR = 0.5*(B-A); + double SS = 0.; + for (int i = 0; i < 8; ++i) { + double DX = XR*X[i]; + if (type == "functs") { + SS += W[i] * (functs(XM+DX, onProton) + functs(XM-DX, onProton)); + } else if (type == "prob_eps") { + SS += W[i] * (prob_eps(XM+DX, onProton, E_in, z_pos) + prob_eps(XM-DX, onProton, E_in, z_pos)); + } else { + throw std::runtime_error("gaussInt: type incorrectly specified"); + } + } + return XR*SS; +} // end gaussInt + } // namespace crpropa From 73f81627938a103184c6f47787b49515d37e79ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 18:27:59 +0100 Subject: [PATCH 16/81] update input parameters for PhotoPionProduction --- test/testInteraction.cpp | 53 +++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 8e5cfe359..05d273fe8 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -134,6 +134,38 @@ TEST(ElectronPairProduction, valuesIRB) { } } +TEST(ElectronPairProduction, valuesBla) { + // Test if energy loss corresponds to the data table. + std::vector x; + std::vector y; + std::ifstream infile(getDataPath("pairBla.txt").c_str()); + while (infile.good()) { + if (infile.peek() != '#') { + double a, b; + infile >> a >> b; + if (infile) { + x.push_back(a * eV); + y.push_back(b * eV / Mpc); + } + } + infile.ignore(std::numeric_limits::max(), '\n'); + } + infile.close(); + + Candidate c; + c.setCurrentStep(1 * Mpc); + c.current.setId(nucleusId(1, 1)); // proton + + ElectronPairProduction epp(IRB); + for (int i = 0; i < x.size(); i++) { + c.current.setEnergy(x[i]); + epp.process(&c); + double dE = x[i] - c.current.getEnergy(); + double dE_table = y[i] * 1 * Mpc; + EXPECT_NEAR(dE, dE_table, 1e-12); + } +} + // NuclearDecay --------------------------------------------------------------- TEST(NuclearDecay, scandium44) { // Test beta+ decay of 44Sc to 44Ca. @@ -394,22 +426,6 @@ TEST(PhotoDisintegration, allIsotopes) { } } -TEST(Photodisintegration, updateParticleParentProperties) -{ // Issue: #204 - PhotoDisintegration pd(CMB); - - Candidate c(nucleusId(56,26), 500 * EeV, Vector3d(1 * Mpc, 0, 0)); - - pd.performInteraction(&c, 1); - // the candidates parent is the original particle - EXPECT_EQ(c.created.getId(), nucleusId(56,26)); - - pd.performInteraction(&c, 1); - // now it has to be changed - EXPECT_NE(c.created.getId(), nucleusId(56,26)); -} - - // ElasticScattering ---------------------------------------------------------- TEST(ElasticScattering, allBackgrounds) { // Test if interaction data files are loaded. @@ -451,6 +467,7 @@ TEST(PhotoPionProduction, allBackgrounds) { ppp.setPhotonField(IRB_Gilmore12); ppp.setPhotonField(IRB_Stecker16_upper); ppp.setPhotonField(IRB_Stecker16_lower); + ppp.setPhotonField(PF1); } TEST(PhotoPionProduction, proton) { @@ -510,7 +527,9 @@ TEST(PhotoPionProduction, limitNextStep) { TEST(PhotoPionProduction, secondaries) { // Test photo-pion interaction for 100 EeV proton. // This test can stochastically fail. - PhotoPionProduction ppp(CMB, true, true, true); + // PhotoPionProduction ppp("field.txt", "geometry.txt", CMB, true, true, true); + // PhotoPionProduction ppp(CMB, ScalarGrid(Vector3d(0.),1,1.),true, true, true); + PhotoPionProduction ppp(CMB, ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, 1.,1.),true, true, true); Candidate c(nucleusId(1, 1), 100 * EeV); c.setCurrentStep(1000 * Mpc); ppp.process(&c); From ad714f102e58b896247936319f4caf41ed5b5647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 21:23:41 +0100 Subject: [PATCH 17/81] unite changes by Julien Doerner with ScalarGrid4d --- include/crpropa/Grid.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/crpropa/Grid.h b/include/crpropa/Grid.h index cbbf3b4cb..3319420f3 100644 --- a/include/crpropa/Grid.h +++ b/include/crpropa/Grid.h @@ -45,7 +45,7 @@ class Grid: public Referenced { size_t Nx, Ny, Nz, Nt; /**< Number of grid points (x,y,z) and number of time points (t) */ Vector3d origin; /**< Origin of the volume that is represented by the grid. */ Vector3d gridOrigin; /**< Grid origin */ - double spacing; /**< Distance between grid points, determines the spatial extension of the grid */ + Vector3d spacing; /**< Distance between grid points, determines the spatial extension of the grid */ double timing; /**< Time between grid points, determines the temporal extension of the grid */ double startTime; /**< Point of time from which the grid starts */ bool reflective; /**< If set to true, the grid is repeated reflectively instead of periodically */ @@ -61,7 +61,7 @@ class Grid: public Referenced { @param N Number of grid points in one direction @param spacing Spacing between grid points */ - Grid(Vector3d origin, size_t N, double spacing) { + Grid(Vector3d origin, size_t N, Vector3d spacing) { setOrigin(origin); setGridSize(N, N, N, 1); setSpacing(spacing); @@ -77,7 +77,7 @@ class Grid: public Referenced { @param Nz Number of grid points in z-direction @param spacing Spacing between grid points */ - Grid(Vector3d origin, size_t Nx, size_t Ny, size_t Nz, double spacing) { + Grid(Vector3d origin, size_t Nx, size_t Ny, size_t Nz, Vector3d spacing) { setOrigin(origin); setGridSize(Nx, Ny, Nz, 1); setSpacing(spacing); @@ -97,7 +97,7 @@ class Grid: public Referenced { @param spacing Spacing between grid points @param timing Amount of time between grid points in t-direction */ - Grid(Vector3d origin, double start, size_t Nx, size_t Ny, size_t Nz, size_t Nt, double spacing, double timing) { + Grid(Vector3d origin, double start, size_t Nx, size_t Ny, size_t Nz, size_t Nt, Vector3d spacing, double timing) { setOrigin(origin); setGridSize(Nx, Ny, Nz, Nt); setSpacing(spacing); @@ -108,7 +108,7 @@ class Grid: public Referenced { void setOrigin(Vector3d origin) { this->origin = origin; - this->gridOrigin = origin + Vector3d(spacing/2); + this->gridOrigin = origin + spacing/2; } // ScalarGrid4d @@ -127,7 +127,7 @@ class Grid: public Referenced { setOrigin(origin); } - void setSpacing(double spacing) { + void setSpacing(Vector3d spacing) { this->spacing = spacing; setOrigin(origin); } @@ -167,7 +167,7 @@ class Grid: public Referenced { return Nt; } - double getSpacing() const { + Vector3d getSpacing() const { return spacing; } From c2830f1c00b37a00759459e2e52b2035c5329adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 21:24:40 +0100 Subject: [PATCH 18/81] update test for spacing taking vector3d --- test/testCore.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/testCore.cpp b/test/testCore.cpp index bc768d45c..054a83169 100644 --- a/test/testCore.cpp +++ b/test/testCore.cpp @@ -414,7 +414,7 @@ TEST(ScalarGrid, SimpleTest) { double spacing = 2.0; Vector3d origin(1., 2., 3.); - ScalarGrid grid(origin, Nx, Ny, Nz, spacing); + ScalarGrid grid(origin, Nx, Ny, Nz, Vector3d(spacing)); EXPECT_TRUE(origin == grid.getOrigin()); EXPECT_EQ(Nx, grid.getNx()); @@ -456,7 +456,7 @@ TEST(ScalarGrid, TestVectorSpacing) { TEST(ScalarGrid, ClosestValue) { // Check some closest values - ScalarGrid grid(Vector3d(0.), 2, 2, 2, 1.); + ScalarGrid grid(Vector3d(0.), 2, 2, 2, Vector3d(1.)); grid.get(0, 0, 0) = 1; grid.get(0, 0, 1) = 2; grid.get(0, 1, 0) = 3; @@ -477,7 +477,7 @@ TEST(VectorGrid, Interpolation) { // Explicitly test trilinear interpolation double spacing = 2.793; int n = 3; - VectorGrid grid(Vector3d(0.), n, n, n, spacing); + VectorGrid grid(Vector3d(0.), n, n, n, Vector3d(spacing)); grid.get(0, 0, 1) = Vector3f(1.7, 0., 0.); // set one value Vector3d b; @@ -501,7 +501,7 @@ TEST(VectorGrid, Interpolation) { TEST(VectordGrid, Scale) { // Test scaling a field - ref_ptr grid = new VectorGrid(Vector3d(0.), 3, 1); + ref_ptr grid = new VectorGrid(Vector3d(0.), 3, Vector3d(1)); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) @@ -519,7 +519,7 @@ TEST(VectorGrid, Periodicity) { size_t n = 3; double spacing = 3; double size = n * spacing; - VectorGrid grid(Vector3d(0.), n, spacing); + VectorGrid grid(Vector3d(0.), n, Vector3d(spacing)); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) @@ -545,8 +545,8 @@ TEST(VectorGrid, Periodicity) { TEST(VectorGrid, DumpLoad) { // Dump and load a field grid - ref_ptr grid1 = new VectorGrid(Vector3d(0.), 3, 1); - ref_ptr grid2 = new VectorGrid(Vector3d(0.), 3, 1); + ref_ptr grid1 = new VectorGrid(Vector3d(0.), 3, Vector3d(1)); + ref_ptr grid2 = new VectorGrid(Vector3d(0.), 3, Vector3d(1)); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) @@ -571,8 +571,8 @@ TEST(VectorGrid, DumpLoad) { TEST(VectorGrid, DumpLoadTxt) { // Dump and load a field grid - ref_ptr grid1 = new VectorGrid(Vector3d(0.), 3, 1); - ref_ptr grid2 = new VectorGrid(Vector3d(0.), 3, 1); + ref_ptr grid1 = new VectorGrid(Vector3d(0.), 3, Vector3d(1)); + ref_ptr grid2 = new VectorGrid(Vector3d(0.), 3, Vector3d(1)); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) @@ -597,7 +597,7 @@ TEST(VectorGrid, DumpLoadTxt) { TEST(VectorGrid, Speed) { // Dump and load a field grid - VectorGrid grid(Vector3d(0.), 3, 3); + VectorGrid grid(Vector3d(0.), 3, Vector3d(3)); for (int ix = 0; ix < 3; ix++) for (int iy = 0; iy < 3; iy++) for (int iz = 0; iz < 3; iz++) From ba18e5d4bb2f01588ae60af05eb3a0004aa6f651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 21:25:00 +0100 Subject: [PATCH 19/81] update test for spacing = vector3d --- test/testInteraction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 05d273fe8..b02567d08 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -529,7 +529,7 @@ TEST(PhotoPionProduction, secondaries) { // This test can stochastically fail. // PhotoPionProduction ppp("field.txt", "geometry.txt", CMB, true, true, true); // PhotoPionProduction ppp(CMB, ScalarGrid(Vector3d(0.),1,1.),true, true, true); - PhotoPionProduction ppp(CMB, ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, 1.,1.),true, true, true); + PhotoPionProduction ppp(CMB, ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.),true, true, true); Candidate c(nucleusId(1, 1), 100 * EeV); c.setCurrentStep(1000 * Mpc); ppp.process(&c); From c309eb88a77b81b97aefb22af648a28eff007797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 21:25:21 +0100 Subject: [PATCH 20/81] update test for spacing = vector3d --- test/testSource.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/testSource.cpp b/test/testSource.cpp index e37cba1ff..9e8d96cbe 100644 --- a/test/testSource.cpp +++ b/test/testSource.cpp @@ -118,7 +118,7 @@ TEST(SourceDensityGrid, withInRange) { Vector3d origin(0, 0, 0); int cells = 10; double spacing = 1; - ref_ptr grid = new ScalarGrid(origin, cells, spacing); + ref_ptr grid = new ScalarGrid(origin, cells, Vector3d(spacing)); for (int ix = 0; ix < cells; ix++) for (int iy = 0; iy < cells; iy++) for (int iz = 0; iz < cells; iz++) @@ -144,7 +144,7 @@ TEST(SourceDensityGrid, OneAllowedCell) { Vector3d origin(0, 0, 0); int cells = 2; double spacing = 2; - ref_ptr grid = new ScalarGrid(origin, cells, spacing); + ref_ptr grid = new ScalarGrid(origin, cells, Vector3d(spacing)); // set all but one cells to 0 for (int ix = 0; ix < cells; ix++) @@ -184,7 +184,7 @@ TEST(SourceDensityGrid1D, withInRange) { Vector3d origin(0, 0, 0); int nCells = 10; double spacing = 1.; - ref_ptr grid = new ScalarGrid(origin, nCells, 1, 1, spacing); + ref_ptr grid = new ScalarGrid(origin, nCells, 1, 1, Vector3d(spacing)); // set some values for (int i = 0; i < 10; i++) { @@ -206,7 +206,7 @@ TEST(SourceDensityGrid1D, OneAllowedCell) { Vector3d origin(0, 0, 0); int nCells = 10; double spacing = 1.; - ref_ptr grid = new ScalarGrid(origin, nCells, 1, 1, spacing); + ref_ptr grid = new ScalarGrid(origin, nCells, 1, 1, Vector3d(spacing)); // set some values for (int i = 0; i < 10; i++) { From e57ef308a45668f4302696e95b90f2353e2db2cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 21:26:00 +0100 Subject: [PATCH 21/81] unite changes by Julien Doerner with ScalarGrid4d --- src/GridTools.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/GridTools.cpp b/src/GridTools.cpp index c9aaefd20..3c0f06a58 100644 --- a/src/GridTools.cpp +++ b/src/GridTools.cpp @@ -90,12 +90,15 @@ void initTurbulence(ref_ptr grid, double Brms, double lMin, double l if ((Nx != Ny) or (Ny != Nz)) throw std::runtime_error("turbulentField: only cubic grid supported"); - double spacing = grid->getSpacing(); - if (lMin < 2 * spacing) + Vector3d spacing = grid->getSpacing(); + if ((spacing.x != spacing.y) or (spacing.y != spacing.z)) + throw std::runtime_error("turbulentField: only equal spacing suported"); + + if (lMin < 2 * spacing.x) throw std::runtime_error("turbulentField: lMin < 2 * spacing"); if (lMin >= lMax) throw std::runtime_error("turbulentField: lMin >= lMax"); - if (lMax > Nx * spacing / 2) + if (lMax > Nx * spacing.x / 2) throw std::runtime_error("turbulentField: lMax > size / 2"); size_t n = Nx; // size of array @@ -266,7 +269,7 @@ void initTurbulence(ref_ptr grid, double Brms, double lMin, double l void fromMagneticField(ref_ptr grid, ref_ptr field) { Vector3d origin = grid->getOrigin(); - double spacing = grid->getSpacing(); + Vector3d spacing = grid->getSpacing(); size_t Nx = grid->getNx(); size_t Ny = grid->getNy(); size_t Nz = grid->getNz(); @@ -281,7 +284,7 @@ void fromMagneticField(ref_ptr grid, ref_ptr field) { void fromMagneticFieldStrength(ref_ptr grid, ref_ptr field) { Vector3d origin = grid->getOrigin(); - double spacing = grid->getSpacing(); + Vector3d spacing = grid->getSpacing(); size_t Nx = grid->getNx(); size_t Ny = grid->getNy(); size_t Nz = grid->getNz(); From 3b7d6f64b1f61412791a6ea29f87503b0dd8febd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 21:26:27 +0100 Subject: [PATCH 22/81] update spacing to be vector3d --- src/magneticField/JF12Field.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/magneticField/JF12Field.cpp b/src/magneticField/JF12Field.cpp index acf15e587..68b1a145e 100644 --- a/src/magneticField/JF12Field.cpp +++ b/src/magneticField/JF12Field.cpp @@ -84,7 +84,7 @@ JF12Field::JF12Field() { void JF12Field::randomStriated(int seed) { useStriatedField = true; int N = 100; - striatedGrid = new ScalarGrid(Vector3d(0.), N, 0.1 * kpc); + striatedGrid = new ScalarGrid(Vector3d(0.), N, Vector3d(0.1 * kpc)); Random random; if (seed != 0) From 7b401ba66ba3d01d111b06d70b6223fa6fa00643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 21:27:03 +0100 Subject: [PATCH 23/81] update ScalarGrid4d constructor to take spacing that is vector3d --- include/crpropa/module/EMDoublePairProduction.h | 2 +- include/crpropa/module/EMInverseComptonScattering.h | 2 +- include/crpropa/module/EMPairProduction.h | 2 +- include/crpropa/module/EMTripletPairProduction.h | 2 +- include/crpropa/module/ElasticScattering.h | 2 +- include/crpropa/module/ElectronPairProduction.h | 2 +- include/crpropa/module/PhotoDisintegration.h | 2 +- include/crpropa/module/PhotoPionProduction.h | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/crpropa/module/EMDoublePairProduction.h b/include/crpropa/module/EMDoublePairProduction.h index 343823c5f..35db30e90 100644 --- a/include/crpropa/module/EMDoublePairProduction.h +++ b/include/crpropa/module/EMDoublePairProduction.h @@ -29,7 +29,7 @@ class EMDoublePairProduction: public Module { public: EMDoublePairProduction( PhotonField photonField = CMB, //!< target photon background - ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, 1.,1.), //!< spacial and temporal dependence of photon field + ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.), //!< spacial and temporal dependence of photon field bool haveElectrons = false, //!< switch to create the secondary electron pair double limit = 0.1 //!< step size limit as fraction of mean free path ); diff --git a/include/crpropa/module/EMInverseComptonScattering.h b/include/crpropa/module/EMInverseComptonScattering.h index 71d691d3f..ea874e7e7 100644 --- a/include/crpropa/module/EMInverseComptonScattering.h +++ b/include/crpropa/module/EMInverseComptonScattering.h @@ -34,7 +34,7 @@ class EMInverseComptonScattering: public Module { public: EMInverseComptonScattering( PhotonField photonField = CMB, //!< target photon background - ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, 1.,1.), + ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.), bool havePhotons = false, //!< switch to create secondary photon double limit = 0.1 //!< step size limit as fraction of mean free path ); diff --git a/include/crpropa/module/EMPairProduction.h b/include/crpropa/module/EMPairProduction.h index e366404b8..b51d53680 100644 --- a/include/crpropa/module/EMPairProduction.h +++ b/include/crpropa/module/EMPairProduction.h @@ -35,7 +35,7 @@ class EMPairProduction: public Module { public: EMPairProduction( PhotonField photonField = CMB, //!< target photon background - ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, 1.,1.), + ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.), bool haveElectrons = false, //!< switch to create secondary electron pair double limit = 0.1 //!< step size limit as fraction of mean free path ); diff --git a/include/crpropa/module/EMTripletPairProduction.h b/include/crpropa/module/EMTripletPairProduction.h index 845c4ac70..8146958d8 100644 --- a/include/crpropa/module/EMTripletPairProduction.h +++ b/include/crpropa/module/EMTripletPairProduction.h @@ -38,7 +38,7 @@ class EMTripletPairProduction: public Module { public: EMTripletPairProduction( PhotonField photonField = CMB, //!< target photon background - ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, 1.,1.), + ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.), bool haveElectrons = false, //!< switch to create secondary electron pair double limit = 0.1 //!< step size limit as fraction of mean free path ); diff --git a/include/crpropa/module/ElasticScattering.h b/include/crpropa/module/ElasticScattering.h index 2eb4e4bc3..0f641f632 100644 --- a/include/crpropa/module/ElasticScattering.h +++ b/include/crpropa/module/ElasticScattering.h @@ -29,7 +29,7 @@ class ElasticScattering: public Module { public: ElasticScattering(PhotonField photonField = CMB, - ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, 1.,1.) ); + ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.) ); void initRate(std::string filename); void initCDF(std::string filename); void setPhotonField(PhotonField photonField); diff --git a/include/crpropa/module/ElectronPairProduction.h b/include/crpropa/module/ElectronPairProduction.h index 8c590b753..27c9f6b9f 100644 --- a/include/crpropa/module/ElectronPairProduction.h +++ b/include/crpropa/module/ElectronPairProduction.h @@ -32,7 +32,7 @@ class ElectronPairProduction: public Module { public: ElectronPairProduction(PhotonField photonField = CMB, - ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, 1.,1.), + ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.), bool haveElectrons = false, double limit = 0.1); diff --git a/include/crpropa/module/PhotoDisintegration.h b/include/crpropa/module/PhotoDisintegration.h index e510a81e3..50be45b68 100644 --- a/include/crpropa/module/PhotoDisintegration.h +++ b/include/crpropa/module/PhotoDisintegration.h @@ -44,7 +44,7 @@ class PhotoDisintegration: public Module { public: PhotoDisintegration(PhotonField photonField = CMB, - ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, 1.,1.), + ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.), bool havePhotons = false, double limit = 0.1); diff --git a/include/crpropa/module/PhotoPionProduction.h b/include/crpropa/module/PhotoPionProduction.h index 04c52a19e..8553c97e6 100644 --- a/include/crpropa/module/PhotoPionProduction.h +++ b/include/crpropa/module/PhotoPionProduction.h @@ -41,7 +41,7 @@ class PhotoPionProduction: public Module { public: PhotoPionProduction( PhotonField photonField = CMB, - ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, 1.,1.), + ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.), bool photons = false, bool neutrinos = false, bool electrons = false, From 5ebe39a34643093a71d76be7c7e431e22c29c5bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 21:28:16 +0100 Subject: [PATCH 24/81] re-implement geometry and time-dependence --- src/module/EMDoublePairProduction.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/module/EMDoublePairProduction.cpp b/src/module/EMDoublePairProduction.cpp index 07baacb0a..8fbee9d17 100644 --- a/src/module/EMDoublePairProduction.cpp +++ b/src/module/EMDoublePairProduction.cpp @@ -8,8 +8,12 @@ namespace crpropa { -EMDoublePairProduction::EMDoublePairProduction(PhotonField photonField, bool haveElectrons, double limit) { +EMDoublePairProduction::EMDoublePairProduction(PhotonField photonField, + ScalarGrid4d geometryGrid, + bool haveElectrons, + double limit) { setPhotonField(photonField); + this->geometryGrid = geometryGrid; this->haveElectrons = haveElectrons; this->limit = limit; } @@ -87,7 +91,14 @@ void EMDoublePairProduction::process(Candidate *candidate) const { return; // interaction rate - double rate = interpolate(E, tabEnergy, tabRate); + Vector3d pos = candidate->current.getPosition(); + double time = candidate->getTrajectoryLength()/c_light; + // geometric scaling + double rate = geometryGrid.interpolate(pos, time); + if (rate == 0.) + return; + + rate *= interpolate(E, tabEnergy, tabRate); rate *= pow(1 + z, 2) * photonFieldScaling(photonField, z); // check for interaction From e476615ff789f0ddd4099868e8783ff99c5fad7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 21:28:46 +0100 Subject: [PATCH 25/81] update constructor of ScalarGrid 4d setOrigin to take vector3d instead of double --- src/module/PhotoPionProduction.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 548f512e3..f337e859b 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -35,7 +35,9 @@ PhotoPionProduction::PhotoPionProduction( PhotonField field, limit = l; setPhotonField(field); this->geometryGrid = geometryGrid; - geometryGrid.setOrigin(Vector3d(-geometryGrid.getSpacing()/2.)); // correct for weird interpolation convention in CRPropa + geometryGrid.setOrigin( Vector3d(-geometryGrid.getSpacing().x/2., + -geometryGrid.getSpacing().y/2., + -geometryGrid.getSpacing().z/2.) ); // correct for weird interpolation convention in CRPropa this->phtnfld = Photon_Field(getDataPath("Scaling/" + photonFieldName(field) + ".txt")); if (useTabData) initHistogram(getDataPath("PhotoPionProduction/SOPHIA_histogram.txt")); } From 09babd06dc988bee5a72fa62e716fc2945d50a6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 1 Jan 2019 21:39:04 +0100 Subject: [PATCH 26/81] correct for in-middle-of-box interpolation convention in CRPropa in each geometryGrid --- src/module/EMDoublePairProduction.cpp | 1 + src/module/EMInverseComptonScattering.cpp | 1 + src/module/EMPairProduction.cpp | 1 + src/module/EMTripletPairProduction.cpp | 1 + src/module/ElasticScattering.cpp | 1 + src/module/ElectronPairProduction.cpp | 1 + src/module/PhotoDisintegration.cpp | 1 + src/module/PhotoPionProduction.cpp | 4 +--- 8 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/module/EMDoublePairProduction.cpp b/src/module/EMDoublePairProduction.cpp index 8fbee9d17..ec99f75ba 100644 --- a/src/module/EMDoublePairProduction.cpp +++ b/src/module/EMDoublePairProduction.cpp @@ -14,6 +14,7 @@ EMDoublePairProduction::EMDoublePairProduction(PhotonField photonField, double limit) { setPhotonField(photonField); this->geometryGrid = geometryGrid; + geometryGrid.setOrigin(-0.5*geometryGrid.getSpacing()); // correct for in-middle-of-box convention in CRPropa this->haveElectrons = haveElectrons; this->limit = limit; } diff --git a/src/module/EMInverseComptonScattering.cpp b/src/module/EMInverseComptonScattering.cpp index 465cd3898..f23b59176 100644 --- a/src/module/EMInverseComptonScattering.cpp +++ b/src/module/EMInverseComptonScattering.cpp @@ -17,6 +17,7 @@ EMInverseComptonScattering::EMInverseComptonScattering(PhotonField photonField, double limit) { setPhotonField(photonField); this->geometryGrid = geometryGrid; + geometryGrid.setOrigin(-0.5*geometryGrid.getSpacing()); // correct for in-middle-of-box convention in CRPropa this->havePhotons = havePhotons; this->limit = limit; } diff --git a/src/module/EMPairProduction.cpp b/src/module/EMPairProduction.cpp index 9cb571754..d45b617a0 100644 --- a/src/module/EMPairProduction.cpp +++ b/src/module/EMPairProduction.cpp @@ -18,6 +18,7 @@ EMPairProduction::EMPairProduction(PhotonField photonField, limit(limit) { setPhotonField(photonField); this->geometryGrid = geometryGrid; + geometryGrid.setOrigin(-0.5*geometryGrid.getSpacing()); // correct for in-middle-of-box convention in CRPropa } void EMPairProduction::setPhotonField(PhotonField photonField) { diff --git a/src/module/EMTripletPairProduction.cpp b/src/module/EMTripletPairProduction.cpp index 5d20f7089..a61f664fe 100644 --- a/src/module/EMTripletPairProduction.cpp +++ b/src/module/EMTripletPairProduction.cpp @@ -16,6 +16,7 @@ EMTripletPairProduction::EMTripletPairProduction(PhotonField photonField, double limit) { setPhotonField(photonField); this->geometryGrid = geometryGrid; + geometryGrid.setOrigin(-0.5*geometryGrid.getSpacing()); // correct for in-middle-of-box convention in CRPropa this->haveElectrons = haveElectrons; this->limit = limit; } diff --git a/src/module/ElasticScattering.cpp b/src/module/ElasticScattering.cpp index ef1ba9a4a..e4fc3345c 100644 --- a/src/module/ElasticScattering.cpp +++ b/src/module/ElasticScattering.cpp @@ -22,6 +22,7 @@ const size_t ElasticScattering::neps = 513; // number of photon background energ ElasticScattering::ElasticScattering(PhotonField f, ScalarGrid4d geometryGrid) { setPhotonField(f); this->geometryGrid = geometryGrid; + geometryGrid.setOrigin(-0.5*geometryGrid.getSpacing()); // correct for in-middle-of-box convention in CRPropa } void ElasticScattering::setPhotonField(PhotonField photonField) { diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index 0b1f00ccc..b60d6eac1 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -16,6 +16,7 @@ ElectronPairProduction::ElectronPairProduction(PhotonField photonField, double limit) { setPhotonField(photonField); this->geometryGrid = geometryGrid; + geometryGrid.setOrigin(-0.5*geometryGrid.getSpacing()); // correct for in-middle-of-box convention in CRPropa this->haveElectrons = haveElectrons; this->limit = limit; } diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 0cf1efefd..23f1abd76 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -22,6 +22,7 @@ PhotoDisintegration::PhotoDisintegration(PhotonField f, double limit) { setPhotonField(f); this->geometryGrid = geometryGrid; + geometryGrid.setOrigin(-0.5*geometryGrid.getSpacing()); // correct for in-middle-of-box convention in CRPropa this->havePhotons = havePhotons; this->limit = limit; } diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index f337e859b..d868eea1d 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -35,9 +35,7 @@ PhotoPionProduction::PhotoPionProduction( PhotonField field, limit = l; setPhotonField(field); this->geometryGrid = geometryGrid; - geometryGrid.setOrigin( Vector3d(-geometryGrid.getSpacing().x/2., - -geometryGrid.getSpacing().y/2., - -geometryGrid.getSpacing().z/2.) ); // correct for weird interpolation convention in CRPropa + geometryGrid.setOrigin(-0.5*geometryGrid.getSpacing()); // correct for in-middle-of-box convention in CRPropa this->phtnfld = Photon_Field(getDataPath("Scaling/" + photonFieldName(field) + ".txt")); if (useTabData) initHistogram(getDataPath("PhotoPionProduction/SOPHIA_histogram.txt")); } From 55c7f4739831cae0a065c9e4d691f79fc76e8836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Thu, 3 Jan 2019 01:16:41 +0100 Subject: [PATCH 27/81] replace broken file --- python/2_headers.i | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/python/2_headers.i b/python/2_headers.i index 194f2d573..3b4ef9546 100644 --- a/python/2_headers.i +++ b/python/2_headers.i @@ -285,6 +285,10 @@ %template(AdvectionFieldRefPtr) crpropa::ref_ptr; %include "crpropa/advectionField/AdvectionField.h" +%implicitconv crpropa::ref_ptr; +%template(DensityRefPtr) crpropa::ref_ptr; +%include "crpropa/massDistribution/Density.h" + %include "crpropa/Grid.h" %include "crpropa/GridTools.h" @@ -311,6 +315,7 @@ %include "crpropa/magneticField/QuimbyMagneticField.h" %include "crpropa/magneticField/AMRMagneticField.h" %include "crpropa/magneticField/JF12Field.h" +%include "crpropa/magneticField/JF12FieldSolenoidal.h" %include "crpropa/magneticField/PT11Field.h" %include "crpropa/magneticField/ArchimedeanSpiralField.h" %include "crpropa/module/BreakCondition.h" @@ -538,3 +543,10 @@ class ParticleCollectorIterator { }; %include "crpropa/module/ParticleCollector.h" + +%include "crpropa/massDistribution/Density.h" +%include "crpropa/massDistribution/Nakanishi.h" +%include "crpropa/massDistribution/Cordes.h" +%include "crpropa/massDistribution/Ferriere.h" +%include "crpropa/massDistribution/Massdistribution.h" +%include "crpropa/massDistribution/ConstantDensity.h" From b54433151afab61a99533cff9d4b4464cac2b428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Thu, 3 Jan 2019 02:56:29 +0100 Subject: [PATCH 28/81] correct for component in kmin/max --- src/GridTools.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GridTools.cpp b/src/GridTools.cpp index 3c0f06a58..532815a9f 100644 --- a/src/GridTools.cpp +++ b/src/GridTools.cpp @@ -130,8 +130,8 @@ void initTurbulence(ref_ptr grid, double Brms, double lMin, double l // parameters goes for non helical calculations double theta, phase, cosPhase, sinPhase; - double kMin = spacing / lMax; - double kMax = spacing / lMin; + double kMin = spacing.x / lMax; + double kMax = spacing.x / lMin; Vector3f b; // real b-field vector Vector3f ek, e1, e2; // orthogonal base Vector3f n0(1, 1, 1); // arbitrary vector to construct orthogonal base From 795465ea0650e2aa9a3b4b65e5212de6fb44dc49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Thu, 3 Jan 2019 03:00:44 +0100 Subject: [PATCH 29/81] consider potentially inequal spacing --- src/GridTools.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/GridTools.cpp b/src/GridTools.cpp index 532815a9f..13af68880 100644 --- a/src/GridTools.cpp +++ b/src/GridTools.cpp @@ -276,7 +276,9 @@ void fromMagneticField(ref_ptr grid, ref_ptr field) { for (size_t ix = 0; ix < Nx; ix++) for (size_t iy = 0; iy < Ny; iy++) for (size_t iz = 0; iz < Nz; iz++) { - Vector3d pos = Vector3d(double(ix) + 0.5, double(iy) + 0.5, double(iz) + 0.5) * spacing + origin; + Vector3d pos = Vector3d( (double(ix) + 0.5) * spacing.x, + (double(iy) + 0.5) * spacing.y, + (double(iz) + 0.5) * spacing.z ) + origin; Vector3d B = field->getField(pos); grid->get(ix, iy, iz) = B; } @@ -291,7 +293,9 @@ void fromMagneticFieldStrength(ref_ptr grid, ref_ptr for (size_t ix = 0; ix < Nx; ix++) for (size_t iy = 0; iy < Ny; iy++) for (size_t iz = 0; iz < Nz; iz++) { - Vector3d pos = Vector3d(double(ix) + 0.5, double(iy) + 0.5, double(iz) + 0.5) * spacing + origin; + Vector3d pos = Vector3d( (double(ix) + 0.5) * spacing.x, + (double(iy) + 0.5) * spacing.y, + (double(iz) + 0.5) * spacing.z ) + origin; double s = field->getField(pos).getR(); grid->get(ix, iy, iz) = s; } From 71c640433842ebc140e1a0377ce4420641c74d30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Thu, 3 Jan 2019 03:16:53 +0100 Subject: [PATCH 30/81] remove obsolete comments --- test/testInteraction.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index b02567d08..0fef3b625 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -527,9 +527,7 @@ TEST(PhotoPionProduction, limitNextStep) { TEST(PhotoPionProduction, secondaries) { // Test photo-pion interaction for 100 EeV proton. // This test can stochastically fail. - // PhotoPionProduction ppp("field.txt", "geometry.txt", CMB, true, true, true); - // PhotoPionProduction ppp(CMB, ScalarGrid(Vector3d(0.),1,1.),true, true, true); - PhotoPionProduction ppp(CMB, ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.),true, true, true); + PhotoPionProduction ppp(CMB, ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.), true, true, true); Candidate c(nucleusId(1, 1), 100 * EeV); c.setCurrentStep(1000 * Mpc); ppp.process(&c); From 981ac7e4115a6af6a4bd31bd94bb8a50ae2f0e8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 8 Jan 2019 17:36:09 +0100 Subject: [PATCH 31/81] replace grid spacing: double -> Vector3d --- src/magneticField/JF12Field.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/magneticField/JF12Field.cpp b/src/magneticField/JF12Field.cpp index 68b1a145e..007b8b5fb 100644 --- a/src/magneticField/JF12Field.cpp +++ b/src/magneticField/JF12Field.cpp @@ -102,7 +102,7 @@ void JF12Field::randomStriated(int seed) { void JF12Field::randomTurbulent(int seed) { useTurbulentField = true; // turbulent field with Kolmogorov spectrum, B_rms = 1 and Lc = 60 parsec - turbulentGrid = new VectorGrid(Vector3d(0.), 256, 4 * parsec); + turbulentGrid = new VectorGrid(Vector3d(0.), 256, Vector3d(4 * parsec)); initTurbulence(turbulentGrid, 1, 8 * parsec, 272 * parsec, -11./3., seed); } #endif From 6647d23023258959adc2afe920fc184cf7863642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 8 Jan 2019 17:42:36 +0100 Subject: [PATCH 32/81] replace grid spacing type: double -> Vector3d --- test/testMagneticField.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index c3d0b5ef6..761c2c7d3 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -78,7 +78,7 @@ TEST(testVectorFieldGrid, Turbulence_bmean_brms) { double lMin = 2 * spacing; double lMax = 8 * spacing; - ref_ptr grid = new VectorGrid(Vector3d(0, 0, 0), n, spacing); + ref_ptr grid = new VectorGrid(Vector3d(0, 0, 0), n, Vector3d(spacing)); initTurbulence(grid, Brms, lMin, lMax); double precision = 1e-7; From bca745f154c650b8765624ba675ec45323539845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 8 Jan 2019 17:50:12 +0100 Subject: [PATCH 33/81] replace grid spacing data type: double -> Vector3d --- test/testMagneticField.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/testMagneticField.cpp b/test/testMagneticField.cpp index 761c2c7d3..f89177cb0 100644 --- a/test/testMagneticField.cpp +++ b/test/testMagneticField.cpp @@ -99,10 +99,10 @@ TEST(testVectorFieldGrid, Turbulence_seed) { double index = -11. / 3.; int seed = 753; - ref_ptr grid1 = new VectorGrid(Vector3d(0, 0, 0), n, spacing); + ref_ptr grid1 = new VectorGrid(Vector3d(0, 0, 0), n, Vector3d(spacing)); initTurbulence(grid1, Brms, lMin, lMax, index, seed); - ref_ptr grid2 = new VectorGrid(Vector3d(0, 0, 0), n, spacing); + ref_ptr grid2 = new VectorGrid(Vector3d(0, 0, 0), n, Vector3d(spacing)); initTurbulence(grid2, Brms, lMin, lMax, index, seed); Vector3d pos(22 * Mpc); @@ -114,7 +114,7 @@ TEST(testVectorFieldGrid, turbulence_Exceptions) { size_t n = 64; double spacing = 10 * Mpc / n; double brms = 1; - ref_ptr grid = new VectorGrid(Vector3d(0, 0, 0), n, spacing); + ref_ptr grid = new VectorGrid(Vector3d(0, 0, 0), n, Vector3d(spacing)); // should be fine EXPECT_NO_THROW(initTurbulence(grid, brms, 2 * spacing, 8 * spacing)); From 4c6a17ae838d4018aa0ba89cd0484c297e7c3922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Wed, 9 Jan 2019 15:08:07 +0100 Subject: [PATCH 34/81] remove grid origin offset and put corresponding info in wiki page --- src/module/EMDoublePairProduction.cpp | 1 - src/module/EMInverseComptonScattering.cpp | 1 - src/module/EMPairProduction.cpp | 1 - src/module/EMTripletPairProduction.cpp | 1 - src/module/ElasticScattering.cpp | 1 - src/module/PhotoDisintegration.cpp | 1 - src/module/PhotoPionProduction.cpp | 3 +-- 7 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/module/EMDoublePairProduction.cpp b/src/module/EMDoublePairProduction.cpp index ec99f75ba..8fbee9d17 100644 --- a/src/module/EMDoublePairProduction.cpp +++ b/src/module/EMDoublePairProduction.cpp @@ -14,7 +14,6 @@ EMDoublePairProduction::EMDoublePairProduction(PhotonField photonField, double limit) { setPhotonField(photonField); this->geometryGrid = geometryGrid; - geometryGrid.setOrigin(-0.5*geometryGrid.getSpacing()); // correct for in-middle-of-box convention in CRPropa this->haveElectrons = haveElectrons; this->limit = limit; } diff --git a/src/module/EMInverseComptonScattering.cpp b/src/module/EMInverseComptonScattering.cpp index f23b59176..465cd3898 100644 --- a/src/module/EMInverseComptonScattering.cpp +++ b/src/module/EMInverseComptonScattering.cpp @@ -17,7 +17,6 @@ EMInverseComptonScattering::EMInverseComptonScattering(PhotonField photonField, double limit) { setPhotonField(photonField); this->geometryGrid = geometryGrid; - geometryGrid.setOrigin(-0.5*geometryGrid.getSpacing()); // correct for in-middle-of-box convention in CRPropa this->havePhotons = havePhotons; this->limit = limit; } diff --git a/src/module/EMPairProduction.cpp b/src/module/EMPairProduction.cpp index d45b617a0..9cb571754 100644 --- a/src/module/EMPairProduction.cpp +++ b/src/module/EMPairProduction.cpp @@ -18,7 +18,6 @@ EMPairProduction::EMPairProduction(PhotonField photonField, limit(limit) { setPhotonField(photonField); this->geometryGrid = geometryGrid; - geometryGrid.setOrigin(-0.5*geometryGrid.getSpacing()); // correct for in-middle-of-box convention in CRPropa } void EMPairProduction::setPhotonField(PhotonField photonField) { diff --git a/src/module/EMTripletPairProduction.cpp b/src/module/EMTripletPairProduction.cpp index a61f664fe..5d20f7089 100644 --- a/src/module/EMTripletPairProduction.cpp +++ b/src/module/EMTripletPairProduction.cpp @@ -16,7 +16,6 @@ EMTripletPairProduction::EMTripletPairProduction(PhotonField photonField, double limit) { setPhotonField(photonField); this->geometryGrid = geometryGrid; - geometryGrid.setOrigin(-0.5*geometryGrid.getSpacing()); // correct for in-middle-of-box convention in CRPropa this->haveElectrons = haveElectrons; this->limit = limit; } diff --git a/src/module/ElasticScattering.cpp b/src/module/ElasticScattering.cpp index e4fc3345c..ef1ba9a4a 100644 --- a/src/module/ElasticScattering.cpp +++ b/src/module/ElasticScattering.cpp @@ -22,7 +22,6 @@ const size_t ElasticScattering::neps = 513; // number of photon background energ ElasticScattering::ElasticScattering(PhotonField f, ScalarGrid4d geometryGrid) { setPhotonField(f); this->geometryGrid = geometryGrid; - geometryGrid.setOrigin(-0.5*geometryGrid.getSpacing()); // correct for in-middle-of-box convention in CRPropa } void ElasticScattering::setPhotonField(PhotonField photonField) { diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 23f1abd76..0cf1efefd 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -22,7 +22,6 @@ PhotoDisintegration::PhotoDisintegration(PhotonField f, double limit) { setPhotonField(f); this->geometryGrid = geometryGrid; - geometryGrid.setOrigin(-0.5*geometryGrid.getSpacing()); // correct for in-middle-of-box convention in CRPropa this->havePhotons = havePhotons; this->limit = limit; } diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index d868eea1d..ab566204b 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -35,7 +35,6 @@ PhotoPionProduction::PhotoPionProduction( PhotonField field, limit = l; setPhotonField(field); this->geometryGrid = geometryGrid; - geometryGrid.setOrigin(-0.5*geometryGrid.getSpacing()); // correct for in-middle-of-box convention in CRPropa this->phtnfld = Photon_Field(getDataPath("Scaling/" + photonFieldName(field) + ".txt")); if (useTabData) initHistogram(getDataPath("PhotoPionProduction/SOPHIA_histogram.txt")); } @@ -434,7 +433,7 @@ void PhotoPionProduction::process(Candidate *candidate) const { double step = candidate->getCurrentStep(); double z = candidate->getRedshift(); Vector3d pos = candidate->current.getPosition(); - double time = candidate->getTrajectoryLength()/c_light; +double time = candidate->getTrajectoryLength()/c_light; // the loop is processed at least once for limiting the next step do { // check if nucleus From 094048d89edac4f581a847dffe5326f8e9deb7d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Thu, 10 Jan 2019 22:15:13 +0100 Subject: [PATCH 35/81] add file to generate tabulated files for interaction modules from a photon field file --- helperFiles/convert_photonField.py | 175 +++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 helperFiles/convert_photonField.py diff --git a/helperFiles/convert_photonField.py b/helperFiles/convert_photonField.py new file mode 100644 index 000000000..7b36646e7 --- /dev/null +++ b/helperFiles/convert_photonField.py @@ -0,0 +1,175 @@ +""" +purpose: convert IRB photon field data from external sources to +a unified format for CRPropa to read. The 7 photon fields that can be converted +by this script are: + IRB_Kneiske04, IRB_Stecker05, IRB_Finke10, IRB_Dominguez11, + IRB_Gilmore12, IRB_Stecker16_upper, IRB_Stecker16_lower +usage: this file should be placed in the CRPropa-data/ folder +output: .txt files named by their field name +Written by Mario Hörbe (mario.hoerbe@rub.de) +""" + +import numpy as np +import pandas as pd +import os + +eV = 1.60217657e-19 # [J] +c0 = 299792458 # [m/s] +h = 6.62606957e-34 # [m^2 kg / s] + + +def IRB_Stecker05(fileDir): + name = 'IRB_Stecker05' + info = '# cosmic infrared and optical background radiation model of Stecker at al. 2005' + redshift = np.linspace(0, 5, 26) + filePath = fileDir + "EBL_Stecker_2005/data2.txt" + d = np.genfromtxt(filePath, unpack=True) + eps = 10**d[0] # [eV] + n = 10**d[1:] # [1/cm^3] + n /= eps # [1/eVcm^3] + n = pd.DataFrame(n) + photonField = [] + energy = [] + for col in n.columns: + energy.append(eps[col]) + photonField.append(n[col].values) + createField(name, info, energy, redshift, photonField) + + +def IRB_Gilmore12(fileDir): + name = "IRB_Gilmore12" + info = "# These tables contain the data for the background flux and associated optical depths of gamma rays for the WMAP5+Fixed ('fixed') and Evolving Dust ('fiducial') models presented in Gilmore, Somerville, Primack, and Dominguez (2012), ArXiv:1104.0671v2" + filePath = fileDir + "EBL_Gilmore_2012/eblflux_fiducial.dat" + redshift = [0.0,0.015,0.025,0.044,0.05,0.2,0.4,0.5,0.6,0.8,1.0,1.25,1.5,2.0,2.5,3.0,4.0,5.0,6.0,7.0] + d = np.genfromtxt(filePath, unpack=True) + wavelength = d[0] # angstrom + eps = 12.39842e3 / wavelength # [eV] + photonField = [] + energy = [] + d = pd.DataFrame(d) + for i in range(len(eps)): + fieldSlice = np.array(list(d[i])[1:]) * 4*np.pi /(100*c0) *1e-10 *6.2415091e11 # eV/cm^3 + fieldSlice /= eps[i]**2 # 1/eVcm^3 + photonField.append(fieldSlice / eV) # /eV?! + energy.append(eps[i]) + # invert, because lambda is antiprop to energy + photonField = [x for x in reversed(photonField)] + energy = [e for e in reversed(energy)] + createField(name, info, energy, redshift, photonField) + + +def IRB_Finke10(fileDir): + name = "IRB_Finke10" + redshift = np.round(np.linspace(0,4.99,500), 2) + info = "# Extragalactic background light model from Finke et al. 2010, DOI:10.1088/0004-637X/712/1/238, Files obtained from http://www.phy.ohiou.edu/~finke/EBL/" + fileDir = fileDir + "EBL_Finke_2010/" + fileList = os.listdir(fileDir) + d = pd.DataFrame() + col = 0 + for file in sorted(fileList): + if "README.txt" not in file: + data = np.genfromtxt(fileDir + file, unpack=True) + # eps = data[0] + eps = data[0] # [eV] + data = pd.DataFrame(data[1],columns=[col/100]) + col += 1 + d = pd.concat([d,data], axis=1, join_axes=[data.index]) + photonField = [] + energy = [] + for i,e in enumerate(eps): + dens = np.array(list(d.iloc[i])) * 6.2415091e11 / eps[i]**2 # [1/eVcm^3] + photonField.append(dens) + energy.append(eps[i]) + createField(name, info, energy, redshift, photonField) + + +def IRB_Dominguez11(fileDir): + name = "IRB_Dominguez11" + info = "# EBL intensities for the paper >Extragalactic background light inferred from AEGIS galaxy-SED-type fractions<, A. Dominguez et al., 2011, MNRAS, 410, 2556" + redshift = np.array([0,0.01,0.03,0.05,0.1,0.2,0.3,0.4,0.5,0.6,0.8,1.0,1.25,1.5,2.0,2.5,3.0,3.9]) + filePath = fileDir + "EBL_Dominguez_2011/ebl_dominguez11.out" + d = np.genfromtxt(filePath, unpack=False) + eps = [1.239842/fieldSlice[0]*eV for fieldSlice in d] # [eV] | 1.238842 = h*c/1µ eV + # nW->W : J->eV : 1/m³->1/cm³ : 1/sm²sr->1/m³ + n = np.array([fieldSlice[1:] *1e-9 *eV /1e6 /eps[i]**2 * (4*np.pi/c0) for i,fieldSlice in enumerate(d)]) # [1/eVcm^3] + energy = [] + for i,x in enumerate(n): + energy.append(eps[i]/eV) + photonField = [x for x in reversed(n)] + energy = [e for e in reversed(energy)] + createField(name, info, energy, redshift, photonField) + + +def IRB_Stecker16_lower(fileDir): + name = "IRB_Stecker16_lower" + info = "# Extragalactic background light model from Stecker et al. 2016, DOI:10.3847/0004-637X/827/1/6 " + redshift = np.linspace(0, 5, 501) + filePath = fileDir + "EBL_Stecker_2016/comoving_enerdens_lo.csv" + d = np.genfromtxt(filePath, delimiter=',') + eps = 10**np.arange(-2.84, 1.14001, 0.01) # [eV] + nu = eps * eV / h # [Hz] + photonField = [] + energy = [] + for i,dens in enumerate(d): + d[i] = d[i] * 6.2415091e11 * nu[i] / eps[i]**2 # 1/eVcm^3 + photonField.append(d[i]) + energy.append(eps[i]) + createField(name, info, energy, redshift, photonField) + + +def IRB_Stecker16_upper(fileDir): + name = "IRB_Stecker16_upper" + info = "# Extragalactic background light model from Stecker et al. 2016, DOI:10.3847/0004-637X/827/1/6 " + redshift = np.linspace(0, 5, 501) + filePath = fileDir + "EBL_Stecker_2016/comoving_enerdens_up.csv" + d = np.genfromtxt(filePath, delimiter=',') + eps = 10**np.arange(-2.84, 1.14001, 0.01) # [eV] + nu = eps * eV / h # [Hz] + photonField = [] + energy = [] + for i,dens in enumerate(d): + d[i] = d[i] * 6.2415091e11 * nu[i] / eps[i]**2 # 1/eVcm^3 + photonField.append(d[i]) + energy.append(eps[i]) + createField(name, info, energy, redshift, photonField) + + +def IRB_Kneiske04(fileDir): + name = "IRB_Kneiske04" + info = "# IRO spectrum from Tanja Kneiske et al. obtained from O. E. Kalashev (http://hecr.inr.ac.ru/)" + redshift = np.linspace(0,5,51) + filePath = fileDir + "EBL_Kneiske_2004/all_z" + d = np.genfromtxt(filePath) + photonField = [] + energy = [] + for i,fieldSlice in enumerate(d): + for j,entry in enumerate(fieldSlice): + if j != 0: + d[i][j] /= 1e6 # 1/eVm^3 -> 1/eVcm^3 + photonField.append(fieldSlice[1:]) + energy.append(fieldSlice[0]) + createField(name, info, energy, redshift, photonField) + + +def createField(name, info, energy, redshift, photonField): + with open(name+".txt", 'w') as f: + f.write(info+"\n") + f.write("# energy / eV:\n") + np.savetxt(f, [energy], fmt="%1.6e", delimiter=" ") + f.write("# redshift:\n") + np.savetxt(f, [redshift], fmt="%1.2f", delimiter=" ") + f.write("# photon field density / 1/eVcm^3:\n") + np.savetxt(f, photonField, fmt="%1.6e", delimiter=" ") + print("done: " + name) + + +if __name__ == "__main__": + + fileDir = "/tables/" + IRB_Kneiske04(fileDir) + IRB_Stecker05(fileDir) + IRB_Finke10(fileDir) + IRB_Dominguez11(fileDir) + IRB_Gilmore12(fileDir) + IRB_Stecker16_upper(fileDir) + IRB_Stecker16_lower(fileDir) From 88dffddc9e3b6d16d7c536676235843368b4b39d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Thu, 10 Jan 2019 22:15:51 +0100 Subject: [PATCH 36/81] add file to convert photon field data of IRB models from the CRPropa-data repository to gain a unified photon field format --- helperFiles/generate_tabFiles.py | 688 +++++++++++++++++++++++++++++++ 1 file changed, 688 insertions(+) create mode 100644 helperFiles/generate_tabFiles.py diff --git a/helperFiles/generate_tabFiles.py b/helperFiles/generate_tabFiles.py new file mode 100644 index 000000000..1e28f22a1 --- /dev/null +++ b/helperFiles/generate_tabFiles.py @@ -0,0 +1,688 @@ +""" +- The purpose of this script is to centrally generate all interaction files needed by CRPropa + from a photonField.txt file +- This script has incorporated all calc_ files contained in the GitHub repository + + https://github.com/CRPropa/CRPropa3-data + + thus credit goes to the authors of the respective code writers. +- Multi-core processing is now supported +- NOTE: spectrum_.txt for ~/src/crpropa/ElectronPairProduction can NOT be + generated by this script, as this appears to get constructed from data provided by + CRPropa2 scripts. As all spectrum scripts appear to only continue zeros or values + *very* close to zero, a copy of spectrum_CMB.txt should be used. +- Data generated by this script have to be written to their proper locations in + ~/share/crpropa/ +- written by Mario Hörbe (mario.hoerbe@rub.de) + + +Usage: + generate_tabFiles.py + generate_tabFiles.py -h | --help + generate_tabFiles.py --version + +Arguments: + path/to/photonField.txt + ~/CRPropa/share/crpropa/ + +Options: + -h, --help Show this message. + --version Print the version. +""" + + +from __future__ import division +from multiprocessing import Process, cpu_count, Pool +import multiprocessing +import os +import sys +from joblib import Parallel, delayed +import numpy as np +from scipy import integrate +from scipy.integrate import cumtrapz, romb +from docopt import docopt + +eV = 1.60217657e-19 # [J] +erg = 1e-7 # [J] +c0 = 299792458 # [m/s] +h = 6.62606957e-34 # [m^2 kg / s] +kB = 1.3806488e-23 # [m^2 kg / s^2 / K] +Mpc = 3.08567758e22 # [m] + + + # arr arr arr +def calc_rate_eps(eps, xs, gamma, field, z=0, cdf=False): + """ + Calculate the interaction rate for given tabulated cross sections against an isotropic photon background. + The tabulated cross sections need to be of length n = 2^i + 1 and the tabulation points log-linearly spaced. + + eps : tabulated photon energies [J] in nucleus rest frame + xs : tabulated cross sections [m^2] + gamma : (array of) nucleus Lorentz factors + field : photon background, see photonField.py + z : redshift + cdf : calculate cumulative differential rate + + Returns : + interaction rate 1/lambda(gamma) [1/Mpc] or + cumulative differential rate d(1/lambda)/d(s_kin) [1/Mpc/J^2] + """ + F = cumtrapz(x=eps, y=eps * xs, initial=0) + n = field.getDensity(np.outer(1. / (2 * gamma), eps), z) + if cdf: + y = n * F / eps**2 + return cumtrapz(x=eps, y=y, initial=0) / np.expand_dims(gamma, -1) * Mpc + else: # Branch of interest + y = n * F / eps + dx = mean_log_spacing(eps) + return romb(y, dx=dx) / gamma * Mpc + + +def calc_rate_s(s_kin, xs, E, field, z=0, cdf=False): + """ + Calculate the interaction rate for given tabulated cross sections against an isotropic photon background. + The tabulated cross sections need to be of length n = 2^i + 1 and the tabulation points log-linearly spaced. + + s_kin : tabulated (s - m**2) for cross sections [J^2] + xs : tabulated cross sections [m^2] + E : (array of) cosmic ray energies [J] + field : photon background, see photonField.py + z : redshift + cdf : calculate cumulative differential rate + + Returns : + interaction rate 1/lambda(gamma) [1/Mpc] or + cumulative differential rate d(1/lambda)/d(s_kin) [1/Mpc/J^2] + """ + F = cumtrapz(x=s_kin, y=s_kin * xs, initial=0) + n = field.getDensity(np.outer(1. / (4 * E), s_kin), z) + if cdf: + y = n * F / s_kin**2 + return cumtrapz(x=s_kin, y=y, initial=0) / 2 / np.expand_dims(E, -1) * Mpc + else: + y = n * F / s_kin + ds = mean_log_spacing(s_kin) + return romb(y, dx=ds) / 2 / E * Mpc + + +def mean_log_spacing(x): + """ """ + return np.mean(np.diff(np.log(x))) + + +def romb_truncate(x, n): + """ Truncate array to largest size n = 2^i + 1 """ + i = int(np.floor(np.log2(n))) + 1 + return x[0:2**i + 1] + + +def romb_pad_zero(x, n): + """ Pad array with zeros """ + npad = n - len(x) + return np.r_[x, np.zeros(npad)] + + +def romb_pad_logspaced(x, n): + """ Pad array with log-linear increasing values """ + npad = n - len(x) + dlx = np.mean(np.diff(np.log(x))) + xpad = x[-1] * np.exp(dlx * np.arange(1, npad + 1)) + return np.r_[x, xpad] + + + +class photonField: + """ customizable photon field """ + + def __init__(self, fromFile, photonFieldName): + self.name = photonFieldName + self.info = os.path.basename(fromFile) + self.redshift, self.fieldData, self.Emin, self.Emax = self.read_photonField(fromFile) + + + def read_photonField(self, fromFile): + """ read in tabulated photonField file """ + inData = [] + with open(fromFile, "r") as inFile: + for line in inFile: + if "#" in line: + continue + data = list(line.split()) + data = [float(d) for d in data] + inData.append(data) + + energy = np.array(inData[0]) + Emin = energy[0] * eV # [J] + Emax = energy[-1] * eV # [J] + redshift = inData[1] + density = np.array(inData[2:]) + + data = {} # dictionary {redshift : (eps, dn/deps)} + for i,z in enumerate(redshift): + data[z] = energy, density[:,i] + return redshift, data, Emin, Emax + + + def getDensity(self, eps, z=0): + """ + Comoving spectral number density dn/deps [1/m^3/J] at given photon energy eps [J] and redshift z. + Multiply with (1+z)^3 for the physical number density. + """ + eps /= eV # J -> eV + if z == 0: + z = np.min(self.redshift) + return np.interp(eps, self.fieldData[z][0], self.fieldData[z][1]) * 6.241509e24 # 1/eVcm^3 -> 1/Jm^3 + + + def getEmin(self): + """Minimum effective photon energy in [J]""" + return self.Emin + # return self.fieldData[z][0][0] * eV + + + def getEmax(self): + """Maximum effective photon energy in [J]""" + return self.Emax + # return self.fieldData[z][0][-1] * eV + + +class Interactions: + """ + Class containing all interaction calculations that provide shared .txt data to CRPropa + """ + + def calc_elasticscattering(fields, writeFilesTo): + # output folder + folder = writeFilesTo + 'ElasticScattering' + if not os.path.exists(folder): + os.makedirs(folder) + + gamma = np.logspace(6, 14, 201) # tabulated UHECR Lorentz-factors + + # load cross section data from TALYS + ddir = 'tables/PD_Talys1.8_Khan/' + eps = np.genfromtxt(ddir + 'eps_elastic.txt') * eV * 1e6 # nuclear rest frame photon energies [J] + data = np.genfromtxt(ddir + 'xs_elastic.txt', dtype=[('Z', int), ('N', int), ('xs', '%if8' % len(eps))]) + + # only consider TALYS cross sections for A >= 12 + idx = (data['Z'] + data['N']) >= 12 + data = data[idx] + + # factor out the principal scaling given by the TRK formula: sigma_int ~ Z*N/A + data['xs'] /= (data['Z'] * data['N'] / (data['Z'] + data['N']))[:, np.newaxis] + + # pad cross sections to next larger 2^n + 1 tabulation points for Romberg integration + eps = romb_pad_logspaced(eps, 513) + xs = np.array([romb_pad_zero(x, 513) for x in data['xs']]) * 1e-31 + + for field in fields: + + # calculate the interaction rate, averaged over all isotopes + ncores = cpu_count() + with Parallel(ncores, verbose=0) as pool: + + rate = list( + pool( + delayed(calc_rate_eps)(eps, x, gamma, field) for x in xs + ) + ) + rate = np.mean(rate, axis=0) + + fname = folder + '/rate_%s.txt' % field.name.split('_')[0][:3] # [:3] added to be readable by respective .cpp file + header = 'Average interaction rate for elastic scattering of %s photons off nuclei\nScale with Z*N/A for nuclei\n1/lambda [1/Mpc] for log10(gamma) = 6-14 in 201 steps' % field.info + np.savetxt(fname, rate, fmt='%g', header=header) + + with Parallel(ncores, verbose=0) as pool: + + C = list( + pool( + delayed(calc_rate_eps)(eps, x, gamma, field, cdf=True) for x in xs + ) + ) + C = [c/np.max(c, axis=1, keepdims=True) for c in C] + CDF = np.zeros((len(gamma), len(eps))) + for c in C: + CDF += c + + CDF /= len(data) + CDF = np.nan_to_num(CDF) + + fname = folder + '/cdf_%s.txt' % field.name.split('_')[0][:3] # [:3] added to be readable by respective .cpp file + data = np.c_[np.log10(gamma), CDF] + fmt = '%g' + '\t%g' * len(eps) + header = '# Average CDF(background photon energy) for elastic scattering with the photon field defined in %s\n# log10(gamma), (1/lambda)_cumulative for eps = log10(2 keV) - log10(263 MeV) in 513 steps' % field.info + np.savetxt(fname, data, fmt=fmt, header=header) + + + def calc_electromagnetic(fields, writeFilesTo): + + me2 = (510.998918E3 * eV)**2 # squared electron mass [J^2/c^4] + sigmaThompson = 6.6524E-29 # Thompson cross section [m^2] + alpha = 1 / 137.035999074 # fine structure constant + + def sigmaPP(s): + """ Pair production cross section (Bethe-Heitler), see Lee 1996 """ + smin = 4 * me2 + if (s < smin): + return 0 + else: + b = np.sqrt(1 - smin / s) + return sigmaThompson * 3 / 16 * (1 - b**2) * ((3 - b**4) * np.log((1 + b) / (1 - b)) - 2 * b * (2 - b**2)) + + + def sigmaDPP(s): + """ Double-pair production cross section, see R.W. Brown eq. (4.5) with k^2 = q^2 = 0 """ + smin = 16 * me2 + if (s < smin): + return 0 + else: + return 6.45E-34 * (1 - smin / s)**6 + + + def sigmaICS(s): + """ Inverse Compton scattering cross sections, see Lee 1996 """ + smin = me2 + if (s < smin): # numerically unstable close to smin + return 0 + else: + # note: formula unstable for (s - smin) / smin < 1E-5 + b = (s - smin) / (s + smin) + A = 2 / b / (1 + b) * (2 + 2 * b - b**2 - 2 * b**3) + B = (2 - 3 * b**2 - b**3) / b**2 * np.log((1 + b) / (1 - b)) + return sigmaThompson * 3 / 8 * smin / s / b * (A - B) + + + def sigmaTPP(s): + """ Triplet-pair production cross section, see Lee 1996 """ + beta = 28 / 9 * np.log(s / me2) - 218 / 27 + if beta < 0: + return 0 + else: + return sigmaThompson * 3 / 8 / np.pi * alpha * beta + + + def getTabulatedXS(sigma, skin): + """ Get crosssection for tabulated s_kin """ + if sigma in (sigmaPP, sigmaDPP): # photon interactions + return np.array([sigma(s) for s in skin]) + if sigma in (sigmaTPP, sigmaICS): # electron interactions + return np.array([sigma(s) for s in skin + me2]) + return False + + + def getSmin(sigma): + """ Return minimum required s_kin = s - (mc^2)^2 for interaction """ + return {sigmaPP: 4 * me2, + sigmaDPP: 16 * me2, + sigmaTPP: np.exp((218 / 27) / (28 / 9)) * me2 - me2, + sigmaICS: 1E-9 * me2 + }[sigma] + + + def getEmin(sigma, field): + """ Return minimum required cosmic ray energy for interaction *sigma* with *field* """ + return getSmin(sigma) / 4 / field.getEmax() + + + def process(sigma, field, name): + # output folder + folder = writeFilesTo + name + if not os.path.exists(folder): + os.makedirs(folder) + + # tabulated energies, limit to energies where the interaction is possible + Emin = getEmin(sigma, field) + E = np.logspace(10, 23, 261) * eV + E = E[E > Emin] + + # ------------------------------------------- + # calculate interaction rates + # ------------------------------------------- + # tabulated values of s_kin = s - mc^2 + # Note: integration method (Romberg) requires 2^n + 1 log-spaced tabulation points + s_kin = np.logspace(6, 23, 2049) * eV**2 + xs = getTabulatedXS(sigma, s_kin) + rate = calc_rate_s(s_kin, xs, E, field) + + # save + fname = folder + '/rate_%s.txt' % field.name + data = np.c_[np.log10(E / eV), rate] + fmt = '%.2f\t%.6g' + header = '%s interaction rates\nphoton field: %s\nlog10(E/eV), 1/lambda [1/Mpc]' % (name, field.info) + np.savetxt(fname, data, fmt=fmt, header=header) + + # ------------------------------------------- + # calculate cumulative differential interaction rates for sampling s values + # ------------------------------------------- + # find minimum value of s_kin + skin1 = getSmin(sigma) # s threshold for interaction + skin2 = 4 * field.getEmin() * E[0] # minimum achievable s in collision with background photon (at any tabulated E) + skin_min = max(skin1, skin2) + + # tabulated values of s_kin = s - mc^2, limit to relevant range + # Note: use higher resolution and then downsample + skin = np.logspace(6.2, 23, 1680 + 1) * eV**2 + skin = skin[skin > skin_min] + + xs = getTabulatedXS(sigma, skin) + rate = calc_rate_s(skin, xs, E, field, cdf=True) + + # downsample + skin_save = np.logspace(6.2, 23, 168 + 1) * eV**2 + skin_save = skin_save[skin_save > skin_min] + rate_save = np.array([np.interp(skin_save, skin, r) for r in rate]) + + # save + data = np.c_[np.log10(E / eV), rate_save] # prepend log10(E/eV) as first column + row0 = np.r_[0, np.log10(skin_save / eV**2)][np.newaxis] + data = np.r_[row0, data] # prepend log10(s_kin/eV^2) as first row + + fname = folder + '/cdf_%s.txt' % field.name + fmt = '%.2f' + '\t%.6g' * np.shape(rate_save)[1] + header = '%s cumulative differential rate\nphoton field: %s\nlog10(E/eV), d(1/lambda)/ds_kin [1/Mpc/eV^2] for log10(s_kin/eV^2) as given in first row' % (name, field.info) + np.savetxt(fname, data, fmt=fmt, header=header) + + for field in fields: + + process(sigmaPP, field, "EMPairProduction") + process(sigmaPP, field, "EMDoublePairProduction") + process(sigmaPP, field, "EMTripletPairProduction") + process(sigmaPP, field, "EMInverseComptonScattering") + + def calc_pairproduction(fields, writeFilesTo): + """ + Calculate the energy loss rate through electron pair production + References: + (B70) Blumenthal 1970, Phys.Rev. D + (C92) Chodorowski et al. 1992, ApJ 400:181-185 + """ + + Mpc = 3.08567758e22 # [m] + r0 = 2.817940e-15 # classical electron radius [m] + alpha = 7.297352e-3 # fine-structure constant + me = 9.10938291e-31 # electron mass [kg] + me_c2 = me * c0**2 # electron mass in [J/c^2] + mp = 1.67262178e-27 # proton mass [kg] + + + def lossRate(gamma, field, z=0): + """ + Loss rate from electron pair production with the photon field defined in given photon background, cf. C92, equation 3.11 + gamma : list of nucleus Lorentz factors + field : photon background + z : redshift + Returns : 1/gamma dgamma/dx [1/Mpc] + """ + + def phi(k): + """ + Parametrization of the integral 3.12 (C92) + """ + _c = np.array([0.8048, 0.1459, 1.137e-3, -3.879e-6]) + _d = np.array([-86.07, 50.96, -14.45, 8 / 3.]) + _f = np.array([2.910, 78.35, 1837]) + # phi(k) for k < 25, eq. 3.14 + if k < 25: + return np.pi / 12 * (k - 2)**4 / (1 + sum(_c * (k - 2)**np.arange(1, 5))) + # phi(k) for k > 25, eq. 3.18 and 3.16 + return k * sum(_d * np.log(k)**np.arange(4)) / (1 - sum(_f * k**-np.arange(1, 4))) + + def integrand(logk, gamma, field): + """ + Integrand of equation 3.11 (C92), logarithmic version + logk : ln(k) = ln(2 gamma eps / (me c^2)), photon energy + gamma : nucleus Lorentz factor + field : photon background + """ + k = np.exp(logk) + eps = k * me_c2 / 2 / gamma # photon energy [J] in lab frame + n = field.getDensity(eps, z) # spectral number density [1/m^3/J] + n *= me_c2 # from substitution d eps / d k + return n * phi(k) / k # includes *k from substitution k -> ln(k) + + rate = np.zeros_like(gamma) + err = np.zeros_like(gamma) + # minimum and maximum energy of the fields photons in units of me*c^2 + epsmin = field.getEmin() / me_c2 + epsmax = field.getEmax() / me_c2 + + for i, g in enumerate(gamma): + lkmin = np.log(max(2, 2 * g * epsmin)) + lkmax = np.log(2 * g * epsmax) + lksep = np.linspace(lkmin, lkmax, 11)[1:-1] + rate[i], err[i] = integrate.quad( + integrand, lkmin, lkmax, points=lksep, args=(g, field)) + + # prefactor of equation 3.11 (C92) and conversion [1/s] --> [1/Mpc] + a = alpha * r0**2 * me / mp * Mpc + return a * rate / gamma, a * err / gamma + + # ------------------------------------------------- + # Generate tables for energy loss rate + # ------------------------------------------------- + gamma = np.logspace(6, 14, 161) # tabulated Lorentz factors + + folder = writeFilesTo + 'ElectronPairProduction' + if not os.path.exists(folder): + os.makedirs(folder) + + for field in fields: + + rate = lossRate(gamma, field)[0] + s = (rate > 1e-12) # truncate if loss rate is < 10^-12 / Mpc + + fname = folder + '/lossrate_%s.txt' % field.name + data = np.c_[np.log10(gamma[s]), rate[s]] + fmt = '%.2f\t%.6e' + header = 'Loss rate for electron-pair production with the photon field defined in %s\nlog10(gamma)\t1/gamma dgamma/dx [1/Mpc]' % field.info + np.savetxt(fname, data, fmt=fmt, header=header) + + + def calc_photodisintigration(fields, writeFilesTo): + + gamma = np.logspace(6, 14, 201) # tabulated UHECR Lorentz-factors + + # ---------------------------------------------------- + # Load cross sections for A < 12 + # ---------------------------------------------------- + ddir1 = 'tables/PD_external/' + isotopes1 = np.genfromtxt(ddir1 + 'isotopes.txt') + eps = np.genfromtxt(ddir1 + 'eps.txt') + d1sum = np.genfromtxt(ddir1 + 'xs_sum.txt', dtype=[('Z', int), ('N', int), ('xs', '%if8' % len(eps))]) + d1exc = np.genfromtxt(ddir1 + 'xs_excl.txt', dtype=[('Z', int), ('N', int), ('ch', int), ('xs', '%if8' % len(eps))]) + # Pad cross sections to next larger 2^n + 1 tabulation points for Romberg integration and convert to SI units + eps1 = romb_pad_logspaced(eps, 513) * eV * 1e6 + xs1sum = np.array([romb_pad_zero(x, 513) for x in d1sum['xs']]) * 1e-31 + xs1exc = np.array([romb_pad_zero(x, 513) for x in d1exc['xs']]) * 1e-31 + + # ---------------------------------------------------- + # Load cross sections for A >= 12 (TALYS) + # ---------------------------------------------------- + ddir2 = 'tables/PD_Talys1.8_Khan/' + isotopes2 = np.genfromtxt(ddir2 + 'isotopes.txt') + eps = np.genfromtxt(ddir2 + 'eps.txt') + d2sum = np.genfromtxt(ddir2 + 'xs_pd_sum.txt', dtype=[('Z', int), ('N', int), ('xs', '%if8' % len(eps))]) + d2exc = np.genfromtxt(ddir2 + 'xs_pd_thin.txt', dtype=[('Z', int), ('N', int), ('ch', int), ('xs', '%if8' % len(eps))]) + # Only consider cross sections for A > 12 + d2sum = d2sum[(d2sum['Z'] + d2sum['N']) >= 12] + d2exc = d2exc[(d2exc['Z'] + d2exc['N']) >= 12] + # Pad cross sections to next larger 2^n + 1 tabulation points for Romberg integration and convert to SI units + eps2 = romb_pad_logspaced(eps, 513) * eV * 1e6 + xs2sum = np.array([romb_pad_zero(x, 513) for x in d2sum['xs']]) * 1e-31 + xs2exc = np.array([romb_pad_zero(x, 513) for x in d2exc['xs']]) * 1e-31 + + # ---------------------------------------------------- + # Load cross sections with photon emission + # ---------------------------------------------------- + d3sum = np.genfromtxt(ddir2 + 'xs_photon_sum.txt', dtype=[('Z', int), ('N', int), ('Zd', int), ('Nd', int), ('xs', '%if8' % len(eps))]) + d3exc = np.genfromtxt(ddir2 + 'xs_photon_thin.txt', dtype=[('Z', int), ('N', int), ('Zd', int), ('Nd', int), ('Ephoton', float), ('xs', '%if8' % len(eps))]) + # Pad cross sections to next larger 2^n + 1 tabulation points for Romberg integration and convert to SI units + eps3 = eps2 + xs3sum = np.array([romb_pad_zero(x, 513) for x in d3sum['xs']]) * 1e-31 + xs3exc = np.array([romb_pad_zero(x, 513) for x in d3exc['xs']]) * 1e-31 + + + def calc_interaction_rates_and_branching_ratios(fields): + + for field in fields: + + # output folder + folder = writeFilesTo + 'Photodisintegration' + if not os.path.exists(folder): + os.makedirs(folder) + + # Calculate total interaction rates + R1 = np.array([calc_rate_eps(eps1, x, gamma, field) for x in xs1sum]) + R2 = np.array([calc_rate_eps(eps2, x, gamma, field) for x in xs2sum]) + + np.savetxt( + folder + '/rate_%s.txt' % field.name, + np.r_[np.c_[d1sum['Z'], d1sum['N'], R1], np.c_[d2sum['Z'], d2sum['N'], R2]], + fmt='%i\t%i' + '\t%g' * 201, + header='Photodisintegration by the %s\nZ, N, 1/lambda [1/Mpc] for log10(gamma) = 6-14 in 201 steps' % field.info) + + # Calculate branching ratios from exclusive interaction rates + B1 = np.array([calc_rate_eps(eps1, x, gamma, field) for x in xs1exc]) + B2 = np.array([calc_rate_eps(eps2, x, gamma, field) for x in xs2exc]) + for (Z, N, A) in isotopes1: + s = (d1exc['Z'] == Z) * (d1exc['N'] == N) + B1[s] /= sum(B1[s]) + for (Z, N, A) in isotopes2: + s = (d2exc['Z'] == Z) * (d2exc['N'] == N) + B2[s] /= sum(B2[s]) + B1 = np.nan_to_num(B1) # set to 0 when total cross section is 0 + B2 = np.nan_to_num(B2) + + np.savetxt( + folder + '/branching_%s.txt' % field.name, + np.r_[np.c_[d1exc['Z'], d1exc['N'], d1exc['ch'], B1], np.c_[d2exc['Z'], d2exc['N'], d2exc['ch'], B2]], + fmt='%i\t%i\t%06d' + '\t%g' * 201, + header='Photo-disintegration with the photon field defined in %s\nZ, N, channel, branching ratio for log10(gamma) = 6-14 in 201 steps' % field.info) + + + def calc_photon_emmission_probablilities(fields): + + for field in fields: + + ncores = cpu_count() + with Parallel(ncores, verbose=10) as pool: + + R3 = list( + pool( + delayed(calc_rate_eps)(eps3, x, gamma, field) for x in xs3sum + ) + ) + with Parallel(ncores, verbose=10) as pool: + + B3 = list( + pool( + delayed(calc_rate_eps)(eps3, x, gamma, field) for x in xs3exc + ) + ) + R3 = np.array(R3) + B3 = np.array(B3) + + for i in range(len(d3sum)): + s = (d3exc['Z'] == d3sum['Z'][i]) * (d3exc['N'] == d3sum['N'][i]) * (d3exc['Zd'] == d3sum['Zd'][i]) * (d3exc['Nd'] == d3sum['Nd'][i]) + B3[s] /= R3[i] + B3 = np.nan_to_num(B3) + + np.savetxt( + (writeFilesTo + 'Photodisintegration/photon_emission_%s.txt') % field.name.split('_')[0], + np.c_[d3exc['Z'], d3exc['N'], d3exc['Zd'], d3exc['Nd'], d3exc['Ephoton'] * 1e6, B3], + fmt='%i\t%i\t%i\t%i\t%g' + '\t%g' * 201, + header='Emission probabilities of photons with discrete energies via photo-disintegration with the photon field defined in %s\nZ, N, Z_daughter, N_daughter, Ephoton [eV], emission probability for log10(gamma) = 6-14 in 201 steps' % field.info) + + Process(target=calc_interaction_rates_and_branching_ratios, args=([fields])).start() + Process(target=calc_photon_emmission_probablilities, args=([fields])).start() + + + def calc_photopionproduction(fields, writeFilesTo): + lgamma = np.linspace(6, 16, 251) # tabulated Lorentz factors + gamma = 10**lgamma + + # ---------------------------------------------------- + # Load proton / neutron cross sections [1/m^2] for tabulated energies [J] + # truncate to largest length 2^i + 1 for Romberg integration + # ---------------------------------------------------- + d = np.genfromtxt('tables/PPP/xs_proton.txt', unpack=True) + eps1 = d[0, :2049] * 1e9 * eV # [J] + xs1 = d[1, :2049] * 1e-34 # [m^2] + + d = np.genfromtxt('tables/PPP/xs_neutron.txt', unpack=True) + eps2 = d[0, :2049] * 1e9 * eV # [J] + xs2 = d[1, :2049] * 1e-34 # [m^2] + + for field in fields: + + # output folder + folder = writeFilesTo + 'PhotoPionProduction' + if not os.path.exists(folder): + os.makedirs(folder) + + # ---------------------------------------------------- + # calculate interaction rates at z=0, default option + # ---------------------------------------------------- + with Parallel(2, verbose=0) as pool: + + r = list( + pool( + delayed(calc_rate_eps)(e, x, gamma, field) for e,x in [(eps1,xs1),(eps2,xs2)] + ) + ) + + r1 = r[0] + r2 = r[1] + + fname = folder + '/rate_%s.txt' % field.name + data = np.c_[lgamma, r1, r2] + # fmt = '%.2f\t%.6e\t%.6e' + # header = ("Photo-pion interaction rate with the photon field defined in %s\nlog10(gamma)" + # "\t1/lambda_proton [1/Mpc]\t1/lambda_neutron [1/Mpc]" % field.info) + # np.savetxt(fname, data, fmt=fmt, header=header) + + # ---------------------------------------------------- + # calculate redshift dependent interaction rates + # ---------------------------------------------------- + redshifts = field.redshift + if redshifts is None: + continue # skip CMB + if len(redshifts) > 100: + redshifts = redshifts[::10] # thin out long redshift lists (Finke10) + + data = [] + for z in redshifts: + r1 = calc_rate_eps(eps1, xs1, gamma, field, z) + r2 = calc_rate_eps(eps2, xs2, gamma, field, z) + data.append(np.c_[[z] * len(lgamma), lgamma, r1, r2]) + + data = np.concatenate([d for d in data], axis=0) + np.nan_to_num(data) + fname = folder + '/rate_%s.txt' % field.name + fmt = '%.2f\t%.2f\t%.6e\t%.6e' + header = ("Photo-pion interaction rate for the %s\n (redshift dependent)" + "z\tlog10(gamma)\t1/lambda_proton [1/Mpc]\t1/lambda_neutron [1/Mpc]" % field.info) + np.savetxt(fname, data, fmt=fmt, header=header) + + +def generatePhotonFieldFiles(fromFile, photonFieldName, writeFilesTo): + """ launch calculation methods """ + if photonFieldName not in ["PF1","PF2","PF3","PF4","PF5","PF6","PF7","PF8"]: + sys.exit("Error: argument photonFieldName must be either PF1, PF2, ..., PF8 \n but is {}".format(photonFieldName)) + + fields = [photonField(fromFile, photonFieldName)] + if not os.path.exists(writeFilesTo): + os.makedirs(writeFilesTo) + + for name, method in Interactions.__dict__.items(): + if callable(method): + Process(target=method, args=(fields, writeFilesTo)).start() + + +if __name__ == "__main__": + + arguments = docopt(__doc__, version='01/19') + + generatePhotonFieldFiles(fromFile=arguments[""], + photonFieldName=os.path.basename(arguments[""])[:-4], + writeFilesTo=arguments[""] ) From ca11bf05003c69f72a3a9edbb7b0d9426dbff8e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Fri, 11 Jan 2019 00:05:04 +0100 Subject: [PATCH 37/81] add example picture of photon field for the Wiki page. May be but elsewhere later. --- helperFiles/photonField_example.png | Bin 0 -> 43060 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 helperFiles/photonField_example.png diff --git a/helperFiles/photonField_example.png b/helperFiles/photonField_example.png new file mode 100644 index 0000000000000000000000000000000000000000..90bb4a0687cddb29e4f13a7b42c3bdecb3a33526 GIT binary patch literal 43060 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

!EKW08JZqEED*ebicClfMjg1v_ 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 OpRA;kM1`2)`~L^aGz4n^ literal 0 HcmV?d00001 From 5fddeeecafd965cb675aae3ca5b80ca47e22e521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Fri, 11 Jan 2019 00:10:37 +0100 Subject: [PATCH 38/81] improve learning effect of example photon field --- helperFiles/photonField_example.png | Bin 43060 -> 45536 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/helperFiles/photonField_example.png b/helperFiles/photonField_example.png index 90bb4a0687cddb29e4f13a7b42c3bdecb3a33526..8c2af12c4ef54da2d6ec60ef1ae332d5f95a4dfd 100644 GIT binary patch literal 45536 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 literal 43060 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

!EKW08JZqEED*ebicClfMjg1v_ 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 OpRA;kM1`2)`~L^aGz4n^ From a1659719e937434bd43dc821ac22c9841ffabd9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Fri, 11 Jan 2019 02:46:11 +0100 Subject: [PATCH 39/81] fix typo --- helperFiles/photonField_example.png | Bin 45536 -> 45475 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/helperFiles/photonField_example.png b/helperFiles/photonField_example.png index 8c2af12c4ef54da2d6ec60ef1ae332d5f95a4dfd..c02fd0f8bf14be68d34e627dad7498a2d52b2026 100644 GIT binary patch literal 45475 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 From 2efa62451c55dbfabcd2cc229a8d6cb4600dd883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Wed, 6 Mar 2019 15:05:20 +0000 Subject: [PATCH 40/81] add photon field test --- test/testPhotonField.cpp | 112 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 test/testPhotonField.cpp diff --git a/test/testPhotonField.cpp b/test/testPhotonField.cpp new file mode 100644 index 000000000..9e05845da --- /dev/null +++ b/test/testPhotonField.cpp @@ -0,0 +1,112 @@ +#include "crpropa/PhotonBackground.h" +#include "crpropa/Candidate.h" +#include "crpropa/Units.h" +#include "crpropa/Common.h" + +#include + +#include "gtest/gtest.h" + +#include + +namespace crpropa { + +TEST(PhotonField, initNativeFields) { + // test if native field files can be found and initialized + std::string nativeFieldNames[10] = {"CMB", + "IRB_Kneiske04", + "IRB_Stecker05", + "IRB_Finke10", + "IRB_Dominguez11", + "IRB_Franceschini08", + "IRB_Gilmore12", + "IRB_Stecker16_lower", + "IRB_Stecker16_upper", + "URB_Protheroe96"}; + for (int i = 0; i < 10; ++i) { + std::string fieldLoc = "Scaling/" + std::string(nativeFieldNames[i]) + ".txt"; + CustomPhotonField cpf = CustomPhotonField(getDataPath(fieldLoc)); + } +} + +TEST(PhotonField, nativeFieldFilesFormat) { + // test if native field files have the correct format + std::string nativeFieldNames[10] = {"CMB", + "IRB_Kneiske04", + "IRB_Stecker05", + "IRB_Finke10", + "IRB_Dominguez11", + "IRB_Franceschini08", + "IRB_Gilmore12", + "IRB_Stecker16_lower", + "IRB_Stecker16_upper", + "URB_Protheroe96"}; + for (int i = 0; i < 10; ++i) { + std::string fieldLoc = "Scaling/" + std::string(nativeFieldNames[i]) + ".txt"; + CustomPhotonField cpf = CustomPhotonField(getDataPath(fieldLoc)); + EXPECT_GT(cpf.photonEnergy.size(), 0); + EXPECT_GT(cpf.photonRedshift.size(), 0); + EXPECT_GT(cpf.photonDensity.size(), 0); + EXPECT_EQ(cpf.photonEnergy.size() * cpf.photonRedshift.size(), cpf.photonDensity.size()); + } +} + + +TEST(PhotonField, customFieldFilesFormat) { + // test if custom field files can be initialized correctly (if any) + // assume that field slot is unused if initialization fails + std::string customFieldNames[8] = {"PF1", "PF2", "PF3", "PF4", + "PF5", "PF6", "PF7", "PF8"}; + for (int i = 0; i < 8; ++i) { + std::string fieldLoc = "Scaling/" + std::string(customFieldNames[i]) + ".txt"; + try + { + CustomPhotonField cpf = CustomPhotonField(getDataPath(fieldLoc)); + EXPECT_GT(cpf.photonEnergy.size(), 0); + EXPECT_GT(cpf.photonRedshift.size(), 0); + EXPECT_GT(cpf.photonDensity.size(), 0); + EXPECT_EQ(cpf.photonEnergy.size() * cpf.photonRedshift.size(), cpf.photonDensity.size()); + } + catch (std::runtime_error &e) + { + continue; // assume that field slot is unused if initialization fails + } + } +} + +TEST(PhotonField, customFieldFilesEntries) { + // test if custom field files comply with the required format + // assume that field slot is unused if initialization fails + std::string customFieldNames[8] = {"PF1", "PF2", "PF3", "PF4", + "PF5", "PF6", "PF7", "PF8"}; + for (int i = 0; i < 8; ++i) { + std::string fieldLoc = "Scaling/" + std::string(customFieldNames[i]) + ".txt"; + try + { + CustomPhotonField cpf = CustomPhotonField(getDataPath(fieldLoc)); + // test if photon energies are in ascending order + for (int i = 1; i < cpf.photonEnergy.size(); ++i) { + EXPECT_LT(cpf.photonEnergy[i-1], cpf.photonEnergy[i]); + } + // test if photon redshifts are in ascending order + for (int i = 1; i < cpf.photonRedshift.size(); ++i) { + EXPECT_LT(cpf.photonRedshift[i-1], cpf.photonRedshift[i]); + } + // test if photon densities are >= 0 + for (int i = 0; i < cpf.photonDensity.size(); ++i) { + EXPECT_GE(cpf.photonDensity[i], 0.); + } + } + catch (std::runtime_error &e) + { + continue; // assume that field slot is unused if initialization fails + } + } +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + +} // namespace crpropa From d9867d228f302cbd97cc62bd8bc0eaffe4fe9669 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Wed, 6 Mar 2019 15:05:34 +0000 Subject: [PATCH 41/81] update CMakeLists with photon field test and boris push --- CMakeLists.txt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cce4b9a2e..ab3918c76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -298,11 +298,13 @@ OPTION(DOWNLOAD_DATA "Download CRProap Data files" ON) if(DOWNLOAD_DATA) message("-- Downloading data file from crpropa.desy.de ~ 50 MB") file(DOWNLOAD - https://www.desy.de/~crpropa/data/interaction_data/data.tar.gz-CHECKSUM +# https://www.desy.de/~crpropa/data/interaction_data/data.tar.gz-CHECKSUM + https://github.com/Froehliche-Kernschmelze/CRPropa3-data/raw/implement_custom_photon_field/data.tar.gz-CHECKSUM ${CMAKE_BINARY_DIR}/data.tar.gz-CHECKSUM) file(STRINGS ${CMAKE_BINARY_DIR}/data.tar.gz-CHECKSUM DATA_CHECKSUM LIMIT_COUNT 1 LENGTH_MINIMUM 32 LENGTH_MAXIMUM 32) file(DOWNLOAD - https://www.desy.de/~crpropa/data/interaction_data/data.tar.gz +# https://www.desy.de/~crpropa/data/interaction_data/data.tar.gz + https://github.com/Froehliche-Kernschmelze/CRPropa3-data/raw/implement_custom_photon_field/data.tar.gz ${CMAKE_BINARY_DIR}/data.tar.gz EXPECTED_MD5 "${DATA_CHECKSUM}") message("-- Extracting data file") @@ -363,7 +365,8 @@ add_library(crpropa SHARED src/module/PhotonEleCa.cpp src/module/PhotonOutput1D.cpp src/module/PropagationCK.cpp - src/module/Redshift.cpp + src/module/PropagationBP.cpp + src/module/Redshift.cpp src/module/RestrictToRegion.cpp src/module/SimplePropagation.cpp src/module/SynchrotronRadiation.cpp @@ -498,6 +501,10 @@ if(ENABLE_TESTING) target_link_libraries(testAdvectionField crpropa gtest gtest_main pthread ${COVERAGE_LIBS}) add_test(testAdvectionField testAdvectionField) + add_executable(testPhotonField test/testPhotonField.cpp) + target_link_libraries(testPhotonField crpropa gtest gtest_main pthread ${COVERAGE_LIBS}) + add_test(testPhotonField testPhotonField) + add_executable(testDensity test/testDensity.cpp) target_link_libraries(testDensity crpropa gtest gtest_main pthread ${COVERAGE_LIBS}) add_test(testDensity testDensity) From 3579cf286ffdec730c36d5b40582ffe050280012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Wed, 6 Mar 2019 15:23:54 +0000 Subject: [PATCH 42/81] update photon background --- include/crpropa/PhotonBackground.h | 76 ++-- src/PhotonBackground.cpp | 673 +++++++++++++---------------- 2 files changed, 336 insertions(+), 413 deletions(-) diff --git a/include/crpropa/PhotonBackground.h b/include/crpropa/PhotonBackground.h index 457a08b29..4896d0f4f 100644 --- a/include/crpropa/PhotonBackground.h +++ b/include/crpropa/PhotonBackground.h @@ -4,14 +4,6 @@ #include #include -#include // cout, endl -#include // sqrt, pow -#include -#include // write to file -#include // max_element -#include // for ::max -#include - namespace crpropa { /** @@ -43,32 +35,54 @@ double photonFieldScaling(PhotonField photonField, double z); // Returns a string representation of the field std::string photonFieldName(PhotonField photonField); +/** + @class CustomPhotonField + @brief Handler class for photon fields. Provides the sampleEps method. + + sampleEps draws a photon from a given photon background. This method + and all methods it depends on have been inspired by the SOPHIA code. + */ +class CustomPhotonField { +public: + /** Constructor for photon field data + @param fieldPath path/to/photonField.txt + */ + explicit CustomPhotonField(std::string fieldPath); + + /* Empty constructor to ease initialization in some modules + */ + CustomPhotonField(); + + /** Draws a photon from the photon background + @param onProton true=proton, false=neutron + @param Ein energy of primary + @param zIn redshift of primary + */ + double sampleEps(bool onProton, double Ein, double zIn) const; -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// custom photon field methods -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + /** Returns the photon field density in 1/(Jm³). + Multiply by h*nu for physical photon density. + @param eps photon energy in eV + @param zIn redshift + */ + double getPhotonDensity(double eps, double z) const; -class Photon_Field { - public: - explicit Photon_Field(std::string fieldPath); - Photon_Field(); - double sample_eps(bool onProton, double E_in, double z_in) const; + /** Returns the crossection of p-gamma interaction + @param eps photon energy + @param onProton true=proton, false=neutron + */ + double SOPHIA_crossection(double eps, bool onProton) const; - private: - void init(std::string fieldPath); - std::vector energy; - std::vector< std::vector > dn_deps; - std::vector redshift; - double get_photonDensity(double eps, int z_pos) const; - double gaussInt(std::string type, double lowerLimit, double upperLimit, bool onProton, double E_in, int z_pos) const; - double functs(double s, bool onProton) const; - double prob_eps(double eps, bool onProton, double E_in, int z_pos) const; - double crossection(double eps, bool onProton) const; - double Pl(double, double, double, double) const; - double Ef(double, double, double) const; - double breitwigner(double, double, double, double, bool onProton) const; - double singleback(double) const; - double twoback(double) const; + std::vector photonEnergy; + std::vector photonRedshift; + std::vector photonDensity; +protected: + void init(std::string fieldPath); + double SOPHIA_probEps(double eps, bool onProton, double Ein, double zIn) const; + double SOPHIA_pl(double x, double xth, double xmax, double alpha) const; + double SOPHIA_ef(double x, double th, double w) const; + double SOPHIA_breitwigner(double sigma_0, double Gamma, double DMM, double epsPrime, bool onProton) const; + double SOPHIA_functs(double s, bool onProton) const; }; /** @}*/ diff --git a/src/PhotonBackground.cpp b/src/PhotonBackground.cpp index f0fed2202..5689c75d7 100644 --- a/src/PhotonBackground.cpp +++ b/src/PhotonBackground.cpp @@ -66,419 +66,328 @@ static PhotonFieldScaling scalingStecker16_upper("IRB_Stecker16_upper"); static PhotonFieldScaling scalingStecker16_lower("IRB_Stecker16_lower"); double photonFieldScaling(PhotonField photonField, double z) { - switch (photonField) { - case CMB: // constant comoving photon number density - case PF1: case PF2: case PF3: case PF4: - case PF5: case PF6: case PF7: case PF8: - return 1; - case IRB: - case IRB_Kneiske04: - return scalingKneiske04.scalingFactor(z); - case IRB_Stecker05: - return scalingStecker05.scalingFactor(z); - case IRB_Franceschini08: - return scalingFranceschini08.scalingFactor(z); - case IRB_Finke10: - return scalingFinke10.scalingFactor(z); - case IRB_Dominguez11: - return scalingDominguez11.scalingFactor(z); - case IRB_Gilmore12: - return scalingGilmore12.scalingFactor(z); - case IRB_Stecker16_upper: - return scalingStecker16_upper.scalingFactor(z); - case IRB_Stecker16_lower: - return scalingStecker16_lower.scalingFactor(z); - case URB_Protheroe96: - if (z < 0.8) { return 1; } - if (z < 6) { return pow((1 + 0.8) / (1 + z), 4); } - else { return 0; } - default: - throw std::runtime_error("PhotonField: unknown photon background"); - } + switch (photonField) { + case CMB: // constant comoving photon number density + case PF1: case PF2: case PF3: case PF4: + case PF5: case PF6: case PF7: case PF8: + return 1; + case IRB: + case IRB_Kneiske04: + return scalingKneiske04.scalingFactor(z); + case IRB_Stecker05: + return scalingStecker05.scalingFactor(z); + case IRB_Franceschini08: + return scalingFranceschini08.scalingFactor(z); + case IRB_Finke10: + return scalingFinke10.scalingFactor(z); + case IRB_Dominguez11: + return scalingDominguez11.scalingFactor(z); + case IRB_Gilmore12: + return scalingGilmore12.scalingFactor(z); + case IRB_Stecker16_upper: + return scalingStecker16_upper.scalingFactor(z); + case IRB_Stecker16_lower: + return scalingStecker16_lower.scalingFactor(z); + case URB_Protheroe96: + if (z < 0.8) { return 1; } + if (z < 6) { return pow((1 + 0.8) / (1 + z), 4); } + else { return 0; } + default: + throw std::runtime_error("PhotonField: unknown photon background"); + } } std::string photonFieldName(PhotonField photonField) { - switch (photonField) { - case CMB: return "CMB"; - case PF1: return "PF1"; - case PF2: return "PF2"; - case PF3: return "PF3"; - case PF4: return "PF4"; - case PF5: return "PF5"; - case PF6: return "PF6"; - case PF7: return "PF7"; - case PF8: return "PF8"; - case IRB: - case IRB_Kneiske04: return "IRB_Kneiske04"; - case IRB_Stecker05: return "IRB_Stecker05"; - case IRB_Franceschini08: return "IRB_Franceschini08"; - case IRB_Finke10: return "IRB_Finke10"; - case IRB_Dominguez11: return "IRB_Dominguez11"; - case IRB_Gilmore12: return "IRB_Gilmore12"; - case IRB_Stecker16_upper: return "IRB_Stecker16_upper"; - case IRB_Stecker16_lower: return "IRB_Stecker16_lower"; - case URB_Protheroe96: return "URB_Protheroe96"; - default: - throw std::runtime_error("PhotonField: unknown photon background"); - } + switch (photonField) { + case CMB: return "CMB"; + case PF1: return "PF1"; + case PF2: return "PF2"; + case PF3: return "PF3"; + case PF4: return "PF4"; + case PF5: return "PF5"; + case PF6: return "PF6"; + case PF7: return "PF7"; + case PF8: return "PF8"; + case IRB: + case IRB_Kneiske04: return "IRB_Kneiske04"; + case IRB_Stecker05: return "IRB_Stecker05"; + case IRB_Franceschini08: return "IRB_Franceschini08"; + case IRB_Finke10: return "IRB_Finke10"; + case IRB_Dominguez11: return "IRB_Dominguez11"; + case IRB_Gilmore12: return "IRB_Gilmore12"; + case IRB_Stecker16_upper: return "IRB_Stecker16_upper"; + case IRB_Stecker16_lower: return "IRB_Stecker16_lower"; + case URB_Protheroe96: return "URB_Protheroe96"; + default: + throw std::runtime_error("PhotonField: unknown photon background"); + } } - -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// custom photon field methods related to SAMPLING -// These methods are taken from SOPHIA. -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - -Photon_Field::Photon_Field(std::string fieldPath) { - // constructor - init(fieldPath); +CustomPhotonField::CustomPhotonField(std::string fieldPath) { + init(fieldPath); } - -Photon_Field::Photon_Field() { - // constructor 2 +CustomPhotonField::CustomPhotonField() { + // empty constructor for initialization in some modules } +void CustomPhotonField::init(std::string filename) { + std::vector< std::vector > dndeps; + std::ifstream infile(filename.c_str()); + if (!infile.good()) + throw std::runtime_error("PhotoPionProduction @ CustomPhotonField::init : could not open file " + filename); + std::string line; + int i = 0; + while (std::getline(infile, line)) { + if (line.at(0) == '#') + continue; + std::istringstream ss(line); + std::vector vec; + double n; + while (ss >> n) + vec.push_back(n); + if (i == 0) { + photonEnergy = vec; + i++; + continue; + } + if (i == 1) { + photonRedshift = vec; + i++; + continue; + } + dndeps.push_back(vec); + } + for (int i = 0; i < photonEnergy.size(); ++i) { + for (int j = 0; j < photonRedshift.size(); ++j) { + photonDensity.push_back(dndeps[i][j]); + } + } + infile.close(); +} -double Photon_Field::sample_eps(bool onProton, double E_in, double z_in) const { +double CustomPhotonField::sampleEps(bool onProton, double Ein, double zIn) const { /* - - input: particle type 0=neutron, 1=proton, its energy [GeV], its redshift - - output: photon energy [eV] of random photon of photon field - - samples distribution of n(epsilon)/epsilon^2 -*/ - const double mass = onProton? 0.93827 : 0.93947; // Gev/c^2 - const double z_max = redshift[redshift.size()-1]; - if (z_in > z_max) { return 0.; } - double z_pos; - double smallestDiff = z_max; - for (int i = 0; i < redshift.size(); ++i) { - double diff = std::abs(z_in-redshift[i]); - if (diff < smallestDiff) { - smallestDiff = diff; - z_pos = i; - } - } - - const double epsMin = energy[0]; - const double epsMax = energy[energy.size()-1]; - double eps; - double p = std::sqrt(E_in*E_in-mass*mass); - double peps; - double cnorm = gaussInt("prob_eps", epsMin, epsMax, onProton, E_in, z_pos); - - // calculate pMax - double highest = 0.; - int closestPos; - for (int i = 0; i < energy.size(); ++i) { - if (dn_deps[i][z_pos] > highest) { - highest = dn_deps[i][z_pos]; - closestPos = i; - } - } - double eps_pMax = energy[closestPos]; - double pMax = prob_eps(eps_pMax, onProton, E_in, z_pos)/cnorm; - if ( (pMax < 0.01) || (pMax > 1.) ) { pMax = 1.; } - - // sample eps randomly between epsMin ... epsMax - Random &random = Random::instance(); - do { - eps = epsMin+random.rand()*(epsMax-epsMin); - peps = prob_eps(eps, onProton, E_in, z_pos)/cnorm; - } while (random.rand()*pMax > peps); - return eps; -} // end sample_eps - - -void Photon_Field::init(std::string filename) { - std::ifstream infile(filename.c_str()); - if (!infile.good()) { - throw std::runtime_error("PhotoPionProduction @ Photon_Field::init : could not open file " + filename); - } - std::string line; - int i = 0; - while ( std::getline(infile, line) ) { - if (line.find('#') == 0 ) continue; - std::istringstream ss(line); - std::vector vec; - double n; - while (ss >> n) vec.push_back(n); - if (i == 0) { energy = vec; i++; continue; } - if (i == 1) { redshift = vec; i++; continue; } - dn_deps.push_back(vec); - } - infile.close(); -} // end init - + - input: particle type with energy Ein at redshift z + - output: photon energy [eV] of random photon of photon field + - samples distribution of n(epsilon)/epsilon^2 +*/ + const double zMax = photonRedshift[photonRedshift.size() - 1]; + if (zIn > zMax) + return 0.; + + Ein /= GeV; // SOPHIA standard unit + // calculate pMax and its norm factor via maximum such that peps <= 1 + double cnorm = 0.; + double pMax = 0.; + for (int i = 0; i < photonEnergy.size(); ++i) { + double prob = SOPHIA_probEps(photonEnergy[i], onProton, Ein, zIn); + cnorm += prob; + if (prob > pMax) + pMax = prob; + } + pMax /= cnorm; + + // sample eps between epsMin ... epsMax + const double epsMin = photonEnergy[0]; + const double epsMax = photonEnergy[photonEnergy.size() - 1]; + double eps; + double peps; + Random &random = Random::instance(); + do { + eps = epsMin + random.rand() * (epsMax - epsMin); + peps = SOPHIA_probEps(eps, onProton, Ein, zIn) / cnorm; + } while (random.rand() * pMax > peps); + return eps; +} -double Photon_Field::prob_eps(double eps, bool onProton, double E_in, int z_pos) const { +double CustomPhotonField::SOPHIA_probEps(double eps, bool onProton, double Ein, double zIn) const { /* - - input: eps [eV] - - output: probability to encounter photon of energy eps - - called by: sample_eps, gaussInt + - input: eps [eV] + - output: probability to encounter photon of energy eps + - called by: sampleEps, gaussInt */ - const double mass = onProton? 0.93827 : 0.93947; // Gev/c^2 - double gamma = E_in/mass; - double beta = std::sqrt(1.-1./gamma/gamma); - double photonDensity = get_photonDensity(eps, z_pos); - if (photonDensity == 0.) { - return 0.; - } else { - double smin = 1.1646; // head-on collision - double smax = std::max(smin, mass*mass+2.*eps/1.e9*E_in*(1.+beta)); - double sintegr = gaussInt("functs", smin, smax, onProton, E_in, z_pos); - return photonDensity/eps/eps*sintegr/8./beta/E_in/E_in*1.e18*1.e6; - } -} // end prob_eps - + const double mass = onProton? 0.93827 : 0.93947; // Gev/c^2 + double gamma = Ein / mass; + double beta = std::sqrt(1. - 1. / gamma / gamma); + double photonDensity = getPhotonDensity(eps * eV, zIn) / 6.2415091e24; // 1/(Jm³) -> 1/(eVcm³) + if (photonDensity == 0.) { + return 0.; + } else { + double sMin = 1.1646; // head-on collision + double sMax = std::max(sMin, mass * mass + 2. * eps / 1.e9 * Ein * (1. + beta)); + static const double x[8] = {.0950125098, .2816035507, .4580167776, .6178762444, + .7554044083, .8656312023, .9445750230, .9894009349}; + static const double w[8] = {.1894506104, .1826034150, .1691565193, .1495959888, + .1246289712, .0951585116, .0622535239, .0271524594}; + double xm = 0.5 * (sMax + sMin); + double xr = 0.5 * (sMax - sMin); + double ss = 0.; + for (int i = 0; i < 8; ++i) { + double dx = xr * x[i]; + ss += w[i] * (SOPHIA_functs(xm + dx, onProton) + SOPHIA_functs(xm - dx, onProton)); + } + double sIntegral = xr * ss; + return photonDensity / eps / eps * sIntegral / 8. / beta / Ein / Ein * 1.e24; + } +} -double Photon_Field::get_photonDensity(double eps, int z_pos) const { +double CustomPhotonField::getPhotonDensity(double eps, double z) const { /* - - input: photon energy [eV], redshift - - output: dn_deps(e,z) [#/(eV cm^3)] from input file - - called by: sample_eps + - input: photon energy, redshift + - output: dndeps(e,z) [#/(eV cm^3)] from input file + - called by: sampleEps */ - // find closest dn_deps - double smallestDiff = energy[energy.size()-1]; - int closestPos; - for (int i = 0; i < energy.size(); ++i) { - double diff = std::abs(eps-energy[i]); - if (diff < smallestDiff) { - smallestDiff = diff; - closestPos = i; - } - } - // linear interpolation of energy - double realDiff = eps-energy[closestPos]; - double rho; - if (realDiff >= 0.) { - rho = realDiff / (energy[closestPos+1] - energy[closestPos]); - return (1.-rho)*dn_deps[closestPos][z_pos] - + rho*dn_deps[closestPos+1][z_pos]; - } else { - rho = 1. - (std::abs(realDiff)/energy[closestPos-1]); - return (1.-rho)*dn_deps[closestPos-1][z_pos] - + rho*dn_deps[closestPos][z_pos]; - } -} // end get_photonDensity - + return interpolate2d(eps / eV, z, photonEnergy, photonRedshift, photonDensity) * 6.2415091e24; // 1/(eVcm³)->1/(Jm³) +} -double Photon_Field::crossection(double x, bool onProton) const { +double CustomPhotonField::SOPHIA_crossection(double x, bool onProton) const { /* - - input: photon energy [eV], specifier: 0=neutron, 1=proton - - output: crossection of nucleon-photon-interaction [area] - - called by: functs + - input: photon energy [eV], specifier: 0=neutron, 1=proton + - output: SOPHIA_crossection of nucleon-photon-interaction [area] + - called by: SOPHIA_functs */ - const double mass = onProton? 0.93827 : 0.93947; // Gev/c^2 - double sth = 1.1646; - double s = mass*mass + 2.*mass*x; - if (s < sth) { return 0.; } - double cross_res = 0.; - double cross_dir = 0.; - double cross_dir1 = 0.; - double cross_dir2 = 0.; - double sig_res[9]; - - // upper: ppppppppp - // lower: nnnnnnnnn - const double AMRES[18] = { 1.231, 1.440, 1.515, 1.525, 1.675, 1.680, 1.690, 1.895, 1.950, - 1.231, 1.440, 1.515, 1.525, 1.675, 1.675, 1.690, 1.895, 1.950 }; - const double BGAMMA[18] = { 5.6, .5, 4.6, 2.5, 1., 2.1, 2., .2, 1., - 6.1, .3, 4., 2.5, 0.0, .2, 2., .2, 1.}; - const double WIDTH[18] = { .11, .35, .11, .1, .16, .125, .29, .35, .3, - .11, .35, .11, .1, .16, .15, .29, .35, .3}; - const double RATIOJ[18] = { 1., .5, 1., .5, .5, 1.5, 1., 1.5, 2., - 1., .5, 1., .5, .5, 1.5, 1., 1.5, 2.}; - const double AM2[2] = { 0.882792, 0.880351 }; - - // int idx = (onProton == 0)? 9:0; // neutron = 0, proton = 1 - int idx = onProton? 0:9; // neutron = 0, proton = 1 - double SIG0[9]; - for (int i = 0; i < 9; ++i) { - SIG0[i] = 4.893089117/AM2[int(onProton)]*RATIOJ[i+idx]*BGAMMA[i+idx]; - } - - if (x <= 10.) { - cross_res = breitwigner(SIG0[0], WIDTH[0+idx], AMRES[0+idx], x, onProton) - * Ef(x, 0.152, 0.17); - sig_res[0] = cross_res; - for (int i = 1; i < 9; ++i) { - sig_res[i] = breitwigner(SIG0[i], WIDTH[i+idx], AMRES[i+idx], x, onProton) - * Ef(x, 0.15, 0.38); - cross_res += sig_res[i]; - } - // direct channel - if ( (x > 0.1) && (x < 0.6) ) { - cross_dir1 = singleback(x) - + 40.*std::exp(-(x-0.29)*(x-0.29) / 0.002) - - 15.*std::exp(-(x-0.37)*(x-0.37) / 0.002); - } else { - cross_dir1 = singleback(x); - } - cross_dir2 = twoback(x); - cross_dir = cross_dir1 + cross_dir2; - } - // fragmentation 2: - double cross_frag2; - if (onProton) { - cross_frag2 = 80.3*Ef(x, 0.5, 0.1) * std::pow(s, -0.34); - } else { - cross_frag2 = 60.2*Ef(x, 0.5, 0.1) * std::pow(s, -0.34); - } - // multipion production/fragmentation 1 cross section - double cs_multidiff; - double cs_multi; - double cross_diffr1; - double cross_diffr2; - double cross_diffr; - if (x > 0.85) { - double ss1 = (x-0.85)/.69; - double ss2; - if (onProton) { - ss2 = 29.3*std::pow(s, -0.34) + 59.3*std::pow(s, 0.095); - } else { - ss2 = 26.4*std::pow(s, -0.34) + 59.3*std::pow(s, 0.095); - } - cs_multidiff = (1.-std::exp(-ss1))*ss2; - cs_multi = 0.89*cs_multidiff; - // diffractive scattering: - cross_diffr1 = .099*cs_multidiff; - cross_diffr2 = .011*cs_multidiff; - cross_diffr = .11*cs_multidiff; - // ************************************** - ss1 = std::pow((x-.85), .75)/.64; - ss2 = 74.1*std::pow(x, -0.44) + 62.*std::pow(s, 0.08); - double cs_tmp = 0.96*(1.-std::exp(-ss1))*ss2; - cross_diffr1 = 0.14*cs_tmp; - cross_diffr2 = 0.013*cs_tmp; - double cs_delta = cross_frag2 - - (cross_diffr1+cross_diffr2-cross_diffr); - if (cs_delta < 0.) { - cross_frag2 = 0.; - cs_multi += cs_delta; - } else { - cross_frag2 = cs_delta; - } - cross_diffr = cross_diffr1 + cross_diffr2; - cs_multidiff = cs_multi + cross_diffr; - // ***************************************** - } else { - cross_diffr = 0.; - cross_diffr1 = 0.; - cross_diffr2 = 0.; - cs_multidiff = 0.; - cs_multi = 0.; - } - // in the original SOPHIA code, this is a switch. - // Here, only one case (NDIR=3) is needed. - return cross_res+cross_dir+cs_multidiff+cross_frag2; -} // end crossection - - -double Photon_Field::Pl(double x, double xth, double xmax, double alpha) const { -/* - - input: photon energy [eV], unknown, unknown, unknown - - output: unknown. - - called by: crossection -*/ - if (xth > x) { return 0.; } - double a = alpha*xmax/xth; - double prod1 = std::pow((x-xth)/(xmax-xth), (a-alpha)); - double prod2 = std::pow(x/xmax, -a); - return prod1*prod2; -} // end Pl - + const double mass = onProton? 0.93827 : 0.93947; // Gev/c^2 + double sth = 1.1646; + double s = mass * mass + 2. * mass * x; + if (s < sth) + return 0.; + // upper: proton resonance masses [GeV] + // lower: neutron resonance masses [GeV] + static const double AMRES[18] = {1.231, 1.440, 1.515, 1.525, 1.675, 1.680, 1.690, 1.895, 1.950, + 1.231, 1.440, 1.515, 1.525, 1.675, 1.675, 1.690, 1.895, 1.950}; + static const double BGAMMA[18] = {5.6, 0.5, 4.6, 2.5, 1., 2.1, 2., 0.2, 1., + 6.1, 0.3, 4.0, 2.5, 0., 0.2, 2., 0.2, 1.}; + static const double WIDTH[18] = {0.11, 0.35, 0.11, 0.1, 0.16, 0.125, 0.29, 0.35, 0.3, + 0.11, 0.35, 0.11, 0.1, 0.16, 0.150, 0.29, 0.35, 0.3}; + static const double RATIOJ[18] = {1., 0.5, 1., 0.5, 0.5, 1.5, 1., 1.5, 2., + 1., 0.5, 1., 0.5, 0.5, 1.5, 1., 1.5, 2.}; + static const double AM2[2] = {0.882792, 0.880351}; + + int idx = onProton? 0 : 9; + double SIG0[9]; + for (int i = 0; i < 9; ++i) { + SIG0[i] = 4.893089117 / AM2[int(onProton)] * RATIOJ[i + idx] * BGAMMA[i + idx]; + } + double cross_dir = 0.; + double cross_res = 0.; + if (x <= 10.) { + cross_res = SOPHIA_breitwigner(SIG0[0], WIDTH[0 + idx], AMRES[0 + idx], x, onProton) + * SOPHIA_ef(x, 0.152, 0.17); + for (int i = 1; i < 9; ++i) { + cross_res = SOPHIA_breitwigner(SIG0[i], WIDTH[i + idx], AMRES[i + idx], x, onProton) + * SOPHIA_ef(x, 0.15, 0.38); + } + // direct channel + double cross_dir1 = 0.; + if ( (x > 0.1) && (x < 0.6) ) { + cross_dir1 = 92.7 * SOPHIA_pl(x, 0.152, 0.25, 2.) // single pion production + + 40.0 * std::exp(-(x - 0.29) * (x - 0.29) / 0.002) + - 15.0 * std::exp(-(x - 0.37) * (x - 0.37) / 0.002); + } else { + cross_dir1 = 92.7 * SOPHIA_pl(x, 0.152, 0.25, 2.); // single pion production + } + double cross_dir2 = 37.7 * SOPHIA_pl(x, 0.4, 0.6, 2.); // double pion production + cross_dir = cross_dir1 + cross_dir2; + } + // fragmentation 2: + double cross_frag2; + if (onProton) { + cross_frag2 = 80.3 * SOPHIA_ef(x, 0.5, 0.1) * std::pow(s, -0.34); + } else { + cross_frag2 = 60.2 * SOPHIA_ef(x, 0.5, 0.1) * std::pow(s, -0.34); + } + // multipion production/fragmentation 1 cross section + double cs_multidiff = 0.; + if (x > 0.85) { + double ss1 = (x - 0.85) / 0.69; + double ss2; + if (onProton) { + ss2 = 29.3 * std::pow(s, -0.34) + 59.3 * std::pow(s, 0.095); + } else { + ss2 = 26.4 * std::pow(s, -0.34) + 59.3 * std::pow(s, 0.095); + } + cs_multidiff = -expm1f(-ss1) * ss2; + // diffractive scattering: + double cross_diffr = 0.11 * cs_multidiff; + // ************************************** + ss1 = std::pow((x - 0.85), 0.75) / 0.64; + ss2 = 74.1 * std::pow(x, -0.44) + 62. * std::pow(s, 0.08); + double cs_tmp = 0.96 * -expm1(-ss1) * ss2; + double cross_diffr1 = 0.14 * cs_tmp; + double cross_diffr2 = 0.013 * cs_tmp; + double cs_delta = cross_frag2 + - (cross_diffr1+cross_diffr2-cross_diffr); + double cs_multi = 0.89 * cs_multidiff; + if (cs_delta < 0.) { + cross_frag2 = 0.; + cs_multi += cs_delta; + } else { + cross_frag2 = cs_delta; + } + cross_diffr = cross_diffr1 + cross_diffr2; + cs_multidiff = cs_multi + cross_diffr; + } + return (cross_res + cross_dir + cs_multidiff + cross_frag2) * 1.e-34; // µbarn to m² +} -double Photon_Field::Ef(double x, double th, double w) const { +double CustomPhotonField::SOPHIA_pl(double x, double xth, double xmax, double alpha) const { /* - - input: photon energy [eV], unknown, unknown - - output: unknown - - called by: crossection + - input: photon energy [eV], threshold [eV], max [eV], unknown [no unit] + - output: unknown [no unit] + - called by: SOPHIA_crossection */ - double wth = w+th; - if (x <= th) { - return 0.; - } else if ( (x > th) && (x < wth) ) { - return (x-th)/w; - } else if (x >= wth) { - return 1.; - } else { - throw std::runtime_error("error in function Ef"); - } -} // end Ef - + if (xth > x) + return 0.; + double a = alpha * xmax / xth; + double prod1 = std::pow((x - xth) / (xmax - xth), (a - alpha)); + double prod2 = std::pow(x / xmax, -a); + return prod1 * prod2; +} -double Photon_Field::breitwigner(double sigma_0, double Gamma, double DMM, double eps_prime, bool onProton) const { +double CustomPhotonField::SOPHIA_ef(double x, double th, double w) const { /* - - input: cross section [µbarn], width [GeV], mass [GeV/c^2] - - output: Breit-Wigner crossection of a resonance widh width Gamma - - called by: crossection + - input: photon energy [eV], threshold [eV], unknown [eV] + - output: unknown [no unit] + - called by: SOPHIA_crossection */ - const double mass = onProton? 0.93827 : 0.93947; // Gev/c^2 - double s = mass*mass + 2.*mass*eps_prime; - double gam2s = Gamma*Gamma*s; - return sigma_0 * (s/eps_prime/eps_prime)*gam2s - / ((s-DMM*DMM)*(s-DMM*DMM)+gam2s); -} // end breitwigner - - -double Photon_Field::singleback(double x) const { -/* - - single pion channel - - called by: crossection -*/ - return 92.7 * Pl(x, .152, .25, 2.); -} // end singleback - + double wth = w + th; + if (x <= th) { + return 0.; + } else if ((x > th) && (x < wth)) { + return (x - th) / w; + } else if (x >= wth) { + return 1.; + } else { + throw std::runtime_error("error in function PhotonBackground::SOPHIA_ef"); + } +} -double Photon_Field::twoback(double x) const { +double CustomPhotonField::SOPHIA_breitwigner(double sigma_0, double Gamma, double DMM, + double epsPrime, bool onProton) const { /* - - two pion production - - called by: crossection + - input: cross section [µbarn], width [GeV], mass [GeV/c^2] + - output: Breit-Wigner SOPHIA_crossection of a resonance widh width Gamma + - called by: SOPHIA_crossection */ - return 37.7 * Pl(x, .4, .6, 2.); -} // end twoback - + const double mass = onProton? 0.93827 : 0.93947; // Gev/c^2 + double s = mass * mass + 2. * mass * epsPrime; + double gam2s = Gamma * Gamma * s; + return sigma_0 * (s / epsPrime / epsPrime) * gam2s + / ((s - DMM*DMM) * (s - DMM * DMM) + gam2s); +} -double Photon_Field::functs(double s, bool onProton) const { +double CustomPhotonField::SOPHIA_functs(double s, bool onProton) const { /* - - input: s [GeV^2] - - output: (s-p^2)*sigma_(nucleon/gamma) [GeV^2*area] - - called by: sample_eps + - input: s [GeV^2] + - output: (s-p^2)*sigma_(nucleon/gamma) [GeV^2*area] + - called by: sampleEps */ - const double mass = onProton? 0.93827 : 0.93947; // Gev/c^2 - double factor = s - mass*mass; - double epsprime = factor/2./mass; - double sigma_pg = crossection(epsprime, onProton); - return factor*sigma_pg; -} // end functs - - -double Photon_Field::gaussInt(std::string type, double A, double B, bool onProton, double E_in, int z_pos) const { -/* - - input: type: specifier of function over which to integrate, - integration limits A and B - - output: 8-points gauss-Legendre integral - - called by: sample_eps, prob_eps -*/ - const double X[8] = { .0950125098, .2816035507, .4580167776, .6178762444, - .7554044083, .8656312023, .9445750230, .9894009349 }; - const double W[8] = { .1894506104, .1826034150, .1691565193, .1495959888, - .1246289712, .0951585116, .0622535239, .0271524594 }; - double XM = 0.5*(B+A); - double XR = 0.5*(B-A); - double SS = 0.; - for (int i = 0; i < 8; ++i) { - double DX = XR*X[i]; - if (type == "functs") { - SS += W[i] * (functs(XM+DX, onProton) + functs(XM-DX, onProton)); - } else if (type == "prob_eps") { - SS += W[i] * (prob_eps(XM+DX, onProton, E_in, z_pos) + prob_eps(XM-DX, onProton, E_in, z_pos)); - } else { - throw std::runtime_error("gaussInt: type incorrectly specified"); - } - } - return XR*SS; -} // end gaussInt + const double mass = onProton? 0.93827 : 0.93947; // Gev/c^2 + double factor = s - mass * mass; + double epsPrime = factor / 2. / mass; + double sigma_pg = SOPHIA_crossection(epsPrime, onProton) / 1.e-34; // m² to µbarn + return factor * sigma_pg; +} } // namespace crpropa From 0babab783012bca229ec7a167141f28539dc289e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Wed, 6 Mar 2019 15:24:20 +0000 Subject: [PATCH 43/81] add borish push --- include/crpropa/module/PropagationBP.h | 137 ++++++++++++++++ src/module/PropagationBP.cpp | 216 +++++++++++++++++++++++++ 2 files changed, 353 insertions(+) create mode 100644 include/crpropa/module/PropagationBP.h create mode 100644 src/module/PropagationBP.cpp diff --git a/include/crpropa/module/PropagationBP.h b/include/crpropa/module/PropagationBP.h new file mode 100644 index 000000000..74dd12fef --- /dev/null +++ b/include/crpropa/module/PropagationBP.h @@ -0,0 +1,137 @@ +#ifndef CRPROPA_PROPAGATIONBP_H +#define CRPROPA_PROPAGATIONBP_H + +#include "crpropa/Module.h" +#include "crpropa/Units.h" +#include "crpropa/magneticField/MagneticField.h" + +namespace crpropa { +/** + * \addtogroup Propagation + * @{ + */ + +/** + @class PropagationBP + @brief Propagation through magnetic fields using the Boris method. + + This module solves the equations of motion of a relativistic charged particle when propagating through a magnetic field.\n + It uses the Boris push integration method.\n + It can be used with a fixed step size or an adaptive version which supports the step size control. + The step size control tries to keep the relative error close to, but smaller than the designated tolerance. + Additionally a minimum and maximum size for the steps can be set. + For neutral particles a rectilinear propagation is applied and a next step of the maximum step size proposed. + */ +class PropagationBP: public Module { + +public: + class Y { + public: + Vector3d x, u; /*< phase-point: position and direction */ + + Y() { + } + + Y(const Vector3d &x, const Vector3d &u) : + x(x), u(u) { + } + + Y(double f) : + x(Vector3d(f, f, f)), u(Vector3d(f, f, f)) { + } + + Y operator *(double f) const { + return Y(x * f, u * f); + } + + Y &operator +=(const Y &y) { + x += y.x; + u += y.u; + return *this; + } + }; + +private: + ref_ptr field; + double tolerance; /** target relative error of the numerical integration */ + double minStep; /** minimum step size of the propagation */ + double maxStep; /** maximum step size of the propagation */ + +public: + /** Default constructor for the Boris push. It is constructed with a fixed step size. + * @param field + * @param minStep */ + PropagationBP(ref_ptr field = NULL, double minStep = (1. * kpc)); + + /** Constructor for the adaptive Boris push. + * @param field + * @param minStep minStep/c_light is the minimum integration timestep + * @param maxStep maxStep/c_light is the maximum integration timestep + * @param tolerance tolerance is criterion for step adjustment. Step adjustment takes place only if minStep < maxStep. */ + PropagationBP(ref_ptr field, double minStep, double maxStep, double tolerance = 1e-4); + + /** Propagates the particle. Is called once per iteration. + * @param candidate The Candidate is a passive object, that holds the information about the state of the cosmic ray and the simulation itself. */ + void process(Candidate *candidate) const; + + /** Calculates the new position and direction of the particle based on the solution of the Lorentz force + * @param pos current position of the candidate + * @param dir current direction of the candidate + * @param step current step size of the candidate + * @param z current redshift is needed to calculate the magnetic field + * @param q current charge of the candidate + * @param m current mass of the candidate + * @return return the new calculated position and direction of the candidate */ + Y dY(Vector3d pos, Vector3d dir, double step, double z, double q, double m) const; + + /** comparison of the position after one step with the position after two steps with step/2. + * @param x1 position after one step of size step + * @param x2 position after two steps of size step/2 + * @param step current step size + * @return measurement of the error of the step */ + double errorEstimation(const Vector3d x1, const Vector3d x2, double step) const; + + /** get magnetic field vector at current candidate position + * @param pos current position of the candidate + * @param z current redshift is needed to calculate the magnetic field + * @return magnetic field vector at the position pos */ + Vector3d getFieldAtPosition(Vector3d pos, double z) const; + + /** Adapte step size if required and calculates the new position and direction of the particle with the usage of the function dY + * @param y current position and direction of candidate + * @param out position and direction of candidate after the step + * @param error error for the current step + * @param h current step size + * @param p current particle state + * @param z current red shift + * @param m current mass of the candidate + * @param q current charge of the candidate */ + void tryStep(const Y &y, Y &out, Y &error, double h, ParticleState &p, double z, double m, double q) const; + + /** set functions for the parameters of the class PropagationBP */ + + /** set a specific magnetic field + * @param field specific magnetic field */ + void setField(ref_ptr field); + /** set a specific tolerance for the step size adaption + * @param tolerance tolerance is criterion for step adjustment. Step adjustment takes place only if minStep < maxStep. */ + void setTolerance(double tolerance); + /** set the minimum step for the Boris push + * @param minStep minStep/c_light is the minimum integration time step */ + void setMinimumStep(double minStep); + /** set the maximum step for the Boris push + * @param maxStep maxStep/c_light is the maximum integration time step */ + void setMaximumStep(double maxStep); + + /** get functions for the parameters of the class PropagationBP, similar to the set functions */ + ref_ptr getField() const; + double getTolerance() const; + double getMinimumStep() const; + double getMaximumStep() const; + std::string getDescription() const; +}; +/** @}*/ + +} // namespace crpropa + +#endif // PROPAGATIONBP_H diff --git a/src/module/PropagationBP.cpp b/src/module/PropagationBP.cpp new file mode 100644 index 000000000..dcfd0c748 --- /dev/null +++ b/src/module/PropagationBP.cpp @@ -0,0 +1,216 @@ +#include "crpropa/module/PropagationBP.h" + +#include +#include +#include + +namespace crpropa { + void PropagationBP::tryStep(const Y &y, Y &out, Y &error, double h, + ParticleState &particle, double z, double m, double q) const { + out = dY(y.x, y.u, h, z, q, m); // 1 step with h + + Y outHelp = dY(y.x, y.u, h/2, z, q, m); // 2 steps with h/2 + Y outCompare = dY(outHelp.x, outHelp.u, h/2, z, q, m); + + error = errorEstimation(out.x , outCompare.x , h); + } + + + PropagationBP::Y PropagationBP::dY(Vector3d pos, Vector3d dir, double step, + double z, double q, double m) const { + // half leap frog step in the position + pos += dir * step / 2.; + + // get B field at particle position + Vector3d B = getFieldAtPosition(pos, z); + + // Boris help vectors + Vector3d t = B * q / 2 / m * step / c_light; + Vector3d s = t * 2 / (1 + t.dot(t)); + Vector3d v_help; + + // Boris push + v_help = dir + dir.cross(t); + dir = dir + v_help.cross(s); + + // the other half leap frog step in the position + pos += dir * step / 2.; + return Y(pos, dir); + } + + + // with a fixed step size + PropagationBP::PropagationBP(ref_ptr field, double minStep) : + minStep(0) { + setField(field); + setTolerance(0.42); + setMaximumStep(minStep); + setMinimumStep(minStep); + } + + + // with adaptive step size + PropagationBP::PropagationBP(ref_ptr field, double minStep, double maxStep, double tolerance) : + minStep(0) { + setField(field); + setTolerance(tolerance); + setMaximumStep(maxStep); + setMinimumStep(minStep); + } + + + void PropagationBP::process(Candidate *candidate) const { + // save the new previous particle state + ParticleState ¤t = candidate->current; + candidate->previous = current; + + // calculate charge of particle + double q = current.getCharge(); + + // rectilinear propagation for neutral particles + if (q == 0) { + double step = clip(candidate->getNextStep(), minStep, maxStep); + Vector3d pos = current.getPosition(); + Vector3d dir = current.getDirection(); + current.setPosition(pos + dir * step); + candidate->setCurrentStep(step); + candidate->setNextStep(maxStep); + return; + } + + // further particle parameters + double z = candidate->getRedshift(); + double m = current.getEnergy()/(c_light * c_light); + + // if minStep is the same as maxStep the adaptive algorithm with its error + // estimation is not needed and the computation time can be saved: + if (minStep == maxStep){ + double step = minStep; + Vector3d pos = current.getPosition(); + Vector3d dir = current.getDirection(); + // half leap frog step in the position + Y yOut = dY(pos, dir, step, z, q, m); + + // full leap frog step in the velocity + candidate->current.setDirection(yOut.u); + candidate->current.setPosition(yOut.x); + candidate->setCurrentStep(step); + candidate->setNextStep(step); + return; + } + + double step = clip(candidate->getNextStep(), minStep, maxStep); + double newStep = step; + double r = 42; // arbitrary value > 1 + Y yIn(current.getPosition(), current.getDirection()); + Y yOut, yErr; + + // try performing step until the target error (tolerance) or the minimum step size has been reached + while (true) { + tryStep(yIn, yOut, yErr, step, current, z, m, q); + r = yErr.u.getR() / tolerance; // ratio of absolute direction error and tolerance + if (r > 1) { // large direction error relative to tolerance, try to decrease step size + if (step == minStep) // already minimum step size + break; + else { + newStep = step * 0.95 * pow(r, -0.2); + newStep = std::max(newStep, 0.1 * step); // limit step size decrease + newStep = std::max(newStep, minStep); // limit step size to minStep + step = newStep; + } + } else { // small direction error relative to tolerance, try to increase step size + if (step != maxStep) { // already maximum step size + newStep = step * 0.95 * pow(r, -0.2); + newStep = std::min(newStep, 5 * step); // limit step size increase + newStep = std::min(newStep, maxStep); // limit step size to max Step + } + break; + } + } + + current.setPosition(yOut.x); + current.setDirection(yOut.u.getUnitVector()); + candidate->setCurrentStep(step); + candidate->setNextStep(newStep); + } + + + void PropagationBP::setField(ref_ptr f) { + field = f; + } + + + ref_ptr PropagationBP::getField() const { + return field; + } + + + Vector3d PropagationBP::getFieldAtPosition(Vector3d pos, double z) const { + Vector3d B(0, 0, 0); + // check if field is valid and use the field vector at the + // position pos with the redshift z + if (field.valid()) + B = field->getField(pos, z); + + return B; + } + + + double PropagationBP::errorEstimation(const Vector3d x1, const Vector3d x2, double step) const { + // compare the position after one step with the position after two steps with step/2. + Vector3d diff = (x1 - x2); + + double S = diff.getR() / (step * (1 - 1/4.) ); // 1/4 = (1/2)² number of steps for x1 divided by number of steps for x2 to the power of p (order) + + return S; + } + + + void PropagationBP::setTolerance(double tol) { + if ((tol > 1) or (tol < 0)) + throw std::runtime_error( + "PropagationBP: target error not in range 0-1"); + tolerance = tol; + } + + + void PropagationBP::setMinimumStep(double min) { + if (min < 0) + throw std::runtime_error("PropagationBP: minStep < 0 "); + if (min > maxStep) + throw std::runtime_error("PropagationBP: minStep > maxStep"); + minStep = min; + } + + + void PropagationBP::setMaximumStep(double max) { + if (max < minStep) + throw std::runtime_error("PropagationBP: maxStep < minStep"); + maxStep = max; + } + + + double PropagationBP::getTolerance() const { + return tolerance; + } + + + double PropagationBP::getMinimumStep() const { + return minStep; + } + + + double PropagationBP::getMaximumStep() const { + return maxStep; + } + + + std::string PropagationBP::getDescription() const { + std::stringstream s; + s << "Propagation in magnetic fields using the adaptive Boris push method."; + s << " Target error: " << tolerance; + s << ", Minimum Step: " << minStep / kpc << " kpc"; + s << ", Maximum Step: " << maxStep / kpc << " kpc"; + return s.str(); + } +} // namespace crpropa From b12b65deb5ef2c18d6eea6d87f8950bb1a9d6189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Wed, 6 Mar 2019 15:37:16 +0000 Subject: [PATCH 44/81] include borish push --- python/2_headers.i | 1 + 1 file changed, 1 insertion(+) diff --git a/python/2_headers.i b/python/2_headers.i index 3b4ef9546..f5b70a4a2 100644 --- a/python/2_headers.i +++ b/python/2_headers.i @@ -326,6 +326,7 @@ %include "crpropa/module/Observer.h" %include "crpropa/module/SimplePropagation.h" %include "crpropa/module/PropagationCK.h" +%include "crpropa/module/PropagationBP.h" %ignore crpropa::Output::enableProperty(const std::string &property, const Variant& defaultValue, const std::string &comment = ""); %extend crpropa::Output{ From 53f8ee9001bbee82abae98701c922686b6102f1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Wed, 6 Mar 2019 15:37:32 +0000 Subject: [PATCH 45/81] update photon field naming convention --- include/crpropa/module/PhotoPionProduction.h | 2 +- src/module/PhotoPionProduction.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/crpropa/module/PhotoPionProduction.h b/include/crpropa/module/PhotoPionProduction.h index 8553c97e6..fccac6332 100644 --- a/include/crpropa/module/PhotoPionProduction.h +++ b/include/crpropa/module/PhotoPionProduction.h @@ -23,7 +23,7 @@ class PhotoPionProduction: public Module { protected: PhotonField photonField; ScalarGrid4d geometryGrid; - Photon_Field phtnfld; + CustomPhotonField customPhotonField; std::vector hashMap; // contains histogram hashtags (workaround until c++11) std::vector< std::vector > histData; // contains histogram data (workaround until c++11) // std::unordered_map > particleMap; // if c++11 diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index ab566204b..ef3ec9357 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -35,7 +35,7 @@ PhotoPionProduction::PhotoPionProduction( PhotonField field, limit = l; setPhotonField(field); this->geometryGrid = geometryGrid; - this->phtnfld = Photon_Field(getDataPath("Scaling/" + photonFieldName(field) + ".txt")); + this->customPhotonField = CustomPhotonField(getDataPath("Scaling/" + photonFieldName(field) + ".txt")); if (useTabData) initHistogram(getDataPath("PhotoPionProduction/SOPHIA_histogram.txt")); } @@ -499,7 +499,7 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, bool onProton // SOPHIA - input: int nature = 1 - static_cast(onProton); // 0=proton, 1=neutron double Ein = EpA / GeV; - double eps = phtnfld.sample_eps(onProton, Ein, z); + double eps = customPhotonField.sampleEps(onProton, Ein, z); // SOPHIA - output: double outputEnergy[2000]; From 07b1bfdaf69ccf82efa4fdcb4c4553462d268b76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Wed, 6 Mar 2019 16:42:37 +0000 Subject: [PATCH 46/81] include borish push --- include/CRPropa.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/CRPropa.h b/include/CRPropa.h index 8497fab72..47c27410a 100644 --- a/include/CRPropa.h +++ b/include/CRPropa.h @@ -45,6 +45,7 @@ #include "crpropa/module/PhotonEleCa.h" #include "crpropa/module/PhotonOutput1D.h" #include "crpropa/module/PropagationCK.h" +#include "crpropa/module/PropagationBP.h" #include "crpropa/module/Redshift.h" #include "crpropa/module/RestrictToRegion.h" #include "crpropa/module/SimplePropagation.h" From 2354a7eee9d9188d0d146cf18cc38a17cb92632b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Fri, 22 Mar 2019 21:40:33 +0000 Subject: [PATCH 47/81] fix bug in secondaries' treatment #225 --- src/module/PhotoPionProduction.cpp | 162 +++++++++++++++++------------ 1 file changed, 93 insertions(+), 69 deletions(-) diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index ef3ec9357..66a69db5f 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -5,11 +5,9 @@ #include "crpropa/PhotonBackground.h" #include +#include #include "sophia.h" -#include // srand, rand, abs ! -#include // log10 ! -#include // std::find #include #include #include @@ -521,72 +519,98 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, bool onProton } // output particle treatment - Random &random = Random::instance(); - Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition()); - bool isPrimary = true; // the first hadron in output is declared the primary - for (int i = 0; i < nOutPart; i++) { // loop over out-going particles - double Eout = outputEnergy[i] * GeV; // only the energy is used; could be changed for more detail - int pType = outPartID[i]; - switch (pType) { - case 13: // proton - // pType = 13 -> 14 - 13 = charge = 1 - case 14: // neutron - if (isPrimary) { - if (A == 1) { - // single interacting nucleon - candidate->current.setEnergy(Eout); - candidate->current.setId(sign * nucleusId(1, 14 - pType)); - } else { - // interacting nucleon is part of nucleus: it is emitted from the nucleus - candidate->current.setEnergy(E - EpA); - candidate->current.setId(sign * nucleusId(A - 1, Z - int(onProton))); - candidate->addSecondary(sign * nucleusId(1, 14 - pType), Eout, pos); - } - isPrimary = false; - } else { - candidate->addSecondary(sign * nucleusId(1, 14 - pType), Eout, pos); - } - break; - case -13: // anti-proton - if (haveAntiNucleons) - candidate->addSecondary(-sign * nucleusId(1, 1), Eout, pos); - break; - case -14: // anti-neutron - if (haveAntiNucleons) - candidate->addSecondary(-sign * nucleusId(1, 0), Eout, pos); - break; - case 1: // photon - if (havePhotons) - candidate->addSecondary(22, Eout, pos); - break; - case 2: // positron - if (haveElectrons) // if this is havePhotons, this works with PPP - candidate->addSecondary(sign * -11, Eout, pos); - break; - case 3: // electron - if (haveElectrons) // if this is havePhotons, this works with PPP - candidate->addSecondary(sign * 11, Eout, pos); - break; - case 15: // nu_e - if (haveNeutrinos) - candidate->addSecondary(sign * 12, Eout, pos); - break; - case 16: // antinu_e - if (haveNeutrinos) - candidate->addSecondary(sign * -12, Eout, pos); - break; - case 17: // nu_muon - if (haveNeutrinos) - candidate->addSecondary(sign * 14, Eout, pos); - break; - case 18: // antinu_muon - if (haveNeutrinos) - candidate->addSecondary(sign * -14, Eout, pos); - break; - default: - throw std::runtime_error("PhotoPionProduction: unexpected particle " + kiss::str(pType)); - } - } + Random &random = Random::instance(); + Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition()); + std::vector pnType; // filled with either 13 (proton) or 14 (neutron) + std::vector pnEnergy; // corresponding energies of proton or neutron + for (int i = 0; i < nOutPart; i++) { // loop over out-going particles + double Eout = outputEnergy[i] * GeV; // only the energy is used; could be changed for more detail + int pType = outPartID[i]; + switch (pType) { + case 13: // proton + case 14: // neutron + // proton and neutron data is taken to determine primary particle in a later step + pnType.push_back(pType); + pnEnergy.push_back(Eout); + break; + case -13: // anti-proton + case -14: // anti-neutron + if (haveAntiNucleons) + try + { + candidate->addSecondary(-sign * nucleusId(1, 14 + pType), Eout, pos); + } + catch (std::runtime_error &e) + { + KISS_LOG_ERROR<< "Something went wrong in the PhotoPionProduction (anti-nucleon production)\n" << "Something went wrong in the PhotoPionProduction\n"<< "Please report this error on https://github.com/CRPropa/CRPropa3/issues including your simulation setup and the following random seed:\n" << Random::instance().getSeed_base64(); + throw; + } + break; + case 1: // photon + if (havePhotons) + candidate->addSecondary(22, Eout, pos); + break; + case 2: // positron + if (haveElectrons) + candidate->addSecondary(sign * -11, Eout, pos); + break; + case 3: // electron + if (haveElectrons) + candidate->addSecondary(sign * 11, Eout, pos); + break; + case 15: // nu_e + if (haveNeutrinos) + candidate->addSecondary(sign * 12, Eout, pos); + break; + case 16: // antinu_e + if (haveNeutrinos) + candidate->addSecondary(sign * -12, Eout, pos); + break; + case 17: // nu_muon + if (haveNeutrinos) + candidate->addSecondary(sign * 14, Eout, pos); + break; + case 18: // antinu_muon + if (haveNeutrinos) + candidate->addSecondary(sign * -14, Eout, pos); + break; + default: + throw std::runtime_error("PhotoPionProduction: unexpected particle " + kiss::str(pType)); + } + } + double maxEnergy = *std::max_element(pnEnergy.begin(), pnEnergy.end()); // criterion for being declared primary + for (int i = 0; i < pnEnergy.size(); ++i) { + if (pnEnergy[i] == maxEnergy) { // nucleon is primary particle + if (A == 1) { + // single interacting nucleon + candidate->current.setEnergy(pnEnergy[i]); + try + { + candidate->current.setId(sign * nucleusId(1, 14 - pnType[i])); + } + catch (std::runtime_error &e) + { + KISS_LOG_ERROR<< "Something went wrong in the PhotoPionProduction (primary particle, A==1)\n" << "Please report this error on https://github.com/CRPropa/CRPropa3/issues including your simulation setup and the following random seed:\n" << Random::instance().getSeed_base64(); + throw; + } + } else { + // interacting nucleon is part of nucleus: it is emitted from the nucleus + candidate->current.setEnergy(E - EpA); + try + { + candidate->current.setId(sign * nucleusId(A - 1, Z - int(onProton))); + candidate->addSecondary(sign * nucleusId(1, 14 - pnType[i]), pnEnergy[i], pos); + } + catch (std::runtime_error &e) + { + KISS_LOG_ERROR<< "Something went wrong in the PhotoPionProduction (primary particle, A!=1)\n" << "Please report this error on https://github.com/CRPropa/CRPropa3/issues including your simulation setup and the following random seed:\n" << Random::instance().getSeed_base64(); + throw; + } + } + } else { // nucleon is secondary proton or neutron + candidate->addSecondary(sign * nucleusId(1, 14 - pnType[i]), pnEnergy[i], pos); + } + } } // double PhotoPionProduction::lossLength(int id, double gamma, double z) { From 72d814116c315958ae5bc009fefb68b9867448f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Sun, 14 Apr 2019 10:46:57 +0100 Subject: [PATCH 48/81] add HadronicInteraction --- CMakeLists.txt | 1 + include/CRPropa.h | 1 + include/crpropa/module/HadronicInteraction.h | 52 +++ python/2_headers.i | 1 + src/module/HadronicInteraction.cpp | 453 +++++++++++++++++++ 5 files changed, 508 insertions(+) create mode 100644 include/crpropa/module/HadronicInteraction.h create mode 100644 src/module/HadronicInteraction.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ab3918c76..e1a56ecf0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -354,6 +354,7 @@ add_library(crpropa SHARED src/module/EMTripletPairProduction.cpp src/module/ElasticScattering.cpp src/module/ElectronPairProduction.cpp + src/module/HadronicInteraction.cpp src/module/HDF5Output.cpp src/module/NuclearDecay.cpp src/module/Observer.cpp diff --git a/include/CRPropa.h b/include/CRPropa.h index 47c27410a..ca058b009 100644 --- a/include/CRPropa.h +++ b/include/CRPropa.h @@ -35,6 +35,7 @@ #include "crpropa/module/EMTripletPairProduction.h" #include "crpropa/module/ElasticScattering.h" #include "crpropa/module/ElectronPairProduction.h" +#include "crpropa/module/HadronicInteraction.h" #include "crpropa/module/HDF5Output.h" #include "crpropa/module/NuclearDecay.h" #include "crpropa/module/Observer.h" diff --git a/include/crpropa/module/HadronicInteraction.h b/include/crpropa/module/HadronicInteraction.h new file mode 100644 index 000000000..98420a190 --- /dev/null +++ b/include/crpropa/module/HadronicInteraction.h @@ -0,0 +1,52 @@ +#ifndef CRPROPA_HADRONICINTERACTION_H +#define CRPROPA_HADRONICINTERACTION_H + +#include "crpropa/Module.h" +#include "crpropa/Vector3.h" + +namespace crpropa { +/** + * \addtogroup EnergyLosses + * @{ + */ + +/** + @class HadronicInteraction + @brief interactions of nuclei with background nucleons (Hydrogen only). + */ +class HadronicInteraction: public Module { +protected: + double massDensity; + bool haveElectrons; + bool havePhotons; + bool haveNeutrinos; + +public: + HadronicInteraction( + double massDensity = 0., + bool electrons = false, + bool photons = false, + bool neutrinos = false); + void setHaveElectrons(bool b); + void setHavePhotons(bool b); + void setHaveNeutrinos(bool b); + void process(Candidate *candidate) const; + double distribution_e(double energy, double x) const; + double distribution_my1(double energy, double x) const; + double distribution_gamma(double energy, double x) const; + int numberOfElectrons(double energy) const; + int numberOfMuonNeutrinos(double energy) const; + int numberOfGammaRays(double energy) const; + double CrossSection_Kelner(double energy) const; + + // these functions are not being used in the simulation + double distribution_Carceller(double energy, double x, double jcap, double a0, double b0) const; + double distribution_Carceller_g(double energy, double x, double jcap, double a0, double b0) const; + double CrossSection_Carceller(double energy) const; + double CrossSection_Galprop(double energy) const; + Vector3d getPosition(double height, double radius) const; +}; + +} // namespace crpropa + +#endif // CRPROPA_HADRONICINTERACTION_H diff --git a/python/2_headers.i b/python/2_headers.i index f5b70a4a2..3bdd63a9d 100644 --- a/python/2_headers.i +++ b/python/2_headers.i @@ -411,6 +411,7 @@ %include "crpropa/module/PhotonOutput1D.h" %include "crpropa/module/NuclearDecay.h" %include "crpropa/module/ElectronPairProduction.h" +%include "crpropa/module/HadronicInteraction.h" %include "crpropa/module/PhotoPionProduction.h" %include "crpropa/module/PhotoDisintegration.h" %include "crpropa/module/ElasticScattering.h" diff --git a/src/module/HadronicInteraction.cpp b/src/module/HadronicInteraction.cpp new file mode 100644 index 000000000..d2ae53083 --- /dev/null +++ b/src/module/HadronicInteraction.cpp @@ -0,0 +1,453 @@ +#include "crpropa/module/HadronicInteraction.h" +#include "crpropa/Units.h" +#include "crpropa/ParticleID.h" +#include "crpropa/ParticleMass.h" +#include "crpropa/Random.h" + +#include +#include +#include +#include + +namespace crpropa { + + +HadronicInteraction::HadronicInteraction(double massDensity, bool electrons, bool photons, bool neutrinos) { + this->massDensity = massDensity; + haveElectrons = electrons; + havePhotons = photons; + haveNeutrinos = neutrinos; + setDescription("HadronicInteraction"); +} + +void HadronicInteraction::setHaveElectrons(bool b) { + haveElectrons = b; +} + +void HadronicInteraction::setHavePhotons(bool b) { + havePhotons = b; +} + +void HadronicInteraction::setHaveNeutrinos(bool b) { + haveNeutrinos = b; +} + +Vector3d HadronicInteraction::getPosition(double height, double radius) const { + Random &random = Random::instance(); + int i = 0; + Vector3d pos(0, 0, 0); + double phi = random.rand() * 2 * M_PI; + int j = 0; + do { + double r = random.rand() * radius; + double yr = random.rand(); + double Fr = exp(-r * r / (2 * 4.2 * 4.2 * kpc * kpc)); + if (yr < Fr) { + pos = Vector3d(cos(phi) * r, sin(phi) * r, 0); + j++; + } + } while (j == 0); + do { + double z = random.rand()* height; + double yz = random.rand(); + double Fz = exp(-z / (10 * pc)); + if (yz < Fz) { + double a = random.rand(); + if (a <= 0.5) + z = -z; + pos += Vector3d(0, 0, z); + j++; + } + } while (j == 1); + return pos; +} + +double HadronicInteraction::distribution_e(double Eprimary, double x) const { + /* Distribution function (energy) for electrons, electron neutrino and + (second) muon neutrinos based on Kelner 2006 - eqs. 62-65 + input: energy: primary's energy / x: Elepton/Epi | if second numu: x: Enumu/Eprimary + */ + double L = log(Eprimary / TeV); + double Be = 1 / (69.5 + 2.65 * L + 0.3 * L * L); + double betae = 1 / pow((0.201 + 0.062 * L + 0.00042 * L * L), 0.25); + double ke = (0.279 + 0.141 * L + 0.0172 * L * L) / (0.3 + (2.3 + L) * (2.3 + L)); + double F = Be * pow((1 + ke * pow(log(x), 2.)), 3.) / (x * (1 + 0.3 / pow(x, betae))) * (pow(-log(x), 5.)); + return F; +} + +// Number of electrons, electron neutrinos and (second) muons neutrinos produced in a given interaction based on Kelner 2006 +int HadronicInteraction::numberOfElectrons(double Eprimary) const { + const double xMax = 1.; + const double xMin = 1. / 100000.; + const double stepSize = 1. / 100000.; + double x = xMin; + double y = 0; + double stepsDone = 0; + do { + y += distribution_e(Eprimary, x); + x += stepSize; + stepsDone++; + } while (x < xMax); + return round(y / stepsDone * (x - 1. / 1000.)); +} + +double HadronicInteraction::distribution_my1(double Eprimary, double x) const { + /* Distribution function (energy) for (first) muon neutrino based on Kelner 2006 + eqs. 66-69. input: energy: primary's energy / x: Enumu1/Eprimary*/ + double L = log(Eprimary / TeV); + double Bm = 1.75 + 0.204 * L + 0.01 * pow(L, 2.); + double betam = 1 / (1.67 + 0.111 * L + 0.0038 * pow(L, 2.)); + double km = 1.07 - 0.086 * L + 0.002 * pow(L, 2.); + x /= 0.427; + double aa = (1 - pow(x, betam)) / (1 + km * pow(x, betam) * (1 - pow(x, betam))); + double A = Bm * log(x) / x * pow(aa, 4.); + double B = 1 / log(x) - 4 * betam * pow(x, betam) / (1 - pow(x, betam)) + - 4 * km * betam * pow(x, betam) * (1 - 2 * pow(x, betam)) + / (1 + km * pow(x, betam) * (1 - pow(x, betam))); + double F = A * B; + return F; +} + +// Number of (first) muon neutrinos produced in a given interaction based on Kelner 2006 +int HadronicInteraction::numberOfMuonNeutrinos(double Eprimary) const { + const double xMax = 0.427; + const double xMin = 1. / 100000.; + const double stepSize = 1. / 100000.; + double x = xMin; + double y = 0.; + int stepsDone = 0; + do { + y += distribution_my1(Eprimary, x); + x += stepSize; + stepsDone++; + } while (x < xMax); + return round(y / stepsDone * (x - 1. / 1000.)); +} + +double HadronicInteraction::distribution_gamma(double Eprimary, double x) const { + /* Distribution function (energy) for gamma rays based on Kelner 2006 eqs. 58-61 + energy: primary's energy / x: Egamma/Eprimary */ + double L = log(Eprimary / TeV); + double Bg = 1.3 + 0.14 * L + 0.011 * L * L; + double betag = 1 / (1.79 + 0.11 * L + 0.008 * L * L); + double kg = 1 / (0.801 + 0.049 * L + 0.014 * L * L); + double A = Bg * log(x) / x; + double B = (1 - pow(x, betag)) / (1 + kg * pow(x, betag) * (1 - pow(x, betag))); + double C = 1 / log(x) - 4 * betag * pow(x, betag) / (1 - pow(x, betag)) + - 4 * kg * betag * pow(x, betag) * (1 - 2 * pow(x, betag)) + / (1 + kg * pow(x, betag) * (1 - pow(x, betag))); + double F = A * pow(B, 4.) * C; + return F; +} + +// Number of gamma rays produced in a given interaction based on Kelner 2006 +int HadronicInteraction::numberOfGammaRays(double Eprimary) const { + const double xMin = 1. / 100000.; + const double xMax = 1.; + const double stepSize = 1. / 100000.; + double x = xMin; + double y = 0.; + int stepsDone = 0; + do { + y += distribution_gamma(Eprimary, x); + x += stepSize; + stepsDone++; + } while (x < xMax); + return round(y / stepsDone * (x - 1. / 1000.)); +} + +// Energy distribution for lepton secondaries of pp interactions based on Carceller 2017 +double HadronicInteraction::distribution_Carceller(double Eprimary, double x, double jcap, double a0, double b0) const { + double a = a0 * (1 + 0.073 * log(Eprimary / PeV) + 0.0070 * log(Eprimary / PeV) * log(Eprimary / PeV)); + double b = b0 * (1 + 0.020 * log(Eprimary / PeV) + 0.0018 * log(Eprimary / PeV) * log(Eprimary / PeV)); + double A = a * pow((1 - jcap * x), 3.) / x; + double B = exp(-b * pow(jcap * x, 0.43)) / pow(1 + pow(0.1 * GeV / (x * Eprimary), 0.5), 2.); + double F = A * B; + return F; +} + +// Energy distribution for gamma photons based on Carceller 2017 +double HadronicInteraction::distribution_Carceller_g(double Eprimary, double x, double jcap, double a0, double b0) const { + double a = a0 * (1 + 0.073 * log(Eprimary / PeV) + 0.0070 * log(Eprimary / PeV) * log(Eprimary / PeV)); + double b = b0 * (1 + 0.020 * log(Eprimary / PeV) + 0.0018 * log(Eprimary / PeV) * log(Eprimary / PeV)); + double A = a * pow((1 - jcap * x), 3.) / x; + double B = exp(-b * pow(jcap * x, 0.43)) / pow(1 + pow(0.2 * GeV / (x * Eprimary), 0.5), 2.); + double F = A * B; + return F; +} + +// Cross Section of inelastic pp interaction based on Tan & Ng 1983 (Used in Galprop) +double HadronicInteraction::CrossSection_Galprop(double Eprimary) const { + double cs_inel; + double U = log(Eprimary / GeV * 1 / 200); + if (U >= 0 and Eprimary >= 3 * GeV) + cs_inel = (32.2 * (1 + 0.0273 * U)) * 1e-31 + 32.2 * 0.01 * pow(U, 2.) * 1e-31; + if (U < 0 and Eprimary >= 3 * GeV) + cs_inel = (32.2 * (1 + 0.0273 * U)) * 1e-31; + if (Eprimary <= 0.3 * GeV) + cs_inel = 0; + return cs_inel; +} + +// Cross Section of inelastic pp interaction based on Kelner 2006 +double HadronicInteraction::CrossSection_Kelner(double Eprimary) const { + double L = log(Eprimary / TeV); + double A = 1 - pow(1.22 * 1e-3 * TeV / Eprimary, 4.); + double cs_inel = (34.3 + 1.88 * L + 0.25 * L * L) * A * A * 1e-31; + return cs_inel; +} + +// Cross Section of inelastic pp interaction based on Carceller 2017 +double HadronicInteraction::CrossSection_Carceller(double Eprimary) const { + double cs_inel = 17.7 * pow(Eprimary / GeV, 0.082) * 1e-31; + return cs_inel; +} + +void HadronicInteraction::process(Candidate *candidate) const { + // Interaction only for protons + if (candidate->current.getId() != 1000010010) + return; + + // Probability of interaction + const double step = candidate->getCurrentStep(); + const double Eprimary = candidate->current.getEnergy(); + const double cs_inel = CrossSection_Kelner(Eprimary); + const double p_pp = cs_inel * massDensity * step; + + // limit next step to mean free path + const double limit = 1 / p_pp * 0.1; + + if (step > limit) + candidate->limitNextStep(limit); + + // Interaction? + Random &random = Random::instance(); + if (random.rand() > p_pp or Eprimary < 1 * GeV) + return; + + const Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition()); // secondaries' pos + + /* Initialize current energies of secondaries */ + double Eout = 0; + + double Egamma = 0; // gamma + double EnuMu1 = 0; // nu_mu1 + double Eelectron = 0; // electron + double EnuE = 0; // nu_e + double EnuMu2 = 0; // nu_mu2 + double Etot = 0; + + /* Establish number of secondaries */ + const int Ngamma = numberOfGammaRays(Eprimary); // number of gamma rays + const int NnuMu1 = numberOfMuonNeutrinos(Eprimary); // number of first myon neutrino + const int Nelectron = numberOfElectrons(Eprimary); // number of electron + const int NnuE = Nelectron; // number of electron neutrino + const int NnuMu2 = Nelectron; // number of second muon neutrino + const int Ntotal = Nelectron + Ngamma + NnuMu1 + NnuE + NnuMu2; // Total number of secondaries in the interaction + + /* Initialization for stopping criteria. + Counter of interim produced particles: */ + int iTotal = 1; + + int iGamma = 1; + int iNuMu1 = 1; + int iElectron = 1; + int iNuE = 1; + int iNuMu2 = 1; + + const double threshold = 0.0001; + int test; + int end = -1; + + /* Jump to random starting point: */ + const double startPoint = random.rand(); + if (startPoint <= 0.2) + goto label1; + if (startPoint <= 0.4) + goto label2; + if (startPoint <= 0.6) + goto label3; + if (startPoint <= 0.8) + goto label4; + if (startPoint <= 1.0) + goto label5; + + do { + label1: + + // Gamma rays + test = iGamma; + // Check if all gamma rays were created + if (iGamma <= Ngamma) { + if (end == -1) { + // pick gamma ray's energy + do { + double x = threshold + random.rand() * (1 - Eout / Eprimary - threshold); + Eout = x * Eprimary; + double E = distribution_gamma(Eprimary, x); + double Emax = distribution_gamma(Eprimary, threshold); + double y = random.rand() * Emax; + + if (y < E and (Etot + Eout) < Eprimary) { + if (havePhotons) + candidate->addSecondary(22, Eout, pos); + Egamma += Eout; + Etot += Eout; + iTotal++; + iGamma++; + if (Etot / Eprimary >= (1 - threshold)) + end = iTotal; + } + } while (test == iGamma); + } else { + Eout = (Eprimary - Etot) / (Ntotal - end); + if (havePhotons) + candidate->addSecondary(22, Eout, pos); + Egamma += Eout; + iTotal++; + iGamma++; + } + } + + label2: + + // First myon neutrino 14 + test = iNuMu1; + if (iNuMu1 <= NnuMu1) { + if (end == -1) { + do { + double x = threshold + random.rand() * (0.427 - threshold); + Eout = x * Eprimary; + double E = distribution_my1(Eprimary, x); + double Emax = distribution_my1(Eprimary, threshold); + double y = random.rand() * Emax; + if (y < E and (Etot + Eout) < Eprimary) { + if (haveNeutrinos) + candidate->addSecondary(14, Eout, pos); + EnuMu1 += Eout; + Etot += Eout; + iTotal++; + iNuMu1++; + if (Etot / Eprimary >= (1 - threshold)) + end = iTotal; + } + } while (test == iNuMu1); + } else { + Eout = (Eprimary - Etot) / (Ntotal - end); + if (haveNeutrinos) + candidate->addSecondary(14, Eout, pos); + EnuMu1 += Eout; + iTotal++; + iNuMu1++; + } + } + + label3: + + // Electron 11 + test = iElectron; + if (iElectron <= Nelectron) { + if (end == -1) { + do { + double x = threshold + random.rand() * (1 - Eout / Eprimary - threshold); + Eout = x * Eprimary; + double E = distribution_e(Eprimary, x); + double Emax = distribution_e(Eprimary, threshold); + double y = random.rand() * Emax; + if (y < E and (Etot + Eout) < Eprimary) { + if (haveElectrons) + candidate->addSecondary(11, Eout, pos); + Etot += Eout; + Eelectron += Eout; + iTotal++; + iElectron++; + if (Etot / Eprimary >= (1 - threshold)) + end = iTotal; + } + } while (test == iElectron); + } else { + Eout = (Eprimary - Etot) / (Ntotal - end); + if (haveElectrons) + candidate->addSecondary(11, Eout, pos); + iTotal++; + iElectron++; + Eelectron += Eout; + } + } + + label4: + + // Electron neutrino 12 + test = iNuE; + if (iNuE <= NnuE) { + if (end == -1) { + do { + double x = threshold + random.rand() * (1 - Eout / Eprimary - threshold); + Eout = x * Eprimary; + double E = distribution_e(Eprimary, x); + double Emax = distribution_e(Eprimary, threshold); + double y = random.rand() * Emax; + if (y < E and (Etot + Eout) < Eprimary) { + if (haveNeutrinos) + candidate->addSecondary(12, Eout, pos); + EnuE += Eout; + Etot += Eout; + iTotal++; + iNuE++; + if (Etot / Eprimary >= (1 - threshold)) + end = iTotal; + } + } while (iNuE == test); + } else { + Eout = (Eprimary - Etot) / (Ntotal - end); + if (haveNeutrinos) + candidate->addSecondary(12, Eout, pos); + iTotal++; + iNuE++; + EnuE += Eout; + } + } + + label5: + + // Second myon neutrino 14 + test = iNuMu2; + if (iNuMu2 <= NnuMu2) { + if (end == -1) { + do { + double x = threshold + random.rand() * (1 - Eout / Eprimary - threshold); + Eout = x * Eprimary; + double E = distribution_e(Eprimary, x); + double Emax = distribution_e(Eprimary, threshold); + double y = random.rand() * Emax; + if (y < E and (Etot + Eout) < Eprimary) { + if (haveNeutrinos) + candidate->addSecondary(14, Eout, pos); + EnuMu2 += Eout; + Etot += Eout; + iTotal++; + iNuMu2++; + if (Etot / Eprimary >= (1 - threshold)) + end = iTotal; + } + } while (iNuMu2 == test); + } else { + Eout = (Eprimary - Etot) / (Ntotal - end); + if (haveNeutrinos) + candidate->addSecondary(14, Eout, pos); + iTotal++; + iNuMu2++; + EnuMu2 += Eout; + } + } + } while (iTotal <= Ntotal); + + if (end != -1) + std::cout << end << " end != -1" << std::endl; + + // Reduce primary's energy + candidate->current.setEnergy(Eprimary - (EnuE + EnuMu2 + Eelectron + EnuMu1 + Egamma)); + return; +} + +} // namespace CRPropa From f729dea6b04fa4f427f4ab600b1abfc2c5dd3472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Sun, 14 Apr 2019 11:45:55 +0100 Subject: [PATCH 49/81] add space- & time-dependence to Hadronic Interaction --- include/crpropa/module/HadronicInteraction.h | 11 +++++ src/module/HadronicInteraction.cpp | 44 ++++++++++++++++---- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/include/crpropa/module/HadronicInteraction.h b/include/crpropa/module/HadronicInteraction.h index 98420a190..33f626b65 100644 --- a/include/crpropa/module/HadronicInteraction.h +++ b/include/crpropa/module/HadronicInteraction.h @@ -3,6 +3,7 @@ #include "crpropa/Module.h" #include "crpropa/Vector3.h" +#include namespace crpropa { /** @@ -17,16 +18,26 @@ namespace crpropa { class HadronicInteraction: public Module { protected: double massDensity; + ScalarGrid4d geometryGrid; bool haveElectrons; bool havePhotons; bool haveNeutrinos; public: + // HadronicInteraction( + // double massDensity = 0., + // bool electrons = false, + // bool photons = false, + // bool neutrinos = false); + HadronicInteraction( double massDensity = 0., + ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.), bool electrons = false, bool photons = false, bool neutrinos = false); + + void setMassDensity(double dens); void setHaveElectrons(bool b); void setHavePhotons(bool b); void setHaveNeutrinos(bool b); diff --git a/src/module/HadronicInteraction.cpp b/src/module/HadronicInteraction.cpp index d2ae53083..4c3f068a0 100644 --- a/src/module/HadronicInteraction.cpp +++ b/src/module/HadronicInteraction.cpp @@ -12,24 +12,45 @@ namespace crpropa { -HadronicInteraction::HadronicInteraction(double massDensity, bool electrons, bool photons, bool neutrinos) { - this->massDensity = massDensity; - haveElectrons = electrons; - havePhotons = photons; - haveNeutrinos = neutrinos; +// HadronicInteraction::HadronicInteraction(double massDensity, +// bool electrons, +// bool photons, +// bool neutrinos) { +// setMassDensity(massDensity); +// this->geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),2.); +// setHaveElectrons(electrons); +// setHavePhotons(photons); +// setHaveNeutrinos(neutrinos); +// setDescription("HadronicInteraction"); +// } + +HadronicInteraction::HadronicInteraction(double massDensity, + ScalarGrid4d geometryGrid, + bool electrons, + bool photons, + bool neutrinos) { + setMassDensity(massDensity); + this->geometryGrid = geometryGrid; + setHaveElectrons(electrons); + setHavePhotons(photons); + setHaveNeutrinos(neutrinos); setDescription("HadronicInteraction"); } +void HadronicInteraction::setMassDensity(double dens) { + this->massDensity = dens; +} + void HadronicInteraction::setHaveElectrons(bool b) { - haveElectrons = b; + this->haveElectrons = b; } void HadronicInteraction::setHavePhotons(bool b) { - havePhotons = b; + this->havePhotons = b; } void HadronicInteraction::setHaveNeutrinos(bool b) { - haveNeutrinos = b; + this->haveNeutrinos = b; } Vector3d HadronicInteraction::getPosition(double height, double radius) const { @@ -212,6 +233,11 @@ void HadronicInteraction::process(Candidate *candidate) const { const double step = candidate->getCurrentStep(); const double Eprimary = candidate->current.getEnergy(); const double cs_inel = CrossSection_Kelner(Eprimary); + + Vector3d pos = candidate->current.getPosition(); + const double time = candidate->getTrajectoryLength()/c_light; + const dens = massDensity * geometryGrid.interpolate(pos, time); + const double p_pp = cs_inel * massDensity * step; // limit next step to mean free path @@ -225,7 +251,7 @@ void HadronicInteraction::process(Candidate *candidate) const { if (random.rand() > p_pp or Eprimary < 1 * GeV) return; - const Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition()); // secondaries' pos + pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition()); // secondaries' pos /* Initialize current energies of secondaries */ double Eout = 0; From c4df65c39f670c309bb8396db587e4e0a3907127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Sun, 14 Apr 2019 11:47:11 +0100 Subject: [PATCH 50/81] fix classifier bug --- src/module/HadronicInteraction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/module/HadronicInteraction.cpp b/src/module/HadronicInteraction.cpp index 4c3f068a0..1a4d13eb2 100644 --- a/src/module/HadronicInteraction.cpp +++ b/src/module/HadronicInteraction.cpp @@ -236,7 +236,7 @@ void HadronicInteraction::process(Candidate *candidate) const { Vector3d pos = candidate->current.getPosition(); const double time = candidate->getTrajectoryLength()/c_light; - const dens = massDensity * geometryGrid.interpolate(pos, time); + const double dens = massDensity * geometryGrid.interpolate(pos, time); const double p_pp = cs_inel * massDensity * step; From 3cf60c77e6e4857ee32d4b06548303a13103a28f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Mon, 15 Apr 2019 22:41:30 +0100 Subject: [PATCH 51/81] add constructor for various input parameters --- include/crpropa/module/HadronicInteraction.h | 24 ++++++---- src/module/HadronicInteraction.cpp | 50 ++++++++++++++------ 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/include/crpropa/module/HadronicInteraction.h b/include/crpropa/module/HadronicInteraction.h index 33f626b65..f1eb3b6e9 100644 --- a/include/crpropa/module/HadronicInteraction.h +++ b/include/crpropa/module/HadronicInteraction.h @@ -18,21 +18,29 @@ namespace crpropa { class HadronicInteraction: public Module { protected: double massDensity; - ScalarGrid4d geometryGrid; + ScalarGrid4d spaceTimeGrid; + ScalarGrid spaceGrid; bool haveElectrons; bool havePhotons; bool haveNeutrinos; public: - // HadronicInteraction( - // double massDensity = 0., - // bool electrons = false, - // bool photons = false, - // bool neutrinos = false); + HadronicInteraction( + double massDensity, + bool electrons = false, + bool photons = false, + bool neutrinos = false); + + HadronicInteraction( + double massDensity, + ScalarGrid4d spaceTimeGrid, + bool electrons = false, + bool photons = false, + bool neutrinos = false); HadronicInteraction( - double massDensity = 0., - ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.), + double massDensity, + ScalarGrid spaceGrid, bool electrons = false, bool photons = false, bool neutrinos = false); diff --git a/src/module/HadronicInteraction.cpp b/src/module/HadronicInteraction.cpp index 1a4d13eb2..8b2583a7f 100644 --- a/src/module/HadronicInteraction.cpp +++ b/src/module/HadronicInteraction.cpp @@ -12,29 +12,45 @@ namespace crpropa { -// HadronicInteraction::HadronicInteraction(double massDensity, -// bool electrons, -// bool photons, -// bool neutrinos) { -// setMassDensity(massDensity); -// this->geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),2.); -// setHaveElectrons(electrons); -// setHavePhotons(photons); -// setHaveNeutrinos(neutrinos); -// setDescription("HadronicInteraction"); -// } +HadronicInteraction::HadronicInteraction(double massDensity, + bool electrons, + bool photons, + bool neutrinos) { + setMassDensity(massDensity); + this->spaceTimeGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.); + this->spaceGrid = ScalarGrid(Vector3d(0.), 1,1,1, Vector3d(1.)); + setHaveElectrons(electrons); + setHavePhotons(photons); + setHaveNeutrinos(neutrinos); + setDescription("HadronicInteraction_isotropicConstant"); +} + +HadronicInteraction::HadronicInteraction(double massDensity, + ScalarGrid4d spaceTimeGrid, + bool electrons, + bool photons, + bool neutrinos) { + setMassDensity(massDensity); + this->spaceTimeGrid = spaceTimeGrid; + this->spaceGrid = ScalarGrid(Vector3d(0.), 1,1,1, Vector3d(1.)); + setHaveElectrons(electrons); + setHavePhotons(photons); + setHaveNeutrinos(neutrinos); + setDescription("HadronicInteraction_spaceTimeDependent"); +} HadronicInteraction::HadronicInteraction(double massDensity, - ScalarGrid4d geometryGrid, + ScalarGrid spaceGrid, bool electrons, bool photons, bool neutrinos) { setMassDensity(massDensity); - this->geometryGrid = geometryGrid; + this->spaceTimeGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.); + this->spaceGrid = spaceGrid; setHaveElectrons(electrons); setHavePhotons(photons); setHaveNeutrinos(neutrinos); - setDescription("HadronicInteraction"); + setDescription("HadronicInteraction_spaceDependentConstant"); } void HadronicInteraction::setMassDensity(double dens) { @@ -236,7 +252,11 @@ void HadronicInteraction::process(Candidate *candidate) const { Vector3d pos = candidate->current.getPosition(); const double time = candidate->getTrajectoryLength()/c_light; - const double dens = massDensity * geometryGrid.interpolate(pos, time); + + // const double dens = massDensity * geometryGrid.interpolate(pos, time); + double dens = massDensity; + // if (geometryGrid.getNx() != 1) + // dens *= geometryGrid.interpolate(pos, time); const double p_pp = cs_inel * massDensity * step; From 49789cf2677a30e42b85fb42949b42bd3fa0a244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Mon, 15 Apr 2019 22:41:52 +0100 Subject: [PATCH 52/81] fix indent --- src/module/PhotoPionProduction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 66a69db5f..5207f5a72 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -431,7 +431,7 @@ void PhotoPionProduction::process(Candidate *candidate) const { double step = candidate->getCurrentStep(); double z = candidate->getRedshift(); Vector3d pos = candidate->current.getPosition(); -double time = candidate->getTrajectoryLength()/c_light; + double time = candidate->getTrajectoryLength()/c_light; // the loop is processed at least once for limiting the next step do { // check if nucleus From fee99c07d1ba56e189a4f01c35fdfb1f325eba7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Mon, 15 Apr 2019 23:47:49 +0100 Subject: [PATCH 53/81] implement density interpolation dependent on variability --- src/module/HadronicInteraction.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/module/HadronicInteraction.cpp b/src/module/HadronicInteraction.cpp index 8b2583a7f..52077a57a 100644 --- a/src/module/HadronicInteraction.cpp +++ b/src/module/HadronicInteraction.cpp @@ -17,8 +17,8 @@ HadronicInteraction::HadronicInteraction(double massDensity, bool photons, bool neutrinos) { setMassDensity(massDensity); - this->spaceTimeGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.); - this->spaceGrid = ScalarGrid(Vector3d(0.), 1,1,1, Vector3d(1.)); + this->spaceTimeGrid = ScalarGrid4d(); + this->spaceGrid = ScalarGrid(); setHaveElectrons(electrons); setHavePhotons(photons); setHaveNeutrinos(neutrinos); @@ -32,7 +32,7 @@ HadronicInteraction::HadronicInteraction(double massDensity, bool neutrinos) { setMassDensity(massDensity); this->spaceTimeGrid = spaceTimeGrid; - this->spaceGrid = ScalarGrid(Vector3d(0.), 1,1,1, Vector3d(1.)); + this->spaceGrid = ScalarGrid(); setHaveElectrons(electrons); setHavePhotons(photons); setHaveNeutrinos(neutrinos); @@ -45,7 +45,7 @@ HadronicInteraction::HadronicInteraction(double massDensity, bool photons, bool neutrinos) { setMassDensity(massDensity); - this->spaceTimeGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.); + this->spaceTimeGrid = ScalarGrid4d(); this->spaceGrid = spaceGrid; setHaveElectrons(electrons); setHavePhotons(photons); @@ -252,13 +252,19 @@ void HadronicInteraction::process(Candidate *candidate) const { Vector3d pos = candidate->current.getPosition(); const double time = candidate->getTrajectoryLength()/c_light; - - // const double dens = massDensity * geometryGrid.interpolate(pos, time); - double dens = massDensity; - // if (geometryGrid.getNx() != 1) - // dens *= geometryGrid.interpolate(pos, time); - const double p_pp = cs_inel * massDensity * step; + double dens = massDensity; + const std::string description = getDescription(); + if (description == "HadronicInteraction_isotropicConstant") { + // do nothing, just check for correct initialization + } else if (description == "HadronicInteraction_spaceDependentConstant") { + dens *= spaceGrid.interpolate(pos); + } else if (description == "HadronicInteraction_spaceTimeDependent") { + dens *= spaceTimeGrid.interpolate(pos, time); + } else { + throw std::runtime_error("HadronicInteraction: invalid description string"); + } + const double p_pp = cs_inel * dens * step; // limit next step to mean free path const double limit = 1 / p_pp * 0.1; From 790c8bffd54b4748fd4b41d3de837d2a0ba691c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Mon, 15 Apr 2019 23:48:49 +0100 Subject: [PATCH 54/81] improve initialization of empty grids --- include/crpropa/Grid.h | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/include/crpropa/Grid.h b/include/crpropa/Grid.h index 3319420f3..d16dc288a 100644 --- a/include/crpropa/Grid.h +++ b/include/crpropa/Grid.h @@ -53,9 +53,15 @@ class Grid: public Referenced { public: Grid() { - // empty constructor for initialization in some modules + // empty grid for initialization in some modules + setOrigin(Vector3d(0.)); + setGridSize(0, 0, 0, 0); + setSpacing(Vector3d(0.)); + setTiming(0.); + setStartTime(0.); + setReflective(false); } - + /** Constructor for cubic grid @param origin Position of the lower left front corner of the volume @param N Number of grid points in one direction @@ -63,7 +69,7 @@ class Grid: public Referenced { */ Grid(Vector3d origin, size_t N, Vector3d spacing) { setOrigin(origin); - setGridSize(N, N, N, 1); + setGridSize(N, N, N, 0); setSpacing(spacing); setTiming(1.); setStartTime(0.); @@ -79,7 +85,7 @@ class Grid: public Referenced { */ Grid(Vector3d origin, size_t Nx, size_t Ny, size_t Nz, Vector3d spacing) { setOrigin(origin); - setGridSize(Nx, Ny, Nz, 1); + setGridSize(Nx, Ny, Nz, 0); setSpacing(spacing); setTiming(1.); setStartTime(0.); @@ -123,8 +129,11 @@ class Grid: public Referenced { this->Ny = Ny; this->Nz = Nz; this->Nt = Nt; - grid.resize(Nx * Ny * Nz * Nt); - setOrigin(origin); + if (Nt == 0) { + grid.resize(Nx * Ny * Nz); + } else { + grid.resize(Nx * Ny * Nz * Nt); + } } void setSpacing(Vector3d spacing) { From ddda3aad06b863395b1fdf0c0d47332004b5b30b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Fri, 10 May 2019 11:31:06 +0100 Subject: [PATCH 55/81] disable print to console --- libs/sophia/sophia_interface.f | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/sophia/sophia_interface.f b/libs/sophia/sophia_interface.f index d47c5a064..5c4d6a6c8 100644 --- a/libs/sophia/sophia_interface.f +++ b/libs/sophia/sophia_interface.f @@ -134,9 +134,9 @@ SUBROUTINE eventgen(L0,E0,eps,theta,Imode) c... check for threshold: sth = 1.1646D0 if (s.lt.sth) then - PRINT*,'input energy below threshold for - & photopion production !' - PRINT*,'sqrt(s) = ',sqrt(s) +C PRINT*,'input energy below threshold for +C & photopion production !' +C PRINT*,'sqrt(s) = ',sqrt(s) NP = 0 RETURN endif @@ -9296,10 +9296,10 @@ SUBROUTINE sophiaevent(nature,Ein,eps,OutPart,OutPartType,NbOut Pp = sqrt(E0*E0-pm*pm) theta = ((pm*pm-s)/2.D0/eps+E0)/Pp if (theta.gt.1.D0) then - PRINT*,'sophiaevent: theta > 1.D0: ', theta +C PRINT*,'sophiaevent: theta > 1.D0: ', theta theta = 0.D0 else if (theta.lt.-1.D0) then - PRINT*,'sophiaevent: theta < -1.D0: ', theta +C PRINT*,'sophiaevent: theta < -1.D0: ', theta theta = 180.D0 else theta = acos(theta)*180.D0/pi From fa33d56f6474085e5145fea292a15530f698415f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Fri, 10 May 2019 11:31:29 +0100 Subject: [PATCH 56/81] account for faulty sophiaevents --- src/module/PhotoPionProduction.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 5207f5a72..71eb13198 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -578,8 +578,13 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, bool onProton throw std::runtime_error("PhotoPionProduction: unexpected particle " + kiss::str(pType)); } } - double maxEnergy = *std::max_element(pnEnergy.begin(), pnEnergy.end()); // criterion for being declared primary - for (int i = 0; i < pnEnergy.size(); ++i) { + + // threshold check is removed from this PPP, so SOPHIA may return 0 particles + if (pnEnergy.size() == 0) + return; + + double maxEnergy = *std::max_element(pnEnergy.begin(), pnEnergy.end()); // criterion for being declared primary + for (int i = 0; i < pnEnergy.size(); ++i) { if (pnEnergy[i] == maxEnergy) { // nucleon is primary particle if (A == 1) { // single interacting nucleon From 22b0a286c601cac9549948339f04d2f30fa24ea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Fri, 10 May 2019 11:31:46 +0100 Subject: [PATCH 57/81] prevent production of photons with infinite energy --- src/module/HadronicInteraction.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/module/HadronicInteraction.cpp b/src/module/HadronicInteraction.cpp index 52077a57a..96de53285 100644 --- a/src/module/HadronicInteraction.cpp +++ b/src/module/HadronicInteraction.cpp @@ -341,8 +341,10 @@ void HadronicInteraction::process(Candidate *candidate) const { double y = random.rand() * Emax; if (y < E and (Etot + Eout) < Eprimary) { - if (havePhotons) - candidate->addSecondary(22, Eout, pos); + if (havePhotons) { + if (1. / Eout != 0.) // BUG: some photons are produced with infinite energy! + candidate->addSecondary(22, Eout, pos); + } Egamma += Eout; Etot += Eout; iTotal++; @@ -353,8 +355,10 @@ void HadronicInteraction::process(Candidate *candidate) const { } while (test == iGamma); } else { Eout = (Eprimary - Etot) / (Ntotal - end); - if (havePhotons) - candidate->addSecondary(22, Eout, pos); + if (havePhotons) { + if (1. / Eout != 0.) // BUG: some photons are produced with infinite energy! + candidate->addSecondary(22, Eout, pos); + } Egamma += Eout; iTotal++; iGamma++; From d06c29ec6e2abd021dfa9ed12fdd5ce3cdad98cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Mon, 13 May 2019 16:57:35 +0100 Subject: [PATCH 58/81] meet style criteria --- src/module/PhotoPionProduction.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 71eb13198..5be3fe1bd 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -124,14 +124,15 @@ void PhotoPionProduction::initHistogram(std::string filename) { throw std::runtime_error("PhotoPionProduction: Could not open file " + filename); std::string line; - while ( std::getline(infile, line) ) { + while (std::getline(infile, line)) { std::istringstream ss(line); std::string hash; ss >> hash; std::vector vec; double n; - while (ss >> n) vec.push_back(n); - // input.insert({ hash, vec }); // with C++11 + while (ss >> n) + vec.push_back(n); + // input.insert({hash, vec}); // with C++11 hashMap.push_back(hash); histData.push_back(vec); } @@ -148,13 +149,13 @@ std::string PhotoPionProduction::hashTag(int n, // nucleon type // method to generate hash tags for navigation in std::unordered_map std::stringstream hash; int exp = std::floor(log10(E)); - int pre = E/pow(10, exp); + int pre = E / pow(10, exp); hash << "#" << n << "_" << pre << "e"; (exp >= 0)? hash << "+" : hash << "-"; if (exp < 10) hash << "0"; hash << std::abs(exp) << "_"; exp = std::floor(log10(e)); - pre = e/pow(10, exp); + pre = e / pow(10, exp); hash << pre << "e"; (exp >= 0)? hash << "+" : hash << "-"; if (exp < 10) hash << "0"; @@ -178,7 +179,7 @@ int PhotoPionProduction::produce(const std::vector &particle) const { r -= particle[index]; index++; } - return index-1; + return index - 1; } @@ -193,7 +194,7 @@ double PhotoPionProduction::drawEnergy(const std::vector &data) const { std::vector p, E; for (int i = 0; i < data.size(); ++i) { p.push_back(data[i]); - E.push_back(data[i+data.size()/2]); + E.push_back(data[i + data.size() / 2]); } int pos = produce(p); if (pos == 0) @@ -201,7 +202,7 @@ double PhotoPionProduction::drawEnergy(const std::vector &data) const { // interpolation Random &random = Random::instance(); double r = random.rand(); - return E[pos-1]*(1.-r) + r*E[pos]; + return E[pos - 1] * (1. - r) + r * E[pos]; } @@ -211,7 +212,7 @@ double PhotoPionProduction::snapToHalfLog(double x) const { selects the closest value where histogram data is available */ int exp = std::floor(log10(x)); - double pre = x/pow(10, exp); + double pre = x / pow(10, exp); if (pre == 1.0) return x; double result = pow(10, std::ceil(log10(x))); @@ -392,7 +393,7 @@ std::vector PhotoPionProduction::sophiaEvent(bool onProton, // 0=p, 1=n double weight = E / (E - availableEnergy); int nOutPart = output.size(); for (int j = 0; j < nOutPart; ++j) { - output.push_back(outE[j]*weight); + output.push_back(outE[j] * weight); } return output; } From 9573b239f8cbab75aeb5fa0285339fa43b87ba48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Mon, 27 May 2019 10:50:46 +0100 Subject: [PATCH 59/81] implement warning when nucleon with E <= 0 is created --- src/module/HadronicInteraction.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/module/HadronicInteraction.cpp b/src/module/HadronicInteraction.cpp index 96de53285..135c225d3 100644 --- a/src/module/HadronicInteraction.cpp +++ b/src/module/HadronicInteraction.cpp @@ -247,7 +247,7 @@ void HadronicInteraction::process(Candidate *candidate) const { // Probability of interaction const double step = candidate->getCurrentStep(); - const double Eprimary = candidate->current.getEnergy(); + double Eprimary = candidate->current.getEnergy(); const double cs_inel = CrossSection_Kelner(Eprimary); Vector3d pos = candidate->current.getPosition(); @@ -502,7 +502,12 @@ void HadronicInteraction::process(Candidate *candidate) const { std::cout << end << " end != -1" << std::endl; // Reduce primary's energy - candidate->current.setEnergy(Eprimary - (EnuE + EnuMu2 + Eelectron + EnuMu1 + Egamma)); + Eprimary -= (EnuE + EnuMu2 + Eelectron + EnuMu1 + Egamma); + if (Eprimary <= 0.) { + std::cout << "warning: Eprimary = " << Eprimary << std::endl; + } else { + candidate->current.setEnergy(Eprimary); + } return; } From 72ffdf008ef2b74e3ca2e51a4fc67bb8dd8376c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Mon, 27 May 2019 10:57:17 +0100 Subject: [PATCH 60/81] deactivate faulty candidates with E <= 0 --- src/module/HadronicInteraction.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/module/HadronicInteraction.cpp b/src/module/HadronicInteraction.cpp index 135c225d3..94cb501d2 100644 --- a/src/module/HadronicInteraction.cpp +++ b/src/module/HadronicInteraction.cpp @@ -505,9 +505,9 @@ void HadronicInteraction::process(Candidate *candidate) const { Eprimary -= (EnuE + EnuMu2 + Eelectron + EnuMu1 + Egamma); if (Eprimary <= 0.) { std::cout << "warning: Eprimary = " << Eprimary << std::endl; - } else { - candidate->current.setEnergy(Eprimary); + candidate->setActive(false); } + candidate->current.setEnergy(Eprimary); return; } From 3e74ce02f3b838c1b20277bb96506fdf4afc5c62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Mon, 27 May 2019 11:03:16 +0100 Subject: [PATCH 61/81] update warning message --- src/module/HadronicInteraction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/module/HadronicInteraction.cpp b/src/module/HadronicInteraction.cpp index 94cb501d2..16929e321 100644 --- a/src/module/HadronicInteraction.cpp +++ b/src/module/HadronicInteraction.cpp @@ -504,7 +504,7 @@ void HadronicInteraction::process(Candidate *candidate) const { // Reduce primary's energy Eprimary -= (EnuE + EnuMu2 + Eelectron + EnuMu1 + Egamma); if (Eprimary <= 0.) { - std::cout << "warning: Eprimary = " << Eprimary << std::endl; + std::cout << "warning: Eprimary = " << Eprimary / GeV << " GeV" << std::endl; candidate->setActive(false); } candidate->current.setEnergy(Eprimary); From 9230f5263ef2653760b70e4040357907f0494a1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Mon, 27 May 2019 20:04:59 +0100 Subject: [PATCH 62/81] - add tag in TextPutput - add ability to tag secondaries in module --- include/crpropa/Candidate.h | 5 +++ include/crpropa/module/HadronicInteraction.h | 10 +++-- include/crpropa/module/Output.h | 3 +- include/crpropa/module/PhotoPionProduction.h | 2 + libs/sophia/sophia.version | 4 ++ src/Candidate.cpp | 46 +++++++++++++++++++- src/module/HadronicInteraction.cpp | 32 ++++++++------ src/module/PhotoPionProduction.cpp | 22 +++++----- src/module/TextOutput.cpp | 15 ++++++- 9 files changed, 109 insertions(+), 30 deletions(-) create mode 100644 libs/sophia/sophia.version diff --git a/include/crpropa/Candidate.h b/include/crpropa/Candidate.h index 43e08392e..1a8bb4849 100644 --- a/include/crpropa/Candidate.h +++ b/include/crpropa/Candidate.h @@ -46,6 +46,7 @@ class Candidate: public Referenced { double trajectoryLength; /**< Comoving distance [m] the candidate has traveled so far */ double currentStep; /**< Size of the currently performed step in [m] comoving units */ double nextStep; /**< Proposed size of the next propagation step in [m] comoving units */ + std::string tag; /**< Information about the process of creation, if any*/ static uint64_t nextSerialNumber; uint64_t serialNumber; @@ -96,6 +97,8 @@ class Candidate: public Referenced { void setNextStep(double step); double getNextStep() const; + void setTag(std::string tag); + std::string getTag() const; /** Make a bid for the next step size: the lowest wins. */ @@ -119,7 +122,9 @@ class Candidate: public Referenced { void addSecondary(Candidate *c); inline void addSecondary(ref_ptr c) { addSecondary(c.get()); }; void addSecondary(int id, double energy, double weight = 1); + void addSecondary(int id, double energy, std::string tag, double weight = 1); void addSecondary(int id, double energy, Vector3d position, double weight = 1); + void addSecondary(int id, double energy, Vector3d position, std::string tag, double weight = 1); void clearSecondaries(); std::string getDescription() const; diff --git a/include/crpropa/module/HadronicInteraction.h b/include/crpropa/module/HadronicInteraction.h index f1eb3b6e9..263c797de 100644 --- a/include/crpropa/module/HadronicInteraction.h +++ b/include/crpropa/module/HadronicInteraction.h @@ -23,27 +23,31 @@ class HadronicInteraction: public Module { bool haveElectrons; bool havePhotons; bool haveNeutrinos; + std::string tag; public: HadronicInteraction( double massDensity, bool electrons = false, bool photons = false, - bool neutrinos = false); + bool neutrinos = false, + std::string tag = "None"); HadronicInteraction( double massDensity, ScalarGrid4d spaceTimeGrid, bool electrons = false, bool photons = false, - bool neutrinos = false); + bool neutrinos = false, + std::string tag = "None"); HadronicInteraction( double massDensity, ScalarGrid spaceGrid, bool electrons = false, bool photons = false, - bool neutrinos = false); + bool neutrinos = false, + std::string = "None"); void setMassDensity(double dens); void setHaveElectrons(bool b); diff --git a/include/crpropa/module/Output.h b/include/crpropa/module/Output.h index 80ff332d2..df2bf0540 100644 --- a/include/crpropa/module/Output.h +++ b/include/crpropa/module/Output.h @@ -50,7 +50,8 @@ class Output: public Module { CreatedPositionColumn, CreatedDirectionColumn, SerialNumberColumn, - WeightColumn + WeightColumn, + TagColumn }; enum OutputType { Trajectory1D, diff --git a/include/crpropa/module/PhotoPionProduction.h b/include/crpropa/module/PhotoPionProduction.h index fccac6332..c5e347cb0 100644 --- a/include/crpropa/module/PhotoPionProduction.h +++ b/include/crpropa/module/PhotoPionProduction.h @@ -36,6 +36,7 @@ class PhotoPionProduction: public Module { bool haveNeutrinos; bool haveElectrons; bool haveAntiNucleons; + std::string tag; bool useTabulatedData; public: @@ -46,6 +47,7 @@ class PhotoPionProduction: public Module { bool neutrinos = false, bool electrons = false, bool antiNucleons = false, + std::string tag = "None", bool useTabulatedData = false, double limit = 0.1); void setPhotonField(PhotonField photonField); diff --git a/libs/sophia/sophia.version b/libs/sophia/sophia.version new file mode 100644 index 000000000..f445aaf40 --- /dev/null +++ b/libs/sophia/sophia.version @@ -0,0 +1,4 @@ +SOPHIA { + global: sophiaevent_; + local: *; +} \ No newline at end of file diff --git a/src/Candidate.cpp b/src/Candidate.cpp index d9a6c6d20..0083c39de 100644 --- a/src/Candidate.cpp +++ b/src/Candidate.cpp @@ -7,12 +7,13 @@ namespace crpropa { Candidate::Candidate(int id, double E, Vector3d pos, Vector3d dir, double z, double weight) : - redshift(z), trajectoryLength(0), weight(1), currentStep(0), nextStep(0), active(true), parent(0) { + redshift(z), trajectoryLength(0), weight(1), tag("None"), currentStep(0), nextStep(0), active(true), parent(0) { ParticleState state(id, E, pos, dir); source = state; created = state; previous = state; current = state; + tag = "None"; #if defined(OPENMP_3_1) #pragma omp atomic capture @@ -69,6 +70,10 @@ double Candidate::getNextStep() const { return nextStep; } +std::string Candidate::getTag() const { + return tag; +} + void Candidate::setRedshift(double z) { redshift = z; } @@ -90,6 +95,10 @@ void Candidate::setNextStep(double step) { nextStep = step; } +void Candidate::setTag(std::string info) { + tag = info.append(" "); +} + void Candidate::limitNextStep(double step) { nextStep = std::min(nextStep, step); } @@ -139,6 +148,22 @@ void Candidate::addSecondary(int id, double energy, double weight) { secondaries.push_back(secondary); } +void Candidate::addSecondary(int id, double energy, std::string tag, double weight) { + ref_ptr secondary = new Candidate; + secondary->setRedshift(redshift); + secondary->setTrajectoryLength(trajectoryLength); + secondary->setWeight(weight); + secondary->setTag(tag); + secondary->source = source; + secondary->previous = previous; + secondary->created = previous; + secondary->current = current; + secondary->current.setId(id); + secondary->current.setEnergy(energy); + secondary->parent = this; + secondaries.push_back(secondary); +} + void Candidate::addSecondary(int id, double energy, Vector3d position, double weight) { ref_ptr secondary = new Candidate; secondary->setRedshift(redshift); @@ -156,6 +181,24 @@ void Candidate::addSecondary(int id, double energy, Vector3d position, double we secondaries.push_back(secondary); } +void Candidate::addSecondary(int id, double energy, Vector3d position, std::string tag, double weight) { + ref_ptr secondary = new Candidate; + secondary->setRedshift(redshift); + secondary->setTrajectoryLength(trajectoryLength - (current.getPosition() - position).getR() ); + secondary->setWeight(weight); + secondary->setTag(tag); + secondary->source = source; + secondary->previous = previous; + secondary->created = previous; + secondary->current = current; + secondary->current.setId(id); + secondary->current.setEnergy(energy); + secondary->current.setPosition(position); + secondary->created.setPosition(position); + secondary->parent = this; + secondaries.push_back(secondary); +} + void Candidate::clearSecondaries() { secondaries.clear(); } @@ -182,6 +225,7 @@ ref_ptr Candidate::clone(bool recursive) const { cloned->trajectoryLength = trajectoryLength; cloned->currentStep = currentStep; cloned->nextStep = nextStep; + cloned->tag = tag; if (recursive) { cloned->secondaries.reserve(secondaries.size()); for (size_t i = 0; i < secondaries.size(); i++) { diff --git a/src/module/HadronicInteraction.cpp b/src/module/HadronicInteraction.cpp index 16929e321..fe84030ec 100644 --- a/src/module/HadronicInteraction.cpp +++ b/src/module/HadronicInteraction.cpp @@ -15,13 +15,15 @@ namespace crpropa { HadronicInteraction::HadronicInteraction(double massDensity, bool electrons, bool photons, - bool neutrinos) { + bool neutrinos, + std::string tag) { setMassDensity(massDensity); this->spaceTimeGrid = ScalarGrid4d(); this->spaceGrid = ScalarGrid(); setHaveElectrons(electrons); setHavePhotons(photons); setHaveNeutrinos(neutrinos); + this->tag = tag; setDescription("HadronicInteraction_isotropicConstant"); } @@ -29,13 +31,15 @@ HadronicInteraction::HadronicInteraction(double massDensity, ScalarGrid4d spaceTimeGrid, bool electrons, bool photons, - bool neutrinos) { + bool neutrinos, + std::string tag) { setMassDensity(massDensity); this->spaceTimeGrid = spaceTimeGrid; this->spaceGrid = ScalarGrid(); setHaveElectrons(electrons); setHavePhotons(photons); setHaveNeutrinos(neutrinos); + this->tag = tag; setDescription("HadronicInteraction_spaceTimeDependent"); } @@ -43,13 +47,15 @@ HadronicInteraction::HadronicInteraction(double massDensity, ScalarGrid spaceGrid, bool electrons, bool photons, - bool neutrinos) { + bool neutrinos, + std::string tag) { setMassDensity(massDensity); this->spaceTimeGrid = ScalarGrid4d(); this->spaceGrid = spaceGrid; setHaveElectrons(electrons); setHavePhotons(photons); setHaveNeutrinos(neutrinos); + this->tag = tag; setDescription("HadronicInteraction_spaceDependentConstant"); } @@ -343,7 +349,7 @@ void HadronicInteraction::process(Candidate *candidate) const { if (y < E and (Etot + Eout) < Eprimary) { if (havePhotons) { if (1. / Eout != 0.) // BUG: some photons are produced with infinite energy! - candidate->addSecondary(22, Eout, pos); + candidate->addSecondary(22, Eout, pos, tag); } Egamma += Eout; Etot += Eout; @@ -357,7 +363,7 @@ void HadronicInteraction::process(Candidate *candidate) const { Eout = (Eprimary - Etot) / (Ntotal - end); if (havePhotons) { if (1. / Eout != 0.) // BUG: some photons are produced with infinite energy! - candidate->addSecondary(22, Eout, pos); + candidate->addSecondary(22, Eout, pos, tag); } Egamma += Eout; iTotal++; @@ -379,7 +385,7 @@ void HadronicInteraction::process(Candidate *candidate) const { double y = random.rand() * Emax; if (y < E and (Etot + Eout) < Eprimary) { if (haveNeutrinos) - candidate->addSecondary(14, Eout, pos); + candidate->addSecondary(14, Eout, pos, tag); EnuMu1 += Eout; Etot += Eout; iTotal++; @@ -391,7 +397,7 @@ void HadronicInteraction::process(Candidate *candidate) const { } else { Eout = (Eprimary - Etot) / (Ntotal - end); if (haveNeutrinos) - candidate->addSecondary(14, Eout, pos); + candidate->addSecondary(14, Eout, pos, tag); EnuMu1 += Eout; iTotal++; iNuMu1++; @@ -412,7 +418,7 @@ void HadronicInteraction::process(Candidate *candidate) const { double y = random.rand() * Emax; if (y < E and (Etot + Eout) < Eprimary) { if (haveElectrons) - candidate->addSecondary(11, Eout, pos); + candidate->addSecondary(11, Eout, pos, tag); Etot += Eout; Eelectron += Eout; iTotal++; @@ -424,7 +430,7 @@ void HadronicInteraction::process(Candidate *candidate) const { } else { Eout = (Eprimary - Etot) / (Ntotal - end); if (haveElectrons) - candidate->addSecondary(11, Eout, pos); + candidate->addSecondary(11, Eout, pos, tag); iTotal++; iElectron++; Eelectron += Eout; @@ -445,7 +451,7 @@ void HadronicInteraction::process(Candidate *candidate) const { double y = random.rand() * Emax; if (y < E and (Etot + Eout) < Eprimary) { if (haveNeutrinos) - candidate->addSecondary(12, Eout, pos); + candidate->addSecondary(12, Eout, pos, tag); EnuE += Eout; Etot += Eout; iTotal++; @@ -457,7 +463,7 @@ void HadronicInteraction::process(Candidate *candidate) const { } else { Eout = (Eprimary - Etot) / (Ntotal - end); if (haveNeutrinos) - candidate->addSecondary(12, Eout, pos); + candidate->addSecondary(12, Eout, pos, tag); iTotal++; iNuE++; EnuE += Eout; @@ -478,7 +484,7 @@ void HadronicInteraction::process(Candidate *candidate) const { double y = random.rand() * Emax; if (y < E and (Etot + Eout) < Eprimary) { if (haveNeutrinos) - candidate->addSecondary(14, Eout, pos); + candidate->addSecondary(14, Eout, pos, tag); EnuMu2 += Eout; Etot += Eout; iTotal++; @@ -490,7 +496,7 @@ void HadronicInteraction::process(Candidate *candidate) const { } else { Eout = (Eprimary - Etot) / (Ntotal - end); if (haveNeutrinos) - candidate->addSecondary(14, Eout, pos); + candidate->addSecondary(14, Eout, pos, tag); iTotal++; iNuMu2++; EnuMu2 += Eout; diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 5be3fe1bd..1bc58f25c 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -23,12 +23,14 @@ PhotoPionProduction::PhotoPionProduction( PhotonField field, bool neutrinos, bool electrons, bool antiNucleons, + std::string tag, bool useTabData, double l) { havePhotons = photons; haveNeutrinos = neutrinos; haveElectrons = electrons; haveAntiNucleons = antiNucleons; + this-> tag = tag; useTabulatedData = useTabData; limit = l; setPhotonField(field); @@ -539,7 +541,7 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, bool onProton if (haveAntiNucleons) try { - candidate->addSecondary(-sign * nucleusId(1, 14 + pType), Eout, pos); + candidate->addSecondary(-sign * nucleusId(1, 14 + pType), Eout, pos, tag); } catch (std::runtime_error &e) { @@ -549,31 +551,31 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, bool onProton break; case 1: // photon if (havePhotons) - candidate->addSecondary(22, Eout, pos); + candidate->addSecondary(22, Eout, pos, tag); break; case 2: // positron if (haveElectrons) - candidate->addSecondary(sign * -11, Eout, pos); + candidate->addSecondary(sign * -11, Eout, pos, tag); break; case 3: // electron if (haveElectrons) - candidate->addSecondary(sign * 11, Eout, pos); + candidate->addSecondary(sign * 11, Eout, pos, tag); break; case 15: // nu_e if (haveNeutrinos) - candidate->addSecondary(sign * 12, Eout, pos); + candidate->addSecondary(sign * 12, Eout, pos, tag); break; case 16: // antinu_e if (haveNeutrinos) - candidate->addSecondary(sign * -12, Eout, pos); + candidate->addSecondary(sign * -12, Eout, pos, tag); break; case 17: // nu_muon if (haveNeutrinos) - candidate->addSecondary(sign * 14, Eout, pos); + candidate->addSecondary(sign * 14, Eout, pos, tag); break; case 18: // antinu_muon if (haveNeutrinos) - candidate->addSecondary(sign * -14, Eout, pos); + candidate->addSecondary(sign * -14, Eout, pos, tag); break; default: throw std::runtime_error("PhotoPionProduction: unexpected particle " + kiss::str(pType)); @@ -605,7 +607,7 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, bool onProton try { candidate->current.setId(sign * nucleusId(A - 1, Z - int(onProton))); - candidate->addSecondary(sign * nucleusId(1, 14 - pnType[i]), pnEnergy[i], pos); + candidate->addSecondary(sign * nucleusId(1, 14 - pnType[i]), pnEnergy[i], pos, tag); } catch (std::runtime_error &e) { @@ -614,7 +616,7 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, bool onProton } } } else { // nucleon is secondary proton or neutron - candidate->addSecondary(sign * nucleusId(1, 14 - pnType[i]), pnEnergy[i], pos); + candidate->addSecondary(sign * nucleusId(1, 14 - pnType[i]), pnEnergy[i], pos, tag); } } } diff --git a/src/module/TextOutput.cpp b/src/module/TextOutput.cpp index a267b449d..21e1dfa76 100644 --- a/src/module/TextOutput.cpp +++ b/src/module/TextOutput.cpp @@ -94,6 +94,8 @@ void TextOutput::printHeader() const { *out << "\tP1x\tP1y\tP1z"; if (fields.test(WeightColumn)) *out << "\tW"; + if (fields.test(TagColumn)) + *out << "\tTag"; for(std::vector::const_iterator iter = properties.begin(); iter != properties.end(); ++iter) { @@ -123,6 +125,8 @@ void TextOutput::printHeader() const { *out << "# Px/P0x/P1x... Heading (unit vector of momentum)\n"; if (fields.test(WeightColumn)) *out << "# W Weights" << " \n"; + if (fields.test(TagColumn)) + *out << "# Tag\n"; for(std::vector::const_iterator iter = properties.begin(); iter != properties.end(); ++iter) { @@ -243,6 +247,11 @@ void TextOutput::process(Candidate *c) const { if (fields.test(WeightColumn)) { p += std::sprintf(buffer + p, "%8.5E\t", c->getWeight()); } + if (fields.test(TagColumn)) { + const std::string tag = c->getTag(); + const char *cstr = tag.c_str(); + p += std::sprintf(buffer + p, "%s", cstr); + } for(std::vector::const_iterator iter = properties.begin(); iter != properties.end(); ++iter) @@ -300,7 +309,7 @@ void TextOutput::load(const std::string &filename, ParticleCollector *collector) continue; ref_ptr c = new Candidate(); - double val_d; int val_i; + double val_d; int val_i; std::string tag; double x, y, z; stream >> val_d; c->setTrajectoryLength(val_d*lengthScale); // D @@ -335,7 +344,9 @@ void TextOutput::load(const std::string &filename, ParticleCollector *collector) stream >> x >> y >> z; c->created.setDirection(Vector3d(x, y, z)*lengthScale); // P1x, P1y, P1z stream >> val_d; - c->setWeight(val_d); // W + c->setWeight(val_d); // Weights + stream >> tag; + c->setTag(tag); // Tag collector->process(c); } From b072679d217e25eb973008c28ae0d64d584abbe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Mon, 27 May 2019 20:06:27 +0100 Subject: [PATCH 63/81] delete file --- libs/sophia/sophia.version | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 libs/sophia/sophia.version diff --git a/libs/sophia/sophia.version b/libs/sophia/sophia.version deleted file mode 100644 index f445aaf40..000000000 --- a/libs/sophia/sophia.version +++ /dev/null @@ -1,4 +0,0 @@ -SOPHIA { - global: sophiaevent_; - local: *; -} \ No newline at end of file From 1abd01cfdffcbcacbb48a11f87d0768cc68ad28a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Wed, 29 May 2019 12:35:44 +0100 Subject: [PATCH 64/81] implement overload of PhotoPionProduction for easy grid use --- include/crpropa/module/PhotoPionProduction.h | 29 ++++++++- src/module/PhotoPionProduction.cpp | 65 ++++++++++++++++++-- test/testInteraction.cpp | 10 +-- 3 files changed, 92 insertions(+), 12 deletions(-) diff --git a/include/crpropa/module/PhotoPionProduction.h b/include/crpropa/module/PhotoPionProduction.h index c5e347cb0..fc4169a64 100644 --- a/include/crpropa/module/PhotoPionProduction.h +++ b/include/crpropa/module/PhotoPionProduction.h @@ -22,7 +22,8 @@ namespace crpropa { class PhotoPionProduction: public Module { protected: PhotonField photonField; - ScalarGrid4d geometryGrid; + ScalarGrid4d spaceTimeGrid; + ScalarGrid spaceGrid; CustomPhotonField customPhotonField; std::vector hashMap; // contains histogram hashtags (workaround until c++11) std::vector< std::vector > histData; // contains histogram data (workaround until c++11) @@ -41,8 +42,7 @@ class PhotoPionProduction: public Module { public: PhotoPionProduction( - PhotonField photonField = CMB, - ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.), + PhotonField photonField, bool photons = false, bool neutrinos = false, bool electrons = false, @@ -50,6 +50,29 @@ class PhotoPionProduction: public Module { std::string tag = "None", bool useTabulatedData = false, double limit = 0.1); + + PhotoPionProduction( + PhotonField photonField, + ScalarGrid4d spaceTimeGrid, + bool photons = false, + bool neutrinos = false, + bool electrons = false, + bool antiNucleons = false, + std::string tag = "None", + bool useTabulatedData = false, + double limit = 0.1); + + PhotoPionProduction( + PhotonField photonField, + ScalarGrid spaceGrid, + bool photons = false, + bool neutrinos = false, + bool electrons = false, + bool antiNucleons = false, + std::string tag = "None", + bool useTabulatedData = false, + double limit = 0.1); + void setPhotonField(PhotonField photonField); void setHavePhotons(bool b); void setHaveNeutrinos(bool b); diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 1bc58f25c..77e623000 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -18,7 +18,6 @@ namespace crpropa { PhotoPionProduction::PhotoPionProduction( PhotonField field, - ScalarGrid4d geometryGrid, bool photons, bool neutrinos, bool electrons, @@ -26,25 +25,73 @@ PhotoPionProduction::PhotoPionProduction( PhotonField field, std::string tag, bool useTabData, double l) { + setPhotonField(field); + this->customPhotonField = CustomPhotonField(getDataPath("Scaling/" + photonFieldName(field) + ".txt")); + this->spaceTimeGrid = ScalarGrid4d(); + this->spaceGrid = ScalarGrid(); havePhotons = photons; haveNeutrinos = neutrinos; haveElectrons = electrons; haveAntiNucleons = antiNucleons; this-> tag = tag; useTabulatedData = useTabData; + if (useTabData) initHistogram(getDataPath("PhotoPionProduction/SOPHIA_histogram.txt")); limit = l; + setDescription("PhotoPionProduction_isotropicConstant"); +} + +PhotoPionProduction::PhotoPionProduction( PhotonField field, + ScalarGrid4d spaceTimeGrid, + bool photons, + bool neutrinos, + bool electrons, + bool antiNucleons, + std::string tag, + bool useTabData, + double l) { setPhotonField(field); - this->geometryGrid = geometryGrid; this->customPhotonField = CustomPhotonField(getDataPath("Scaling/" + photonFieldName(field) + ".txt")); + this->spaceTimeGrid = spaceTimeGrid; + this->spaceGrid = ScalarGrid(); + havePhotons = photons; + haveNeutrinos = neutrinos; + haveElectrons = electrons; + haveAntiNucleons = antiNucleons; + this-> tag = tag; + useTabulatedData = useTabData; if (useTabData) initHistogram(getDataPath("PhotoPionProduction/SOPHIA_histogram.txt")); + limit = l; + setDescription("PhotoPionProduction_spaceDependentConstant"); } +PhotoPionProduction::PhotoPionProduction( PhotonField field, + ScalarGrid spaceGrid, + bool photons, + bool neutrinos, + bool electrons, + bool antiNucleons, + std::string tag, + bool useTabData, + double l) { + setPhotonField(field); + this->customPhotonField = CustomPhotonField(getDataPath("Scaling/" + photonFieldName(field) + ".txt")); + this->spaceTimeGrid = ScalarGrid4d(); + this->spaceGrid = spaceGrid; + havePhotons = photons; + haveNeutrinos = neutrinos; + haveElectrons = electrons; + haveAntiNucleons = antiNucleons; + this-> tag = tag; + useTabulatedData = useTabData; + if (useTabData) initHistogram(getDataPath("PhotoPionProduction/SOPHIA_histogram.txt")); + limit = l; +} void PhotoPionProduction::setPhotonField(PhotonField field) { photonField = field; std::string fname = photonFieldName(field); - setDescription("PhotoPionProduction: " + fname); initRate(getDataPath("PhotoPionProduction/rate_" + fname + ".txt")); + this->customPhotonField = CustomPhotonField(getDataPath("Scaling/" + photonFieldName(field) + ".txt")); } void PhotoPionProduction::setHavePhotons(bool b) { @@ -410,7 +457,17 @@ double PhotoPionProduction::nucleonMFP(double gamma, double z, bool onProton, Ve return std::numeric_limits::max(); // geometric scaling - double rate = geometryGrid.interpolate(pos, time); + double rate = 1.; + const std::string description = getDescription(); + if (description == "PhotoPionProduction_isotropicConstant") { + // do nothing, just check for correct initialization + } else if (description == "PhotoPionProduction_spaceDependentConstant") { + rate *= spaceGrid.interpolate(pos); + } else if (description == "PhotoPionProduction_spaceTimeDependent") { + rate *= spaceTimeGrid.interpolate(pos, time); + } else { + throw std::runtime_error("PhotoPionProduction: invalid description string"); + } if (rate == 0.) return std::numeric_limits::max(); diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 0fef3b625..e52d16467 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -458,7 +458,7 @@ TEST(ElasticScattering, secondaries) { // PhotoPionProduction -------------------------------------------------------- TEST(PhotoPionProduction, allBackgrounds) { // Test if all interaction data files can be loaded. - PhotoPionProduction ppp; + PhotoPionProduction ppp(CMB); ppp.setPhotonField(IRB_Kneiske04); ppp.setPhotonField(IRB_Stecker05); ppp.setPhotonField(IRB_Franceschini08); @@ -473,7 +473,7 @@ TEST(PhotoPionProduction, allBackgrounds) { TEST(PhotoPionProduction, proton) { // Test photo-pion interaction for 100 EeV proton. // This test can stochastically fail. - PhotoPionProduction ppp; + PhotoPionProduction ppp(CMB); Candidate c(nucleusId(1, 1), 100 * EeV); c.setCurrentStep(1000 * Mpc); ppp.process(&c); @@ -491,7 +491,7 @@ TEST(PhotoPionProduction, proton) { TEST(PhotoPionProduction, helium) { // Test photo-pion interaction for 400 EeV He nucleus. // This test can stochastically fail. - PhotoPionProduction ppp; + PhotoPionProduction ppp(CMB); Candidate c; c.current.setId(nucleusId(4, 2)); c.current.setEnergy(400 * EeV); @@ -505,7 +505,7 @@ TEST(PhotoPionProduction, helium) { TEST(PhotoPionProduction, thisIsNotNucleonic) { // Test if noting happens to an electron. - PhotoPionProduction ppp; + PhotoPionProduction ppp(CMB); Candidate c; c.current.setId(11); // electron c.current.setEnergy(10 * EeV); @@ -517,7 +517,7 @@ TEST(PhotoPionProduction, thisIsNotNucleonic) { TEST(PhotoPionProduction, limitNextStep) { // Test if the interaction limits the next propagation step. - PhotoPionProduction ppp; + PhotoPionProduction ppp(CMB); Candidate c(nucleusId(1, 1), 200 * EeV); c.setNextStep(std::numeric_limits::max()); ppp.process(&c); From ce54caae857d06237c7a453589c578f53f2293e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 11 Jun 2019 00:11:37 +0100 Subject: [PATCH 65/81] fix description string --- src/module/PhotoPionProduction.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 77e623000..ed7b8a760 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -61,7 +61,7 @@ PhotoPionProduction::PhotoPionProduction( PhotonField field, useTabulatedData = useTabData; if (useTabData) initHistogram(getDataPath("PhotoPionProduction/SOPHIA_histogram.txt")); limit = l; - setDescription("PhotoPionProduction_spaceDependentConstant"); + setDescription("PhotoPionProduction_spaceTimeDependent"); } PhotoPionProduction::PhotoPionProduction( PhotonField field, @@ -85,6 +85,7 @@ PhotoPionProduction::PhotoPionProduction( PhotonField field, useTabulatedData = useTabData; if (useTabData) initHistogram(getDataPath("PhotoPionProduction/SOPHIA_histogram.txt")); limit = l; + setDescription("PhotoPionProduction_spaceDependentConstant"); } void PhotoPionProduction::setPhotonField(PhotonField field) { From fdbca2756722f50dbd3188024781989431d9cf13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Thu, 13 Jun 2019 08:12:11 +0100 Subject: [PATCH 66/81] update tag option --- include/crpropa/module/HadronicInteraction.h | 6 +++--- include/crpropa/module/PhotoPionProduction.h | 6 +++--- src/module/PhotoPionProduction.cpp | 5 +++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/crpropa/module/HadronicInteraction.h b/include/crpropa/module/HadronicInteraction.h index 263c797de..4c475508a 100644 --- a/include/crpropa/module/HadronicInteraction.h +++ b/include/crpropa/module/HadronicInteraction.h @@ -31,7 +31,7 @@ class HadronicInteraction: public Module { bool electrons = false, bool photons = false, bool neutrinos = false, - std::string tag = "None"); + std::string tag = "HadrInt"); HadronicInteraction( double massDensity, @@ -39,7 +39,7 @@ class HadronicInteraction: public Module { bool electrons = false, bool photons = false, bool neutrinos = false, - std::string tag = "None"); + std::string tag = "HadrInt"); HadronicInteraction( double massDensity, @@ -47,7 +47,7 @@ class HadronicInteraction: public Module { bool electrons = false, bool photons = false, bool neutrinos = false, - std::string = "None"); + std::string tag = "HadrInt"); void setMassDensity(double dens); void setHaveElectrons(bool b); diff --git a/include/crpropa/module/PhotoPionProduction.h b/include/crpropa/module/PhotoPionProduction.h index fc4169a64..2caabeb59 100644 --- a/include/crpropa/module/PhotoPionProduction.h +++ b/include/crpropa/module/PhotoPionProduction.h @@ -47,7 +47,7 @@ class PhotoPionProduction: public Module { bool neutrinos = false, bool electrons = false, bool antiNucleons = false, - std::string tag = "None", + std::string tag = "PPP", bool useTabulatedData = false, double limit = 0.1); @@ -58,7 +58,7 @@ class PhotoPionProduction: public Module { bool neutrinos = false, bool electrons = false, bool antiNucleons = false, - std::string tag = "None", + std::string tag = "PPP", bool useTabulatedData = false, double limit = 0.1); @@ -69,7 +69,7 @@ class PhotoPionProduction: public Module { bool neutrinos = false, bool electrons = false, bool antiNucleons = false, - std::string tag = "None", + std::string tag = "PPP", bool useTabulatedData = false, double limit = 0.1); diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index ed7b8a760..990ffd2f8 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -33,7 +33,7 @@ PhotoPionProduction::PhotoPionProduction( PhotonField field, haveNeutrinos = neutrinos; haveElectrons = electrons; haveAntiNucleons = antiNucleons; - this-> tag = tag; + this->tag = tag; useTabulatedData = useTabData; if (useTabData) initHistogram(getDataPath("PhotoPionProduction/SOPHIA_histogram.txt")); limit = l; @@ -558,8 +558,9 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, bool onProton // SOPHIA - input: int nature = 1 - static_cast(onProton); // 0=proton, 1=neutron double Ein = EpA / GeV; + // std::cout << "b "; double eps = customPhotonField.sampleEps(onProton, Ein, z); - + // std::cout << eps << " "; // SOPHIA - output: double outputEnergy[2000]; int outPartID[2000]; From e7e8996017a531871aeacd5b8aad94cff44f6ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Thu, 13 Jun 2019 08:13:37 +0100 Subject: [PATCH 67/81] overload function for non-gridded initializations --- include/crpropa/module/EMPairProduction.h | 27 ++++++- src/module/EMPairProduction.cpp | 93 +++++++++++++++++------ 2 files changed, 91 insertions(+), 29 deletions(-) diff --git a/include/crpropa/module/EMPairProduction.h b/include/crpropa/module/EMPairProduction.h index b51d53680..a604c315a 100644 --- a/include/crpropa/module/EMPairProduction.h +++ b/include/crpropa/module/EMPairProduction.h @@ -19,8 +19,11 @@ namespace crpropa { class EMPairProduction: public Module { private: PhotonField photonField; - ScalarGrid4d geometryGrid; + ScalarGrid4d spaceTimeGrid; + ScalarGrid spaceGrid; + bool haveElectrons; + std::string tag; double limit; // tabulated interaction rate 1/lambda(E) @@ -34,11 +37,27 @@ class EMPairProduction: public Module { public: EMPairProduction( - PhotonField photonField = CMB, //!< target photon background - ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.), + PhotonField photonField, //!< target photon background + bool haveElectrons = false, //!< switch to create secondary electron pair + std::string tag = "EMPP", + double limit = 0.1 //!< step size limit as fraction of mean free path + ); + + EMPairProduction( + PhotonField photonField, //!< target photon background + ScalarGrid4d spaceTimeGrid, + bool haveElectrons = false, //!< switch to create secondary electron pair + std::string tag = "EMPP", + double limit = 0.1 //!< step size limit as fraction of mean free path + ); + + EMPairProduction( + PhotonField photonField, //!< target photon background + ScalarGrid spaceGrid, bool haveElectrons = false, //!< switch to create secondary electron pair + std::string tag = "EMPP", double limit = 0.1 //!< step size limit as fraction of mean free path - ); + ); void setPhotonField(PhotonField photonField); void setHaveElectrons(bool haveElectrons); diff --git a/src/module/EMPairProduction.cpp b/src/module/EMPairProduction.cpp index 9cb571754..c43c44345 100644 --- a/src/module/EMPairProduction.cpp +++ b/src/module/EMPairProduction.cpp @@ -12,18 +12,46 @@ namespace crpropa { static const double mec2 = mass_electron * c_squared; EMPairProduction::EMPairProduction(PhotonField photonField, - ScalarGrid4d geometryGrid, bool haveElectrons, + std::string tag, double limit) : haveElectrons(haveElectrons), limit(limit) { setPhotonField(photonField); - this->geometryGrid = geometryGrid; + this->spaceTimeGrid = ScalarGrid4d(); + this->spaceGrid = ScalarGrid(); + this->tag = tag; + setDescription("EMPairProduction_isotropicConstant"); +} + +EMPairProduction::EMPairProduction(PhotonField photonField, + ScalarGrid4d spaceTimeGrid, + bool haveElectrons, + std::string tag, + double limit) : haveElectrons(haveElectrons), + limit(limit) { + setPhotonField(photonField); + this->spaceTimeGrid = spaceTimeGrid; + this->spaceGrid = ScalarGrid(); + this->tag = tag; + setDescription("EMPairProduction_spaceTimeDependent"); +} + +EMPairProduction::EMPairProduction(PhotonField photonField, + ScalarGrid spaceGrid, + bool haveElectrons, + std::string tag, + double limit) : haveElectrons(haveElectrons), + limit(limit) { + setPhotonField(photonField); + this->spaceTimeGrid = ScalarGrid4d(); + this->spaceGrid = spaceGrid; + this->tag = tag; + setDescription("EMPairProduction_spaceDependentConstant"); } void EMPairProduction::setPhotonField(PhotonField photonField) { this->photonField = photonField; std::string fname = photonFieldName(photonField); - setDescription("EMPairProduction: " + fname); initRate(getDataPath("EMPairProduction/rate_" + fname + ".txt")); initCumulativeRate(getDataPath("EMPairProduction/cdf_" + fname + ".txt")); } @@ -183,24 +211,30 @@ void EMPairProduction::performInteraction(Candidate *candidate) const { if (E < tabE.front() or (E > tabE.back())) return; + // geometric scaling + Vector3d pos = candidate->current.getPosition(); + double time = candidate->getTrajectoryLength()/c_light; + + double geometricScaling = 1.; + const std::string description = getDescription(); + if (description == "EMPairProduction_isotropicConstant") { + // do nothing, just check for correct initialization + } else if (description == "EMPairProduction_spaceDependentConstant") { + geometricScaling *= spaceGrid.interpolate(pos); + } else if (description == "EMPairProduction_spaceTimeDependent") { + geometricScaling *= spaceTimeGrid.interpolate(pos, time); + } else { + throw std::runtime_error("EMPairProduction: invalid description string"); + } + if (geometricScaling == 0.) + return; + // sample the value of s Random &random = Random::instance(); size_t i = closestIndex(E, tabE); // find closest tabulation point - - // geometric scaling - Vector3d pos = candidate->current.getPosition(); - double time = candidate->getTrajectoryLength()/c_light; - double geometricScaling = geometryGrid.interpolate(pos, time); - if (geometricScaling == 0.) - return; - - std::vector tabCDF_geoScaled; - for (int j = 0; j < tabCDF[i].size(); ++j) { - tabCDF_geoScaled.push_back(tabCDF[i][j]*geometricScaling); - } - size_t j = random.randBin(tabCDF_geoScaled); - double lo = std::max(4 * mec2 * mec2, tabs[j-1]); // first s-tabulation point below min(s_kin) = (2 me c^2)^2; ensure physical value - double hi = tabs[j]; + size_t j = random.randBin(tabCDF[i]); + double lo = std::max(4 * mec2 * mec2, tabs[j-1] * geometricScaling); // first s-tabulation point below min(s_kin) = (2 me c^2)^2; ensure physical value + double hi = tabs[j] * geometricScaling; double s = lo + random.rand() * (hi - lo); // sample electron / positron energy @@ -210,8 +244,8 @@ void EMPairProduction::performInteraction(Candidate *candidate) const { // sample random position along current step pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition()); - candidate->addSecondary(-11, Ee / (1 + z), pos); - candidate->addSecondary(11, Ep / (1 + z), pos); + candidate->addSecondary(-11, Ee / (1 + z), pos, tag); + candidate->addSecondary(11, Ep / (1 + z), pos, tag); } void EMPairProduction::process(Candidate *candidate) const { @@ -228,12 +262,21 @@ void EMPairProduction::process(Candidate *candidate) const { return; // interaction rate - // geometric scaling + double rate = 1.; Vector3d pos = candidate->current.getPosition(); - double time = candidate->getTrajectoryLength()/c_light; - double rate = geometryGrid.interpolate(pos, time); - if (rate == 0.) - return; + double time = candidate->getTrajectoryLength()/c_light; + const std::string description = getDescription(); + if (description == "EMPairProduction_isotropicConstant") { + // do nothing, just check for correct initialization + } else if (description == "EMPairProduction_spaceDependentConstant") { + rate *= spaceGrid.interpolate(pos); + } else if (description == "EMPairProduction_spaceTimeDependent") { + rate *= spaceTimeGrid.interpolate(pos, time); + } else { + throw std::runtime_error("EMPairProduction: invalid description string"); + } + if (rate == 0.) + return; rate *= interpolate(E, tabEnergy, tabRate); rate *= pow(1 + z, 2) * photonFieldScaling(photonField, z); From dfea6b024bdcdba33878d8012622bc46898264a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Thu, 13 Jun 2019 08:15:00 +0100 Subject: [PATCH 68/81] update EMPairProduction signature --- test/testInteraction.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index e52d16467..fdf4beaa9 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -565,7 +565,7 @@ TEST(Redshift, limitRedshiftDecrease) { // EMPairProduction ----------------------------------------------------------- TEST(EMPairProduction, limitNextStep) { // Test if the interaction limits the next propagation step. - EMPairProduction m; + EMPairProduction m(CMB); Candidate c(22, 1E17 * eV); c.setNextStep(std::numeric_limits::max()); m.process(&c); @@ -574,7 +574,7 @@ TEST(EMPairProduction, limitNextStep) { TEST(EMPairProduction, secondaries) { // Test if secondaries are correctly produced. - EMPairProduction m; + EMPairProduction m(CMB); m.setHaveElectrons(true); std::vector fields; From ebd10d55e980d7b83f1dc75c76f013e08230f8fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Thu, 13 Jun 2019 08:16:57 +0100 Subject: [PATCH 69/81] overload function for non-gridded initialization --- include/crpropa/module/ElasticScattering.h | 20 ++++++++-- src/module/ElasticScattering.cpp | 46 +++++++++++++++++----- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/include/crpropa/module/ElasticScattering.h b/include/crpropa/module/ElasticScattering.h index 0f641f632..1911236f8 100644 --- a/include/crpropa/module/ElasticScattering.h +++ b/include/crpropa/module/ElasticScattering.h @@ -15,7 +15,9 @@ namespace crpropa { class ElasticScattering: public Module { private: PhotonField photonField; - ScalarGrid4d geometryGrid; + ScalarGrid4d spaceTimeGrid; + ScalarGrid spaceGrid; + std::string tag; std::vector tabRate; // elastic scattering rate std::vector > tabCDF; // CDF as function of background photon energy @@ -28,8 +30,20 @@ class ElasticScattering: public Module { static const size_t neps; // number of eps steps public: - ElasticScattering(PhotonField photonField = CMB, - ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.) ); + ElasticScattering(PhotonField photonField, + std::string tag = "ElScatt" + ); + + ElasticScattering(PhotonField photonField, + ScalarGrid4d spaceTimeGrid, + std::string tag = "ElScatt" + ); + + ElasticScattering(PhotonField photonField, + ScalarGrid spaceGrid, + std::string tag = "ElScatt" + ); + void initRate(std::string filename); void initCDF(std::string filename); void setPhotonField(PhotonField photonField); diff --git a/src/module/ElasticScattering.cpp b/src/module/ElasticScattering.cpp index ef1ba9a4a..ddfd5f6fa 100644 --- a/src/module/ElasticScattering.cpp +++ b/src/module/ElasticScattering.cpp @@ -19,15 +19,33 @@ const double ElasticScattering::epsmin = log10(2 * eV) + 3; // log10 minimum const double ElasticScattering::epsmax = log10(2 * eV) + 8.12; // log10 maximum photon background energy in nucleus rest frame for elastic scattering const size_t ElasticScattering::neps = 513; // number of photon background energies in nucleus rest frame -ElasticScattering::ElasticScattering(PhotonField f, ScalarGrid4d geometryGrid) { +ElasticScattering::ElasticScattering(PhotonField f, std::string tag) { setPhotonField(f); - this->geometryGrid = geometryGrid; + this->spaceTimeGrid = ScalarGrid4d(); + this->spaceGrid = ScalarGrid(); + this->tag = tag; + setDescription("ElasticScattering_isotropicConstant"); +} + +ElasticScattering::ElasticScattering(PhotonField f, ScalarGrid4d spaceTimeGrid, std::string tag) { + setPhotonField(f); + this->spaceTimeGrid = spaceTimeGrid; + this->spaceGrid = ScalarGrid(); + this->tag = tag; + setDescription("ElasticScattering_spaceDependentConstant"); +} + +ElasticScattering::ElasticScattering(PhotonField f, ScalarGrid spaceGrid, std::string tag) { + setPhotonField(f); + this->spaceTimeGrid = ScalarGrid4d(); + this->spaceGrid = spaceGrid; + this->tag = tag; + setDescription("ElasticScattering_spaceTimeDependent"); } void ElasticScattering::setPhotonField(PhotonField photonField) { this->photonField = photonField; std::string fname = photonFieldName(photonField); - setDescription("ElasticScattering: " + fname); initRate(getDataPath("ElasticScattering/rate_" + fname.substr(0,3) + ".txt")); initCDF(getDataPath("ElasticScattering/cdf_" + fname.substr(0,3) + ".txt")); } @@ -99,12 +117,22 @@ void ElasticScattering::process(Candidate *candidate) const { double step = candidate->getCurrentStep(); while (step > 0) { - - // geometric scaling - double rate = geometryGrid.interpolate(pos, time); + double rate = 1.; + Vector3d pos = candidate->current.getPosition(); + double time = candidate->getTrajectoryLength()/c_light; + const std::string description = getDescription(); + if (description == "ElasticScattering_isotropicConstant") { + // do nothing, just check for correct initialization + } else if (description == "ElasticScattering_spaceDependentConstant") { + rate *= spaceGrid.interpolate(pos); + } else if (description == "ElasticScattering_spaceTimeDependent") { + rate *= spaceTimeGrid.interpolate(pos, time); + } else { + throw std::runtime_error("ElasticScattering: invalid description string"); + } if (rate == 0.) return; - + rate *= interpolateEquidistant(lg, lgmin, lgmax, tabRate); rate *= Z * N / double(A); // TRK scaling rate *= pow(1 + z, 2) * photonFieldScaling(photonField, z); // cosmological scaling @@ -125,8 +153,8 @@ void ElasticScattering::process(Candidate *candidate) const { double cosTheta = 2 * random.rand() - 1; double E = eps * candidate->current.getLorentzFactor() * (1. - cosTheta); - Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition()); - candidate->addSecondary(22, E, pos); + pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition()); + candidate->addSecondary(22, E, pos, tag); // repeat with remaining step step -= randDist; From 54d04e037d407af7f5b568dca77511edffc2ac72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Thu, 13 Jun 2019 17:53:37 +0100 Subject: [PATCH 70/81] improve sampling routine --- src/PhotonBackground.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/PhotonBackground.cpp b/src/PhotonBackground.cpp index 5689c75d7..d26b86ede 100644 --- a/src/PhotonBackground.cpp +++ b/src/PhotonBackground.cpp @@ -194,8 +194,15 @@ double CustomPhotonField::sampleEps(bool onProton, double Ein, double zIn) const double eps; double peps; Random &random = Random::instance(); + int nTrySample = 0; do { - eps = epsMin + random.rand() * (epsMax - epsMin); + nTrySample++; + if (nTrySample <= 10000) { + eps = epsMin + random.rand() * (epsMax - epsMin); + } else { + eps = log10(epsMin) + random.rand() * (log10(epsMax) - log10(epsMin)); + eps = pow(10, eps); + } peps = SOPHIA_probEps(eps, onProton, Ein, zIn) / cnorm; } while (random.rand() * pMax > peps); return eps; From cb453fdd2061750b03fa03df929bfb8702e1f532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Thu, 13 Jun 2019 17:53:57 +0100 Subject: [PATCH 71/81] update signatures --- test/testInteraction.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index fdf4beaa9..dc82c9e89 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -730,7 +730,7 @@ TEST(EMTripletPairProduction, secondaries) { // EMInverseComptonScattering ------------------------------------------------- TEST(EMInverseComptonScattering, limitNextStep) { // Test if the interaction limits the next propagation step. - EMInverseComptonScattering m; + EMInverseComptonScattering m(CMB); Candidate c(11, 1E17 * eV); c.setNextStep(std::numeric_limits::max()); m.process(&c); @@ -739,7 +739,7 @@ TEST(EMInverseComptonScattering, limitNextStep) { TEST(EMInverseComptonScattering, secondaries) { // Test if secondaries are correctly produced. - EMInverseComptonScattering m; + EMInverseComptonScattering m(CMB); m.setHavePhotons(true); std::vector fields; From 2a1eed784723bd27eb22ab005f215ced8650511f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Thu, 13 Jun 2019 17:54:07 +0100 Subject: [PATCH 72/81] ovoerload functions for improved handling --- .../module/EMInverseComptonScattering.h | 26 +++++-- src/module/EMInverseComptonScattering.cpp | 71 ++++++++++++++----- src/module/ElasticScattering.cpp | 3 +- 3 files changed, 78 insertions(+), 22 deletions(-) diff --git a/include/crpropa/module/EMInverseComptonScattering.h b/include/crpropa/module/EMInverseComptonScattering.h index ea874e7e7..0e22d0fc6 100644 --- a/include/crpropa/module/EMInverseComptonScattering.h +++ b/include/crpropa/module/EMInverseComptonScattering.h @@ -18,8 +18,10 @@ namespace crpropa { class EMInverseComptonScattering: public Module { private: PhotonField photonField; - ScalarGrid4d geometryGrid; + ScalarGrid4d spaceTimeGrid; + ScalarGrid spaceGrid; bool havePhotons; + std::string tag; double limit; // tabulated interaction rate 1/lambda(E) @@ -33,11 +35,27 @@ class EMInverseComptonScattering: public Module { public: EMInverseComptonScattering( - PhotonField photonField = CMB, //!< target photon background - ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.), + PhotonField photonField, //!< target photon background bool havePhotons = false, //!< switch to create secondary photon + std::string tag = "EMIC", double limit = 0.1 //!< step size limit as fraction of mean free path - ); + ); + + EMInverseComptonScattering( + PhotonField photonField, //!< target photon background + ScalarGrid4d spaceTimeGrid, + bool havePhotons = false, //!< switch to create secondary photon + std::string tag = "EMIC", + double limit = 0.1 //!< step size limit as fraction of mean free path + ); + + EMInverseComptonScattering( + PhotonField photonField, //!< target photon background + ScalarGrid spaceGrid, + bool havePhotons = false, //!< switch to create secondary photon + std::string tag = "EMIC", + double limit = 0.1 //!< step size limit as fraction of mean free path + ); void setPhotonField(PhotonField photonField); void setHavePhotons(bool havePhotons); diff --git a/src/module/EMInverseComptonScattering.cpp b/src/module/EMInverseComptonScattering.cpp index 465cd3898..022429a31 100644 --- a/src/module/EMInverseComptonScattering.cpp +++ b/src/module/EMInverseComptonScattering.cpp @@ -12,19 +12,49 @@ namespace crpropa { static const double mec2 = mass_electron * c_squared; EMInverseComptonScattering::EMInverseComptonScattering(PhotonField photonField, - ScalarGrid4d geometryGrid, bool havePhotons, + std::string tag, double limit) { setPhotonField(photonField); - this->geometryGrid = geometryGrid; + this->spaceTimeGrid = ScalarGrid4d(); + this->spaceGrid = ScalarGrid(); this->havePhotons = havePhotons; + this->tag = tag; this->limit = limit; + setDescription("EMInverseComptonScattering_isotropicConstant"); +} + +EMInverseComptonScattering::EMInverseComptonScattering(PhotonField photonField, + ScalarGrid4d spaceTimeGrid, + bool havePhotons, + std::string tag, + double limit) { + setPhotonField(photonField); + this->spaceTimeGrid = spaceTimeGrid; + this->spaceGrid = ScalarGrid(); + this->havePhotons = havePhotons; + this->tag = tag; + this->limit = limit; + setDescription("EMInverseComptonScattering_spaceTimeDependent"); +} + +EMInverseComptonScattering::EMInverseComptonScattering(PhotonField photonField, + ScalarGrid spaceGrid, + bool havePhotons, + std::string tag, + double limit) { + setPhotonField(photonField); + this->spaceTimeGrid = ScalarGrid4d(); + this->spaceGrid = spaceGrid; + this->havePhotons = havePhotons; + this->tag = tag; + this->limit = limit; + setDescription("EMInverseComptonScattering_spaceDependentConstant"); } void EMInverseComptonScattering::setPhotonField(PhotonField photonField) { this->photonField = photonField; std::string fname = photonFieldName(photonField); - setDescription("EMInverseComptonScattering: " + fname); initRate(getDataPath("EMInverseComptonScattering/rate_" + fname + ".txt")); initCumulativeRate(getDataPath("EMInverseComptonScattering/cdf_" + fname + ".txt")); } @@ -176,20 +206,29 @@ void EMInverseComptonScattering::performInteraction(Candidate *candidate) const if (E < tabE.front() or E > tabE.back()) return; + // geometric scaling + Vector3d pos = candidate->current.getPosition(); + const double time = candidate->getTrajectoryLength()/c_light; + + double geometricScaling = 1.; + const std::string description = getDescription(); + if (description == "EMInverseComptonScattering_isotropicConstant") { + // do nothing, just check for correct initialization + } else if (description == "EMInverseComptonScattering_spaceDependentConstant") { + geometricScaling *= spaceGrid.interpolate(pos); + } else if (description == "EMInverseComptonScattering_spaceTimeDependent") { + geometricScaling *= spaceTimeGrid.interpolate(pos, time); + } else { + throw std::runtime_error("EMInverseComptonScattering: invalid description string"); + } + if (geometricScaling == 0.) + return; + // sample the value of s Random &random = Random::instance(); size_t i = closestIndex(E, tabE); - Vector3d pos = candidate->current.getPosition(); - double time = candidate->getTrajectoryLength()/c_light; - double geometricScaling = geometryGrid.interpolate(pos, time); - if (geometricScaling == 0.) - return; - std::vector tabCDF_geoScaled; - for (int j = 0; j < tabCDF[i].size(); ++j) { - tabCDF_geoScaled.push_back(tabCDF[i][j]*geometricScaling); - } - size_t j = random.randBin(tabCDF_geoScaled); - double s_kin = pow(10, log10(tabs[j]) + (random.rand() - 0.5) * 0.1); + size_t j = random.randBin(tabCDF[i]); + double s_kin = pow(10, log10(tabs[j] * geometricScaling) + (random.rand() - 0.5) * 0.1); double s = s_kin + mec2 * mec2; // sample electron energy after scattering @@ -200,7 +239,7 @@ void EMInverseComptonScattering::performInteraction(Candidate *candidate) const double Esecondary = E - Enew; if (havePhotons) { Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition()); - candidate->addSecondary(22, Esecondary / (1 + z), pos); + candidate->addSecondary(22, Esecondary / (1 + z), pos, tag); } // update the primary particle energy; do this after adding the secondary to correctly set the secondary's parent @@ -224,7 +263,7 @@ void EMInverseComptonScattering::process(Candidate *candidate) const { // geometric scaling Vector3d pos = candidate->current.getPosition(); double time = candidate->getTrajectoryLength()/c_light; - double rate = geometryGrid.interpolate(pos, time); + double rate = spaceTimeGrid.interpolate(pos, time); if (rate == 0.) return; rate *= interpolate(E, tabEnergy, tabRate); diff --git a/src/module/ElasticScattering.cpp b/src/module/ElasticScattering.cpp index ddfd5f6fa..65fadc881 100644 --- a/src/module/ElasticScattering.cpp +++ b/src/module/ElasticScattering.cpp @@ -117,9 +117,8 @@ void ElasticScattering::process(Candidate *candidate) const { double step = candidate->getCurrentStep(); while (step > 0) { + // geometric scaling double rate = 1.; - Vector3d pos = candidate->current.getPosition(); - double time = candidate->getTrajectoryLength()/c_light; const std::string description = getDescription(); if (description == "ElasticScattering_isotropicConstant") { // do nothing, just check for correct initialization From 7bdf7abe886e78776e1e01deb7ffb6d658e7421a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Thu, 13 Jun 2019 19:03:25 +0100 Subject: [PATCH 73/81] update signatures --- test/testInteraction.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index dc82c9e89..8611e08c2 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -619,7 +619,7 @@ TEST(EMPairProduction, secondaries) { // EMDoublePairProduction ----------------------------------------------------- TEST(EMDoublePairProduction, limitNextStep) { // Test if the interaction limits the next propagation step. - EMDoublePairProduction m; + EMDoublePairProduction m(CMB); Candidate c(22, 1E17 * eV); c.setNextStep(std::numeric_limits::max()); m.process(&c); @@ -628,7 +628,7 @@ TEST(EMDoublePairProduction, limitNextStep) { TEST(EMDoublePairProduction, secondaries) { // Test if secondaries are correctly produced. - EMDoublePairProduction m; + EMDoublePairProduction m(CMB); m.setHaveElectrons(true); std::vector fields; @@ -673,7 +673,7 @@ TEST(EMDoublePairProduction, secondaries) { // EMTripletPairProduction ---------------------------------------------------- TEST(EMTripletPairProduction, limitNextStep) { // Test if the interaction limits the next propagation step. - EMTripletPairProduction m; + EMTripletPairProduction m(CMB); Candidate c(11, 1E17 * eV); c.setNextStep(std::numeric_limits::max()); m.process(&c); @@ -682,7 +682,7 @@ TEST(EMTripletPairProduction, limitNextStep) { TEST(EMTripletPairProduction, secondaries) { // Test if secondaries are correctly produced. - EMTripletPairProduction m; + EMTripletPairProduction m(CMB); m.setHaveElectrons(true); std::vector fields; From 43b568e236a2e637d969ce655f304e89e97f4fb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Thu, 13 Jun 2019 19:03:49 +0100 Subject: [PATCH 74/81] overload functions for better handling add tag option --- .../crpropa/module/EMDoublePairProduction.h | 26 ++++++- .../crpropa/module/EMTripletPairProduction.h | 26 ++++++- src/module/EMDoublePairProduction.cpp | 61 ++++++++++++--- src/module/EMTripletPairProduction.cpp | 77 ++++++++++++++----- 4 files changed, 153 insertions(+), 37 deletions(-) diff --git a/include/crpropa/module/EMDoublePairProduction.h b/include/crpropa/module/EMDoublePairProduction.h index 35db30e90..bddb409e3 100644 --- a/include/crpropa/module/EMDoublePairProduction.h +++ b/include/crpropa/module/EMDoublePairProduction.h @@ -18,8 +18,10 @@ namespace crpropa { class EMDoublePairProduction: public Module { private: PhotonField photonField; - ScalarGrid4d geometryGrid; + ScalarGrid4d spaceTimeGrid; + ScalarGrid spaceGrid; bool haveElectrons; + std::string tag; double limit; // tabulated interaction rate 1/lambda(E) @@ -28,11 +30,27 @@ class EMDoublePairProduction: public Module { public: EMDoublePairProduction( - PhotonField photonField = CMB, //!< target photon background - ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.), //!< spacial and temporal dependence of photon field + PhotonField PhotonField, //!< target photon background bool haveElectrons = false, //!< switch to create the secondary electron pair + std::string tag = "EMDPP", double limit = 0.1 //!< step size limit as fraction of mean free path - ); + ); + + EMDoublePairProduction( + PhotonField PhotonField, //!< target photon background + ScalarGrid4d spaceTimeGrid, //!< spacial and temporal dependence of photon field + bool haveElectrons = false, //!< switch to create the secondary electron pair + std::string tag = "EMDPP", + double limit = 0.1 //!< step size limit as fraction of mean free path + ); + + EMDoublePairProduction( + PhotonField PhotonField, //!< target photon background + ScalarGrid spaceGrid, //!< spacial dependence of photon field + bool haveElectrons = false, //!< switch to create the secondary electron pair + std::string tag = "EMDPP", + double limit = 0.1 //!< step size limit as fraction of mean free path + ); void setPhotonField(PhotonField photonField); void setHaveElectrons(bool haveElectrons); diff --git a/include/crpropa/module/EMTripletPairProduction.h b/include/crpropa/module/EMTripletPairProduction.h index 8146958d8..db28c4d19 100644 --- a/include/crpropa/module/EMTripletPairProduction.h +++ b/include/crpropa/module/EMTripletPairProduction.h @@ -22,8 +22,10 @@ namespace crpropa { class EMTripletPairProduction: public Module { private: PhotonField photonField; - ScalarGrid4d geometryGrid; + ScalarGrid4d spaceTimeGrid; + ScalarGrid spaceGrid; bool haveElectrons; + std::string tag; double limit; // tabulated interaction rate 1/lambda(E) @@ -37,11 +39,27 @@ class EMTripletPairProduction: public Module { public: EMTripletPairProduction( - PhotonField photonField = CMB, //!< target photon background - ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.), + PhotonField photonField, //!< target photon background bool haveElectrons = false, //!< switch to create secondary electron pair + std::string tag = "EMTPP", double limit = 0.1 //!< step size limit as fraction of mean free path - ); + ); + + EMTripletPairProduction( + PhotonField photonField, //!< target photon background + ScalarGrid4d spaceTimeGrid, + bool haveElectrons = false, //!< switch to create secondary electron pair + std::string tag = "EMTPP", + double limit = 0.1 //!< step size limit as fraction of mean free path + ); + + EMTripletPairProduction( + PhotonField photonField, //!< target photon background + ScalarGrid spaceGrid, + bool haveElectrons = false, //!< switch to create secondary electron pair + std::string tag = "EMTPP", + double limit = 0.1 //!< step size limit as fraction of mean free path + ); void setPhotonField(PhotonField photonField); void setHaveElectrons(bool haveElectrons); diff --git a/src/module/EMDoublePairProduction.cpp b/src/module/EMDoublePairProduction.cpp index 8fbee9d17..8871b4a78 100644 --- a/src/module/EMDoublePairProduction.cpp +++ b/src/module/EMDoublePairProduction.cpp @@ -9,19 +9,50 @@ namespace crpropa { EMDoublePairProduction::EMDoublePairProduction(PhotonField photonField, - ScalarGrid4d geometryGrid, bool haveElectrons, + std::string tag, double limit) { setPhotonField(photonField); - this->geometryGrid = geometryGrid; + this->spaceTimeGrid = ScalarGrid4d(); + this->spaceGrid = ScalarGrid(); this->haveElectrons = haveElectrons; + this->tag = tag; this->limit = limit; + setDescription("EMDoublePairProduction_isotropicConstant"); +} + +EMDoublePairProduction::EMDoublePairProduction(PhotonField photonField, + ScalarGrid4d spaceTimeGrid, + bool haveElectrons, + std::string tag, + double limit) { + setPhotonField(photonField); + this->spaceTimeGrid = spaceTimeGrid; + this->spaceGrid = ScalarGrid(); + this->haveElectrons = haveElectrons; + this->tag = tag; + this->limit = limit; + setDescription("EMDoublePairProduction_spaceTimeDependent"); +} + +EMDoublePairProduction::EMDoublePairProduction(PhotonField photonField, + ScalarGrid spaceGrid, + bool haveElectrons, + std::string tag, + double limit) { + setPhotonField(photonField); + this->spaceTimeGrid = ScalarGrid4d(); + this->spaceGrid = spaceGrid; + this->haveElectrons = haveElectrons; + this->tag = tag; + this->limit = limit; + setDescription("EMDoublePairProduction_spaceDependentConstant"); + } void EMDoublePairProduction::setPhotonField(PhotonField photonField) { this->photonField = photonField; std::string fname = photonFieldName(photonField); - setDescription("EMDoublePairProduction: " + fname); initRate(getDataPath("EMDoublePairProduction/rate_" + fname + ".txt")); } @@ -73,8 +104,8 @@ void EMDoublePairProduction::performInteraction(Candidate *candidate) const { Random &random = Random::instance(); Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition()); - candidate->addSecondary( 11, Ee, pos); - candidate->addSecondary(-11, Ee, pos); + candidate->addSecondary( 11, Ee, pos, tag); + candidate->addSecondary(-11, Ee, pos, tag); } void EMDoublePairProduction::process(Candidate *candidate) const { @@ -91,13 +122,25 @@ void EMDoublePairProduction::process(Candidate *candidate) const { return; // interaction rate - Vector3d pos = candidate->current.getPosition(); - double time = candidate->getTrajectoryLength()/c_light; + double rate = 1.; + // geometric scaling - double rate = geometryGrid.interpolate(pos, time); + Vector3d pos = candidate->current.getPosition(); + double time = candidate->getTrajectoryLength()/c_light; + + const std::string description = getDescription(); + if (description == "EMDoublePairProduction_isotropicConstant") { + // do nothing, just check for correct initialization + } else if (description == "EMDoublePairProduction_spaceDependentConstant") { + rate *= spaceGrid.interpolate(pos); + } else if (description == "EMDoublePairProduction_spaceTimeDependent") { + rate *= spaceTimeGrid.interpolate(pos, time); + } else { + throw std::runtime_error("EMDoublePairProduction: invalid description string"); + } if (rate == 0.) return; - + rate *= interpolate(E, tabEnergy, tabRate); rate *= pow(1 + z, 2) * photonFieldScaling(photonField, z); diff --git a/src/module/EMTripletPairProduction.cpp b/src/module/EMTripletPairProduction.cpp index 5d20f7089..308bf1c0b 100644 --- a/src/module/EMTripletPairProduction.cpp +++ b/src/module/EMTripletPairProduction.cpp @@ -11,19 +11,49 @@ namespace crpropa { static const double mec2 = mass_electron * c_squared; EMTripletPairProduction::EMTripletPairProduction(PhotonField photonField, - ScalarGrid4d geometryGrid, bool haveElectrons, + std::string tag, double limit) { setPhotonField(photonField); - this->geometryGrid = geometryGrid; + this->spaceTimeGrid = ScalarGrid4d(); + this->spaceGrid = ScalarGrid(); this->haveElectrons = haveElectrons; + this->tag = tag; this->limit = limit; + setDescription("EMTripletPairProduction_isotropicConstant"); +} + +EMTripletPairProduction::EMTripletPairProduction(PhotonField photonField, + ScalarGrid4d spaceTimeGrid, + bool haveElectrons, + std::string tag, + double limit) { + setPhotonField(photonField); + this->spaceTimeGrid = spaceTimeGrid; + this->spaceGrid = ScalarGrid(); + this->haveElectrons = haveElectrons; + this->tag = tag; + this->limit = limit; + setDescription("EMTripletPairProduction_spaceTimeDependent"); +} + +EMTripletPairProduction::EMTripletPairProduction(PhotonField photonField, + ScalarGrid spaceGrid, + bool haveElectrons, + std::string tag, + double limit) { + setPhotonField(photonField); + this->spaceTimeGrid = ScalarGrid4d(); + this->spaceGrid = spaceGrid; + this->haveElectrons = haveElectrons; + this->tag = tag; + this->limit = limit; + setDescription("EMTripletPairProduction_spaceDependentConstant"); } void EMTripletPairProduction::setPhotonField(PhotonField photonField) { this->photonField = photonField; std::string fname = photonFieldName(photonField); - setDescription("EMTripletPairProduction: " + fname); initRate(getDataPath("EMTripletPairProduction/rate_" + fname + ".txt")); initCumulativeRate(getDataPath("EMTripletPairProduction/cdf_" + fname + ".txt")); } @@ -108,23 +138,30 @@ void EMTripletPairProduction::performInteraction(Candidate *candidate) const { if (E < tabE.front() or E > tabE.back()) return; + // geometric scaling + // geometric scaling + Vector3d pos = candidate->current.getPosition(); + const double time = candidate->getTrajectoryLength()/c_light; + + double geometricScaling = 1.; + const std::string description = getDescription(); + if (description == "EMPairProduction_isotropicConstant") { + // do nothing, just check for correct initialization + } else if (description == "EMPairProduction_spaceDependentConstant") { + geometricScaling *= spaceGrid.interpolate(pos); + } else if (description == "EMPairProduction_spaceTimeDependent") { + geometricScaling *= spaceTimeGrid.interpolate(pos, time); + } else { + throw std::runtime_error("EMPairProduction: invalid description string"); + } + if (geometricScaling == 0.) + return; + // sample the value of eps Random &random = Random::instance(); size_t i = closestIndex(E, tabE); - - // geometric scaling - Vector3d pos = candidate->current.getPosition(); - double time = candidate->getTrajectoryLength()/c_light; - double geometricScaling = geometryGrid.interpolate(pos, time); - if (geometricScaling == 0.) - return; - - std::vector tabCDF_geoScaled; - for (int j = 0; j < tabCDF[i].size(); ++j) { - tabCDF_geoScaled.push_back(tabCDF[i][j]*geometricScaling); - } - size_t j = random.randBin(tabCDF_geoScaled); - double s_kin = pow(10, log10(tabs[j]) + (random.rand() - 0.5) * 0.1); + size_t j = random.randBin(tabCDF[i]); + double s_kin = pow(10, log10(tabs[j] * geometricScaling) + (random.rand() - 0.5) * 0.1); double eps = s_kin / 4 / E; // random background photon energy // Use approximation from A. Mastichiadis et al., Astroph. Journ. 300:178-189 (1986), eq. 30. @@ -134,8 +171,8 @@ void EMTripletPairProduction::performInteraction(Candidate *candidate) const { if (haveElectrons) { Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition()); - candidate->addSecondary( 11, Epp, pos); - candidate->addSecondary(-11, Epp, pos); + candidate->addSecondary( 11, Epp, pos, tag); + candidate->addSecondary(-11, Epp, pos, tag); } // update the primary particle energy; do this after adding the secondaries to correctly set the secondaries parent @@ -159,7 +196,7 @@ void EMTripletPairProduction::process(Candidate *candidate) const { // geometric scaling Vector3d pos = candidate->current.getPosition(); double time = candidate->getTrajectoryLength()/c_light; - double rate = geometryGrid.interpolate(pos, time); + double rate = spaceTimeGrid.interpolate(pos, time); if (rate == 0.) return; From 5b757cc73fb12ef3c41c0f5cfc017020099f8a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Thu, 13 Jun 2019 19:06:37 +0100 Subject: [PATCH 75/81] cast time to const --- src/module/EMPairProduction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/module/EMPairProduction.cpp b/src/module/EMPairProduction.cpp index c43c44345..4d1304b86 100644 --- a/src/module/EMPairProduction.cpp +++ b/src/module/EMPairProduction.cpp @@ -213,7 +213,7 @@ void EMPairProduction::performInteraction(Candidate *candidate) const { // geometric scaling Vector3d pos = candidate->current.getPosition(); - double time = candidate->getTrajectoryLength()/c_light; + const double time = candidate->getTrajectoryLength()/c_light; double geometricScaling = 1.; const std::string description = getDescription(); From 1ae500141cc4c13bd636487da40c81e5393c2ec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Fri, 14 Jun 2019 12:00:51 +0100 Subject: [PATCH 76/81] overload functions for better handling --- .../crpropa/module/ElectronPairProduction.h | 30 ++++++-- include/crpropa/module/PhotoDisintegration.h | 27 +++++-- src/module/ElectronPairProduction.cpp | 55 +++++++++++--- src/module/PhotoDisintegration.cpp | 71 +++++++++++++++---- test/testInteraction.cpp | 4 +- 5 files changed, 153 insertions(+), 34 deletions(-) diff --git a/include/crpropa/module/ElectronPairProduction.h b/include/crpropa/module/ElectronPairProduction.h index 27c9f6b9f..aecce46eb 100644 --- a/include/crpropa/module/ElectronPairProduction.h +++ b/include/crpropa/module/ElectronPairProduction.h @@ -23,18 +23,36 @@ namespace crpropa { class ElectronPairProduction: public Module { private: PhotonField photonField; - ScalarGrid4d geometryGrid; + ScalarGrid4d spaceTimeGrid; + ScalarGrid spaceGrid; + bool haveElectrons; + std::string tag; + double limit; ///< fraction of energy loss length to limit the next step + std::vector tabLossRate; /*< tabulated energy loss rate in [J/m] for protons at z = 0 */ std::vector tabLorentzFactor; /*< tabulated Lorentz factor */ std::vector > tabSpectrum; /*< electron/positron cdf(Ee|log10(gamma)) for log10(Ee/eV)=7-24 in 170 steps and log10(gamma)=6-13 in 70 steps and*/ - double limit; ///< fraction of energy loss length to limit the next step - bool haveElectrons; public: - ElectronPairProduction(PhotonField photonField = CMB, - ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.), + ElectronPairProduction(PhotonField photonField, + bool haveElectrons = false, + std::string tag = "EPP", + double limit = 0.1 + ); + + ElectronPairProduction(PhotonField photonField, + ScalarGrid4d spaceTimeGrid, + bool haveElectrons = false, + std::string tag = "EPP", + double limit = 0.1 + ); + + ElectronPairProduction(PhotonField photonField, + ScalarGrid spaceGrid, bool haveElectrons = false, - double limit = 0.1); + std::string tag = "EPP", + double limit = 0.1 + ); void setPhotonField(PhotonField photonField); void setHaveElectrons(bool haveElectrons); diff --git a/include/crpropa/module/PhotoDisintegration.h b/include/crpropa/module/PhotoDisintegration.h index 50be45b68..4a3e3f874 100644 --- a/include/crpropa/module/PhotoDisintegration.h +++ b/include/crpropa/module/PhotoDisintegration.h @@ -20,9 +20,11 @@ namespace crpropa { class PhotoDisintegration: public Module { private: PhotonField photonField; - ScalarGrid4d geometryGrid; - double limit; // fraction of mean free path for limiting the next step + ScalarGrid4d spaceTimeGrid; + ScalarGrid spaceGrid; bool havePhotons; + std::string tag; + double limit; // fraction of mean free path for limiting the next step struct Branch { int channel; // number of emitted (n, p, H2, H3, He3, He4) @@ -43,10 +45,25 @@ class PhotoDisintegration: public Module { static const size_t nlg; // number of Lorentz-factor steps public: - PhotoDisintegration(PhotonField photonField = CMB, - ScalarGrid4d geometryGrid = ScalarGrid4d(Vector3d(0.),0., 1,1,1,1, Vector3d(1.),1.), + PhotoDisintegration(PhotonField photonField, + bool havePhotons = false, + std::string tag = "PD", + double limit = 0.1 + ); + + PhotoDisintegration(PhotonField photonField, + ScalarGrid4d spaceTimeGrid, + bool havePhotons = false, + std::string tag = "PD", + double limit = 0.1 + ); + + PhotoDisintegration(PhotonField photonField, + ScalarGrid spaceGrid, bool havePhotons = false, - double limit = 0.1); + std::string tag = "PD", + double limit = 0.1 + ); void setPhotonField(PhotonField photonField); void setHavePhotons(bool havePhotons); diff --git a/src/module/ElectronPairProduction.cpp b/src/module/ElectronPairProduction.cpp index b60d6eac1..c49d1f537 100644 --- a/src/module/ElectronPairProduction.cpp +++ b/src/module/ElectronPairProduction.cpp @@ -11,20 +11,49 @@ namespace crpropa { ElectronPairProduction::ElectronPairProduction(PhotonField photonField, - ScalarGrid4d geometryGrid, bool haveElectrons, + std::string tag, double limit) { setPhotonField(photonField); - this->geometryGrid = geometryGrid; - geometryGrid.setOrigin(-0.5*geometryGrid.getSpacing()); // correct for in-middle-of-box convention in CRPropa + this->spaceTimeGrid = ScalarGrid4d(); + this->spaceGrid = ScalarGrid(); this->haveElectrons = haveElectrons; + this->tag = tag; this->limit = limit; + setDescription("ElectronPairProduction_isotropicConstant"); +} + +ElectronPairProduction::ElectronPairProduction(PhotonField photonField, + ScalarGrid4d spaceTimeGrid, + bool haveElectrons, + std::string tag, + double limit) { + setPhotonField(photonField); + this->spaceTimeGrid = spaceTimeGrid; + this->spaceGrid = ScalarGrid(); + this->haveElectrons = haveElectrons; + this->tag = tag; + this->limit = limit; + setDescription("ElectronPairProduction_spaceTimeDependent"); +} + +ElectronPairProduction::ElectronPairProduction(PhotonField photonField, + ScalarGrid spaceGrid, + bool haveElectrons, + std::string tag, + double limit) { + setPhotonField(photonField); + this->spaceTimeGrid = ScalarGrid4d(); + this->spaceGrid = spaceGrid; + this->haveElectrons = haveElectrons; + this->tag = tag; + this->limit = limit; + setDescription("ElectronPairProduction_spaceDependentConstant"); } void ElectronPairProduction::setPhotonField(PhotonField photonField) { this->photonField = photonField; std::string fname = photonFieldName(photonField); - setDescription("ElectronPairProduction: " + fname); initRate(getDataPath("ElectronPairProduction/lossrate_" + fname + ".txt")); initSpectrum(getDataPath("ElectronPairProduction/spectrum_" + fname.substr(0,3) + ".txt")); } @@ -90,7 +119,17 @@ double ElectronPairProduction::lossLength(int id, double lf, double z, Vector3d return std::numeric_limits::max(); // below energy threshold // geometric scaling - double rate = geometryGrid.interpolate(pos, time); + double rate = 1.; + const std::string description = getDescription(); + if (description == "ElectronPairProduction_isotropicConstant") { + // do nothing, just check for correct initialization + } else if (description == "ElectronPairProduction_spaceDependentConstant") { + rate *= spaceGrid.interpolate(pos); + } else if (description == "ElectronPairProduction_spaceTimeDependent") { + rate *= spaceTimeGrid.interpolate(pos, time); + } else { + throw std::runtime_error("ElectronPairProduction: invalid description string"); + } if (rate == 0.) return std::numeric_limits::max(); @@ -113,7 +152,7 @@ void ElectronPairProduction::process(Candidate *c) const { double lf = c->current.getLorentzFactor(); double z = c->getRedshift(); Vector3d pos = c->current.getPosition(); - double time = c->getTrajectoryLength()/c_light; + const double time = c->getTrajectoryLength()/c_light; double losslen = lossLength(id, lf, z, pos, time); // energy loss length // check if interaction does not happen @@ -141,8 +180,8 @@ void ElectronPairProduction::process(Candidate *c) const { // create pair and repeat with remaining energy dE -= Epair; Vector3d pos = random.randomInterpolatedPosition(c->previous.getPosition(), c->current.getPosition()); - c->addSecondary( 11, Ee, pos); - c->addSecondary(-11, Ee, pos); + c->addSecondary( 11, Ee, pos, tag); + c->addSecondary(-11, Ee, pos, tag); } } diff --git a/src/module/PhotoDisintegration.cpp b/src/module/PhotoDisintegration.cpp index 0cf1efefd..cfe3e83fc 100644 --- a/src/module/PhotoDisintegration.cpp +++ b/src/module/PhotoDisintegration.cpp @@ -17,19 +17,49 @@ const double PhotoDisintegration::lgmax = 14; // maximum log10(Lorentz-factor) const size_t PhotoDisintegration::nlg = 201; // number of Lorentz-factor steps PhotoDisintegration::PhotoDisintegration(PhotonField f, - ScalarGrid4d geometryGrid, bool havePhotons, + std::string tag, double limit) { setPhotonField(f); - this->geometryGrid = geometryGrid; + this->spaceTimeGrid = ScalarGrid4d(); + this->spaceGrid = ScalarGrid(); this->havePhotons = havePhotons; + this->tag = tag; this->limit = limit; + setDescription("PhotoDisintegration_isotropicConstant"); +} + +PhotoDisintegration::PhotoDisintegration(PhotonField f, + ScalarGrid4d spaceTimeGrid, + bool havePhotons, + std::string tag, + double limit) { + setPhotonField(f); + this->spaceTimeGrid = spaceTimeGrid; + this->spaceGrid = ScalarGrid(); + this->havePhotons = havePhotons; + this->tag = tag; + this->limit = limit; + setDescription("PhotoDisintegration_spaceTimeDependent"); +} + +PhotoDisintegration::PhotoDisintegration(PhotonField f, + ScalarGrid spaceGrid, + bool havePhotons, + std::string tag, + double limit) { + setPhotonField(f); + this->spaceTimeGrid = ScalarGrid4d(); + this->spaceGrid = spaceGrid; + this->havePhotons = havePhotons; + this->tag = tag; + this->limit = limit; + setDescription("PhotoDisintegration_spaceDependent"); } void PhotoDisintegration::setPhotonField(PhotonField photonField) { this->photonField = photonField; std::string fname = photonFieldName(photonField); - setDescription("PhotoDisintegration: " + fname); initRate(getDataPath("Photodisintegration/rate_" + fname + ".txt")); initBranching(getDataPath("Photodisintegration/branching_" + fname + ".txt")); initPhotonEmission(getDataPath("Photodisintegration/photon_emission_" + fname.substr(0,3) + ".txt")); @@ -177,10 +207,25 @@ void PhotoDisintegration::process(Candidate *candidate) const { if ((lg <= lgmin) or (lg >= lgmax)) return; - // geometrical scaling - double rate = geometryGrid.interpolate(pos, time); - if (rate == 0) + // geometric scaling + double rate = 1.; + + Vector3d pos = candidate->current.getPosition(); + const double time = candidate->getTrajectoryLength() / c_light; + + const std::string description = getDescription(); + if (description == "EMDoublePairProduction_isotropicConstant") { + // do nothing, just check for correct initialization + } else if (description == "EMDoublePairProduction_spaceDependentConstant") { + rate *= spaceGrid.interpolate(pos); + } else if (description == "EMDoublePairProduction_spaceTimeDependent") { + rate *= spaceTimeGrid.interpolate(pos, time); + } else { + throw std::runtime_error("EMDoublePairProduction: invalid description string"); + } + if (rate == 0.) return; + rate *= interpolateEquidistant(lg, lgmin, lgmax, pdRate[idx]); rate *= pow(1 + z, 2) * photonFieldScaling(photonField, z); // cosmological scaling, rate per comoving distance @@ -234,17 +279,17 @@ void PhotoDisintegration::performInteraction(Candidate *candidate, int channel) Random &random = Random::instance(); Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition()); for (size_t i = 0; i < nNeutron; i++) - candidate->addSecondary(nucleusId(1, 0), EpA, pos); + candidate->addSecondary(nucleusId(1, 0), EpA, pos, tag); for (size_t i = 0; i < nProton; i++) - candidate->addSecondary(nucleusId(1, 1), EpA, pos); + candidate->addSecondary(nucleusId(1, 1), EpA, pos, tag); for (size_t i = 0; i < nH2; i++) - candidate->addSecondary(nucleusId(2, 1), EpA * 2, pos); + candidate->addSecondary(nucleusId(2, 1), EpA * 2, pos, tag); for (size_t i = 0; i < nH3; i++) - candidate->addSecondary(nucleusId(3, 1), EpA * 3, pos); + candidate->addSecondary(nucleusId(3, 1), EpA * 3, pos, tag); for (size_t i = 0; i < nHe3; i++) - candidate->addSecondary(nucleusId(3, 2), EpA * 3, pos); + candidate->addSecondary(nucleusId(3, 2), EpA * 3, pos, tag); for (size_t i = 0; i < nHe4; i++) - candidate->addSecondary(nucleusId(4, 2), EpA * 4, pos); + candidate->addSecondary(nucleusId(4, 2), EpA * 4, pos, tag); if (not havePhotons) return; @@ -265,7 +310,7 @@ void PhotoDisintegration::performInteraction(Candidate *candidate, int channel) // boost to lab frame double cosTheta = 2 * random.rand() - 1; double E = pdPhoton[key][i].energy * lf * (1 - cosTheta); - candidate->addSecondary(22, E, pos); + candidate->addSecondary(22, E, pos, tag); } } diff --git a/test/testInteraction.cpp b/test/testInteraction.cpp index 8611e08c2..601d7dbad 100644 --- a/test/testInteraction.cpp +++ b/test/testInteraction.cpp @@ -384,7 +384,7 @@ TEST(PhotoDisintegration, iron) { TEST(PhotoDisintegration, thisIsNotNucleonic) { // Test that nothing happens to an electron. - PhotoDisintegration pd; + PhotoDisintegration pd(CMB); Candidate c; c.setCurrentStep(1 * Mpc); c.current.setId(11); // electron @@ -396,7 +396,7 @@ TEST(PhotoDisintegration, thisIsNotNucleonic) { TEST(PhotoDisintegration, limitNextStep) { // Test if the interaction limits the next propagation step. - PhotoDisintegration pd; + PhotoDisintegration pd(CMB); Candidate c; c.setNextStep(std::numeric_limits::max()); c.current.setId(nucleusId(4, 2)); From 68d9dab3af8a05c4abb139dfba2963fbf28d0d45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Mon, 17 Jun 2019 18:34:15 +0100 Subject: [PATCH 77/81] add tag function to synchrotron radiation --- include/crpropa/module/SynchrotronRadiation.h | 13 +++++++++++-- src/module/SynchrotronRadiation.cpp | 8 +++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/include/crpropa/module/SynchrotronRadiation.h b/include/crpropa/module/SynchrotronRadiation.h index 6651b3eb6..f32a36e12 100644 --- a/include/crpropa/module/SynchrotronRadiation.h +++ b/include/crpropa/module/SynchrotronRadiation.h @@ -27,14 +27,23 @@ class SynchrotronRadiation: public Module { double limit; ///< fraction of energy loss length to limit the next step bool havePhotons; ///< flag for production of secondary photons + std::string tag; double secondaryThreshold; ///< threshold energy for secondary photons + std::vector tabx; ///< tabulated fraction E_photon/E_critical from 10^-6 to 10^2 in 801 log-spaced steps std::vector tabCDF; ///< tabulated CDF of synchrotron spectrum public: - SynchrotronRadiation(ref_ptr field, bool havePhotons = false, double limit = 0.1); - SynchrotronRadiation(double Brms = 0, bool havePhotons = false, double limit = 0.1); + SynchrotronRadiation(ref_ptr field, + bool havePhotons = false, + std::string tag = "synch", + double limit = 0.1); + + SynchrotronRadiation(double Brms = 0, + bool havePhotons = false, + std::string tag = "synch", + double limit = 0.1); void setField(ref_ptr field); ref_ptr getField(); diff --git a/src/module/SynchrotronRadiation.cpp b/src/module/SynchrotronRadiation.cpp index 35e8fda1b..2ffb75d9b 100644 --- a/src/module/SynchrotronRadiation.cpp +++ b/src/module/SynchrotronRadiation.cpp @@ -8,20 +8,22 @@ namespace crpropa { -SynchrotronRadiation::SynchrotronRadiation(ref_ptr field, bool havePhotons, double limit) { +SynchrotronRadiation::SynchrotronRadiation(ref_ptr field, bool havePhotons, std::string tag, double limit) { Brms = 0.; setField(field); initSpectrum(); this->havePhotons = havePhotons; this->limit = limit; + this->tag = tag; secondaryThreshold = 1e7 * eV; } -SynchrotronRadiation::SynchrotronRadiation(double Brms, bool havePhotons, double limit) { +SynchrotronRadiation::SynchrotronRadiation(double Brms, bool havePhotons, std::string tag, double limit) { this->Brms = Brms; initSpectrum(); this->havePhotons = havePhotons; this->limit = limit; + this->tag = tag; secondaryThreshold = 1e7 * eV; } @@ -147,7 +149,7 @@ void SynchrotronRadiation::process(Candidate *candidate) const { dE -= Egamma; Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition()); if (Egamma > secondaryThreshold) // create only photons with energies above threshold - candidate->addSecondary(22, Egamma, pos); + candidate->addSecondary(22, Egamma, pos, tag); } } From 4a2d3c5818050a14950b8fc7d4a693a4965c3615 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Thu, 20 Jun 2019 15:59:24 +0100 Subject: [PATCH 78/81] reduce scope of interpolation to save resources --- src/module/SynchrotronRadiation.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/module/SynchrotronRadiation.cpp b/src/module/SynchrotronRadiation.cpp index 2ffb75d9b..aade53aaf 100644 --- a/src/module/SynchrotronRadiation.cpp +++ b/src/module/SynchrotronRadiation.cpp @@ -147,9 +147,11 @@ void SynchrotronRadiation::process(Candidate *candidate) const { // create synchrotron photon and repeat with remaining energy dE -= Egamma; - Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition()); - if (Egamma > secondaryThreshold) // create only photons with energies above threshold + // create only photons with energies above threshold + if (Egamma > secondaryThreshold) { + Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition()); candidate->addSecondary(22, Egamma, pos, tag); + } } } From 2cd004488f964de9e474af9a532747dc2cbc6695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Thu, 20 Jun 2019 15:59:58 +0100 Subject: [PATCH 79/81] update docstrings improve readability --- src/PhotonBackground.cpp | 28 +++++++++++++--------------- src/module/PhotoPionProduction.cpp | 5 ++--- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/PhotonBackground.cpp b/src/PhotonBackground.cpp index d26b86ede..58b3d6781 100644 --- a/src/PhotonBackground.cpp +++ b/src/PhotonBackground.cpp @@ -168,15 +168,13 @@ void CustomPhotonField::init(std::string filename) { double CustomPhotonField::sampleEps(bool onProton, double Ein, double zIn) const { /* - - input: particle type with energy Ein at redshift z - - output: photon energy [eV] of random photon of photon field - - samples distribution of n(epsilon)/epsilon^2 + - input: particle type with energy Ein [GeV] (SOPHIA standard unit) at redshift z + - output: photon energy [eV] of encountered photon in photon field */ const double zMax = photonRedshift[photonRedshift.size() - 1]; if (zIn > zMax) return 0.; - Ein /= GeV; // SOPHIA standard unit // calculate pMax and its norm factor via maximum such that peps <= 1 double cnorm = 0.; double pMax = 0.; @@ -210,14 +208,14 @@ double CustomPhotonField::sampleEps(bool onProton, double Ein, double zIn) const double CustomPhotonField::SOPHIA_probEps(double eps, bool onProton, double Ein, double zIn) const { /* - - input: eps [eV] - - output: probability to encounter photon of energy eps + - input: photon energy eps [eV], bool onProton, primary's energy Ein [GeV], redshift z + - output: non-normalized probability to encounter photon of energy eps - called by: sampleEps, gaussInt */ const double mass = onProton? 0.93827 : 0.93947; // Gev/c^2 double gamma = Ein / mass; double beta = std::sqrt(1. - 1. / gamma / gamma); - double photonDensity = getPhotonDensity(eps * eV, zIn) / 6.2415091e24; // 1/(Jm³) -> 1/(eVcm³) + double photonDensity = getPhotonDensity(eps * eV, zIn) / 6.2415091e24; // 1/(Jm^3) -> 1/(eVcm^3) if (photonDensity == 0.) { return 0.; } else { @@ -241,17 +239,17 @@ double CustomPhotonField::SOPHIA_probEps(double eps, bool onProton, double Ein, double CustomPhotonField::getPhotonDensity(double eps, double z) const { /* - - input: photon energy, redshift - - output: dndeps(e,z) [#/(eV cm^3)] from input file + - input: photon energy eps [J], redshift z + - output: n(eps, z) / eps [# /(J m^3)] - called by: sampleEps */ - return interpolate2d(eps / eV, z, photonEnergy, photonRedshift, photonDensity) * 6.2415091e24; // 1/(eVcm³)->1/(Jm³) + return interpolate2d(eps / eV, z, photonEnergy, photonRedshift, photonDensity) * 6.2415091e24; // 1/(eVcm^3)->1/(Jm^3) } double CustomPhotonField::SOPHIA_crossection(double x, bool onProton) const { /* - - input: photon energy [eV], specifier: 0=neutron, 1=proton - - output: SOPHIA_crossection of nucleon-photon-interaction [area] + - input: photon energy [GeV], specifier: 0=neutron, 1=proton + - output: SOPHIA_crossection of nucleon-photon-interaction [m^2] - called by: SOPHIA_functs */ const double mass = onProton? 0.93827 : 0.93947; // Gev/c^2 @@ -282,7 +280,7 @@ double CustomPhotonField::SOPHIA_crossection(double x, bool onProton) const { cross_res = SOPHIA_breitwigner(SIG0[0], WIDTH[0 + idx], AMRES[0 + idx], x, onProton) * SOPHIA_ef(x, 0.152, 0.17); for (int i = 1; i < 9; ++i) { - cross_res = SOPHIA_breitwigner(SIG0[i], WIDTH[i + idx], AMRES[i + idx], x, onProton) + cross_res += SOPHIA_breitwigner(SIG0[i], WIDTH[i + idx], AMRES[i + idx], x, onProton) * SOPHIA_ef(x, 0.15, 0.38); } // direct channel @@ -335,7 +333,7 @@ double CustomPhotonField::SOPHIA_crossection(double x, bool onProton) const { cross_diffr = cross_diffr1 + cross_diffr2; cs_multidiff = cs_multi + cross_diffr; } - return (cross_res + cross_dir + cs_multidiff + cross_frag2) * 1.e-34; // µbarn to m² + return (cross_res + cross_dir + cs_multidiff + cross_frag2) * 1.e-34; // mubarn to m^2 } double CustomPhotonField::SOPHIA_pl(double x, double xth, double xmax, double alpha) const { @@ -393,7 +391,7 @@ double CustomPhotonField::SOPHIA_functs(double s, bool onProton) const { const double mass = onProton? 0.93827 : 0.93947; // Gev/c^2 double factor = s - mass * mass; double epsPrime = factor / 2. / mass; - double sigma_pg = SOPHIA_crossection(epsPrime, onProton) / 1.e-34; // m² to µbarn + double sigma_pg = SOPHIA_crossection(epsPrime, onProton) / 1.e-34; // m^2 to mubarn return factor * sigma_pg; } diff --git a/src/module/PhotoPionProduction.cpp b/src/module/PhotoPionProduction.cpp index 990ffd2f8..8dd76870b 100644 --- a/src/module/PhotoPionProduction.cpp +++ b/src/module/PhotoPionProduction.cpp @@ -557,10 +557,9 @@ void PhotoPionProduction::performInteraction(Candidate *candidate, bool onProton // SOPHIA - input: int nature = 1 - static_cast(onProton); // 0=proton, 1=neutron - double Ein = EpA / GeV; - // std::cout << "b "; + double Ein = EpA / GeV; // GeV is the SOPHIA standard unit double eps = customPhotonField.sampleEps(onProton, Ein, z); - // std::cout << eps << " "; + // SOPHIA - output: double outputEnergy[2000]; int outPartID[2000]; From 7fbddfe05c67163dc36a0acdc8d8d45e779b12f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Mon, 15 Jul 2019 22:32:44 +0100 Subject: [PATCH 80/81] fix interpolation choice bug --- src/module/EMDoublePairProduction.cpp | 4 ++-- src/module/EMInverseComptonScattering.cpp | 20 ++++++++++++---- src/module/EMTripletPairProduction.cpp | 28 +++++++++++++++-------- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/module/EMDoublePairProduction.cpp b/src/module/EMDoublePairProduction.cpp index 8871b4a78..44dad8b32 100644 --- a/src/module/EMDoublePairProduction.cpp +++ b/src/module/EMDoublePairProduction.cpp @@ -126,8 +126,8 @@ void EMDoublePairProduction::process(Candidate *candidate) const { // geometric scaling Vector3d pos = candidate->current.getPosition(); - double time = candidate->getTrajectoryLength()/c_light; - + double time = candidate->getTrajectoryLength() / c_light; + const std::string description = getDescription(); if (description == "EMDoublePairProduction_isotropicConstant") { // do nothing, just check for correct initialization diff --git a/src/module/EMInverseComptonScattering.cpp b/src/module/EMInverseComptonScattering.cpp index 022429a31..acd22bb30 100644 --- a/src/module/EMInverseComptonScattering.cpp +++ b/src/module/EMInverseComptonScattering.cpp @@ -208,8 +208,8 @@ void EMInverseComptonScattering::performInteraction(Candidate *candidate) const // geometric scaling Vector3d pos = candidate->current.getPosition(); - const double time = candidate->getTrajectoryLength()/c_light; - + const double time = candidate->getTrajectoryLength() / c_light; + double geometricScaling = 1.; const std::string description = getDescription(); if (description == "EMInverseComptonScattering_isotropicConstant") { @@ -262,10 +262,22 @@ void EMInverseComptonScattering::process(Candidate *candidate) const { // interaction rate // geometric scaling Vector3d pos = candidate->current.getPosition(); - double time = candidate->getTrajectoryLength()/c_light; - double rate = spaceTimeGrid.interpolate(pos, time); + const double time = candidate->getTrajectoryLength() / c_light; + + double rate = 1.; + const std::string description = getDescription(); + if (description == "EMInverseComptonScattering_isotropicConstant") { + // do nothing, just check for correct initialization + } else if (description == "EMInverseComptonScattering_spaceDependentConstant") { + rate *= spaceGrid.interpolate(pos); + } else if (description == "EMInverseComptonScattering_spaceTimeDependent") { + rate *= spaceTimeGrid.interpolate(pos, time); + } else { + throw std::runtime_error("EMInverseComptonScattering: invalid description string"); + } if (rate == 0.) return; + rate *= interpolate(E, tabEnergy, tabRate); rate *= pow(1 + z, 2) * photonFieldScaling(photonField, z); diff --git a/src/module/EMTripletPairProduction.cpp b/src/module/EMTripletPairProduction.cpp index 308bf1c0b..3b69cb224 100644 --- a/src/module/EMTripletPairProduction.cpp +++ b/src/module/EMTripletPairProduction.cpp @@ -139,20 +139,19 @@ void EMTripletPairProduction::performInteraction(Candidate *candidate) const { return; // geometric scaling - // geometric scaling Vector3d pos = candidate->current.getPosition(); - const double time = candidate->getTrajectoryLength()/c_light; + const double time = candidate->getTrajectoryLength() / c_light; double geometricScaling = 1.; const std::string description = getDescription(); - if (description == "EMPairProduction_isotropicConstant") { + if (description == "EMTripletPairProduction_isotropicConstant") { // do nothing, just check for correct initialization - } else if (description == "EMPairProduction_spaceDependentConstant") { + } else if (description == "EMTripletPairProduction_spaceDependentConstant") { geometricScaling *= spaceGrid.interpolate(pos); - } else if (description == "EMPairProduction_spaceTimeDependent") { + } else if (description == "EMTripletPairProduction_spaceTimeDependent") { geometricScaling *= spaceTimeGrid.interpolate(pos, time); } else { - throw std::runtime_error("EMPairProduction: invalid description string"); + throw std::runtime_error("EMTripletPairProduction: invalid description string"); } if (geometricScaling == 0.) return; @@ -195,11 +194,22 @@ void EMTripletPairProduction::process(Candidate *candidate) const { // geometric scaling Vector3d pos = candidate->current.getPosition(); - double time = candidate->getTrajectoryLength()/c_light; - double rate = spaceTimeGrid.interpolate(pos, time); + const double time = candidate->getTrajectoryLength() / c_light; + + double rate = 1.; + const std::string description = getDescription(); + if (description == "EMTripletPairProduction_isotropicConstant") { + // do nothing, just check for correct initialization + } else if (description == "EMTripletPairProduction_spaceDependentConstant") { + rate *= spaceGrid.interpolate(pos); + } else if (description == "EMTripletPairProduction_spaceTimeDependent") { + rate *= spaceTimeGrid.interpolate(pos, time); + } else { + throw std::runtime_error("EMTripletPairProduction: invalid description string"); + } if (rate == 0.) return; - + rate *= interpolate(E, tabEnergy, tabRate); // cosmological scaling of interaction distance (comoving) rate *= pow(1 + z, 2) * photonFieldScaling(photonField, z); From 9eb46f7ab31a3f0ad01ddbb72571a47a8b46a0f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=B6rbe?= Date: Tue, 16 Jul 2019 22:39:41 +0100 Subject: [PATCH 81/81] fix bug where s could have been larger than s_max (hard coded!) by increasing s_max to very high value. Interpolation precision may have been compromised in log-space but probably isn't too severe --- src/module/EMInverseComptonScattering.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/module/EMInverseComptonScattering.cpp b/src/module/EMInverseComptonScattering.cpp index acd22bb30..3aa1737b3 100644 --- a/src/module/EMInverseComptonScattering.cpp +++ b/src/module/EMInverseComptonScattering.cpp @@ -150,16 +150,16 @@ class ICSSecondariesEnergyDistribution { // create the cumulative energy distribution of the up-scattered photon ICSSecondariesEnergyDistribution() { - Ns = 1000; - Nrer = 1000; + Ns = 2000; + Nrer = 2000; s_min = mec2 * mec2; - s_max = 1e23 * eV * eV; + s_max = 1e33 * eV * eV; dls = (log(s_max) - log(s_min)) / Ns; - data = std::vector< std::vector >(1000, std::vector(1000)); - std::vector data_i(1000); + data = std::vector< std::vector >(2000, std::vector(2000)); + std::vector data_i(2000); // tabulate s bin borders - s_values = std::vector(1001); + s_values = std::vector(2001); for (size_t i = 0; i < Ns + 1; ++i) s_values[i] = s_min * exp(i*dls); @@ -185,6 +185,14 @@ class ICSSecondariesEnergyDistribution { // draw random energy for the up-scattered photon Ep(Ee, s) double sample(double Ee, double s) { + if (s > s_max) + throw std::runtime_error("EMInverseComptonScattering.cpp: Error in:\n\ + double sample(double Ee, double s):\n\ + s > s_max.\n\ + This may be caused by too strong energies involved\n\ + on either the primary particles' or photons' part.\n\ + increasing the internal value of s_max in\n\ + ICSSecondariesEnergyDistribution() most likely fixes this."); size_t idx = std::lower_bound(s_values.begin(), s_values.end(), s) - s_values.begin(); std::vector s0 = data[idx]; Random &random = Random::instance(); @@ -223,7 +231,6 @@ void EMInverseComptonScattering::performInteraction(Candidate *candidate) const } if (geometricScaling == 0.) return; - // sample the value of s Random &random = Random::instance(); size_t i = closestIndex(E, tabE);