Atmospheric Dispersion model

Atmospheric Dispersion model preview image

1 collaborator

Default-person A Bedouch (Author)

Tags

physics 

Tagged by A Bedouch over 1 year ago

Visible to everyone | Changeable by everyone
Model was written in NetLogo 6.4.0 • Viewed 366 times • Downloaded 21 times • Run 0 times
Download the 'Atmospheric Dispersion model' modelDownload this modelEmbed this model

Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)


Atmospheric Diffusion model

CONTEXT

Why is the sky blue ? Or sometimes red, orange and pink? It all has to do with how the light coming from the sun interacts with our atmosphere.

Light, which is constitued of photons of different wavelengths, is traveling in straight lines. However, when in our atmosphere, it collides with molecules it is deviated. This phenomenon is called diffusion.

The main mechanism for atmospheric diffusion is Rayleigh scattering, where the visible light interacts with small atoms and molecules in the atmosphere. The particularity of Rayleigh scattering is that it heavily depends on the wavelength of the incoming light ray: the scattering probability is proportional to λ^(−4). Red light (λ ~ 645 nm) nearly 5 times more likely to be scattered than blue light (λ ~ 440 nm). A consequence is that when looking at the atmosphere elsewhere than the sun, blue light is much more likely to be reflected of some molecule and end up in our eye than red light. Hence why during the day, the sky appears light blue!

This is illustrated in the below figure: figure

WHAT IS IT?

This model aims to simulate how light rays are diffused in an atmosphere and what colour the atmosphere would appear using various parameters. This model simulates a 2D atmosphere with a given height, by integrating light how many light rays of which colour arrive on the observer.

HOW IT WORKS

This model is an implementation of a basic ray tracing algorithm. In this context it is common to actually perform the simulation backwards: we emit rays from the observers and see if they collide with a light source or not. The reason behind simulating rays backwards is to save computations. If we were to send rays from the sun, only a small fraction would end up colliding with the observer.

While the rays are in the atmosphere, they have a chance of being scattered: i.e. be deflected. This chance is dependent on the ray colour: - green light is 1.8 times less likely to be scattered than blue light - red light is 2.6 times less likely to be scattered than green light

The Rayleigh mecanism doesn't scatter light rays uniformely, indeed a ray incoming with angle φ is more likely to be scattered either in the same direction or directly backwards. More precisely, the probabiliy is proportional to the cos^2 of the angle φ:

P(φ) = γ cos(φ)^2

Once a ray exits the atmosphere, we can check if it would have been emitted by the sun. Because the sun in "infinitely far", we don't actually need to simulate the sun and check for collision with the light ray. We can simply look at the angle the ray exits the atmosphere. If that angle is within the sun angular disk, then it is emitted. Note: periodic conditions are applied horizontally: this means that the simulation is infinitely wide which is only an approximation.

The simulation simply repeatedly sends rays in random directions and checks if they will "collide" with the sun after they exit the atmosphere. Then, for each direction and each color, we count the fraction of rays colliding with the sun. This yields for each direction an RGB triplet.

Once many light rays have been sent, we call that process integration, we can simply visualise what colour the atmosphere would look like in each direction.

HOW TO USE

The model has two modes: - Integration mode - Visualisation mode

The default mode, integration, shows how each ray is simulated and scatters through the atmosphere. It is possible to toggle traces behind the rays to see how they travel.

The visualisation mode can be activated by toggling the "show-result?" switch. In this mode, the simulation will send pseudo-light rays in every direction representing the overall color. These pseudo-rays aren't scattered nor do they count for integration, they only exist visually to see the resulting color.

In practice, I would recommend first playing around in integration mode with only a handful of light rays and see how they interact with the atmosphere, and how various parameter impact the simulation.

In order to produce a coherent image (good signal noise ratio, we need a lot of data points. Therefore we need to integrate a lot of rays. Therefore I recommend picking the maximum number of rays and turn off the "view updates". After about 10000 ticks or more, activate the "view updates" button, and toggle show-results?

Finally, this integrations gives us ratios between RGB values, but in order to produce a visible image, we need to multiply these values by a certain factor. This is what I called gain. There are two gain modes, one where the same gain is applied to the whole simulation, and one where the gain is applied separately on each direction separately. The latter shows colour better but doesn't show how disparately bright and dark areas of the sky are. Note that this gain is comparable to what ISO is in photography.

THINGS TO NOTICE

I suggest to try the default parameters, where the sun is right overhead and some default values. Once it is integrated enough, show the visualisation. The result should be a mainly blue sky, with a strongly white / pink cone overhead (where the sun is located). This is exactly how our atmosphere works: the blue rays are more likely to indireclty end up in our eyes from the atmospheric scattering! We also note that around the horizon (low elevation), the sky appears more pink-ish. This is akin to a red sunset sky, though I am not entirely sure if it is physically accurate in this situation.

Here's an example of output using default parameters

THINGS TO TRY

The user can try to change all the parameters. In particular how changing the scattering probability, the atmosphere's height, or the sun's elevation affects the image.

EXTENDING THE MODEL

One could extend the model by adding more complex scattering mechanisms such as Mie scattering. Another option would be to improve the geometry: our atmosphere is curved and not infinitely large. In particular, our atmosphere is very thin (100km) with respect to the earth's curvature (6400km radius). This should improve the image at low sun elevation and make more realistic sunsets.

CREDITS AND REFERENCES

All code written by A Bedouch. Rayleigh scattering illustration from wikimedia

Comments and Questions

Please start the discussion about this model! (You'll first need to log in.)

Click to Run Model

rays-own [initial-heading]
breed [simulated-rays simulated-ray]
breed [rays ray]
globals [red_em blue_em green_em red_rec blue_rec green_rec test-list]


;;; HELPER PROCEDURES

to-report is-scattered [t_color]
  ;; gives scattering probability as a function of the light ray color
  let probability (ifelse-value
    t_color = blue [base_probability]
    t_color = green [base_probability / 1.8]
    t_color = red [base_probability / 4.6]
                 [0])
  report (random-float 100 <= probability)
end 

to-report scatter-angle
  ;; Rayleigh scattering has a scattering probability proportional to cos(theta)^2
  let which_sign random 2
  let sign (ifelse-value
    which_sign = 0 [ -1 ]
    which_sign = 1 [ 1 ]
  )
  report ((acos (sign * sqrt(random-float 1))) * 2) - 90
end 

to-report is-oob [y]
  ;; check if the y coordinate is out of bounds
  ;; returns 1 if reached the top of the simulation (escaped the atmosphere)
  ;; returns 2 if collided with the ground
  ;; returns 0 if no collisions
  if y > max-pycor - 0.5 [report 1]
  if y < min-pycor + 0.5 [report 2]
  report 0
end 

to-report check-sun-collision [exit-angle]
  ;; Checks if the exit-angle is within the sun's diameter
  if exit-angle > 180 [set exit-angle (exit-angle - 360)]
  report (
    (exit-angle > sun_angle - sun_diameter / 2 ) and
    (exit-angle < sun_angle + sun_diameter / 2 )
  )
end 

to-report get-index [angle]
  ;; For a given angle, gets the index of the cone bin
  if angle > 180 [set angle (angle - 360)]
  set angle (angle + 90)
  report floor(angle / 180 * division-factor)
end 

to-report get-color [red_emitted red_received green_emitted green_received blue_emitted blue_received]
  ;; yields an rgb vector of the color corresponding to the fraction of emitted and received rays
  ifelse relative-gain?
  [
    let multiplier max rgb (red_received / red_emitted) (green_received / green_emitted) (blue_received / blue_emitted)
    ifelse multiplier = 0 [report rgb 0 0 0]
    [
      let new-gain (relative-gain / 100) * (255 / multiplier)
      report rgb (new-gain * red_received / red_emitted) (new-gain * green_received / green_emitted) (new-gain * blue_received / blue_emitted)
    ]
  ]
  [report rgb (gain * red_received / red_emitted) (gain * green_received / green_emitted) (gain * blue_received / blue_emitted)]
end 


;;; SETUP PROCEDURES

to setup
  clear-all
  setup-rays
  setup-atmosphere
  setup-simulated-rays
  setup-counters
  reset-ticks
end 

to setup-rays
  ;; setup the rays with random colour and direction
  set-default-shape rays "line"
  create-rays n_rays [setxy 0 min-pycor + 1]
  ask rays [
    let choice random 3
    set color (ifelse-value
      who mod 3 = 0 [ red ]
      who mod 3 = 1 [ blue ]
      who mod 3 = 2 [ green ])
    set heading (random-float 180) - 90
    set initial-heading heading
  ]
end 

to setup-counters
  ;; setup counters for emitted and received rays of each colours, one counter for each bin of sky
  set red_em (n-values division-factor [1])
  set green_em (n-values division-factor [1])
  set blue_em (n-values division-factor [1])
  set red_rec (n-values division-factor [1])
  set green_rec (n-values division-factor [1])
  set blue_rec (n-values division-factor [1])
end 

to setup-simulated-rays
  ;; setup simulated rays with the calculated colours
  set-default-shape simulated-rays "line"
  let tot 180 * 3
  create-simulated-rays tot [setxy 0 min-pycor + 1]
  ask simulated-rays [
    set hidden? true
    set heading (((who - n_rays) * 180 / tot) - 90)
    set size 2
    set pen-mode "down"
    set pen-size 2
  ]
end 


;;; LOOP PROCEDURES

to increment-color-counter [escaped init-heading escape-heading tcolor]
  ;; increment colour of the correct bin for a ray of color tcolor and initial and escape heading

  let index get-index init-heading
  (
    ifelse
    tcolor = red   [set red_em replace-item index red_em   (item index red_em + 1)]
    tcolor = blue  [set blue_em replace-item index blue_em  (item index green_em + 1)]
    tcolor = green [set green_em replace-item index green_em (item index green_em + 1)]
)
  if escaped and (check-sun-collision escape-heading) [
    (
      ifelse
      tcolor = red   [set red_rec replace-item index red_rec   (item index red_rec + 1)]
      tcolor = blue  [set blue_rec replace-item index blue_rec  (item index green_rec + 1)]
      tcolor = green [set green_rec replace-item index green_rec (item index green_rec + 1)]
    )
]
end 

to setup-atmosphere
  ask patches [
    ifelse pycor + max-pycor < 2 * max-pycor * atmosphere_height / 100 [ set pcolor blue + 3.5 ]
    [ set pcolor black]
  ]
end 

to go
  ;; flow control of what to display and what to compute
  move-rays
  if-else draw-path
  [ask rays [pen-down]]
  [ask rays [pen-up]]
  setup-atmosphere
  ifelse show-result? [
    set draw-path false
    ask rays [set hidden? true]
    ask simulated-rays [
      set hidden? false
      set pen-mode "down"
      get-simulated-color
   ]
    move-simulated-rays
  ]
  [
    ask rays [set hidden? false]
    ask simulated-rays [
      set hidden? true
      set pen-mode "up"
    ]
    clear-drawing
  ]
  tick
end 

to reset-ray
  set pen-mode "up"
  set xcor 0
  set ycor min-pycor + 1
  set heading (random-float 180) - 90
  set initial-heading heading
  if draw-path [set pen-mode "down"]
end 

to move-rays
  ;; move and scatter r
  ask rays [
    if pcolor != black [
      if is-scattered color [
        right (heading + scatter-angle)
      ]
    ]
    forward light_path
    let oob is-oob ycor

    ;; escaped the atmosphere
    if oob = 1 [
      increment-color-counter true initial-heading heading color
      reset-ray
    ]

    ;; collided with ground
    if oob = 2 [
      increment-color-counter true initial-heading heading color
      reset-ray
    ]
  ]
end 

to get-simulated-color
  ask simulated-rays [
    let index get-index heading
    set color get-color
      (item index red_em)
      (item index red_rec)
      (item index green_em)
      (item index green_rec)
      (item index blue_em)
      (item index blue_rec)
  ]
end 

to move-simulated-rays
  ask simulated-rays [
    foreach (n-values 50 [1]) [
      forward 0.1
      if ((xcor < min-pxcor + 0.05) or
        (xcor > max-pxcor - 0.05) or
        (ycor > max-pycor - 0.05)
      ) [setxy 0 min-pycor + 1]
    ]
  ]
end 

There is only one version of this model, created over 1 year ago by A Bedouch.

Attached files

File Type Description Last updated
Atmospheric Dispersion model.png preview Preview for 'Atmospheric Dispersion model' over 1 year ago, by A Bedouch Download
example.png png example output over 1 year ago, by A Bedouch Download
rayleigh.jpg png physics principle illustration over 1 year ago, by A Bedouch Download

This model does not have any ancestors.

This model does not have any descendants.