foscat 3.6.0__py3-none-any.whl → 3.7.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.
foscat/alm.py CHANGED
@@ -1,178 +1,191 @@
1
+ import time
2
+
1
3
  import healpy as hp
2
4
  import numpy as np
3
- import time
4
5
 
5
- class alm():
6
6
 
7
- def __init__(self,backend=None,lmax=24,
8
- nside=None,limit_range=1E10):
9
-
7
+ class alm:
8
+
9
+ def __init__(self, backend=None, lmax=24, nside=None, limit_range=1e10):
10
+
10
11
  if backend is None:
11
12
  import foscat.scat_cov as sc
12
- self.sc=sc.funct()
13
- self.backend=self.sc.backend
13
+
14
+ self.sc = sc.funct()
15
+ self.backend = self.sc.backend
14
16
  else:
15
- self.backend=backend.backend
16
-
17
- self._logtab={}
18
- self.lth={}
19
- self.lph={}
20
- self.matrix_shift_ph={}
21
- self.ratio_mm={}
22
- self.P_mm={}
23
- self.A={}
24
- self.B={}
17
+ self.backend = backend.backend
18
+
19
+ self._logtab = {}
20
+ self.lth = {}
21
+ self.lph = {}
22
+ self.matrix_shift_ph = {}
23
+ self.ratio_mm = {}
24
+ self.P_mm = {}
25
+ self.A = {}
26
+ self.B = {}
25
27
  if nside is not None:
26
- self.maxlog=6*nside+1
27
- self.lmax=3*nside
28
+ self.maxlog = 6 * nside + 1
29
+ self.lmax = 3 * nside
28
30
  else:
29
- self.lmax=lmax
30
- self.maxlog=2*lmax+1
31
-
32
- for k in range(1,self.maxlog):
33
- self._logtab[k]=self.backend.bk_log(self.backend.bk_cast(k))
34
- self._logtab[0]=0.0
31
+ self.lmax = lmax
32
+ self.maxlog = 2 * lmax + 1
33
+
34
+ for k in range(1, self.maxlog):
35
+ self._logtab[k] = self.backend.bk_log(self.backend.bk_cast(k))
36
+ self._logtab[0] = 0.0
35
37
 
36
38
  if nside is not None:
37
39
  self.ring_th(nside)
38
40
  self.ring_ph(nside)
39
41
  self.shift_ph(nside)
40
-
41
- self._limit_range=1/limit_range
42
- self._log_limit_range=np.log(limit_range)
43
-
44
42
 
45
- self.Yp={}
46
- self.Ym={}
43
+ self._limit_range = 1 / limit_range
44
+ self._log_limit_range = np.log(limit_range)
45
+
46
+ self.Yp = {}
47
+ self.Ym = {}
47
48
 
48
- def ring_th(self,nside):
49
+ def ring_th(self, nside):
49
50
  if nside not in self.lth:
50
- n=0
51
- ith=[]
52
- for k in range(nside-1):
53
- N=4*(k+1)
51
+ n = 0
52
+ ith = []
53
+ for k in range(nside - 1):
54
+ N = 4 * (k + 1)
54
55
  ith.append(n)
55
- n+=N
56
-
57
- for k in range(2*nside+1):
58
- N=4*nside
56
+ n += N
57
+
58
+ for k in range(2 * nside + 1):
59
+ N = 4 * nside
59
60
  ith.append(n)
60
- n+=N
61
- for k in range(nside-1):
62
- N=4*(nside-1-k)
61
+ n += N
62
+ for k in range(nside - 1):
63
+ N = 4 * (nside - 1 - k)
63
64
  ith.append(n)
64
- n+=N
65
-
66
- th,ph=hp.pix2ang(nside,ith)
67
-
68
- self.lth[nside]=th
65
+ n += N
66
+
67
+ th, ph = hp.pix2ang(nside, ith)
68
+
69
+ self.lth[nside] = th
69
70
  return self.lth[nside]
70
-
71
- def ring_ph(self,nside):
71
+
72
+ def ring_ph(self, nside):
72
73
  if nside not in self.lph:
73
- n=0
74
- iph=[]
75
- for k in range(nside-1):
76
- N=4*(k+1)
74
+ n = 0
75
+ iph = []
76
+ for k in range(nside - 1):
77
+ N = 4 * (k + 1)
77
78
  iph.append(n)
78
- n+=N
79
-
80
- for k in range(2*nside+1):
81
- N=4*nside
79
+ n += N
80
+
81
+ for k in range(2 * nside + 1):
82
+ N = 4 * nside
82
83
  iph.append(n)
83
- n+=N
84
- for k in range(nside-1):
85
- N=4*(nside-1-k)
84
+ n += N
85
+ for k in range(nside - 1):
86
+ N = 4 * (nside - 1 - k)
86
87
  iph.append(n)
87
- n+=N
88
-
89
- th,ph=hp.pix2ang(nside,iph)
90
-
91
- self.lph[nside]=ph
92
-
93
- def shift_ph(self,nside):
94
-
88
+ n += N
89
+
90
+ th, ph = hp.pix2ang(nside, iph)
91
+
92
+ self.lph[nside] = ph
93
+
94
+ def shift_ph(self, nside):
95
+
95
96
  if nside not in self.matrix_shift_ph:
96
97
  self.ring_th(nside)
97
98
  self.ring_ph(nside)
98
- x=(-1J*np.arange(3*nside)).reshape(1,3*nside)
99
- self.matrix_shift_ph[nside]=self.backend.bk_cast(self.backend.bk_exp(x*self.lph[nside].reshape(4*nside-1,1)))
100
-
101
- self.lmax=3*nside-1
102
-
103
- ratio_mm={}
104
-
105
- for m in range(3*nside):
106
- val=np.zeros([self.lmax-m+1])
107
- aval=np.zeros([self.lmax-m+1])
108
- bval=np.zeros([self.lmax-m+1])
109
-
110
- if m>0:
111
- val[0]=self.double_factorial_log(2*m - 1)-0.5*np.sum(np.log(1+np.arange(2*m)))
99
+ x = (-1j * np.arange(3 * nside)).reshape(1, 3 * nside)
100
+ self.matrix_shift_ph[nside] = self.backend.bk_cast(
101
+ self.backend.bk_exp(x * self.lph[nside].reshape(4 * nside - 1, 1))
102
+ )
103
+
104
+ self.lmax = 3 * nside - 1
105
+
106
+ ratio_mm = {}
107
+
108
+ for m in range(3 * nside):
109
+ val = np.zeros([self.lmax - m + 1])
110
+ aval = np.zeros([self.lmax - m + 1])
111
+ bval = np.zeros([self.lmax - m + 1])
112
+
113
+ if m > 0:
114
+ val[0] = self.double_factorial_log(2 * m - 1) - 0.5 * np.sum(
115
+ np.log(1 + np.arange(2 * m))
116
+ )
112
117
  else:
113
- val[0]=self.double_factorial_log(2*m - 1)
114
- if m<self.lmax:
115
- aval[1]=(2*m + 1)
116
- val[1] = val[0]-0.5*self.log(2*m+1)
117
-
118
- for l in range(m + 2, self.lmax+1):
119
- aval[l-m]=(2*l - 1)/ (l - m)
120
- bval[l-m]=(l + m - 1)/ (l - m)
121
- val[l-m] = val[l-m-1] + 0.5*self.log(l-m) - 0.5*self.log(l+m)
122
-
123
- self.A[nside,m]=self.backend.constant((aval))
124
- self.B[nside,m]=self.backend.constant((bval))
125
- self.ratio_mm[nside,m]=self.backend.constant(np.sqrt(4*np.pi)*np.expand_dims(np.exp(val),1))
118
+ val[0] = self.double_factorial_log(2 * m - 1)
119
+ if m < self.lmax:
120
+ aval[1] = 2 * m + 1
121
+ val[1] = val[0] - 0.5 * self.log(2 * m + 1)
122
+
123
+ for l in range(m + 2, self.lmax + 1):
124
+ aval[l - m] = (2 * l - 1) / (l - m)
125
+ bval[l - m] = (l + m - 1) / (l - m)
126
+ val[l - m] = (
127
+ val[l - m - 1]
128
+ + 0.5 * self.log(l - m)
129
+ - 0.5 * self.log(l + m)
130
+ )
131
+
132
+ self.A[nside, m] = self.backend.constant((aval))
133
+ self.B[nside, m] = self.backend.constant((bval))
134
+ self.ratio_mm[nside, m] = self.backend.constant(
135
+ np.sqrt(4 * np.pi) * np.expand_dims(np.exp(val), 1)
136
+ )
126
137
  # Calcul de P_{mm}(x)
127
- P_mm=np.ones([3*nside,4*nside-1])
128
- x=np.cos(self.lth[nside])
138
+ P_mm = np.ones([3 * nside, 4 * nside - 1])
139
+ x = np.cos(self.lth[nside])
129
140
  if m == 0:
130
141
  P_mm[m] = 1.0
131
- for m in range(3*nside-1):
132
- P_mm[m] = (0.5-m%2)*2 * (1 - x**2)**(m/2)
133
- self.P_mm[nside]=self.backend.constant(P_mm)
134
-
135
- def init_Ys(self,s,nside):
142
+ for m in range(3 * nside - 1):
143
+ P_mm[m] = (0.5 - m % 2) * 2 * (1 - x**2) ** (m / 2)
144
+ self.P_mm[nside] = self.backend.constant(P_mm)
145
+
146
+ def init_Ys(self, s, nside):
136
147
 
137
- if (s,nside) not in self.Yp:
148
+ if (s, nside) not in self.Yp:
138
149
  import quaternionic
139
150
  import spherical
140
151
 
141
- ell_max = 3*nside-1 # Use the largest ℓ value you expect to need
152
+ ell_max = 3 * nside - 1 # Use the largest ℓ value you expect to need
142
153
  wigner = spherical.Wigner(ell_max)
143
154
 
144
- #th,ph=hp.pix2ang(nside,np.arange(12*nside*nside))
145
-
146
- lth=self.ring_th(nside)
147
-
148
- R = quaternionic.array.from_spherical_coordinates(lth, 0*lth)
149
- self.Yp[s,nside] = {}
150
- self.Ym[s,nside] = {}
151
- iplus = (wigner.sYlm( s, R)*(4*np.pi/(12*nside**2))).T.real
152
- imoins = (wigner.sYlm(-s, R)*(4*np.pi/(12*nside**2))).T.real
153
-
154
- for m in range(ell_max+1):
155
- idx=np.array([wigner.Yindex(k, m) for k in range(m,ell_max+1)])
156
- vnorm=1/np.expand_dims(np.sqrt(2*(np.arange(ell_max-m+1)+m)+1),1)
157
- self.Yp[s,nside][m] = iplus[idx]*vnorm
158
- self.Ym[s,nside][m] = imoins[idx]*vnorm
159
-
160
- del(iplus)
161
- del(imoins)
162
- del(wigner)
163
-
164
- def log(self,v):
155
+ # th,ph=hp.pix2ang(nside,np.arange(12*nside*nside))
156
+
157
+ lth = self.ring_th(nside)
158
+
159
+ R = quaternionic.array.from_spherical_coordinates(lth, 0 * lth)
160
+ self.Yp[s, nside] = {}
161
+ self.Ym[s, nside] = {}
162
+ iplus = (wigner.sYlm(s, R) * (4 * np.pi / (12 * nside**2))).T.real
163
+ imoins = (wigner.sYlm(-s, R) * (4 * np.pi / (12 * nside**2))).T.real
164
+
165
+ for m in range(ell_max + 1):
166
+ idx = np.array([wigner.Yindex(k, m) for k in range(m, ell_max + 1)])
167
+ vnorm = 1 / np.expand_dims(
168
+ np.sqrt(2 * (np.arange(ell_max - m + 1) + m) + 1), 1
169
+ )
170
+ self.Yp[s, nside][m] = iplus[idx] * vnorm
171
+ self.Ym[s, nside][m] = imoins[idx] * vnorm
172
+
173
+ del iplus
174
+ del imoins
175
+ del wigner
176
+
177
+ def log(self, v):
165
178
  return np.log(v)
166
- if isinstance(v,np.ndarray):
179
+ if isinstance(v, np.ndarray):
167
180
  return np.array([self.backend.bk_log(self.backend.bk_cast(k)) for k in v])
168
- if v<self.maxlog:
181
+ if v < self.maxlog:
169
182
  return self._logtab[v]
170
183
  else:
171
- self._logtab[v]=self.backend.bk_log(self.backend.bk_cast(v))
184
+ self._logtab[v] = self.backend.bk_log(self.backend.bk_cast(v))
172
185
  return self._logtab[v]
173
186
 
174
187
  # Fonction pour calculer la double factorielle
175
- def double_factorial_log(self,n):
188
+ def double_factorial_log(self, n):
176
189
  if n <= 0:
177
190
  return 0.0
178
191
  result = 0.0
@@ -180,7 +193,7 @@ class alm():
180
193
  result += np.log(i)
181
194
  return result
182
195
 
183
- def recurrence_fn(self,states, inputs):
196
+ def recurrence_fn(self, states, inputs):
184
197
  """
185
198
  Fonction de récurrence pour tf.scan.
186
199
  states: un tuple (U_{n-1}, U_{n-2}) de forme [m]
@@ -190,62 +203,73 @@ class alm():
190
203
  a_n, b_n = inputs # a_n est de forme [m], b_n est un scalaire
191
204
  U_n = a_n * U_prev - b_n * U_prev2
192
205
  return (U_n, U_prev) # Avancer les états
193
- # Calcul des P_{lm}(x) pour tout l inclus dans [m,lmax]
194
- def compute_legendre_m(self,x,m,lmax,nside):
195
- result=np.zeros([lmax-m+1,x.shape[0]])
196
- ratio=np.zeros([lmax-m+1,1])
197
-
198
- ratio[0,0] = self.double_factorial_log(2*m - 1)-0.5*np.sum(self.log(1+np.arange(2*m)))
199
-
206
+
207
+ # Calcul des P_{lm}(x) pour tout l inclus dans [m,lmax]
208
+ def compute_legendre_m(self, x, m, lmax, nside):
209
+ result = np.zeros([lmax - m + 1, x.shape[0]])
210
+ ratio = np.zeros([lmax - m + 1, 1])
211
+
212
+ ratio[0, 0] = self.double_factorial_log(2 * m - 1) - 0.5 * np.sum(
213
+ self.log(1 + np.arange(2 * m))
214
+ )
215
+
200
216
  # Étape 1 : Calcul de P_{mm}(x)
201
217
  if m == 0:
202
218
  Pmm = 1.0
203
219
  else:
204
- #Pmm = (-1)**m * (1 - x**2)**(m/2)
205
- Pmm = (0.5-m%2)*2 * (1 - x**2)**(m/2)
206
-
207
-
220
+ # Pmm = (-1)**m * (1 - x**2)**(m/2)
221
+ Pmm = (0.5 - m % 2) * 2 * (1 - x**2) ** (m / 2)
222
+
208
223
  # Si l == m, c'est directement P_{mm}
209
- result[0] = Pmm
210
-
224
+ result[0] = Pmm
225
+
211
226
  if m == lmax:
212
- return result*np.exp(ratio)*np.sqrt(4*np.pi)
213
-
227
+ return result * np.exp(ratio) * np.sqrt(4 * np.pi)
228
+
214
229
  # Étape 2 : Calcul de P_{l+1, m}(x)
215
- result[1] = x * (2*m + 1) * result[0]
230
+ result[1] = x * (2 * m + 1) * result[0]
231
+
232
+ ratio[1, 0] = ratio[0, 0] - 0.5 * self.log(2 * m + 1)
216
233
 
217
- ratio[1,0] = ratio[0,0]-0.5*self.log(2*m+1)
218
-
219
234
  # Étape 3 : Récurence pour l > m + 1
220
- for l in range(m + 2, lmax+1):
221
- result[l-m] = ((2*l - 1) * x * result[l-m-1] - (l + m - 1) * result[l-m-2]) / (l - m)
222
- ratio[l-m,0] = 0.5*self.log(l-m)-0.5*self.log(l+m)+ratio[l-m-1,0]
223
- if np.max(abs(result[l-m]))>self._limit_range:
224
- result[l-m-1]*= self._limit_range
225
- result[l-m]*= self._limit_range
226
- ratio[l-m-1,0]+= self._log_limit_range
227
- ratio[l-m,0]+= self._log_limit_range
228
-
229
- return result*np.exp(ratio)*np.sqrt(4*np.pi)
235
+ for l in range(m + 2, lmax + 1):
236
+ result[l - m] = (
237
+ (2 * l - 1) * x * result[l - m - 1] - (l + m - 1) * result[l - m - 2]
238
+ ) / (l - m)
239
+ ratio[l - m, 0] = (
240
+ 0.5 * self.log(l - m) - 0.5 * self.log(l + m) + ratio[l - m - 1, 0]
241
+ )
242
+ if np.max(abs(result[l - m])) > self._limit_range:
243
+ result[l - m - 1] *= self._limit_range
244
+ result[l - m] *= self._limit_range
245
+ ratio[l - m - 1, 0] += self._log_limit_range
246
+ ratio[l - m, 0] += self._log_limit_range
247
+
248
+ return result * np.exp(ratio) * np.sqrt(4 * np.pi)
230
249
 
231
250
  # Calcul des P_{lm}(x) pour tout l inclus dans [m,lmax]
232
- def compute_legendre_m_old2(self,x,m,lmax,nside):
233
-
234
- result={}
235
-
251
+ def compute_legendre_m_old2(self, x, m, lmax, nside):
252
+
253
+ result = {}
254
+
236
255
  # Si l == m, c'est directement P_{mm}
237
- result[0] = self.P_mm[nside][m]
238
-
256
+ result[0] = self.P_mm[nside][m]
257
+
239
258
  if m == lmax:
240
- v=self.backend.bk_reshape(result[0]*self.ratio_mm[nside,m][0],[1,4*nside-1])
241
- return self.backend.bk_complex(v,0*v)
242
-
259
+ v = self.backend.bk_reshape(
260
+ result[0] * self.ratio_mm[nside, m][0], [1, 4 * nside - 1]
261
+ )
262
+ return self.backend.bk_complex(v, 0 * v)
263
+
243
264
  # Étape 2 : Calcul de P_{l+1, m}(x)
244
- result[1] = x * self.A[nside,m][1] * result[0]
245
-
265
+ result[1] = x * self.A[nside, m][1] * result[0]
266
+
246
267
  # Étape 3 : Récurence pour l > m + 1
247
- for l in range(m + 2, lmax+1):
248
- result[l-m] = self.A[nside,m][l-m] * x * result[l-m-1] - self.B[nside,m][l-m] * result[l-m-2]
268
+ for l in range(m + 2, lmax + 1):
269
+ result[l - m] = (
270
+ self.A[nside, m][l - m] * x * result[l - m - 1]
271
+ - self.B[nside, m][l - m] * result[l - m - 2]
272
+ )
249
273
  """
250
274
  if np.max(abs(result[l-m]))>self._limit_range:
251
275
  result[l-m-1]*= self._limit_range
@@ -253,45 +277,62 @@ class alm():
253
277
  ratio[l-m-1]+= self._log_limit_range
254
278
  ratio[l-m]+= self._log_limit_range
255
279
  """
256
- result=self.backend.bk_reshape(self.backend.bk_concat([result[k] for k in range(lmax+1-m)],axis=0),[lmax+1-m,4*nside-1])
280
+ result = self.backend.bk_reshape(
281
+ self.backend.bk_concat([result[k] for k in range(lmax + 1 - m)], axis=0),
282
+ [lmax + 1 - m, 4 * nside - 1],
283
+ )
284
+
285
+ return self.backend.bk_complex(result * self.ratio_mm[nside, m], 0 * result)
257
286
 
258
- return self.backend.bk_complex(result*self.ratio_mm[nside,m],0*result)
287
+ def compute_legendre_m_old(self, x, m, lmax, nside):
259
288
 
260
-
261
- def compute_legendre_m_old(self,x,m,lmax,nside):
262
-
263
289
  import tensorflow as tf
264
- result={}
265
-
290
+
291
+ result = {}
292
+
266
293
  # Si l == m, c'est directement P_{mm}
267
- U_0 = self.P_mm[nside][m]
268
-
294
+ U_0 = self.P_mm[nside][m]
295
+
269
296
  if m == lmax:
270
- v=self.backend.bk_reshape(U_0*self.ratio_mm[nside,m][0],[1,4*nside-1])
271
- return self.backend.bk_complex(v,0*v)
272
-
273
- # Étape 2 : Calcul de P_{l+1, m}(x)
274
- U_1 = x * self.A[nside,m][1] * U_0
275
- if m == lmax-1:
276
- result = tf.concat([self.backend.bk_expand_dims(U_0,0),
277
- self.backend.bk_expand_dims(U_1,0)],0)
278
- return self.backend.bk_complex(result*self.ratio_mm[nside,m],0*result)
297
+ v = self.backend.bk_reshape(
298
+ U_0 * self.ratio_mm[nside, m][0], [1, 4 * nside - 1]
299
+ )
300
+ return self.backend.bk_complex(v, 0 * v)
279
301
 
280
- a_values = self.backend.bk_expand_dims(self.A[nside,m],1)*self.backend.bk_expand_dims(x,0)
302
+ # Étape 2 : Calcul de P_{l+1, m}(x)
303
+ U_1 = x * self.A[nside, m][1] * U_0
304
+ if m == lmax - 1:
305
+ result = tf.concat(
306
+ [
307
+ self.backend.bk_expand_dims(U_0, 0),
308
+ self.backend.bk_expand_dims(U_1, 0),
309
+ ],
310
+ 0,
311
+ )
312
+ return self.backend.bk_complex(result * self.ratio_mm[nside, m], 0 * result)
313
+
314
+ a_values = self.backend.bk_expand_dims(
315
+ self.A[nside, m], 1
316
+ ) * self.backend.bk_expand_dims(x, 0)
281
317
  # Initialiser les états avec (U_1, U_0) pour chaque m
282
318
  initial_states = (U_1, U_0)
283
- inputs = (a_values[2:], self.B[nside,m][2:])
319
+ inputs = (a_values[2:], self.B[nside, m][2:])
284
320
  # Appliquer tf.scan
285
321
  result = tf.scan(self.recurrence_fn, inputs, initializer=initial_states)
286
322
  # Le premier élément de result contient les U[n]
287
- result = tf.concat([self.backend.bk_expand_dims(U_0,0),
288
- self.backend.bk_expand_dims(U_1,0),
289
- result[0]], axis=0)
323
+ result = tf.concat(
324
+ [
325
+ self.backend.bk_expand_dims(U_0, 0),
326
+ self.backend.bk_expand_dims(U_1, 0),
327
+ result[0],
328
+ ],
329
+ axis=0,
330
+ )
290
331
  """
291
332
  # Étape 3 : Récurence pour l > m + 1
292
333
  for l in range(m + 2, lmax+1):
293
334
  result[l-m] = self.A[nside,m][l-m] * x * result[l-m-1] - self.B[nside,m][l-m] * result[l-m-2]
294
-
335
+
295
336
  if np.max(abs(result[l-m]))>self._limit_range:
296
337
  result[l-m-1]*= self._limit_range
297
338
  result[l-m]*= self._limit_range
@@ -299,392 +340,598 @@ class alm():
299
340
  ratio[l-m]+= self._log_limit_range
300
341
  result=self.backend.bk_reshape(self.backend.bk_concat([result[k] for k in range(lmax+1-m)],axis=0),[lmax+1-m,4*nside-1])
301
342
  """
302
-
303
- return self.backend.bk_complex(result*self.ratio_mm[nside,m],0*result)
304
343
 
305
-
344
+ return self.backend.bk_complex(result * self.ratio_mm[nside, m], 0 * result)
345
+
306
346
  # Calcul des s_P_{lm}(x) pour tout l inclus dans [m,lmax]
307
- def compute_legendre_spin2_m(self,co_th,si_th,m,lmax):
308
- result=np.zeros([lmax-m+2,co_th.shape[0]])
309
- ratio =np.zeros([lmax-m+2,1])
310
-
311
- ratio[1,0] = self.double_factorial_log(2*m - 1)-0.5*np.sum(self.log(1+np.arange(2*m)))
347
+ def compute_legendre_spin2_m(self, co_th, si_th, m, lmax):
348
+ result = np.zeros([lmax - m + 2, co_th.shape[0]])
349
+ ratio = np.zeros([lmax - m + 2, 1])
350
+
351
+ ratio[1, 0] = self.double_factorial_log(2 * m - 1) - 0.5 * np.sum(
352
+ self.log(1 + np.arange(2 * m))
353
+ )
312
354
  # Étape 1 : Calcul de P_{mm}(x)
313
355
  if m == 0:
314
356
  Pmm = 1.0
315
357
  else:
316
- #Pmm = (-1)**m * (1 - x**2)**(m/2)
317
- Pmm = (0.5-m%2)*2 * (1 - co_th**2)**(m/2)
318
-
319
-
358
+ # Pmm = (-1)**m * (1 - x**2)**(m/2)
359
+ Pmm = (0.5 - m % 2) * 2 * (1 - co_th**2) ** (m / 2)
360
+
320
361
  # Si l == m, c'est directement P_{mm}
321
- result[1] = Pmm
322
-
362
+ result[1] = Pmm
363
+
323
364
  if m == lmax:
324
- ylm=result*np.exp(ratio)
325
- ylm[1:]*=(np.sqrt(4*np.pi*(2*(np.arange(lmax-m+1)+m)+1))).reshape(lmax+1-m,1)
365
+ ylm = result * np.exp(ratio)
366
+ ylm[1:] *= (
367
+ np.sqrt(4 * np.pi * (2 * (np.arange(lmax - m + 1) + m) + 1))
368
+ ).reshape(lmax + 1 - m, 1)
326
369
 
327
370
  else:
328
371
  # Étape 2 : Calcul de P_{l+1, m}(x)
329
- result[2] = co_th * (2*m + 1) * result[0]
372
+ result[2] = co_th * (2 * m + 1) * result[0]
373
+
374
+ ratio[2, 0] = ratio[1, 0] - self.log(2 * m + 1) / 2
330
375
 
331
- ratio[2,0] = ratio[1,0]-self.log(2*m+1)/2
332
-
333
376
  # Étape 3 : Récurence pour l > m + 1
334
- for l in range(m + 2, lmax+1):
335
- result[l-m+1] = ((2*l - 1) * co_th * result[l-m] - (l + m - 1) * result[l-m-1]) / (l - m)
336
- ratio[l-m+1,0] = (self.log(l-m)-self.log(l+m))/2+ratio[l-m,0]
337
- if np.max(abs(result[l-m+1]))>self._limit_range:
338
- result[l-m]*= self._limit_range
339
- result[l-m+1]*= self._limit_range
340
- ratio[l-m,0]+= self._log_limit_range
341
- ratio[l-m+1,0]+= self._log_limit_range
342
-
343
- ylm=result*np.exp(ratio)
344
- ylm[1:]*=(np.sqrt(4*np.pi*(2*(np.arange(lmax-m+1)+m)+1))).reshape(lmax+1-m,1)
345
-
346
- ell=(np.arange(lmax+1-m)+m).reshape(lmax+1-m,1)
347
-
348
- cot_th=co_th/si_th
349
- si2_th=si_th*si_th
350
-
351
- a = (2*m**2-ell*(ell+1))/(si2_th.reshape(1,si2_th.shape[0]))+ell*(ell-1)*cot_th*cot_th
352
- b = 2*m*(ell-1)*cot_th/si_th
353
- w=np.zeros([lmax+1-m,1])
354
- l=ell[ell>1]
355
- w[ell>1]=np.sqrt(1/((l+2)*(l+1)*(l)*(l-1)))
356
- w=w.reshape(lmax+1-m,1)
357
-
358
- alpha_plus=w*(a+b)
359
- alpha_moins=w*(a-b)
360
-
361
- a=2*np.sqrt((2*ell+1)/(2*ell-1)*(ell*ell-m*m))
362
- b=m/si2_th
363
-
364
- beta_plus=w*a*(cot_th/si_th+b)
365
- beta_moins=w*a*(cot_th/si_th-b)
366
-
367
- ylm_plus = alpha_plus*ylm[1:]+ beta_plus*ylm[:-1]
368
- ylm_moins = alpha_moins*ylm[1:] + beta_moins*ylm[:-1]
369
-
370
- return ylm_plus,ylm_moins
371
-
372
- def rfft2fft(self,val,axis=0):
373
- r=self.backend.bk_rfft(val)
374
- if axis==0:
375
- r_inv=self.backend.bk_reverse(self.backend.bk_conjugate(r[1:-1]),axis=axis)
377
+ for l in range(m + 2, lmax + 1):
378
+ result[l - m + 1] = (
379
+ (2 * l - 1) * co_th * result[l - m]
380
+ - (l + m - 1) * result[l - m - 1]
381
+ ) / (l - m)
382
+ ratio[l - m + 1, 0] = (self.log(l - m) - self.log(l + m)) / 2 + ratio[
383
+ l - m, 0
384
+ ]
385
+ if np.max(abs(result[l - m + 1])) > self._limit_range:
386
+ result[l - m] *= self._limit_range
387
+ result[l - m + 1] *= self._limit_range
388
+ ratio[l - m, 0] += self._log_limit_range
389
+ ratio[l - m + 1, 0] += self._log_limit_range
390
+
391
+ ylm = result * np.exp(ratio)
392
+ ylm[1:] *= (
393
+ np.sqrt(4 * np.pi * (2 * (np.arange(lmax - m + 1) + m) + 1))
394
+ ).reshape(lmax + 1 - m, 1)
395
+
396
+ ell = (np.arange(lmax + 1 - m) + m).reshape(lmax + 1 - m, 1)
397
+
398
+ cot_th = co_th / si_th
399
+ si2_th = si_th * si_th
400
+
401
+ a = (2 * m**2 - ell * (ell + 1)) / (
402
+ si2_th.reshape(1, si2_th.shape[0])
403
+ ) + ell * (ell - 1) * cot_th * cot_th
404
+ b = 2 * m * (ell - 1) * cot_th / si_th
405
+ w = np.zeros([lmax + 1 - m, 1])
406
+ l = ell[ell > 1]
407
+ w[ell > 1] = np.sqrt(1 / ((l + 2) * (l + 1) * (l) * (l - 1)))
408
+ w = w.reshape(lmax + 1 - m, 1)
409
+
410
+ alpha_plus = w * (a + b)
411
+ alpha_moins = w * (a - b)
412
+
413
+ a = 2 * np.sqrt((2 * ell + 1) / (2 * ell - 1) * (ell * ell - m * m))
414
+ b = m / si2_th
415
+
416
+ beta_plus = w * a * (cot_th / si_th + b)
417
+ beta_moins = w * a * (cot_th / si_th - b)
418
+
419
+ ylm_plus = alpha_plus * ylm[1:] + beta_plus * ylm[:-1]
420
+ ylm_moins = alpha_moins * ylm[1:] + beta_moins * ylm[:-1]
421
+
422
+ return ylm_plus, ylm_moins
423
+
424
+ def rfft2fft(self, val, axis=0):
425
+ r = self.backend.bk_rfft(val)
426
+ if axis == 0:
427
+ r_inv = self.backend.bk_reverse(
428
+ self.backend.bk_conjugate(r[1:-1]), axis=axis
429
+ )
430
+ else:
431
+ r_inv = self.backend.bk_reverse(
432
+ self.backend.bk_conjugate(r[:, 1:-1]), axis=axis
433
+ )
434
+ return self.backend.bk_concat([r, r_inv], axis=axis)
435
+
436
+ def irfft2fft(self, val, N, axis=0):
437
+ if axis == 0:
438
+ return self.backend.bk_irfft(val[0 : N // 2 + 1])
376
439
  else:
377
- r_inv=self.backend.bk_reverse(self.backend.bk_conjugate(r[:,1:-1]),axis=axis)
378
- return self.backend.bk_concat([r,r_inv],axis=axis)
379
-
380
- def comp_tf(self,im,nside,realfft=False):
381
-
382
- n=0
383
-
384
- ft_im=[]
385
- for k in range(nside-1):
386
- N=4*(k+1)
387
-
440
+ return self.backend.bk_irfft(val[:, 0 : N // 2 + 1])
441
+
442
+ def comp_tf(self, im, nside, realfft=False):
443
+
444
+ self.shift_ph(nside)
445
+ n = 0
446
+
447
+ ft_im = []
448
+ for k in range(nside - 1):
449
+ N = 4 * (k + 1)
450
+
388
451
  if realfft:
389
- tmp=self.rfft2fft(im[n:n+N])
452
+ tmp = self.rfft2fft(im[n : n + N])
390
453
  else:
391
- tmp=self.backend.bk_fft(im[n:n+N])
392
-
393
- l_n=tmp.shape[0]
394
-
395
- if l_n<3*nside+1:
396
- repeat_n=3*nside//l_n+1
397
- tmp=self.backend.bk_tile(tmp,repeat_n,axis=0)
398
-
399
- ft_im.append(tmp[0:3*nside])
400
-
401
- n+=N
402
- if nside>1:
403
- result=self.backend.bk_reshape(self.backend.bk_concat(ft_im,axis=0),[nside-1,3*nside])
404
-
405
- N=4*nside*(2*nside+1)
406
- v=self.backend.bk_reshape(im[n:n+N],[2*nside+1,4*nside])
454
+ tmp = self.backend.bk_fft(im[n : n + N])
455
+
456
+ l_n = tmp.shape[0]
457
+
458
+ if l_n < 3 * nside + 1:
459
+ repeat_n = 3 * nside // l_n + 1
460
+ tmp = self.backend.bk_tile(tmp, repeat_n, axis=0)
461
+
462
+ ft_im.append(tmp[0 : 3 * nside])
463
+
464
+ n += N
465
+ if nside > 1:
466
+ result = self.backend.bk_reshape(
467
+ self.backend.bk_concat(ft_im, axis=0), [nside - 1, 3 * nside]
468
+ )
469
+
470
+ N = 4 * nside * (2 * nside + 1)
471
+ v = self.backend.bk_reshape(im[n : n + N], [2 * nside + 1, 4 * nside])
407
472
  if realfft:
408
- v_fft=self.rfft2fft(v,axis=1)[:,:3*nside]
473
+ v_fft = self.rfft2fft(v, axis=1)[:, : 3 * nside]
409
474
  else:
410
- v_fft=self.backend.bk_fft(v)[:,:3*nside]
475
+ v_fft = self.backend.bk_fft(v)[:, : 3 * nside]
411
476
 
412
- n+=N
413
- if nside>1:
414
- result=self.backend.bk_concat([result,v_fft],axis=0)
477
+ n += N
478
+ if nside > 1:
479
+ result = self.backend.bk_concat([result, v_fft], axis=0)
415
480
  else:
416
- result=v_fft
417
-
418
- if nside>1:
419
- ft_im=[]
420
- for k in range(nside-1):
421
- N=4*(nside-1-k)
481
+ result = v_fft
482
+
483
+ if nside > 1:
484
+ ft_im = []
485
+ for k in range(nside - 1):
486
+ N = 4 * (nside - 1 - k)
422
487
 
423
488
  if realfft:
424
- tmp=self.rfft2fft(im[n:n+N])[0:l_n]
489
+ tmp = self.rfft2fft(im[n : n + N])[0:l_n]
425
490
  else:
426
- tmp=self.backend.bk_fft(im[n:n+N])[0:l_n]
491
+ tmp = self.backend.bk_fft(im[n : n + N])[0:l_n]
427
492
 
428
- l_n=tmp.shape[0]
493
+ l_n = tmp.shape[0]
429
494
 
430
- if l_n<3*nside+1:
431
- repeat_n=3*nside//l_n+1
432
- tmp=self.backend.bk_tile(tmp,repeat_n,axis=0)
495
+ if l_n < 3 * nside + 1:
496
+ repeat_n = 3 * nside // l_n + 1
497
+ tmp = self.backend.bk_tile(tmp, repeat_n, axis=0)
433
498
 
434
- ft_im.append(tmp[0:3*nside])
435
- n+=N
499
+ ft_im.append(tmp[0 : 3 * nside])
500
+ n += N
436
501
 
437
- lastresult=self.backend.bk_reshape(self.backend.bk_concat(ft_im,axis=0),[nside-1,3*nside])
438
- return self.backend.bk_concat([result,lastresult],axis=0)*self.matrix_shift_ph[nside]
502
+ lastresult = self.backend.bk_reshape(
503
+ self.backend.bk_concat(ft_im, axis=0), [nside - 1, 3 * nside]
504
+ )
505
+ return (
506
+ self.backend.bk_concat([result, lastresult], axis=0)
507
+ * self.matrix_shift_ph[nside]
508
+ )
439
509
  else:
440
- return result*self.matrix_shift_ph[nside]
441
-
442
- def anafast(self,im,map2=None,nest=False,spin=2):
443
-
444
- """The `anafast` function computes the L1 and L2 norm power spectra.
510
+ return result * self.matrix_shift_ph[nside]
511
+
512
+ def icomp_tf(self, i_im, nside, realfft=False):
513
+
514
+ self.shift_ph(nside)
515
+
516
+ n = 0
517
+ im = []
518
+ ft_im = i_im * self.backend.bk_conjugate(self.matrix_shift_ph[nside])
519
+
520
+ for k in range(nside - 1):
521
+ N = 4 * (k + 1)
522
+
523
+ if realfft:
524
+ tmp = self.irfft2fft(ft_im[k], N)
525
+ else:
526
+ tmp = self.backend.bk_ifft(im[k], N)
527
+
528
+ im.append(tmp[0:N])
445
529
 
446
- Currently, it is not optimized for single-pass computation due to the relatively inefficient computation of \(Y_{lm}\).
530
+ n += N
531
+
532
+ if nside > 1:
533
+ result = self.backend.bk_concat(im, axis=0)
534
+
535
+ N = 4 * nside * (2 * nside + 1)
536
+ v = ft_im[nside - 1 : 3 * nside, 0 : 2 * nside + 1]
537
+ if realfft:
538
+ v_fft = self.backend.bk_reshape(
539
+ self.irfft2fft(v, N, axis=1), [4 * nside * (2 * nside + 1)]
540
+ )
541
+ else:
542
+ v_fft = self.backend.bk_ifft(v)
543
+
544
+ n += N
545
+ if nside > 1:
546
+ result = self.backend.bk_concat([result, v_fft], axis=0)
547
+ else:
548
+ result = v_fft
549
+
550
+ if nside > 1:
551
+ im = []
552
+ for k in range(nside - 1):
553
+ N = 4 * (nside - 1 - k)
554
+
555
+ if realfft:
556
+ tmp = self.irfft2fft(ft_im[k + 3 * nside], N)
557
+ else:
558
+ tmp = self.backend.bk_ifft(im[k + 3 * nside], N)
559
+
560
+ im.append(tmp[0:N])
561
+
562
+ n += N
563
+
564
+ return self.backend.bk_concat([result] + im, axis=0)
565
+ else:
566
+ return result
567
+
568
+ def anafast(self, im, map2=None, nest=False, spin=2):
569
+ """The `anafast` function computes the L1 and L2 norm power spectra.
570
+
571
+ Currently, it is not optimized for single-pass computation due to the relatively inefficient computation of \(Y_{lm}\).
447
572
  Nonetheless, it utilizes TensorFlow and can be integrated into gradient computations.
448
573
 
449
574
  Input:
450
- - `im`: a vector of size \([12 \times \text{Nside}^2]\) for scalar data, or of size \([2, 12 \times \text{Nside}^2]\) for Q,U polar data,
575
+ - `im`: a vector of size \([12 \times \text{Nside}^2]\) for scalar data, or of size \([2, 12 \times \text{Nside}^2]\) for Q,U polar data,
451
576
  or of size \([3, 12 \times \text{Nside}^2]\) for I,Q,U polar data.
452
- - `map2` (optional): a vector of size \([12 \times \text{Nside}^2]\) for scalar data, or of size
577
+ - `map2` (optional): a vector of size \([12 \times \text{Nside}^2]\) for scalar data, or of size
453
578
  \([3, 12 \times \text{Nside}^2]\) for polar data. If provided, cross power spectra will be computed.
454
579
  - `nest=True`: alters the ordering of the input maps.
455
580
  - `spin=2` for 1/2 spin data as Q and U. Spin=1 for seep fields
456
581
 
457
582
  Output:
458
- -A tensor of size \([l_{\text{max}} \times (l_{\text{max}}-1)]\) formatted as \([6, \ldots]\),
583
+ -A tensor of size \([l_{\text{max}} \times (l_{\text{max}}-1)]\) formatted as \([6, \ldots]\),
459
584
  ordered as TT, EE, BB, TE, EB.TBanafast function computes L1 and L2 norm powerspctra.
460
585
 
461
586
  """
462
- i_im=self.backend.bk_cast(im)
587
+ i_im = self.backend.bk_cast(im)
463
588
  if map2 is not None:
464
- i_map2=self.backend.bk_cast(map2)
465
-
466
- doT=True
467
- if len(i_im.shape)==1: # nopol
468
- nside=int(np.sqrt(i_im.shape[0]//12))
589
+ i_map2 = self.backend.bk_cast(map2)
590
+
591
+ doT = True
592
+ if len(i_im.shape) == 1: # nopol
593
+ nside = int(np.sqrt(i_im.shape[0] // 12))
469
594
  else:
470
- if i_im.shape[0]==2:
471
- doT=False
472
- nside=int(np.sqrt(i_im.shape[1]//12))
473
-
595
+ if i_im.shape[0] == 2:
596
+ doT = False
597
+ nside = int(np.sqrt(i_im.shape[1] // 12))
598
+
474
599
  self.shift_ph(nside)
475
-
476
- if doT: # nopol
477
- if len(i_im.shape)==2: # pol
478
- l_im=i_im[0]
600
+
601
+ if doT: # nopol
602
+ if len(i_im.shape) == 2: # pol
603
+ l_im = i_im[0]
479
604
  if map2 is not None:
480
- l_map2=i_map2[0]
605
+ l_map2 = i_map2[0]
481
606
  else:
482
- l_im=i_im
607
+ l_im = i_im
483
608
  if map2 is not None:
484
- l_map2=i_map2
485
-
609
+ l_map2 = i_map2
610
+
486
611
  if nest:
487
- idx=hp.ring2nest(nside,np.arange(12*nside**2))
488
- if len(i_im.shape)==1: # nopol
489
- ft_im=self.comp_tf(self.backend.bk_gather(l_im,idx),nside,realfft=True)
612
+ idx = hp.ring2nest(nside, np.arange(12 * nside**2))
613
+ if len(i_im.shape) == 1: # nopol
614
+ ft_im = self.comp_tf(
615
+ self.backend.bk_gather(l_im, idx), nside, realfft=True
616
+ )
490
617
  if map2 is not None:
491
- ft_im2=self.comp_tf(self.backend.bk_gather(l_map2,idx),nside,realfft=True)
618
+ ft_im2 = self.comp_tf(
619
+ self.backend.bk_gather(l_map2, idx), nside, realfft=True
620
+ )
492
621
  else:
493
- ft_im=self.comp_tf(l_im,nside,realfft=True)
622
+ ft_im = self.comp_tf(l_im, nside, realfft=True)
494
623
  if map2 is not None:
495
- ft_im2=self.comp_tf(l_map2,nside,realfft=True)
496
-
497
- lth=self.ring_th(nside)
498
-
499
- co_th=np.cos(lth)
500
-
501
- lmax=3*nside-1
502
-
503
- cl2=None
504
- cl2_L1=None
505
- dt2=0
506
- dt3=0
507
- dt4=0
508
- if len(i_im.shape)==2: # nopol
509
-
510
- self.init_Ys(spin,nside)
511
-
624
+ ft_im2 = self.comp_tf(l_map2, nside, realfft=True)
625
+
626
+ lth = self.ring_th(nside)
627
+
628
+ co_th = np.cos(lth)
629
+
630
+ lmax = 3 * nside - 1
631
+
632
+ cl2 = None
633
+ cl2_L1 = None
634
+ dt2 = 0
635
+ dt3 = 0
636
+ dt4 = 0
637
+ if len(i_im.shape) == 2: # nopol
638
+
639
+ self.init_Ys(spin, nside)
640
+
512
641
  if nest:
513
- idx=hp.ring2nest(nside,np.arange(12*nside**2))
514
- l_Q=self.backend.bk_gather(i_im[int(doT)],idx)
515
- l_U=self.backend.bk_gather(i_im[1+int(doT)],idx)
516
- ft_im_Pp=self.comp_tf(self.backend.bk_complex(l_Q,l_U),nside)
517
- ft_im_Pm=self.comp_tf(self.backend.bk_complex(l_Q,-l_U),nside)
642
+ idx = hp.ring2nest(nside, np.arange(12 * nside**2))
643
+ l_Q = self.backend.bk_gather(i_im[int(doT)], idx)
644
+ l_U = self.backend.bk_gather(i_im[1 + int(doT)], idx)
645
+ ft_im_Pp = self.comp_tf(self.backend.bk_complex(l_Q, l_U), nside)
646
+ ft_im_Pm = self.comp_tf(self.backend.bk_complex(l_Q, -l_U), nside)
518
647
  if map2 is not None:
519
- l_Q=self.backend.bk_gather(i_map2[int(doT)],idx)
520
- l_U=self.backend.bk_gather(i_map2[1+int(doT)],idx)
521
- ft_im2_Pp=self.comp_tf(self.backend.bk_complex(l_Q,l_U),nside)
522
- ft_im2_Pm=self.comp_tf(self.backend.bk_complex(l_Q,-l_U),nside)
648
+ l_Q = self.backend.bk_gather(i_map2[int(doT)], idx)
649
+ l_U = self.backend.bk_gather(i_map2[1 + int(doT)], idx)
650
+ ft_im2_Pp = self.comp_tf(self.backend.bk_complex(l_Q, l_U), nside)
651
+ ft_im2_Pm = self.comp_tf(self.backend.bk_complex(l_Q, -l_U), nside)
523
652
  else:
524
- ft_im_Pp=self.comp_tf(self.backend.bk_complex(i_im[int(doT)],i_im[1+int(doT)]),nside)
525
- ft_im_Pm=self.comp_tf(self.backend.bk_complex(i_im[int(doT)],-i_im[1+int(doT)]),nside)
653
+ ft_im_Pp = self.comp_tf(
654
+ self.backend.bk_complex(i_im[int(doT)], i_im[1 + int(doT)]), nside
655
+ )
656
+ ft_im_Pm = self.comp_tf(
657
+ self.backend.bk_complex(i_im[int(doT)], -i_im[1 + int(doT)]), nside
658
+ )
526
659
  if map2 is not None:
527
- ft_im2_Pp=self.comp_tf(self.backend.bk_complex(i_map2[int(doT)],i_map2[1+int(doT)]),nside)
528
- ft_im2_Pm=self.comp_tf(self.backend.bk_complex(i_map2[int(doT)],-i_map2[1+int(doT)]),nside)
529
-
530
- for m in range(lmax+1):
660
+ ft_im2_Pp = self.comp_tf(
661
+ self.backend.bk_complex(i_map2[int(doT)], i_map2[1 + int(doT)]),
662
+ nside,
663
+ )
664
+ ft_im2_Pm = self.comp_tf(
665
+ self.backend.bk_complex(
666
+ i_map2[int(doT)], -i_map2[1 + int(doT)]
667
+ ),
668
+ nside,
669
+ )
670
+
671
+ for m in range(lmax + 1):
672
+
673
+ plm = self.compute_legendre_m(co_th, m, 3 * nside - 1, nside) / (
674
+ 12 * nside**2
675
+ )
531
676
 
532
- plm=self.compute_legendre_m(co_th,m,3*nside-1,nside)/(12*nside**2)
533
-
534
677
  if doT:
535
- tmp=self.backend.bk_reduce_sum(plm*ft_im[:,m],1)
678
+ tmp = self.backend.bk_reduce_sum(plm * ft_im[:, m], 1)
536
679
 
537
680
  if map2 is not None:
538
- tmp2=self.backend.bk_reduce_sum(plm*ft_im2[:,m],1)
681
+ tmp2 = self.backend.bk_reduce_sum(plm * ft_im2[:, m], 1)
539
682
  else:
540
- tmp2=tmp
541
-
542
- if len(i_im.shape)==2: # pol
543
- plmp=self.Yp[spin,nside][m]
544
- plmm=self.Ym[spin,nside][m]
545
-
546
- tmpp=self.backend.bk_reduce_sum(plmp*ft_im_Pp[:,m],1)
547
- tmpm=self.backend.bk_reduce_sum(plmm*ft_im_Pm[:,m],1)
548
-
549
- almE=-(tmpp+tmpm)/2.0
550
- almB=(tmpp-tmpm)/(2J)
551
-
683
+ tmp2 = tmp
684
+
685
+ if len(i_im.shape) == 2: # pol
686
+ plmp = self.Yp[spin, nside][m]
687
+ plmm = self.Ym[spin, nside][m]
688
+
689
+ tmpp = self.backend.bk_reduce_sum(plmp * ft_im_Pp[:, m], 1)
690
+ tmpm = self.backend.bk_reduce_sum(plmm * ft_im_Pm[:, m], 1)
691
+
692
+ almE = -(tmpp + tmpm) / 2.0
693
+ almB = (tmpp - tmpm) / (2j)
694
+
552
695
  if map2 is not None:
553
- tmpp2=self.backend.bk_reduce_sum(plmp*ft_im2_Pp[:,m],1)
554
- tmpm2=self.backend.bk_reduce_sum(plmm*ft_im2_Pm[:,m],1)
555
-
556
- almE2=-(tmpp2+tmpm2)/2.0
557
- almB2=(tmpp2-tmpm2)/(2J)
696
+ tmpp2 = self.backend.bk_reduce_sum(plmp * ft_im2_Pp[:, m], 1)
697
+ tmpm2 = self.backend.bk_reduce_sum(plmm * ft_im2_Pm[:, m], 1)
698
+
699
+ almE2 = -(tmpp2 + tmpm2) / 2.0
700
+ almB2 = (tmpp2 - tmpm2) / (2j)
558
701
  else:
559
- almE2=almE
560
- almB2=almB
561
-
702
+ almE2 = almE
703
+ almB2 = almB
704
+
562
705
  if doT:
563
- tmpTT=self.backend.bk_real((tmp*self.backend.bk_conjugate(tmp2)))
564
- tmpTE=self.backend.bk_real((tmp*self.backend.bk_conjugate(almE2)))
565
- tmpTB=-self.backend.bk_real((tmp*self.backend.bk_conjugate(almB2)))
566
-
567
- tmpEE=self.backend.bk_real((almE*self.backend.bk_conjugate(almE2)))
568
- tmpBB=self.backend.bk_real((almB*self.backend.bk_conjugate(almB2)))
569
- tmpEB=-self.backend.bk_real((almE*self.backend.bk_conjugate(almB2)))
570
-
706
+ tmpTT = self.backend.bk_real(
707
+ (tmp * self.backend.bk_conjugate(tmp2))
708
+ )
709
+ tmpTE = self.backend.bk_real(
710
+ (tmp * self.backend.bk_conjugate(almE2))
711
+ )
712
+ tmpTB = -self.backend.bk_real(
713
+ (tmp * self.backend.bk_conjugate(almB2))
714
+ )
715
+
716
+ tmpEE = self.backend.bk_real((almE * self.backend.bk_conjugate(almE2)))
717
+ tmpBB = self.backend.bk_real((almB * self.backend.bk_conjugate(almB2)))
718
+ tmpEB = -self.backend.bk_real((almE * self.backend.bk_conjugate(almB2)))
719
+
571
720
  if map2 is not None:
572
- tmpEB=(tmpEB-self.backend.bk_real((almE2*self.backend.bk_conjugate(almB))))/2
573
-
574
- if doT:
575
- tmpTE=(tmpTE+self.backend.bk_real((tmp2*self.backend.bk_conjugate(almE))))/2
576
- tmpTB=(tmpTB-self.backend.bk_real((tmp2*self.backend.bk_conjugate(almB))))/2
577
-
721
+ tmpEB = (
722
+ tmpEB
723
+ - self.backend.bk_real(
724
+ (almE2 * self.backend.bk_conjugate(almB))
725
+ )
726
+ ) / 2
578
727
 
579
- if m==0:
580
728
  if doT:
581
- l_cl=self.backend.bk_concat([tmpTT,tmpEE,tmpBB,tmpTE,tmpEB,tmpTB],0)
729
+ tmpTE = (
730
+ tmpTE
731
+ + self.backend.bk_real(
732
+ (tmp2 * self.backend.bk_conjugate(almE))
733
+ )
734
+ ) / 2
735
+ tmpTB = (
736
+ tmpTB
737
+ - self.backend.bk_real(
738
+ (tmp2 * self.backend.bk_conjugate(almB))
739
+ )
740
+ ) / 2
741
+
742
+ if m == 0:
743
+ if doT:
744
+ l_cl = self.backend.bk_concat(
745
+ [tmpTT, tmpEE, tmpBB, tmpTE, tmpEB, tmpTB], 0
746
+ )
582
747
  else:
583
- l_cl=self.backend.bk_concat([tmpEE,tmpBB,tmpEB],0)
748
+ l_cl = self.backend.bk_concat([tmpEE, tmpBB, tmpEB], 0)
584
749
  else:
585
- offset_tensor=self.backend.bk_zeros((m),dtype=self.backend.all_bk_type)
750
+ offset_tensor = self.backend.bk_zeros(
751
+ (m), dtype=self.backend.all_bk_type
752
+ )
586
753
  if doT:
587
- l_cl=self.backend.bk_concat([self.backend.bk_concat([offset_tensor,tmpTT],axis=0),
588
- self.backend.bk_concat([offset_tensor,tmpEE],axis=0),
589
- self.backend.bk_concat([offset_tensor,tmpBB],axis=0),
590
- self.backend.bk_concat([offset_tensor,tmpTE],axis=0),
591
- self.backend.bk_concat([offset_tensor,tmpEB],axis=0),
592
- self.backend.bk_concat([offset_tensor,tmpTB],axis=0)],axis=0)
754
+ l_cl = self.backend.bk_concat(
755
+ [
756
+ self.backend.bk_concat([offset_tensor, tmpTT], axis=0),
757
+ self.backend.bk_concat([offset_tensor, tmpEE], axis=0),
758
+ self.backend.bk_concat([offset_tensor, tmpBB], axis=0),
759
+ self.backend.bk_concat([offset_tensor, tmpTE], axis=0),
760
+ self.backend.bk_concat([offset_tensor, tmpEB], axis=0),
761
+ self.backend.bk_concat([offset_tensor, tmpTB], axis=0),
762
+ ],
763
+ axis=0,
764
+ )
593
765
  else:
594
- l_cl=self.backend.bk_concat([self.backend.bk_concat([offset_tensor,tmpEE],axis=0),
595
- self.backend.bk_concat([offset_tensor,tmpBB],axis=0),
596
- self.backend.bk_concat([offset_tensor,tmpEB],axis=0)],axis=0)
597
-
766
+ l_cl = self.backend.bk_concat(
767
+ [
768
+ self.backend.bk_concat([offset_tensor, tmpEE], axis=0),
769
+ self.backend.bk_concat([offset_tensor, tmpBB], axis=0),
770
+ self.backend.bk_concat([offset_tensor, tmpEB], axis=0),
771
+ ],
772
+ axis=0,
773
+ )
774
+
598
775
  if doT:
599
- l_cl=self.backend.bk_reshape(l_cl,[6,lmax+1])
776
+ l_cl = self.backend.bk_reshape(l_cl, [6, lmax + 1])
600
777
  else:
601
- l_cl=self.backend.bk_reshape(l_cl,[3,lmax+1])
778
+ l_cl = self.backend.bk_reshape(l_cl, [3, lmax + 1])
602
779
  else:
603
- tmp=self.backend.bk_real((tmp*self.backend.bk_conjugate(tmp2)))
604
- if m==0:
605
- l_cl=tmp
780
+ tmp = self.backend.bk_real((tmp * self.backend.bk_conjugate(tmp2)))
781
+ if m == 0:
782
+ l_cl = tmp
606
783
  else:
607
- offset_tensor=self.backend.bk_zeros((m),dtype=self.backend.all_bk_type)
608
- l_cl=self.backend.bk_concat([offset_tensor,tmp],axis=0)
609
-
784
+ offset_tensor = self.backend.bk_zeros(
785
+ (m), dtype=self.backend.all_bk_type
786
+ )
787
+ l_cl = self.backend.bk_concat([offset_tensor, tmp], axis=0)
788
+
610
789
  if cl2 is None:
611
- cl2=l_cl
790
+ cl2 = l_cl
612
791
  else:
613
- cl2+=2*l_cl
614
-
615
- #cl2=cl2*(4*np.pi) #self.backend.bk_sqrt(self.backend.bk_cast(4*np.pi)) #(2*np.arange(cl2.shape[0])+1)))
616
-
617
- cl2_l1=self.backend.bk_L1(cl2)
618
-
619
- return cl2,cl2_l1
620
-
621
- def map2alm(self,im,nest=False):
622
- nside=int(np.sqrt(im.shape[0]//12))
623
-
792
+ cl2 += 2 * l_cl
793
+
794
+ # cl2=cl2*(4*np.pi) #self.backend.bk_sqrt(self.backend.bk_cast(4*np.pi)) #(2*np.arange(cl2.shape[0])+1)))
795
+
796
+ cl2_l1 = self.backend.bk_L1(cl2)
797
+
798
+ return cl2, cl2_l1
799
+
800
+ def map2alm(self, im, nest=False):
801
+ nside = int(np.sqrt(im.shape[0] // 12))
802
+
803
+ ph = self.shift_ph(nside)
804
+
624
805
  if nest:
625
- idx=hp.ring2nest(nside,np.arange(12*nside**2))
626
- ft_im=self.comp_tf(self.backend.bk_cast(self.backend.bk_gather(im,idx)),nside,realfft=True)
806
+ idx = hp.ring2nest(nside, np.arange(12 * nside**2))
807
+ ft_im = self.comp_tf(
808
+ self.backend.bk_cast(self.backend.bk_gather(im, idx)),
809
+ nside,
810
+ realfft=True,
811
+ )
627
812
  else:
628
- ft_im=self.comp_tf(self.backend.bk_cast(im),nside,realfft=True)
629
-
630
- lth=self.ring_th(nside)
631
-
632
- co_th=np.cos(lth)
633
-
634
- lmax=3*nside-1
635
-
636
- alm=None
637
- for m in range(lmax+1):
638
- plm=self.compute_legendre_m(co_th,m,3*nside-1,nside)/(12*nside**2)
639
-
640
- tmp=self.backend.bk_reduce_sum(plm*ft_im[:,m],1)
641
- if m==0:
642
- alm=tmp
813
+ ft_im = self.comp_tf(self.backend.bk_cast(im), nside, realfft=True)
814
+
815
+ lth = self.ring_th(nside)
816
+
817
+ co_th = np.cos(lth)
818
+
819
+ lmax = 3 * nside - 1
820
+
821
+ alm = None
822
+ for m in range(lmax + 1):
823
+ plm = self.compute_legendre_m(co_th, m, 3 * nside - 1, nside) / (
824
+ 12 * nside**2
825
+ )
826
+
827
+ tmp = self.backend.bk_reduce_sum(plm * ft_im[:, m], 1)
828
+ if m == 0:
829
+ alm = tmp
643
830
  else:
644
- alm=self.backend.bk_concat([alm,tmp],axis=0)
645
-
831
+ alm = self.backend.bk_concat([alm, tmp], axis=0)
832
+
646
833
  return alm
647
834
 
648
- def map2alm_spin(self,im_Q,im_U,spin=2,nest=False):
649
-
650
- if spin==0:
651
- return self.map2alm(im_Q,nest=nest),self.map2alm(im_U,nest=nest)
835
+ def alm2map(self, nside, alm):
836
+
837
+ lth = self.ring_th(nside)
838
+
839
+ co_th = np.cos(lth)
840
+
841
+ ft_im = []
842
+
843
+ n = 0
652
844
 
653
- nside=int(np.sqrt(im_Q.shape[0]//12))
845
+ lmax = 3 * nside - 1
846
+
847
+ for m in range(lmax + 1):
848
+ plm = self.compute_legendre_m(co_th, m, 3 * nside - 1, nside) / (
849
+ 12 * nside**2
850
+ )
851
+
852
+ print(alm[n : n + lmax - m + 1].shape, plm.shape)
853
+ ft_im.append(
854
+ self.backend.bk_reduce_sum(
855
+ self.backend.bk_reshape(
856
+ alm[n : n + lmax - m + 1], [lmax - m + 1, 1]
857
+ )
858
+ * plm,
859
+ 0,
860
+ )
861
+ )
862
+
863
+ n = n + lmax - m + 1
864
+
865
+ return self.backend.bk_reshape(
866
+ self.backend.bk_concat(ft_im, 0), [lmax + 1, 4 * nside - 1]
867
+ )
654
868
 
655
- lth=self.ring_th(nside)
656
-
657
- co_th=np.cos(lth)
658
-
659
869
  if nest:
660
- idx=hp.ring2nest(nside,np.arange(12*nside**2))
661
- l_Q=self.backend.bk_gather(im_Q,idx)
662
- l_U=self.backend.bk_gather(im_U,idx)
663
- ft_im_1=self.comp_tf(self.backend.bk_complex(l_Q,l_U),nside)
664
- ft_im_2=self.comp_tf(self.backend.bk_complex(l_Q,-l_U),nside)
870
+ idx = hp.ring2nest(nside, np.arange(12 * nside**2))
871
+ ft_im = self.comp_tf(
872
+ self.backend.bk_cast(self.backend.bk_gather(im, idx)),
873
+ nside,
874
+ realfft=True,
875
+ )
665
876
  else:
666
- ft_im_1=self.comp_tf(self.backend.bk_complex(im_Q,im_U),nside)
667
- ft_im_2=self.comp_tf(self.backend.bk_complex(im_Q,-im_U),nside)
668
-
669
- lmax=3*nside-1
670
-
671
- alm=None
672
- for m in range(lmax+1):
673
- #not yet debug use spherical
674
- #plmp1,plmm1=self.compute_legendre_spin2_m(co_th,si_th,m,3*nside-1)
675
- #plmp1/=(12*nside**2)
676
- #plmm1/=(12*nside**2)
677
-
678
- plmp=self.Yp[spin,nside][m]
679
- plmm=self.Ym[spin,nside][m]
680
-
681
- tmpp=self.backend.bk_reduce_sum(plmp*ft_im_1[:,m],1)
682
- tmpm=self.backend.bk_reduce_sum(plmm*ft_im_2[:,m],1)
683
- if m==0:
684
- almE=-(tmpp+tmpm)/2.0
685
- almB=(tmpp-tmpm)/(2J)
877
+ ft_im = self.comp_tf(self.backend.bk_cast(im), nside, realfft=True)
878
+
879
+ lmax = 3 * nside - 1
880
+
881
+ alm = None
882
+ for m in range(lmax + 1):
883
+ plm = self.compute_legendre_m(co_th, m, 3 * nside - 1, nside) / (
884
+ 12 * nside**2
885
+ )
886
+
887
+ tmp = self.backend.bk_reduce_sum(plm * ft_im[:, m], 1)
888
+ if m == 0:
889
+ alm = tmp
686
890
  else:
687
- almE=self.backend.bk_concat([almE,-(tmpp+tmpm)/2],axis=0)
688
- almB=self.backend.bk_concat([almB,(tmpp-tmpm)/(2J)],axis=0)
689
-
690
- return almE,almB
891
+ alm = self.backend.bk_concat([alm, tmp], axis=0)
892
+
893
+ return o_map
894
+
895
+ def map2alm_spin(self, im_Q, im_U, spin=2, nest=False):
896
+
897
+ if spin == 0:
898
+ return self.map2alm(im_Q, nest=nest), self.map2alm(im_U, nest=nest)
899
+
900
+ nside = int(np.sqrt(im_Q.shape[0] // 12))
901
+
902
+ lth = self.ring_th(nside)
903
+
904
+ co_th = np.cos(lth)
905
+
906
+ if nest:
907
+ idx = hp.ring2nest(nside, np.arange(12 * nside**2))
908
+ l_Q = self.backend.bk_gather(im_Q, idx)
909
+ l_U = self.backend.bk_gather(im_U, idx)
910
+ ft_im_1 = self.comp_tf(self.backend.bk_complex(l_Q, l_U), nside)
911
+ ft_im_2 = self.comp_tf(self.backend.bk_complex(l_Q, -l_U), nside)
912
+ else:
913
+ ft_im_1 = self.comp_tf(self.backend.bk_complex(im_Q, im_U), nside)
914
+ ft_im_2 = self.comp_tf(self.backend.bk_complex(im_Q, -im_U), nside)
915
+
916
+ lmax = 3 * nside - 1
917
+
918
+ alm = None
919
+ for m in range(lmax + 1):
920
+ # not yet debug use spherical
921
+ # plmp1,plmm1=self.compute_legendre_spin2_m(co_th,si_th,m,3*nside-1)
922
+ # plmp1/=(12*nside**2)
923
+ # plmm1/=(12*nside**2)
924
+
925
+ plmp = self.Yp[spin, nside][m]
926
+ plmm = self.Ym[spin, nside][m]
927
+
928
+ tmpp = self.backend.bk_reduce_sum(plmp * ft_im_1[:, m], 1)
929
+ tmpm = self.backend.bk_reduce_sum(plmm * ft_im_2[:, m], 1)
930
+ if m == 0:
931
+ almE = -(tmpp + tmpm) / 2.0
932
+ almB = (tmpp - tmpm) / (2j)
933
+ else:
934
+ almE = self.backend.bk_concat([almE, -(tmpp + tmpm) / 2], axis=0)
935
+ almB = self.backend.bk_concat([almB, (tmpp - tmpm) / (2j)], axis=0)
936
+
937
+ return almE, almB