Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing the Propagation Medium Density #379

Open
wjwoodley opened this issue Sep 13, 2023 · 1 comment
Open

Changing the Propagation Medium Density #379

wjwoodley opened this issue Sep 13, 2023 · 1 comment

Comments

@wjwoodley
Copy link

wjwoodley commented Sep 13, 2023

I (with @afedynitch) am trying to use PROPOSAL v7.4.2 to propagate muons through rock and I've noticed that when I change the density of the rock, the energy loss of the secondaries is identical, whereas at least some variation should be expected. This is essentially what I am running:

import proposal as pp

densities = [1, 5, 100] # [gcm^-3]

for i in densities:
    
    mu = pp.particle.MuMinusDef()
    rock = pp.medium.StandardRock()
    
    args = {
        "particle_def": mu,
        "target": rock,
        "interpolate": True,
        "cuts": pp.EnergyCutSettings(500, 0.05, True)
    }

    cross_sections = pp.crosssection.make_std_crosssection(**args)
    
    brems_param = pp.parametrization.bremsstrahlung.KelnerKokoulinPetrukhin(lpm=True, particle_def=mu, medium=rock)
    epair_param = pp.parametrization.pairproduction.KelnerKokoulinPetrukhin(lpm=True, particle_def=mu, medium=rock)
    ionis_param = pp.parametrization.ionization.BetheBlochRossi(energy_cuts=args["cuts"])
    shado_param = pp.parametrization.photonuclear.ShadowButkevichMikheyev()
    photo_param = pp.parametrization.photonuclear.AbramowiczLevinLevyMaor97(shadow_effect=shado_param)

    cross_sections[0] = pp.crosssection.make_crosssection(brems_param, **args)
    cross_sections[1] = pp.crosssection.make_crosssection(epair_param, **args)
    cross_sections[2] = pp.crosssection.make_crosssection(ionis_param, **args)
    cross_sections[3] = pp.crosssection.make_crosssection(photo_param, **args)

    collection = pp.PropagationUtilityCollection()
    collection.interaction = pp.make_interaction(cross_sections, True)
    collection.displacement = pp.make_displacement(cross_sections, True)
    collection.time = pp.make_time(cross_sections, mu, True)
    collection.decay = pp.make_decay(cross_sections, mu, True)
    pp.PropagationUtilityCollection.cont_rand = False

    utility = pp.PropagationUtility(collection = collection)
    detector = pp.geometry.Sphere(position = pp.Cartesian3D(0, 0, 0), radius = 10000000, inner_radius = 0)
    
    # Change the density
    
    density_distr = pp.density_distribution.density_homogeneous(mass_density=i)
    
    # Create the propagator

    propagator = pp.Propagator(mu, [(detector, utility, density_distr)])

    init_state = pp.particle.ParticleState()
    init_state.position = pp.Cartesian3D(0, 0, 0)
    init_state.direction = pp.Cartesian3D(0, 0, -1)
    init_state.energy = 1e5 + mu.mass

    # Propagate the muons

    pp.RandomGenerator.get().set_seed(500)

    # Propagate 3 km = 3e5 cm
    
    track = propagator.propagate(init_state, 3e5)

    # Print the secondaries' energies

    print(track.track_energies())

This outputs three identical lists:

[100105.6583745, 94190.74778033089, 89409.65106976482, 81521.10358506946, 80895.58736895806, 61667.89445004389, 58036.095812057545, 17981.00001545329, 17439.233219985068, 105.6583745]
[100105.6583745, 94190.74778033089, 89409.65106976482, 81521.10358506946, 80895.58736895806, 61667.89445004389, 58036.095812057545, 17981.00001545329, 17439.233219985068, 105.6583745]
[100105.6583745, 94190.74778033089, 89409.65106976482, 81521.10358506946, 80895.58736895806, 61667.89445004389, 58036.095812057545, 17981.00001545329, 17439.233219985068, 105.6583745]

Am I setting the density correctly? I seem to remember getting different results in the past (I unfortunately don't have a record of the exact PROPOSAL version I used, but it was earlier than v7.1.0); has something changed?

@Jean1995
Copy link
Member

Hello! There are a few aspects that are important to note here.

Firstly, with the line pp.RandomGenerator.get().set_seed(500), you are resetting the random seed for every propagation process, so the same sequence of random number will be used for the different propagations (I believe this is intentional to compare the propagation process for the different mass densities, but I just wanted to mention it for the sake of completness).

Since PROPOSAL 7, we started to calculate everything internally in grammage. This means that changing the mass density does not have any effect on the calculations of energy losses, scattering, etc. (which is ok in first order approximation! more about this aspsect later...). The only difference for the three different propagations is therefore the (trivial) conversion from grammage to distance. This difference can be seen when you look, for example, at the propagated distances of the particles (i.e. print(track.track_propagated_distances())). Otherwise, all three propagation see the same cross sections, to the final energies are identical.

I've mentioned that for the calculation of energy losses, changing the mass density doesn't have an effect. This is only a valid approximation for linear effects, but doesn't work for non-linear effects, for example calculation of the LPM effect. To take these effects into account, this density correction needs to be explicitly passed to the parametrizations. You can do this by passing a density_correction argument, defining the correction factor to the standard density of the defined medium, to the parametrizations which consider the LPM effect.

See this adapted script:

import proposal as pp

densities = [1, 5, 100] # [gcm^-3]

for i in densities:
    
    mu = pp.particle.MuMinusDef()
    rock = pp.medium.StandardRock()

    
    args = {
        "particle_def": mu,
        "target": rock,
        "interpolate": True,
        "cuts": pp.EnergyCutSettings(500, 0.05, True)
    }

    cross_sections = pp.crosssection.make_std_crosssection(**args)
    
    density_correction = i / rock.mass_density # non-linear density corrections
    brems_param = pp.parametrization.bremsstrahlung.KelnerKokoulinPetrukhin(lpm=True, particle_def=mu, medium=rock, density_correction=density_correction)
    epair_param = pp.parametrization.pairproduction.KelnerKokoulinPetrukhin(lpm=True, particle_def=mu, medium=rock, density_correction=density_correction)
    ionis_param = pp.parametrization.ionization.BetheBlochRossi(energy_cuts=args["cuts"])
    shado_param = pp.parametrization.photonuclear.ShadowButkevichMikheyev()
    photo_param = pp.parametrization.photonuclear.AbramowiczLevinLevyMaor97(shadow_effect=shado_param)

    cross_sections[0] = pp.crosssection.make_crosssection(brems_param, **args)
    cross_sections[1] = pp.crosssection.make_crosssection(epair_param, **args)
    cross_sections[2] = pp.crosssection.make_crosssection(ionis_param, **args)
    cross_sections[3] = pp.crosssection.make_crosssection(photo_param, **args)

    collection = pp.PropagationUtilityCollection()
    collection.interaction = pp.make_interaction(cross_sections, True)
    collection.displacement = pp.make_displacement(cross_sections, True)
    collection.time = pp.make_time(cross_sections, mu, True)
    collection.decay = pp.make_decay(cross_sections, mu, True)
    pp.PropagationUtilityCollection.cont_rand = False

    utility = pp.PropagationUtility(collection = collection)
    detector = pp.geometry.Sphere(position = pp.Cartesian3D(0, 0, 0), radius = 10000000, inner_radius = 0)
    
    # Change the density
    
    density_distr = pp.density_distribution.density_homogeneous(mass_density=i)
    
    # Create the propagator

    propagator = pp.Propagator(mu, [(detector, utility, density_distr)])

    init_state = pp.particle.ParticleState()
    init_state.position = pp.Cartesian3D(0, 0, 0)
    init_state.direction = pp.Cartesian3D(0, 0, -1)
    init_state.energy = 1e5 + mu.mass

    # Propagate the muons

    pp.RandomGenerator.get().set_seed(500)

    # Propagate 3 km = 3e5 cm
    
    track = propagator.propagate(init_state, 3e5)

    # Print the secondaries' energies

    print(track.track_energies())

The corresponding output looks like this:

[100105.6583745, 94190.74779420358, 89409.65072571643, 81521.10325981908, 80895.5870354933, 61667.89418854576, 58036.09549228725, 17980.99964755952, 17439.232851920482, 105.6583745, 105.6583745]
[100105.6583745, 94190.74779109083, 89409.65045834142, 81521.10296014052, 80895.58674834007, 61667.89371871539, 58036.09530609559, 17980.999125967555, 17439.23233082569, 105.6583745, 105.6583745]
[100105.6583745, 94190.74785993651, 89409.65518622864, 81521.10791857465, 80895.59170423132, 61667.89928473408, 58036.10043307323, 17981.005846754393, 17439.239049203396, 105.6583745, 105.6583745]

Note that the differences are very small, since the non-linear corrections are negligible at the involved energies.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants