rafael-fuente / diffractsim

✨🔬 A flexible diffraction simulator for exploring and visualizing physical optics.
https://rafael-fuente.github.io/simulating-diffraction-patterns-with-the-angular-spectrum-method-and-python.html
Other
754 stars 93 forks source link

plot_intensity() and plot_colors() show different results #28

Closed CakeUser321 closed 2 years ago

CakeUser321 commented 2 years ago

Hi,

firstly I would like to thank you for this nice package. However, I am experiencing some trouble with the visualisation functions. Below, you can find the example "circular_aperture_lens.py" with two added lines of code. It seems to me that the functions plot_intensity() and plot_colors() show different results, which is somehow confusing. Is this a bug or did I use the functions not as intended?

import diffractsim
diffractsim.set_backend("CPU") #Change the string to "CUDA" to use GPU acceleration

from diffractsim import MonochromaticField, nm, mm, cm, CircularAperture, Lens

F = MonochromaticField(
    wavelength = 543 * nm, extent_x=13. * mm, extent_y=13. * mm, Nx=2000, Ny=2000, intensity =0.01
)

F.add(CircularAperture(radius = 0.7*mm))
F.propagate(100*cm)
F.add(Lens(f = 100*cm)) # Just remove this command to see the pattern without lens
F.propagate(100*cm)

rgb = F.get_colors()
F.plot_colors(rgb, xlim=[-3*mm,3*mm], ylim=[-3*mm,3*mm])
F.plot_intensity(F.get_intensity(), xlim=[-3*mm,3*mm], ylim=[-3*mm,3*mm])
rafael-fuente commented 2 years ago

It's not a bug. F.get_colors() returns the colors according to the human color perception, which is not linear with the intensity of the field. The human perception contrast is more accurately represented as 0.42 power of intensity. There is an implemented argument square_root = True in F.plot_intensity() that takes the square root of the intensity and therefore increases the contrast and matches more accurately the human perception scale:


import diffractsim
diffractsim.set_backend("CPU") #Change the string to "CUDA" to use GPU acceleration

from diffractsim import MonochromaticField, nm, mm, cm, CircularAperture, Lens

F = MonochromaticField(
    wavelength = 543 * nm, extent_x=13. * mm, extent_y=13. * mm, Nx=2000, Ny=2000, intensity =0.01
)

F.add(CircularAperture(radius = 0.7*mm))
F.propagate(100*cm)
F.add(Lens(f = 100*cm)) # Just remove this command to see the pattern without lens
F.propagate(100*cm)

rgb = F.get_colors()
F.plot_colors(rgb, xlim=[-3*mm,3*mm], ylim=[-3*mm,3*mm])
F.plot_intensity(F.get_intensity(), xlim=[-3*mm,3*mm], ylim=[-3*mm,3*mm] , square_root = True)

F.plot_colors output: Figure_1

F.plot_intensity output: Figure_2

seamusomurchu commented 2 years ago

It is useful to plot according to the human visual scale, however in this example of the code above, if you give a wavelegnth less than 380 nm, nothing at all is plotted. It would be useful if the code could be generalized to plot wavelengths other than visual wavelengths. i.e. use a colour mapping for non-visual wavelengths such as radio, mm-Wave, NIR, Xray etc. Or is diffractsim only valid for optical wavelengths?

rafael-fuente commented 2 years ago

Diffractsim is valid for all wavelengths, visible or not.
But if you try a wavelength outside a visible wavelength and plot the results with F.plot_colors(), nothing will appear since there is no color to match the human vision.

However, you can always use F.plot_intensity() for non-visible wavelengths. Here is an example with a 360 nm:

import diffractsim
diffractsim.set_backend("CPU") #Change the string to "CUDA" to use GPU acceleration

from diffractsim import MonochromaticField, nm, mm, cm, CircularAperture, Lens

F = MonochromaticField(
    wavelength = 360  * nm, extent_x=13. * mm, extent_y=13. * mm, Nx=2000, Ny=2000, intensity =0.01
)

F.add(CircularAperture(radius = 0.7*mm))
F.propagate(100*cm)
F.add(Lens(f = 100*cm)) # Just remove this command to see the pattern without lens
F.propagate(100*cm)

F.plot_intensity(F.get_intensity(), xlim=[-3*mm,3*mm], ylim=[-3*mm,3*mm] , square_root = True)

360