-
84.85%
Rate
-
196
Hits
-
35
Missed
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
- 345
- 346
- 347
- 348
- 349
- 350
- 351
- 352
- 353
- 354
- 355
- 356
- 357
- 358
- 359
- 360
- 361
- 362
- 363
- 364
- 365
- 366
- 367
- 368
- 369
- 370
- 371
- 372
- 373
- 374
- 375
- 376
- 377
- 378
- 379
- 380
- 381
- 382
- 383
- 384
- 385
- 386
- 387
- 388
- 389
- 390
- 391
- 392
- 393
- 394
- 395
- 396
- 397
- 398
- 399
- 400
- 401
- 402
- 403
- 404
- 405
- 406
- 407
- 408
- 409
- 410
- 411
- 412
- 413
- 414
- 415
- 416
- 417
- 418
- 419
- 420
- 421
- 422
- 423
- 424
- 425
- 426
- 427
- 428
- 429
- 430
- 431
- 432
- 433
- 434
- 435
- 436
- 437
- 438
- 439
- 440
- 441
- 442
- 443
- 444
-
-
-
-
-
- 1x
- 1x
- 1x
- 1x
- 1x
- 1x
- 1x
-
- 1x
-
-
-
-
-
-
-
- 18x
- 12x
- 6x
- 3x
-
- 3x
-
-
-
-
-
-
-
-
-
-
-
- 18x
-
-
- 18x
- 36x
- 18x
- 18x
- 18x
- 18x
- 36x
-
-
-
-
-
-
-
-
-
- 1x
-
- 1x
- 12x
- 12x
- 12x
- 12x
- 12x
-
-
-
-
-
-
-
-
-
-
- 6x
-
-
- 6x
- 6x
- 12x
- 6x
- 12x
-
-
-
-
-
-
-
-
-
-
- 1x
-
- 1x
- 6x
- 6x
-
-
-
-
-
-
-
-
-
-
- 1x
-
- 1x
- 6x
- 6x
-
-
-
-
-
-
-
-
-
-
- 6x
-
- 6x
- 6x
- 6x
- 6x
- 6x
- 6x
- 6x
- 6x
- 6x
- 6x
-
-
- 6x
- 6x
-
-
-
-
- 12x
- 6x
- 12x
- 6x
-
- 6x
- 6x
- 6x
- 6x
- 6x
- 6x
- 6x
- 6x
- 6x
- 6x
- 6x
- 6x
- 6x
- 6x
- 6x
- 6x
- 6x
- 6x
- 6x
- 12x
- 12x
-
-
-
- 6x
- 6x
- 12x
-
-
- 12x
-
-
-
-
-
-
-
- 1x
-
-
-
- 16x
-
-
- 16x
-
-
-
-
-
- 8x
- 6x
- 3x
- 3x
- 2x
- 1x
-
- 2x
- 6x
- 2x
-
- 10x
- 10x
- 10x
- 5x
- 4x
- 2x
-
-
- 6x
- 6x
- 6x
-
-
- 10x
- 15x
- 10x
-
- 5x
-
-
-
- 58x
-
-
-
-
- 29x
-
-
- 1x
- 82x
- 37x
- 45x
- 8x
- 37x
- 29x
- 8x
- 2x
- 6x
- 6x
-
-
-
-
-
-
-
- 1x
-
-
-
-
-
-
-
-
-
-
-
-
- 1x
-
-
- 31x
-
- 31x
- 31x
-
-
- 31x
- 31x
- 54x
- 54x
- 27x
-
- 27x
- 27x
- 27x
-
-
-
-
-
- 4x
- 4x
- 8x
-
-
-
-
- 4x
- 8x
- 4x
- 8x
-
-
-
-
-
-
- 31x
- 4x
- 4x
-
-
-
-
-
-
-
- 31x
- 31x
- 1x
- 1x
-
-
-
-
- 1x
- 1x
-
- 60x
-
-
-
-
-
-
- 31x
- 13x
- 29x
- 16x
- 1x
- 1x
-
-
-
-
- 15x
- 7x
-
-
-
-
-
-
-
- 13x
- 13x
- 12x
-
-
-
-
- 16x
- 16x
- 32x
- 32x
-
-
-
-
-
-
-
-
-
-
- 13x
-
-
-
- 18x
-
- 48x
- 30x
- 27x
- 6x
- 21x
- 18x
-
-
-
-
-
-
-
-
-
-
- 18x
-
-
-
- 18x
- 6x
- 6x
- 6x
- 12x
- 12x
- 6x
- 6x
- 6x
- 12x
- 6x
- 6x
- 6x
- 6x
- 12x
-
-
-
-
-
-
-
- 18x
-
-
- 1x
-
-
-
-
-
-
- 1x
- 1x
-
-
-
-
-
-
- 1x
- -------------------------------------------------------------------------------
- -- Open sky muon flux models for PUMAS
- -- Author: Valentin Niess
- -- License: GNU LGPL-3.0
- -------------------------------------------------------------------------------
- local ffi = require('ffi')
- local lfs = require('lfs')
- local clib = require('pumas.clib')
- local constants = require('pumas.constants')
- local coordinates = require('pumas.coordinates')
- local error = require('pumas.error')
- local metatype = require('pumas.metatype')
-
- local flux = {}
-
-
- -------------------------------------------------------------------------------
- -- Flux scaling according to a constant charge ratio
- -------------------------------------------------------------------------------
- local function ChargeRatio (charge_ratio)
- return function (charge)
- if charge == nil then
- return 1
- elseif charge < 0 then
- return 1 / (1 + charge_ratio)
- else
- return charge_ratio / (1 + charge_ratio)
- end
- end
- end
-
-
- -------------------------------------------------------------------------------
- -- Gaisser muon flux model
- --
- -- Ref: Particle Data Group (Cosmic Rays)
- -------------------------------------------------------------------------------
- local function GaisserFlux (normalisation, gamma, charge_ratio)
- local ratio = ChargeRatio(charge_ratio)
-
- return function (kinetic_energy, cos_theta, charge)
- if cos_theta < 0 then return 0 end
- local Emu = kinetic_energy + constants.MUON_MASS
- local ec = 1.1 * Emu * cos_theta
- local rpi = 1 + ec / 115
- local rK = 1 + ec / 850
- return normalisation * math.pow(Emu, -gamma) *
- (1 / rpi + 0.054 / rK) * ratio(charge)
- end
- end
-
-
- -------------------------------------------------------------------------------
- -- Volkova's parameterization of cos(theta*)
- -------------------------------------------------------------------------------
- local cos_theta_star
- do
- local p = { 0.102573, -0.068287, 0.958633, 0.0407253, 0.817285 }
-
- function cos_theta_star (cos_theta)
- local cs2 = (cos_theta * cos_theta + p[1] * p[1] +
- p[2] * math.pow(cos_theta, p[3]) +
- p[4] * math.pow(cos_theta, p[5])) /
- (1 + p[1] * p[1] + p[2] + p[4])
- return (cs2 > 0) and math.sqrt(cs2) or 0
- end
- end
-
-
- -------------------------------------------------------------------------------
- -- GCCLY flux model
- --
- -- Ref: https://arxiv.org/abs/1509.06176
- -------------------------------------------------------------------------------
- local function GcclyFlux (normalisation, gamma, charge_ratio)
- local gaisser = GaisserFlux(normalisation, gamma, charge_ratio)
-
- return function (kinetic_energy, cos_theta, charge)
- local cs = cos_theta_star(cos_theta)
- if cs < 0 then return 0 end
- local Emu = kinetic_energy + constants.MUON_MASS
- return math.pow(1 + 3.64 / (Emu * math.pow(cs, 1.29)), -gamma) *
- gaisser(kinetic_energy, cs, charge)
- end
- end
-
-
- -------------------------------------------------------------------------------
- -- Chirkin's parameterization of average mass overburden as function of
- -- x=cos(theta), in g/cm^2
- -------------------------------------------------------------------------------
- local mass_overburden
- do
- local p = { -0.017326, 0.114236, 1.15043, 0.0200854, 1.16714 }
-
- function mass_overburden (x)
- return 1E+02 / (p[1] + p[2] * math.pow(x, p[3]) +
- p[4] * math.pow((1 - x * x), p[5]))
- end
- end
-
-
- -------------------------------------------------------------------------------
- -- Chirkin's parameterization of average muon path length as function of
- -- x=cos(theta), in m
- -------------------------------------------------------------------------------
- local path_length
- do
- local p = { 1.3144, 50.2813, 1.33545, 0.252313, 41.0344 }
-
- function path_length (x)
- return 1E+06 / (p[1] + p[2] * math.pow(x, p[3]) +
- p[4] * math.pow((1 - x * x), p[5]))
- end
- end
-
-
- -------------------------------------------------------------------------------
- -- Chirkin flux model
- --
- -- Ref: https://arxiv.org/abs/hep-ph/0407078
- -------------------------------------------------------------------------------
- local function ChirkinFlux (normalisation, gamma, charge_ratio)
- local gaisser = GaisserFlux(normalisation, gamma, charge_ratio)
-
- local a = 2.62E-03
- local b = 3.05E-06
- local astar = 0.487E-03
- local bstar = 8.766E-06
- local X0 = 114.8
- local c0 = astar - bstar * a / b
- c0 = c0 * c0
- local c1 = (astar * astar - c0) / a
- local c2 = bstar * bstar / b
- local d1 = 0.054
-
- return function (kinetic_energy, cos_theta, charge)
- local cs = cos_theta_star(cos_theta)
- if cs < 0 then return 0 end
-
- -- Calculate the effective initial energy, EI, and its derivative
- local EI, dEIdEf
- do
- local X = mass_overburden(cos_theta) - X0
- local ebx = math.exp(b * X)
- local Ef = kinetic_energy + constants.MUON_MASS
- local Ei = ((a + b * Ef) * ebx - a) / b
-
- local sE = 0.5 * c2 * (Ei * Ei - Ef * Ef) + c1 * (Ei - Ef) +
- c0 / b * math.log((a + b * Ei) / (a + b * Ef))
- local dXf = astar + bstar * Ef
- local dXi = astar + bstar * Ei
- local dsEdEf = ebx * dXi * dXi / (a + b * Ei) -
- dXf * dXf / (a + b * Ef)
- local d0 = 1.1 * cs / 115
- local d2 = 1.1 * cs / 850
- local d01 = 1 / (1 + d0 * Ei)
- local d21 = 1 / (1 + d2 * Ei)
- local num1 = d0 * d01 * d01
- local num2 = d1 * d2 * d21 * d21
- local num = num1 + num2
- local iden = 1 / (d01 + d1 * d21)
- local fr = -gamma / Ei - num * iden
- local dfrdEf = gamma / (Ei * Ei) +
- (num * num * iden + 2 * (d0 * num1 * d01 +
- d2 * num2 * d21)) * iden
- EI = Ei + 0.5 * sE * fr
- dEIdEf = math.abs(ebx * (1 + 0.5 * dfrdEf * sE) +
- 0.5 * fr * dsEdEf)
- end
-
- -- Calculate the survival factor (W)
- local d0 = path_length(cos_theta)
- local ctau = 658.65
- local W = math.exp(-d0 / ctau * constants.MUON_MASS / EI)
-
- -- Return the modified Gaisser's flux
- return dEIdEf * W * gaisser(EI, cs, charge)
- end
- end
-
-
- -------------------------------------------------------------------------------
- -- Muon flux metatype
- -------------------------------------------------------------------------------
- local MuonFlux = {}
-
- do
- local function sample (self, state)
- if metatype(self) ~= 'MuonFlux' then
- error.raise{fname = 'sample', argnum = 1,
- expected = 'a MuonFlux table', got = metatype.a(self)}
- elseif metatype(state) ~= 'State' then
- error.raise{fname = 'sample', argnum = 2,
- expected = 'a State table', got = metatype.a(state)}
- end
-
- local altitude, cos_theta
- if self._axis == 'vertical' then
- self._position:set(state.position)
- altitude = self._position.altitude - self._origin
- if rawget(self, '_altitude') and
- (math.abs(self._altitude - altitude) > 1E-03) then
- return false
- end
- local frame = coordinates.LocalFrame(self._position)
- self._direction:set(state.direction):transform(frame)
- cos_theta = -self._direction.z
- else
- altitude = (state.position[0] - self._origin.x) * self._axis.x +
- (state.position[1] - self._origin.y) * self._axis.y +
- (state.position[2] - self._origin.z) * self._axis.z
- if rawget(self, '_altitude') and
- (math.abs(altitude - self._altitude) > 1E-03) then
- return false
- end
-
- cos_theta = -state.direction[0] * self._axis.x -
- state.direction[1] * self._axis.y -
- state.direction[2] * self._axis.z
- end
-
- local f = self._spectrum(
- state.energy, cos_theta, state.charge, altitude)
- state.weight = state.weight * f
-
- return true, f
- end
-
- local function spectrum (self, energy, cos_theta, charge, altitude)
- if metatype(self) ~= 'MuonFlux' then
- error.raise{fname = 'spectrum', argnum = 1,
- expected = 'a MuonFlux table', got = metatype.a(self)}
- end
-
- return self._spectrum(energy, cos_theta, charge, altitude)
- end
-
- function MuonFlux:__index (k)
- if k == '__metatype' then
- return 'MuonFlux'
- elseif k == 'sample' then
- return sample
- elseif k == 'spectrum' then
- return spectrum
- elseif k == 'altitude' then
- return rawget(self, '_altitude')
- elseif k == 'model' then
- return rawget(self, '_model')
- else
- error.raise{['type'] = 'MuonFlux', bad_member = k}
- end
- end
- end
-
-
- function MuonFlux.__newindex (_, k)
- if (k == 'altitude') or (k == 'model') then
- error.raise{['type'] = 'MuonFlux', not_mutable = k}
- else
- error.raise{['type'] = 'MuonFlux', bad_member = k}
- end
- end
-
-
- -------------------------------------------------------------------------------
- -- Muon flux constructor
- -------------------------------------------------------------------------------
- do
- local raise_error = error.ErrorFunction{fname = 'MuonFlux'}
-
- local function new (cls, options)
- options = options or {}
-
- local model = options.model or 'mceq'
- local self = {_model = model}
-
- -- Set the vertical axis and the origin of the model
- local axis = options.axis or 'vertical'
- if axis == 'vertical' then
- self._position = coordinates.GeodeticPoint()
- self._direction = coordinates.CartesianVector()
- self._axis = axis
-
- local origin = options.origin or 0
- if type(origin) == 'number' then
- self._origin = origin
- else
- raise_error{argname = 'origin', expected = 'a number',
- got = metatype.a(origin)}
- end
- else
- local mt = metatype(axis)
- if mt == 'table' then
- self._axis = coordinates.CartesianVector(axis)
- else
- self._axis = coordinates.CartesianVector():set(axis)
- end
-
- local origin = options.origin or {0, 0, 0}
- mt = metatype(origin)
- if mt == 'table' then
- self._origin = coordinates.CartesianPoint(origin)
- else
- self._origin = coordinates.CartesianPoint():set(origin)
- end
- end
-
- -- Set any default altitude
- if options.altitude then
- if type(options.altitude) == 'number' then
- self._altitude = options.altitude
- else
- raise_error{argname = 'altitude', expected = 'a number',
- got = metatype.a(options.altitude)}
- end
- end
-
- local tag, data
- if type(model) == 'string' then
- if lfs.attributes(model, 'mode') == 'file' then
- data = clib.pumas_flux_tabulation_load(model)
- if data == nil then
- raise_error{argname = 'model',
- description = 'could not load flux tabulation from '..
- model}
- end
- ffi.gc(data, ffi.C.free)
- self._data = data
- else
- tag = model:lower()
- end
- elseif type(model) ~= 'function' then
- raise_error{argname = 'model',
- expected = 'a function or a string', got = metatype.a(model)}
- end
-
- if (tag == 'mceq') or (tag == nil) or data then
- local normalisation = 1
- for k, v in pairs(options) do
- if k == 'normalisation' then
- if type(v) == 'number' then
- normalisation = v
- else
- raise_error{argname = 'normalisation',
- expected = 'a number', got = metatype.a(v)}
- end
- elseif (k ~= 'altitude') and (k ~= 'axis') and
- (k ~= 'model') and (k ~= 'origin')
- then
- raise_error{
- argnum = 2, description = "unknown option '"..k..
- "' for 'mceq' model"}
- end
- end
-
- if tag or data then
- if not data then
- data = clib.pumas_flux_tabulation_data[0]
- end
-
- self._spectrum = function (
- kinetic_energy, cos_theta, charge, altitude)
- altitude = altitude or rawget(self, '_altitude') or 0
- charge = charge or 0
- return clib.pumas_flux_tabulation_get(data, kinetic_energy,
- cos_theta, altitude, charge) * normalisation
- end
- else
- self._spectrum = function (
- kinetic_energy, cos_theta, charge, altitude)
- altitude = altitude or rawget(self, '_altitude') or 0
- return model(data, kinetic_energy, cos_theta, charge,
- altitude) * normalisation
- end
- end
-
- return setmetatable(self, cls)
- end
-
- local charge_ratio, gamma
- local normalisation = 1
- local function parse_args ()
- for k, v in pairs(options) do
- if k == 'charge_ratio' then charge_ratio = v
- elseif k == 'gamma' then
- gamma = v
- elseif k == 'normalisation' then normalisation = v
- elseif (k ~= 'altitude') and (k ~= 'axis') and (k ~= 'model')
- and (k ~= 'origin')
- then
- raise_error{
- argnum = 2,
- description = "unknown option '"..k..
- "' for '"..model.."' model"
- }
- end
- end
-
- charge_ratio = charge_ratio or 1.2766
- -- Ref: CMS (https://arxiv.org/abs/1005.5332)
- end
-
- if tag == 'gaisser' then
- parse_args()
- gamma = gamma or 2.7
- normalisation = normalisation * 1.4E+03
- self._spectrum = GaisserFlux(normalisation, gamma, charge_ratio)
- elseif tag == 'gccly' then
- parse_args()
- gamma = gamma or 2.7
- normalisation = normalisation * 1.4E+03
- self._spectrum = GcclyFlux(normalisation, gamma, charge_ratio)
- elseif tag == 'chirkin' then
- parse_args()
- gamma = gamma or 2.715
- normalisation = normalisation * 9.814E+02
- self._spectrum = ChirkinFlux(normalisation, gamma, charge_ratio)
- else
- raise_error{
- argnum = 1,
- description = "'unknown flux model '"..model.."'"
- }
- end
-
- return setmetatable(self, cls)
- end
-
- flux.MuonFlux = setmetatable(MuonFlux, {__call = new})
- end
-
-
- -------------------------------------------------------------------------------
- -- Register the subpackage
- -------------------------------------------------------------------------------
- function flux.register_to (t)
- t.MuonFlux = flux.MuonFlux
- end
-
-
- -------------------------------------------------------------------------------
- -- Return the package
- -------------------------------------------------------------------------------
- return flux