opticspy / lightpipes

LightPipes for Python, "Pure Python version"
https://opticspy.github.io/lightpipes/
BSD 3-Clause "New" or "Revised" License
223 stars 52 forks source link

Warning when paraxiality is violated #59

Open jmmelko opened 3 years ago

jmmelko commented 3 years ago

I suggest to add a warning when the paraxial approximation is violated, especially when using the Lens function. Or to add a special function to test it on demand. I know this cannot replace common physical sense, but that could help.

I have read that it happens when :

z <~ m * (x^4/labda)^(1/3).

for a lens, z == f, and x could be half the grid siz. As for m, we could use 1 as a first implementation. Indeed, we can safely assume that most people will use a grid “a few times” larger than the beam radius w. Let’s call this margin N. So, if the m=1 condition is violated at r=grid.siz, then the m=N violation will occur at r=grid.siz/m == w.

FredvanGoor commented 3 years ago

I released a new version of LightPipes (2.0.8) which includes a new command "propagate". This command is still experimental and the idea is to call Fresnel or Forvard depending on some criterium. Maybe the formula z <~ m * (x^4/labda)^(1/3) can be used for this? Please provide me with comments about this!

Fred van Goor.

At this moment the propagate command (in propagators.py) looks like this:

def Propagate(Fin,z,UseFresnel=False,UseForvard=False):
    xs,ys=D4sigma(Fin)
    M=10
    NF=M*(((xs**4)/Fin.lam)**0.333)/z # Check with formula given by jjmelko in issue 59
    #NF=xs*xs/Fin.lam/z #Check with Fresnel number
    print(NF)
    if Fin._IsGauss: #obvious choice ...
        print('using GForvard, pure Gauss field')
        return GForvard(Fin,z)
    else:
        if UseFresnel and not UseForvard:
            print('forced to use Fresnel')
            return Fresnel(Fin,z)
        if UseForvard and not UseFresnel:
            print('forced to use Forvard')
            return Forvard(Fin,z)
        if UseForvard and UseFresnel:
            print('cannot force both methods!, no propagation performed')
            return Fin
        if NF > 1:
            print('using Fresnel because NF = {:4.2f}'.format(NF))
            return Fresnel(Fin,z)
        else:
            print('using Forvard because NF = {:4.2f}'.format(NF))
            return Forvard(Fin,z)
jmmelko commented 3 years ago

That’s great but I thought that only Forward, with a double-u, was exact, while Forvard and Fresnel were paraxial approximations.

In any case I think that an automatic propagator is a good idea, that’s what is used by VirtualLab Fusion (they also have the Spectrum of Plane Wave method, SPW):

46868820-0063-4EAF-B207-70438365A06C

Of Forward is added, I think that a safeguard should be added when grid size is large.

And maybe the NF criterion should be rescaled to a reference NF0 value, to be more intuitive, especially when printing the reason why a propagator has been chosen. For instance: “has been chosen because the grid size is Y% larger than the maximum value allowed within the paraxial approximation”.

x0 = ((z**3/m)*lbda)**0.25
m = 10 #in your implementation
Y = x/x0