Deviations from Rayleigh's law
Our goal is to reproduce Figure 2
from the paper Cottier et all, 2019, where the authors studied the statistics of the scattered light, and found that the variance of the intensity distribution deviates from the expected Rayleigh's law.
Step 1 - Use distributed resources
This step is optional, but if you have a lot of memory of cpu cores, is a good ideia to use it. Since this is optional, if you don't have a cluster to test, just comment the lines related to addprocs
using CairoMakie, LinearAlgebra
using Statistics: mean, var
using StatsBase: fit, normalize, Histogram
addprocs(2;
exeflags=`--project=$(Base.active_project()) --threads 4`,
topology=:master_worker,
enable_threaded_blas=true
)
@everywhere begin
using CoupledDipoles, Random, Dagger
function produce_intensities(rep, N, L, w₀, s, Δ, sensors)
Random.seed!(1134 + rep)
atoms = Atom(Cube(), N, L)
laser = Laser(Gaussian3D(w₀), s, Δ)
simulation = LinearOptics(Scalar(), atoms, laser)
βₙ = steady_state(simulation)
intensities = scattered_intensity(simulation, βₙ, sensors; regime = :far_field)
return intensities
end
end
Step 2 - Setup Parameters
We use the exact configuration parameters from the paper. You will notice may Warning
messages. This happen because a small laser waist leads to unreasonable results.
If you are studying Cottier's paper, note that the results from the paper are not accurate due to its small laser waist, even though they general paper's message is still correct.
### ------------ ATOMS SPECS ---------------------
L = 32.4
N = [684, 6066]
### ------------ LASER SPECS ---------------------
Δ = 1.0
s = 1e-6
w₀ = L / 4
### ------------ SIMULATION SPECS ---------------------
sensors = get_sensors_ring(; num_pts = 720, kR = 300, θ = 5π / 12)
maxRep = 15
Step 3 - Produce Intensities
For each atom number N
, create maxRep
atomic configurations, compute their state states, and scattered light intensity. The normalization over the mean comes from the paper.
all_intensities = map(N) do N
_intensities = map(1:maxRep) do rep
Dagger.@spawn produce_intensities(rep, N, L, w₀, s, Δ, sensors)
end
many_intensities = fetch.(_intensities)
many_intensities = reduce(vcat, many_intensities)
all_intensities_over_mean = many_intensities ./ mean(many_intensities)
all_intensities_over_mean
end;
Step 4 - Histograms
Instead of ploting histogram
for each particle number, we are interested in the data from the histogram
to display it in a scatter
plot. Also, this is the moment to compute the variance of all intensities.
bins = 10.0 .^ range(log10(1e-6), log10(75); length = 30)
xy_data = map(eachindex(N)) do n
h = fit(Histogram, all_intensities[n], bins)
h_norm = normalize(h; mode = :pdf)
bins_edges = collect(h_norm.edges[1])
bins_centers = [sqrt(bins_edges[i] * bins_edges[i+1]) for i = 1:(length(bins_edges)-1)]
variance = var(all_intensities[n])
# x_data_histogram, y_data_histogram, variance
(bins_centers, h_norm.weights, variance)
end
Step 5 - Plot
Overlay the Distribution Probability in a single figure.
The begin-end
structure is just to facilitate the Figure development for the user. It is easier to just run the block at once at every little plot tweak, than select and run everything all the time.
begin
fig = Figure(size = (800, 450))
ax = Axis(
fig[1, 1],
xlabel = "Intensity",
ylabel = "Probability Distribution",
title = "",
xlabelsize = 25,
ylabelsize = 25,
xticklabelsize = 20,
yticklabelsize = 20,
xscale = log10,
yscale = log10,
)
## theoretical curve
x_ray = range(0.01, 50; step = 0.15)
y_ray = exp.(-x_ray)
lines!(ax, x_ray, y_ray, linestyle = :dash, label = "Rayleigh", color = :black, linewidth = 4)
for n = 1:2
x = xy_data[n][1]
y = xy_data[n][2]
v = xy_data[n][3] # variance
notNull = findall(y .> 0)
scatter!(
ax,
x[notNull],
y[notNull];
label = "N=$(N[n]), Variance = $( round(v,digits=3 ))",
marker = :circle,
markersize = 20,
)
end
ylims!(1e-6, 10)
xlims!(1e-1, 100)
axislegend(position = :rt, labelsize = 20)
CairoMakie.save("rayleigh_deviation.png", fig)
fig
end