foscat 2026.2.2__tar.gz → 2026.2.5__tar.gz
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-2026.2.2/src/foscat.egg-info → foscat-2026.2.5}/PKG-INFO +1 -1
- {foscat-2026.2.2 → foscat-2026.2.5}/pyproject.toml +1 -1
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/FoCUS.py +2 -2
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/SphereDownGeo.py +109 -2
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/scat_cov.py +4 -2
- {foscat-2026.2.2 → foscat-2026.2.5/src/foscat.egg-info}/PKG-INFO +1 -1
- {foscat-2026.2.2 → foscat-2026.2.5}/LICENSE +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/README.md +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/setup.cfg +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/BkBase.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/BkNumpy.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/BkTensorflow.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/BkTorch.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/CNN.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/CircSpline.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/GCNN.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/HOrientedConvol.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/HealBili.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/HealSpline.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/Plot.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/Softmax.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/SphereUpGeo.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/SphericalStencil.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/Spline1D.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/Synthesis.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/UNET.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/__init__.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/alm.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/alm_loc.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/backend.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/backend_tens.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/heal_NN.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/healpix_unet_torch.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/healpix_vit_skip.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/healpix_vit_torch-old.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/healpix_vit_torch.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/loss_backend_tens.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/loss_backend_torch.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/planar_vit.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/scat.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/scat1D.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/scat2D.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/scat_cov1D.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/scat_cov2D.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/scat_cov_map.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/scat_cov_map2D.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat/unet_2_d_from_healpix_params.py +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat.egg-info/SOURCES.txt +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat.egg-info/dependency_links.txt +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat.egg-info/requires.txt +0 -0
- {foscat-2026.2.2 → foscat-2026.2.5}/src/foscat.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: foscat
|
|
3
|
-
Version: 2026.2.
|
|
3
|
+
Version: 2026.2.5
|
|
4
4
|
Summary: Generate synthetic Healpix or 2D data using Cross Scattering Transform
|
|
5
5
|
Author-email: Jean-Marc DELOUIS <jean.marc.delouis@ifremer.fr>
|
|
6
6
|
Maintainer-email: Theo Foulquier <theo.foulquier@ifremer.fr>
|
|
@@ -39,7 +39,7 @@ class FoCUS:
|
|
|
39
39
|
mpi_rank=0
|
|
40
40
|
):
|
|
41
41
|
|
|
42
|
-
self.__version__ = "2026.02.
|
|
42
|
+
self.__version__ = "2026.02.4"
|
|
43
43
|
# P00 coeff for normalization for scat_cov
|
|
44
44
|
self.TMPFILE_VERSION = TMPFILE_VERSION
|
|
45
45
|
self.P1_dic = None
|
|
@@ -1579,7 +1579,7 @@ class FoCUS:
|
|
|
1579
1579
|
|
|
1580
1580
|
xx=np.tile(np.arange(self.KERNELSZ)-self.KERNELSZ//2,self.KERNELSZ).reshape(self.KERNELSZ,self.KERNELSZ)
|
|
1581
1581
|
|
|
1582
|
-
if nside>
|
|
1582
|
+
if nside>0:
|
|
1583
1583
|
wwr=(np.exp(-pw2*(xx**2+(xx.T)**2))*np.cos(pw*xx*np.pi)).reshape(1,1,self.KERNELSZ*self.KERNELSZ)
|
|
1584
1584
|
wwr-=wwr.mean()
|
|
1585
1585
|
wwi=(np.exp(-pw2*(xx**2+(xx.T)**2))*np.sin(pw*xx*np.pi)).reshape(1,1,self.KERNELSZ*self.KERNELSZ)
|
|
@@ -106,7 +106,7 @@ class SphereDownGeo(nn.Module):
|
|
|
106
106
|
|
|
107
107
|
M = self._build_down_matrix() # shape (K_out, K_in or N_in)
|
|
108
108
|
|
|
109
|
-
self.M = M
|
|
109
|
+
self.M = M
|
|
110
110
|
|
|
111
111
|
if use_csr:
|
|
112
112
|
self.M = self.M.to_sparse_csr().to(self.device)
|
|
@@ -209,6 +209,113 @@ class SphereDownGeo(nn.Module):
|
|
|
209
209
|
return np.ones_like(w) / max(np.sqrt(w.size), 1.0)
|
|
210
210
|
return w / np.sqrt(s2)
|
|
211
211
|
|
|
212
|
+
def _build_down_matrix(self) -> torch.Tensor:
|
|
213
|
+
nside_in = self.nside_in
|
|
214
|
+
nside_out = self.nside_out
|
|
215
|
+
sigma = float(self.sigma_rad)
|
|
216
|
+
|
|
217
|
+
p_out = self.cell_ids_out.astype(np.int64) # [K]
|
|
218
|
+
K = p_out.size
|
|
219
|
+
offs = np.arange(4, dtype=np.int64) # [4]
|
|
220
|
+
|
|
221
|
+
# --- (A) Choix du voisinage côté coarse
|
|
222
|
+
# Option 1 (minimal, très rapide) : uniquement le parent -> 4 enfants
|
|
223
|
+
#parents = p_out[:, None] # [K,1]
|
|
224
|
+
|
|
225
|
+
# Option 2 (plus “lisse”) : parent + 8 voisins -> 9 parents -> 36 enfants
|
|
226
|
+
neigh8 = hp.get_all_neighbours(nside_out, p_out, nest=True) # [8,K] (healpy renvoie souvent [8,K])
|
|
227
|
+
parents = np.concatenate([p_out[None, :], neigh8], axis=0).T # [K,9]
|
|
228
|
+
idx=np.where(parents==-1)
|
|
229
|
+
parents[idx[0],idx[1]]=parents[idx[0],idx[1]-1]
|
|
230
|
+
|
|
231
|
+
# --- enfants fins (NESTED) : child_id = 4*parent + {0,1,2,3}
|
|
232
|
+
children = (4 * parents[..., None] + offs[None, None, :]).reshape(K, -1) # [K, 4] ou [K,36]
|
|
233
|
+
|
|
234
|
+
# Si option voisins activée : invalider enfants des parents=-1
|
|
235
|
+
#mask_child = np.repeat(mask_parent, 4, axis=1) # [K,36]
|
|
236
|
+
#children_flat = children[mask_child]
|
|
237
|
+
#print(mask_child.shape,children.shape,K)
|
|
238
|
+
rows_flat = np.repeat(np.arange(K, dtype=np.int64), children.shape[1])#[mask_child.ravel()]
|
|
239
|
+
|
|
240
|
+
# Option minimal (sans voisins) :
|
|
241
|
+
children_flat = children.reshape(-1) # [K*4]
|
|
242
|
+
#rows_flat = np.repeat(np.arange(K, dtype=np.int64), children.shape[1])
|
|
243
|
+
|
|
244
|
+
# --- Subset: map vers indices compacts
|
|
245
|
+
if self.has_in_subset:
|
|
246
|
+
in_ids = self.in_cell_ids # trié/unique :contentReference[oaicite:4]{index=4}
|
|
247
|
+
idx = np.searchsorted(in_ids, children_flat)
|
|
248
|
+
|
|
249
|
+
in_range = idx < in_ids.size # idx est toujours >=0 pour searchsorted
|
|
250
|
+
idx2 = idx[in_range]
|
|
251
|
+
child2 = children_flat[in_range]
|
|
252
|
+
|
|
253
|
+
ok2 = (in_ids[idx2] == child2) # comparaison safe
|
|
254
|
+
ok = np.zeros_like(in_range, dtype=bool)
|
|
255
|
+
ok[in_range] = ok2
|
|
256
|
+
|
|
257
|
+
cols_flat = idx[ok]
|
|
258
|
+
rows_flat2 = rows_flat[ok]
|
|
259
|
+
child_ids_kept = children_flat[ok]
|
|
260
|
+
else:
|
|
261
|
+
cols_flat = children_flat
|
|
262
|
+
rows_flat2 = rows_flat
|
|
263
|
+
child_ids_kept = children_flat
|
|
264
|
+
|
|
265
|
+
if rows_flat2.size == 0:
|
|
266
|
+
indices = torch.zeros((2, 0), dtype=torch.long, device=self.device)
|
|
267
|
+
vals_t = torch.zeros((0,), dtype=self.dtype, device=self.device)
|
|
268
|
+
return torch.sparse_coo_tensor(indices, vals_t, size=(self.K_out, self.K_in),
|
|
269
|
+
device=self.device, dtype=self.dtype).coalesce()
|
|
270
|
+
|
|
271
|
+
# --- poids gaussiens (vectorisé)
|
|
272
|
+
# centres coarse: vec0 [K,3]
|
|
273
|
+
vx0, vy0, vz0 = hp.pix2vec(nside_out, p_out, nest=True)
|
|
274
|
+
vec0 = np.stack([vx0, vy0, vz0], axis=1) # [K,3]
|
|
275
|
+
|
|
276
|
+
# vec des enfants gardés
|
|
277
|
+
vx, vy, vz = hp.pix2vec(nside_in, child_ids_kept, nest=True)
|
|
278
|
+
vec = np.stack([vx, vy, vz], axis=1) # [nnz,3]
|
|
279
|
+
|
|
280
|
+
# dot(vec, vec0[row])
|
|
281
|
+
dots = np.einsum("ij,ij->i", vec, vec0[rows_flat2])
|
|
282
|
+
dots = np.clip(dots, -1.0, 1.0)
|
|
283
|
+
ang = np.arccos(dots)
|
|
284
|
+
w = np.exp(-2.0 * (ang / max(sigma, 1e-30)) ** 2)
|
|
285
|
+
|
|
286
|
+
# --- normalisation par ligne (row-wise), sans boucle
|
|
287
|
+
# On recompose un tableau dense “temporaire” [K, m] via indexation
|
|
288
|
+
m = children.shape[1]
|
|
289
|
+
# position within row (0..m-1)
|
|
290
|
+
jpos = np.tile(np.arange(m, dtype=np.int64), K)
|
|
291
|
+
if self.has_in_subset:
|
|
292
|
+
jpos = jpos.reshape(-1)[ok] # aligné sur rows_flat2/child_ids_kept
|
|
293
|
+
# si option voisins + mask_child : jpos = jpos[mask_child.reshape(-1)][ok] etc.
|
|
294
|
+
|
|
295
|
+
W = np.zeros((K, m), dtype=np.float64)
|
|
296
|
+
W[rows_flat2, jpos] = w
|
|
297
|
+
|
|
298
|
+
if self.weight_norm == "l1":
|
|
299
|
+
s = W.sum(axis=1, keepdims=True)
|
|
300
|
+
s[s <= 0] = 1.0
|
|
301
|
+
W /= s
|
|
302
|
+
else: # l2
|
|
303
|
+
s2 = np.sqrt((W * W).sum(axis=1, keepdims=True))
|
|
304
|
+
s2[s2 <= 0] = 1.0
|
|
305
|
+
W /= s2
|
|
306
|
+
|
|
307
|
+
# extraire w normalisés aux mêmes nnz
|
|
308
|
+
w_norm = W[rows_flat2, jpos].astype(np.float32)
|
|
309
|
+
|
|
310
|
+
# --- sparse
|
|
311
|
+
rows_t = torch.tensor(rows_flat2, dtype=torch.long, device=self.device)
|
|
312
|
+
cols_t = torch.tensor(cols_flat, dtype=torch.long, device=self.device)
|
|
313
|
+
vals_t = torch.tensor(w_norm, dtype=self.dtype, device=self.device)
|
|
314
|
+
|
|
315
|
+
indices = torch.stack([rows_t, cols_t], dim=0)
|
|
316
|
+
return torch.sparse_coo_tensor(indices, vals_t, size=(self.K_out, self.K_in),
|
|
317
|
+
device=self.device, dtype=self.dtype).coalesce()
|
|
318
|
+
'''
|
|
212
319
|
def _build_down_matrix(self) -> torch.Tensor:
|
|
213
320
|
"""Construct sparse matrix M (K_out, K_in or N_in) for the selected coarse pixels."""
|
|
214
321
|
nside_in = self.nside_in
|
|
@@ -302,7 +409,7 @@ class SphereDownGeo(nn.Module):
|
|
|
302
409
|
dtype=self.dtype,
|
|
303
410
|
).coalesce()
|
|
304
411
|
return M
|
|
305
|
-
|
|
412
|
+
'''
|
|
306
413
|
# ---------------- forward ----------------
|
|
307
414
|
def forward(self, x: torch.Tensor):
|
|
308
415
|
"""
|
|
@@ -2378,7 +2378,7 @@ class funct(FOC.FoCUS):
|
|
|
2378
2378
|
if image2 is not None:
|
|
2379
2379
|
tmpi2 = self.up_grade(tmpi2, l_nside * 2)
|
|
2380
2380
|
l_nside = int(np.sqrt(tmp.shape[-1] // 12))
|
|
2381
|
-
nscale = int(np.log(l_nside) / np.log(2))
|
|
2381
|
+
nscale = int(np.log(l_nside) / np.log(2)+1)
|
|
2382
2382
|
cmat = {}
|
|
2383
2383
|
cmat2 = {}
|
|
2384
2384
|
|
|
@@ -2564,7 +2564,7 @@ class funct(FOC.FoCUS):
|
|
|
2564
2564
|
mat2[0 : k + 1, None, ...].astype("complex64")
|
|
2565
2565
|
)
|
|
2566
2566
|
|
|
2567
|
-
if k <
|
|
2567
|
+
if k < nscale - 1:
|
|
2568
2568
|
tmp, _ = self.ud_grade_2(tmp)
|
|
2569
2569
|
if image2 is not None:
|
|
2570
2570
|
tmpi2, _ = self.ud_grade_2(tmpi)
|
|
@@ -2702,6 +2702,7 @@ class funct(FOC.FoCUS):
|
|
|
2702
2702
|
nside = int(np.sqrt(npix // 12))
|
|
2703
2703
|
|
|
2704
2704
|
J = int(np.log2(nside)+1) # Number of j scales
|
|
2705
|
+
|
|
2705
2706
|
if cell_ids is not None:
|
|
2706
2707
|
J=np.min([J,int(np.log(cell_ids.shape[0]) / (2*np.log(2)))-1])
|
|
2707
2708
|
|
|
@@ -2764,6 +2765,7 @@ class funct(FOC.FoCUS):
|
|
|
2764
2765
|
I2 = self.up_grade(I2, nside * 2)
|
|
2765
2766
|
|
|
2766
2767
|
nside = nside * 2
|
|
2768
|
+
Jmax = Jmax +1
|
|
2767
2769
|
|
|
2768
2770
|
# Normalize the masks because they have different pixel numbers
|
|
2769
2771
|
# vmask /= self.backend.bk_reduce_sum(vmask, axis=1)[:, None] # [Nmask, Npix]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: foscat
|
|
3
|
-
Version: 2026.2.
|
|
3
|
+
Version: 2026.2.5
|
|
4
4
|
Summary: Generate synthetic Healpix or 2D data using Cross Scattering Transform
|
|
5
5
|
Author-email: Jean-Marc DELOUIS <jean.marc.delouis@ifremer.fr>
|
|
6
6
|
Maintainer-email: Theo Foulquier <theo.foulquier@ifremer.fr>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|