AnisoCADO 0.2.3__py3-none-any.whl → 0.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of AnisoCADO might be problematic. Click here for more details.

anisocado/psf_utils.py CHANGED
@@ -1,16 +1,6 @@
1
- """Originally from file _anisocado.py"""
1
+ # -*- coding: utf-8 -*-
2
+ """Originally from file _anisocado.py.
2
3
 
3
- import numpy as np
4
- from . import pupil_utils
5
-
6
- # ____ _____ _ ____ __ __ _____
7
- # | _ \| ____| / \ | _ \| \/ | ____|
8
- # | |_) | _| / _ \ | | | | |\/| | _|
9
- # | _ <| |___ / ___ \| |_| | | | | |___
10
- # |_| \_\_____/_/ \_\____/|_| |_|_____|
11
-
12
- """
13
- Hello.
14
4
  This files contains some useful functions related to psf generation.
15
5
  They are just raw, so that you can insert them into your own classes
16
6
  as desired.
@@ -23,6 +13,9 @@ It contains examples that will show you how to use the functions, what they do,
23
13
  etc.
24
14
  """
25
15
 
16
+ import numpy as np
17
+ from . import pupil_utils
18
+
26
19
 
27
20
  def defineDmFrequencyArea(kx, ky, rotdegree, dactu=0.5403):
28
21
  """
@@ -46,19 +39,18 @@ def defineDmFrequencyArea(kx, ky, rotdegree, dactu=0.5403):
46
39
  wavelength = 1.65e-6 # metres
47
40
  kx, ky = computeSpatialFreqArrays(N, pixelSize, wavelength)
48
41
  M4 = defineDmFrequencyArea(kx, ky, 0)
49
- plt.imshow(np.fft.fftshift(M4).T, origin='l')
42
+ plt.imshow(np.fft.fftshift(M4).T, origin="l")
50
43
 
51
44
  """
52
-
53
45
  # cut-off frequency
54
46
  fc = (1./np.sqrt(3)) / dactu
55
47
 
56
48
  # mask frequency definition
57
49
  A = np.pi/3 # 60 degrees
58
50
  A0 = rotdegree * np.pi / 180
59
- msk = np.abs(np.cos(A0)*ky+np.sin(A0)*kx)<fc
60
- msk = np.logical_and(msk, np.abs(np.cos(A+A0)*ky+np.sin(A+A0)*kx)<fc)
61
- msk = np.logical_and(msk, np.abs(np.cos(2*A+A0)*ky+np.sin(2*A+A0)*kx)<fc)
51
+ msk = np.abs(np.cos(A0)*ky+np.sin(A0)*kx) < fc
52
+ msk = np.logical_and(msk, np.abs(np.cos(A+A0)*ky+np.sin(A+A0)*kx) < fc)
53
+ msk = np.logical_and(msk, np.abs(np.cos(2*A+A0)*ky+np.sin(2*A+A0)*kx) < fc)
62
54
  k = np.sqrt(kx**2 + ky**2)
63
55
  msk = np.logical_and(msk, k < (fc*1.115))
64
56
 
@@ -85,7 +77,6 @@ def computeSpatialFreqArrays(N, pixelSize, wavelength):
85
77
  kx, ky, uk = computeSpatialFreqArrays(N, pixelSize, wavelength)
86
78
 
87
79
  """
88
-
89
80
  # array of indices centred 'as expected' by Fourier frequencies, in 1D
90
81
  k1d = np.fft.fftshift(np.arange(N) - (N//2))
91
82
 
@@ -97,7 +88,7 @@ def computeSpatialFreqArrays(N, pixelSize, wavelength):
97
88
  k1d = k1d * uk # now this is a spatial freq in metres^-1
98
89
 
99
90
  # now creating 2D arrays of spatial frequency
100
- kx, ky = np.meshgrid(k1d, k1d, indexing='ij') # for convention [x,y]
91
+ kx, ky = np.meshgrid(k1d, k1d, indexing="ij") # for convention [x,y]
101
92
 
102
93
  return kx, ky, uk
103
94
 
@@ -126,7 +117,6 @@ def computeWiener(kx, ky, L0, r0):
126
117
  W = computeWiener(kx, ky, L0, r0)
127
118
 
128
119
  """
129
-
130
120
  # computation of Wiener spectrum expressed in radians^2 (at the wavelength
131
121
  # where r0(lambda) is expressed !)
132
122
  Wiener = (kx**2 + ky**2 + 1./L0**2.)**(-11./6)
@@ -178,7 +168,6 @@ def anisoplanaticSpectrum(Cn2h, layerAltitude, L0, offx, offy, wavelength,
178
168
  wavelength, kx, ky, W, M4)
179
169
 
180
170
  """
181
-
182
171
  # number of turbulent layers involved in that computation
183
172
  nlayers = len(Cn2h)
184
173
 
@@ -190,10 +179,11 @@ def anisoplanaticSpectrum(Cn2h, layerAltitude, L0, offx, offy, wavelength,
190
179
 
191
180
  # loop over turbulent layers, summing transfer function of each layer
192
181
  for i in range(nlayers):
193
- dx = layerAltitude[i] * offx / RASC # shift in metres on the layer in X
194
- dy = layerAltitude[i] * offy / RASC # idem, in Y
182
+ # shift in metres on the layer in X
183
+ dx = layerAltitude[i] * offx / RASC
184
+ dy = layerAltitude[i] * offy / RASC # idem, in Y
195
185
  tmp = (2j*np.pi*dx)*kx + (2j*np.pi*dy)*ky
196
- Haniso += Cn2h[i] * np.abs(1 - np.exp( tmp ))**2
186
+ Haniso += Cn2h[i] * np.abs(1 - np.exp(tmp))**2
197
187
 
198
188
  # now applying the transfer function on the Wiener spectrum, only in the
199
189
  # spatial frequency range of M4
@@ -228,9 +218,8 @@ def fittingSpectrum(Wiener, M4):
228
218
  f = fittingSpectrum(W, M4)
229
219
 
230
220
  """
231
-
232
221
  Wfit = Wiener.copy()
233
- Wfit[M4] = 0.0 # M4 cancels whatever is in its compensation domain
222
+ Wfit[M4] = 0.0 # M4 cancels whatever is in its compensation domain
234
223
  return Wfit
235
224
 
236
225
 
@@ -255,7 +244,6 @@ def otherSpectrum(nmRms, M4, uk, wavelength):
255
244
  f = otherSpectrum(nmRms, M4, uk, wavelength)
256
245
 
257
246
  """
258
-
259
247
  fact = 2 * np.pi * nmRms * 1e-9 / uk / wavelength
260
248
  fact = fact**2
261
249
  tot = np.sum(M4)
@@ -280,12 +268,11 @@ def aliasingSpectrum(kx, ky, r0, L0, M4, dssp=0.4015):
280
268
  W = aliasingSpectrum(kx, ky, r0, L0, M4)
281
269
 
282
270
  """
283
-
284
271
  ke = 1.0 / dssp # computes the sampling spatial-frequency of the WFS
285
272
 
286
273
  kxt = kx[M4]
287
274
  kyt = ky[M4]
288
- Wt = ((kxt-ke)**2 + kyt**2 + 1./L0**2.)**(-11./6)
275
+ Wt = ((kxt-ke)**2 + kyt**2 + 1./L0**2.)**(-11./6)
289
276
  Wt += ((kxt+ke)**2 + kyt**2 + 1./L0**2.)**(-11./6)
290
277
  Wt += (kxt**2 + (kyt-ke)**2 + 1./L0**2.)**(-11./6)
291
278
  Wt += (kxt**2 + (kyt+ke)**2 + 1./L0**2.)**(-11./6)
@@ -317,9 +304,9 @@ def computeBpSpectrum(kx, ky, V, Fe, tret, gain, Wiener, M4):
317
304
  f = computeBpSpectrum(kx, ky, V, Fe, tret, gain, W, M4)
318
305
 
319
306
  """
320
-
321
307
  k = np.sqrt(kx*kx + ky*ky)
322
- nu = k * V / np.sqrt(2) # pourquoi un sqrt(2) ? je ne saurais dire ...!!!
308
+ # pourquoi un sqrt(2) ? je ne saurais dire ...!!!
309
+ nu = k * V / np.sqrt(2)
323
310
  Wbp = hcor(nu, Fe, tret, gain, 500) * Wiener
324
311
  Wbp[np.logical_not(M4)] = 0.
325
312
  return Wbp
@@ -337,17 +324,16 @@ def hcor(freq, Fe, tret, G, BP, an=True):
337
324
  end of the integration and the start of the command.
338
325
 
339
326
  """
340
-
341
327
  Te = 1. / Fe
342
328
  p = 1j * 2 * np.pi * freq + 1e-12
343
329
 
344
- Hint = 1./(1-np.exp(-p*Te)) # numeric integrator
330
+ Hint = 1./(1-np.exp(-p*Te)) # numeric integrator
345
331
  Hccd = (1.-np.exp(-p*Te))/(p*Te) # echant bloqueur avec retard 1/2 trame
346
332
  Hdac = Hccd # echant bloqueur avec retard 1/2 trame
347
333
  Hret = np.exp(-p*tret)
348
334
  Hmir = 1./(1. + 1j*freq/BP)
349
335
  Hbo = Hint * Hccd * Hdac * Hret * Hmir
350
- Hcor = 1./abs(1 + Hbo*G)**2
336
+ Hcor = 1./abs(1 + Hbo*G)**2
351
337
 
352
338
  return Hcor
353
339
 
@@ -362,14 +348,14 @@ def convertSpectrum2Dphi(W, uk):
362
348
  Uses Dphi(r) = $ $ (1-cos(2.pi.k.r)) W(k) d2k
363
349
  Computation of Dphi is in radians^2 at the wavelength of r0.
364
350
  """
365
-
366
351
  W[0, 0] = 0.0
367
352
  W[0, 0] = -np.sum(W)
368
- Dphi = 2*np.abs(np.fft.fft2(W)) * (uk**2)
353
+ Dphi = 2*np.abs(np.fft.fft2(W)) * (uk**2)
369
354
  return Dphi
370
355
 
371
356
 
372
- def fake_generatePupil(N, deadSegments, rotdegree, pixelSize, wavelength, rng=np.random.default_rng()):
357
+ def fake_generatePupil(N, deadSegments, rotdegree, pixelSize, wavelength,
358
+ rng=np.random.default_rng()):
373
359
  """
374
360
  <N> : size of the output image, that is made to match the size
375
361
  of the (square) psf image to be processed. In other
@@ -414,11 +400,9 @@ def fake_generatePupil(N, deadSegments, rotdegree, pixelSize, wavelength, rng=np
414
400
 
415
401
 
416
402
  def computeEeltOTF(pup):
417
- """
418
- """
419
- # Computation of telescope OTF
403
+ """Compute the telescope OTF."""
420
404
  Nx, Ny = pup.shape
421
- FTOtel = np.fft.fft2( np.abs(np.fft.fft2(pup))**2 ).real
405
+ FTOtel = np.fft.fft2(np.abs(np.fft.fft2(pup))**2).real
422
406
  FTOtel /= np.sum(pup)**2 * Nx * Ny
423
407
  return FTOtel
424
408
 
@@ -472,12 +456,11 @@ def core_generatePsf(Dphi, FTOtel):
472
456
  plt.imshow( psf[N//2-window:N//2+window, N//2-window:N//2+window]**0.3 )
473
457
 
474
458
  """
475
-
476
459
  # total FTO
477
460
  FTO = np.exp(-0.5*Dphi) * FTOtel
478
461
 
479
462
  # PSF
480
- psf = np.fft.fftshift( np.fft.fft2(FTO).real )
463
+ psf = np.fft.fftshift(np.fft.fft2(FTO).real)
481
464
  return psf
482
465
 
483
466
 
@@ -510,7 +493,6 @@ def createAdHocScaoPsf(N, pixelSize, wavelengthIR, rotdegree, r0Vis, nmRms):
510
493
  r0Vis, nmRms)
511
494
 
512
495
  """
513
-
514
496
  # let's compute r0 in the IR using the
515
497
  # r0 chromatic translation formula
516
498
  wavelengthVis = 500e-9
@@ -566,14 +548,13 @@ def airmassImpact(r0_at_zenith, zenith_distance):
566
548
  distance. This function converts a r0 given at zenith into the real r0
567
549
  actually observed by the telescope.
568
550
  """
569
-
570
551
  z = zenith_distance * np.pi / 180 # the same, in radians
571
552
  r0 = r0_at_zenith * np.cos(z)**(3./5)
572
553
 
573
554
  return r0
574
555
 
575
556
 
576
- def get_atmospheric_turbulence(myProfile='EsoMedian'):
557
+ def get_atmospheric_turbulence(myProfile="EsoMedian"):
577
558
  """
578
559
  Returns the relative level of turbulence at a given height
579
560
 
@@ -614,7 +595,7 @@ def get_atmospheric_turbulence(myProfile='EsoMedian'):
614
595
  Parameters
615
596
  ----------
616
597
  myProfile : str, optional
617
- Profile name: ['EsoQ1', 'EsoMedian', 'EsoQ4', 'oldEso', 'gendron']
598
+ Profile name: ["EsoQ1", "EsoMedian", "EsoQ4", "oldEso", "gendron"]
618
599
 
619
600
  Returns
620
601
  -------
@@ -624,15 +605,14 @@ def get_atmospheric_turbulence(myProfile='EsoMedian'):
624
605
  Relative strength of turbulence
625
606
 
626
607
  """
627
-
628
608
  layerAltitude, Cn2h = [], []
629
609
 
630
- if myProfile == 'oldEso':
610
+ if myProfile == "oldEso":
631
611
  layerAltitude = [47., 140, 281, 562, 1125, 2250, 4500, 9000, 18000.]
632
612
  Cn2h = [0.5224, 0.026, 0.0444, 0.116, 0.0989,
633
613
  0.0295, 0.0598, 0.043, 0.06]
634
614
 
635
- elif myProfile == 'officialEsoMedian' or myProfile == 'EsoMedian' :
615
+ elif myProfile == "officialEsoMedian" or myProfile == "EsoMedian":
636
616
  layerAltitude = [30, 90, 150, 200, 245, 300, 390, 600, 1130, 1880, 2630,
637
617
  3500, 4500, 5500, 6500, 7500, 8500, 9500, 10500, 11500,
638
618
  12500, 13500, 14500, 15500, 16500, 17500, 18500, 19500,
@@ -644,7 +624,7 @@ def get_atmospheric_turbulence(myProfile='EsoMedian'):
644
624
  Cn2h = np.array(Cn2h)
645
625
  Cn2h /= np.sum(Cn2h)
646
626
 
647
- elif myProfile == 'EsoQ1':
627
+ elif myProfile == "EsoQ1":
648
628
  layerAltitude = [30, 90, 150, 200, 245, 300, 390, 600, 1130, 1880, 2630,
649
629
  3500, 4500, 5500, 6500, 7500, 8500, 9500, 10500, 11500,
650
630
  12500, 13500, 14500, 15500, 16500, 17500, 18500, 19500,
@@ -656,7 +636,7 @@ def get_atmospheric_turbulence(myProfile='EsoMedian'):
656
636
  Cn2h = np.array(Cn2h)
657
637
  Cn2h /= np.sum(Cn2h)
658
638
 
659
- elif myProfile == 'EsoQ4':
639
+ elif myProfile == "EsoQ4":
660
640
  layerAltitude = [30, 90, 150, 200, 245, 300, 390, 600, 1130, 1880, 2630,
661
641
  3500, 4500, 5500, 6500, 7500, 8500, 9500, 10500, 11500,
662
642
  12500, 13500, 14500, 15500, 16500, 17500, 18500, 19500,
@@ -668,7 +648,7 @@ def get_atmospheric_turbulence(myProfile='EsoMedian'):
668
648
  Cn2h = np.array(Cn2h)
669
649
  Cn2h /= np.sum(Cn2h)
670
650
 
671
- elif myProfile == 'gendron':
651
+ elif myProfile == "gendron":
672
652
  Cn2h = [1.0]
673
653
  layerAltitude = [4414.]
674
654
 
@@ -697,11 +677,11 @@ def get_profile_defaults(myProfile="EsoMedian"):
697
677
  seeing = 0.67
698
678
  zen_dist = 30
699
679
  wind_alpha = 1.
700
- if myProfile == 'EsoQ1':
680
+ if myProfile == "EsoQ1":
701
681
  seeing = 0.4
702
682
  zen_dist = 0
703
683
  wind_alpha = 0.88
704
- elif myProfile == 'EsoQ4':
684
+ elif myProfile == "EsoQ4":
705
685
  seeing = 1.0
706
686
  zen_dist = 60
707
687
  wind_alpha = 1.3
@@ -728,6 +708,3 @@ def round_edges(kernel, edge_width=10):
728
708
  kernel[:, -n:] *= falloff
729
709
 
730
710
  return kernel
731
-
732
-
733
-