sarpyx 0.1.5__py3-none-any.whl → 0.1.6__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.
Files changed (48) hide show
  1. docs/examples/advanced/batch_processing.py +1 -1
  2. docs/examples/advanced/custom_processing_chains.py +1 -1
  3. docs/examples/advanced/performance_optimization.py +1 -1
  4. docs/examples/basic/snap_integration.py +1 -1
  5. docs/examples/intermediate/quality_assessment.py +1 -1
  6. outputs/baseline/20260205-234828/__init__.py +33 -0
  7. outputs/baseline/20260205-234828/main.py +493 -0
  8. outputs/final/20260205-234851/__init__.py +33 -0
  9. outputs/final/20260205-234851/main.py +493 -0
  10. sarpyx/__init__.py +2 -2
  11. sarpyx/algorithms/__init__.py +2 -2
  12. sarpyx/cli/__init__.py +1 -1
  13. sarpyx/cli/focus.py +3 -5
  14. sarpyx/cli/main.py +106 -7
  15. sarpyx/cli/shipdet.py +1 -1
  16. sarpyx/cli/worldsar.py +549 -0
  17. sarpyx/processor/__init__.py +1 -1
  18. sarpyx/processor/core/decode.py +43 -8
  19. sarpyx/processor/core/focus.py +104 -57
  20. sarpyx/science/__init__.py +1 -1
  21. sarpyx/sla/__init__.py +8 -0
  22. sarpyx/sla/metrics.py +101 -0
  23. sarpyx/{snap → snapflow}/__init__.py +1 -1
  24. sarpyx/snapflow/engine.py +6165 -0
  25. sarpyx/{snap → snapflow}/op.py +0 -1
  26. sarpyx/utils/__init__.py +1 -1
  27. sarpyx/utils/geos.py +652 -0
  28. sarpyx/utils/grid.py +285 -0
  29. sarpyx/utils/io.py +77 -9
  30. sarpyx/utils/meta.py +55 -0
  31. sarpyx/utils/nisar_utils.py +652 -0
  32. sarpyx/utils/rfigen.py +108 -0
  33. sarpyx/utils/wkt_utils.py +109 -0
  34. sarpyx/utils/zarr_utils.py +55 -37
  35. {sarpyx-0.1.5.dist-info → sarpyx-0.1.6.dist-info}/METADATA +9 -5
  36. {sarpyx-0.1.5.dist-info → sarpyx-0.1.6.dist-info}/RECORD +41 -32
  37. {sarpyx-0.1.5.dist-info → sarpyx-0.1.6.dist-info}/WHEEL +1 -1
  38. sarpyx-0.1.6.dist-info/licenses/LICENSE +201 -0
  39. sarpyx-0.1.6.dist-info/top_level.txt +4 -0
  40. tests/test_zarr_compat.py +35 -0
  41. sarpyx/processor/core/decode_v0.py +0 -0
  42. sarpyx/processor/core/decode_v1.py +0 -849
  43. sarpyx/processor/core/focus_old.py +0 -1550
  44. sarpyx/processor/core/focus_v1.py +0 -1566
  45. sarpyx/processor/core/focus_v2.py +0 -1625
  46. sarpyx/snap/engine.py +0 -633
  47. sarpyx-0.1.5.dist-info/top_level.txt +0 -2
  48. {sarpyx-0.1.5.dist-info → sarpyx-0.1.6.dist-info}/entry_points.txt +0 -0
sarpyx/utils/rfigen.py ADDED
@@ -0,0 +1,108 @@
1
+ import numpy as np
2
+ from scipy.constants import c
3
+
4
+ def freq2wavelen(f_hz):
5
+ return c / f_hz
6
+
7
+ def fspl(r_m, wavelen_m):
8
+ return (4 * np.pi * r_m / wavelen_m) ** 2
9
+
10
+ def GenerateRFISignal(sqd, RadPar=None, verbose=False):
11
+ """Generate Radio Frequency Interference (RFI) signal for SAR data.
12
+
13
+ Args:
14
+ sqd (np.ndarray): Input SAR single look complex data with shape (rows, cols).
15
+ RadPar (dict): Radar parameters containing:
16
+ - 'bw': Bandwidth in Hz
17
+ - 'fo': Center frequency in Hz
18
+ - 'fs': Sampling frequency in Hz
19
+
20
+ Returns:
21
+ tuple: A tuple containing:
22
+ - sInterf (np.ndarray): Generated interference signal with same shape as sqd
23
+ - IR (dict): Dictionary containing RFI parameters used in generation
24
+ """
25
+
26
+
27
+ if sqd is None:
28
+ raise ValueError('The parameter "sqd" must be a valid numpy ndarray.')
29
+
30
+
31
+ RadPar = {
32
+ 'fo': 5405000454.33435,
33
+ 'fs': 64345238.12571428,
34
+ 'bw': 56504455.48389234,
35
+ 'ts': 1.554116558005821e-08
36
+ } if RadPar is None else RadPar
37
+
38
+
39
+ IR = {}
40
+
41
+ # === RFI Physical Parameters ===
42
+ IR['freqShift'] = (np.random.rand() - 0.5) * RadPar['bw'] # shift within radar BW
43
+ IR['fc'] = RadPar['fo'] + IR['freqShift']
44
+ IR['SIR_dB'] = np.random.uniform(-25, -5) # control strength
45
+ IR['bw'] = np.random.uniform(0.005, 0.05) * RadPar['bw'] # narrower than radar BW
46
+ IR['PRF'] = np.random.randint(1000, 2000)
47
+ IR['duty'] = np.random.uniform(0.1, 0.5) # sparse duty
48
+ IR['Gain'] = 1.0
49
+ IR['Lambda'] = freq2wavelen(IR['fc'])
50
+ IR['T'] = IR['duty'] / IR['PRF']
51
+ IR['K'] = IR['bw'] / IR['T']
52
+ fs = RadPar['fs']
53
+ IR['t'] = np.arange(-IR['T']/2, IR['T']/2, 1/fs)
54
+
55
+ # === Chirp Pulse Generation ===
56
+ chirp = np.exp(1j * np.pi * IR['K'] * IR['t']**2)
57
+ chirp *= np.exp(1j * 2 * np.pi * IR['freqShift'] * IR['t']) # center-shift
58
+ chirp *= np.hanning(len(chirp)) # envelope
59
+ chirp /= np.max(np.abs(chirp))
60
+
61
+ # === Pulse Train (1D) ===
62
+ rows, cols = sqd.shape
63
+ burst_duration = rows / IR['PRF']
64
+ IRstream_len = int(burst_duration * fs)
65
+ pulse_spacing = int(fs / IR['PRF'])
66
+ pulse_len = len(chirp)
67
+ IRstream = np.zeros(IRstream_len, dtype=np.complex64)
68
+
69
+ pulse_indices = np.arange(0, IRstream_len - pulse_len, pulse_spacing)
70
+ N_total = len(pulse_indices)
71
+ N_active = int(IR['duty'] * N_total)
72
+ active_idx = np.random.choice(pulse_indices, N_active, replace=False)
73
+ for idx in active_idx:
74
+ IRstream[idx:idx+pulse_len] += chirp
75
+
76
+ # === Map to Burst Grid (Spatial Submask) ===
77
+ IRmap = np.zeros((rows, cols), dtype=np.complex64)
78
+ # Random RFI spatial extent (5-95% of image dimensions)
79
+ az_fraction = np.random.uniform(0.05, 0.95)
80
+ rg_fraction = np.random.uniform(0.05, 0.95)
81
+ sub_rows = int(rows * az_fraction)
82
+ sub_cols = int(cols * rg_fraction)
83
+
84
+ # Random position ensuring no border overflow
85
+ az_start = np.random.randint(0, max(1, rows - sub_rows + 1))
86
+ az_stop = az_start + sub_rows
87
+ rg_start = np.random.randint(0, max(1, cols - sub_cols + 1))
88
+ rg_stop = rg_start + sub_cols
89
+
90
+ # reshape with tiling
91
+ IRstream_crop = IRstream[:sub_rows * sub_cols]
92
+ IRmap[az_start:az_stop, rg_start:rg_stop] = IRstream_crop.reshape((sub_rows, sub_cols))
93
+
94
+ # === Power Calibration ===
95
+ signal_power_lin = np.mean(np.abs(sqd)**2)
96
+ signal_power_dB = 10 * np.log10(signal_power_lin)
97
+ PrRFI_dB = signal_power_dB - IR['SIR_dB']
98
+ PrRFI = 10 ** (PrRFI_dB / 10)
99
+ sInterf = IRmap * np.sqrt(PrRFI)
100
+
101
+ # === Metadata & Logging ===
102
+ IR['AffectedAz'] = (az_start, az_stop)
103
+ IR['AffectedRg'] = (rg_start, rg_stop)
104
+ if verbose:
105
+ print(f"[INFO] Injected RFI: freq offset = {IR['freqShift']/1e6:.2f} MHz, bw = {IR['bw']/1e6:.2f} MHz")
106
+ print(f"[INFO] SIR = {IR['SIR_dB']} dB, Affected area: Az[{az_start}:{az_stop}], Rg[{rg_start}:{rg_stop}]")
107
+
108
+ return sInterf, IR
@@ -0,0 +1,109 @@
1
+ """This script provides utility functions for extracting Well-Known Text (WKT) representations of geographic footprints
2
+ from satellite product metadata. It includes functions for extracting WKT polygons from Sentinel-1 products using
3
+ the Copernicus Data Search API and from Terrasar-X product XML files.
4
+ """
5
+
6
+ from pathlib import Path
7
+ from phidown.search import CopernicusDataSearcher
8
+ from shapely.geometry import shape
9
+ import xml.etree.ElementTree as ET
10
+
11
+
12
+
13
+
14
+
15
+ def sentinel1_wkt_extractor_cdse(product_name: str, display_results: bool = False, verbose: bool = False) -> str | None:
16
+ """
17
+ Extract WKT footprint from Sentinel-1 product using Copernicus Data Search.
18
+
19
+ Args:
20
+ product_name (str): Name of the Sentinel-1 product to search for.
21
+ display_results (bool): Whether to display search results. Defaults to False.
22
+
23
+ Returns:
24
+ str | None: WKT representation of the product footprint polygon, or None if not found.
25
+ """
26
+ searcher = CopernicusDataSearcher()
27
+ if verbose:
28
+ print(f"Searching for product with exact name: {product_name}\n")
29
+ df_exact = searcher.query_by_name(product_name=product_name)
30
+
31
+ if not df_exact.empty:
32
+ if display_results:
33
+ searcher.display_results(top_n=1)
34
+ if verbose:
35
+ print(df_exact)
36
+ print("\nProduct found successfully.")
37
+
38
+ geofootprint = df_exact['GeoFootprint'].values[0]
39
+ if verbose:
40
+ print(f"Product with GeoFootprint: '{geofootprint}' found.")
41
+
42
+ polygon = shape(geofootprint)
43
+ wkt_polygon = polygon.wkt
44
+
45
+ if verbose:
46
+ print(f"\nWKT Polygon:\n{wkt_polygon}")
47
+ return wkt_polygon
48
+ else:
49
+ if verbose:
50
+ print("No product found with the specified name.")
51
+ return None
52
+
53
+
54
+ def terrasar_wkt_extractor(product_path: Path) -> str:
55
+ """
56
+ Extract WKT footprint from Terrasar-X product XML file.
57
+
58
+ Args:
59
+ product_path (Path): Path to the input Terrasar-X product XML file.
60
+
61
+ Returns:
62
+ str: WKT representation of the product footprint polygon.
63
+ """
64
+ if isinstance(product_path, str):
65
+ product_path = Path(product_path)
66
+ assert product_path.exists(), f"Product path {product_path} does not exist."
67
+ assert product_path.suffix.lower() == '.xml', f"Product path {product_path} is not an XML file."
68
+
69
+ tree = ET.parse(product_path)
70
+ root = tree.getroot()
71
+
72
+ # Find all sceneCornerCoord elements and extract coordinates
73
+ corners = [(float(corner.find('lon').text), float(corner.find('lat').text))
74
+ for corner in root.findall('.//sceneCornerCoord')]
75
+
76
+ # Close the polygon by repeating the first point at the end
77
+ if corners:
78
+ corners.append(corners[0])
79
+
80
+ # Create WKT polygon string
81
+ return f"POLYGON(({', '.join(f'{lon} {lat}' for lon, lat in corners)}))"
82
+
83
+
84
+
85
+
86
+ if __name__ == "__main__":
87
+ import argparse
88
+
89
+ parser = argparse.ArgumentParser(description="Extract WKT footprint from satellite product metadata.")
90
+ parser.add_argument('--mode', type=str, required=True, help="Mode of operation: 'S1TOPS', 'S1STRIP', 'BM', 'TSX', etc.")
91
+ parser.add_argument('--product-path', type=str, required=True, help="Name of the satellite product.")
92
+ args = parser.parse_args()
93
+
94
+
95
+ MODE = args.mode # Example mode, can be 'S1TOPS', 'S1STRIP', 'BM', 'TSX', etc.
96
+ PRODUCT_PATH = Path(args.product_path)
97
+ PRODUCT_NAME = PRODUCT_PATH.name
98
+
99
+ if MODE == 'S1TOPS' or MODE == 'S1STRIP':
100
+ # Example usage for Sentinel-1 product
101
+ sentinel1_product_name = PRODUCT_NAME
102
+ wkt_sentinel1 = sentinel1_wkt_extractor_cdse(sentinel1_product_name, display_results=False)
103
+ print(f"\nSentinel-1 WKT Polygon:\n{wkt_sentinel1}")
104
+
105
+ elif MODE == 'TSX':
106
+ # Example usage for Terrasar-X product
107
+ terrasar_product_path = PRODUCT_PATH
108
+ wkt_terrasar = terrasar_wkt_extractor(terrasar_product_path)
109
+ print(f"\nTerrasar-X WKT Polygon:\n{wkt_terrasar}")
@@ -39,45 +39,42 @@ def save_array_to_zarr(array: 'np.ndarray',
39
39
  chunk_size = max(64, chunk_size) # Ensure minimum chunk size
40
40
  chunks = (chunk_size, chunk_size)
41
41
 
42
- # Use maximum compression with zstd and byte shuffle
43
- codec = numcodecs.Blosc(
44
- cname='zstd', # Best compression ratio
45
- clevel=compressor_level, # Maximum compression level
46
- shuffle=numcodecs.Blosc.BITSHUFFLE # Better for floating point data
47
- )
48
-
49
- # Create Zarr array with specified shape, dtype, and compression
50
- zarr_array = zarr.open(
51
- file_path,
52
- mode='w',
53
- shape=array.shape,
42
+ # Use maximum compression with zstd and byte shuffle (Zarr 3.x format)
43
+ compressors = [{'name': 'blosc', 'configuration': {'cname': 'zstd', 'clevel': compressor_level, 'shuffle': 'bitshuffle'}}]
44
+
45
+ # Create Zarr array using group + create_array pattern for Zarr 3.x compatibility
46
+ store = zarr.open_group(file_path, mode='w')
47
+ zarr_array = store.create_array(
48
+ name='data',
49
+ shape=array.shape,
54
50
  dtype=array.dtype,
55
- zarr_format=2,
56
- compressor=codec,
57
51
  chunks=chunks,
52
+ compressors=compressors,
53
+ overwrite=True
58
54
  )
59
55
  zarr_array[:] = array
60
56
 
61
- zarr_array.attrs['parent_product'] = parent_product if parent_product else 'unknown'
62
- zarr_array.attrs['creation_date'] = pd.Timestamp.now().isoformat()
57
+ # Store attributes on the group level for easier access
58
+ store.attrs['parent_product'] = parent_product if parent_product else 'unknown'
59
+ store.attrs['creation_date'] = pd.Timestamp.now().isoformat()
63
60
  # Add metadata as attributes if provided
64
61
  if metadata_df is not None:
65
62
  # Handle NaN values by filling them with None or converting to string
66
63
  metadata_clean = metadata_df.fillna('null')
67
64
 
68
65
  # Convert DataFrame to dictionary for zarr attributes
69
- zarr_array.attrs['metadata'] = metadata_clean.to_dict('records')
70
- zarr_array.attrs['metadata_columns'] = list(metadata_df.columns)
71
- zarr_array.attrs['metadata_dtypes'] = metadata_df.dtypes.astype(str).to_dict()
66
+ store.attrs['metadata'] = metadata_clean.to_dict('records')
67
+ store.attrs['metadata_columns'] = list(metadata_df.columns)
68
+ store.attrs['metadata_dtypes'] = metadata_df.dtypes.astype(str).to_dict()
72
69
  print(f'Added metadata with {len(metadata_df)} records as zarr attributes')
73
70
 
74
71
  # Add ephemeris data as attributes if provided
75
72
  if ephemeris_df is not None:
76
73
  ephemeris_clean = ephemeris_df.fillna('null')
77
74
 
78
- zarr_array.attrs['ephemeris'] = ephemeris_clean.to_dict('records')
79
- zarr_array.attrs['ephemeris_columns'] = list(ephemeris_df.columns)
80
- zarr_array.attrs['ephemeris_dtypes'] = ephemeris_df.dtypes.astype(str).to_dict()
75
+ store.attrs['ephemeris'] = ephemeris_clean.to_dict('records')
76
+ store.attrs['ephemeris_columns'] = list(ephemeris_df.columns)
77
+ store.attrs['ephemeris_dtypes'] = ephemeris_df.dtypes.astype(str).to_dict()
81
78
  print(f'Added ephemeris with {len(ephemeris_df)} records as zarr attributes')
82
79
 
83
80
  print(f'Saved array to {file_path} with maximum compression (zstd-9, chunks={chunks})')
@@ -212,14 +209,10 @@ def dask_slice_saver(
212
209
  zarr_path = Path(zarr_path)
213
210
  zarr_path.parent.mkdir(parents=True, exist_ok=True)
214
211
 
215
- store = zarr.open_group(str(zarr_path), mode='w', zarr_format=2)
212
+ store = zarr.open_group(str(zarr_path), mode='w')
216
213
 
217
214
  # Configure compression codec
218
- compressor = numcodecs.Blosc(
219
- cname='zstd',
220
- clevel=clevel,
221
- shuffle=numcodecs.Blosc.BITSHUFFLE
222
- )
215
+ compressors = [{'name': 'blosc', 'configuration': {'cname': 'zstd', 'clevel': clevel, 'shuffle': 'bitshuffle'}}]
223
216
 
224
217
  # Save arrays with optimized compression
225
218
  for array_name in required_arrays:
@@ -240,7 +233,7 @@ def dask_slice_saver(
240
233
  shape=array_data.shape,
241
234
  dtype=array_data.dtype,
242
235
  chunks=chunk_shape,
243
- compressor=compressor,
236
+ compressors=compressors,
244
237
  overwrite=True
245
238
  )
246
239
  zarr_array[:] = array_data
@@ -497,7 +490,7 @@ def concatenate_slices_efficient(
497
490
  shutil.rmtree(output_path)
498
491
 
499
492
  # Create output Zarr store and initialize arrays
500
- print(f'🏗️ Creating output Zarr store at: {output_path}')
493
+ print(f'🏗️ Creating output Zarr store (Using Zarr v{zarr.__version__}) at: {output_path}')
501
494
  output_path.parent.mkdir(parents=True, exist_ok=True)
502
495
  output_store = zarr.open(str(output_path), mode='w')
503
496
 
@@ -588,6 +581,7 @@ class ZarrManager:
588
581
  self.file_path = file_path
589
582
  self.filename = Path(file_path).stem
590
583
  self._zarr_array = None
584
+ self._zarr_store = None # Cache for the group/store (for attributes)
591
585
  self._metadata = None
592
586
  self._ephemeris = None
593
587
  self.echoes_shape = self.load().shape if self.load() is not None else None
@@ -596,11 +590,34 @@ class ZarrManager:
596
590
  """
597
591
  Load the zarr array and cache it.
598
592
 
593
+ Handles both Zarr 3.x format (group with 'data' array) and legacy format (direct array).
594
+
599
595
  Returns:
600
596
  zarr.Array: The loaded zarr array
601
597
  """
602
598
  if self._zarr_array is None:
603
- self._zarr_array = zarr.open(self.file_path, mode='r')
599
+ self._zarr_store = zarr.open(self.file_path, mode='r')
600
+ # Check if it's a group with a 'data' array (Zarr 3.x format)
601
+ if isinstance(self._zarr_store, zarr.Group) and 'data' in self._zarr_store:
602
+ self._zarr_array = self._zarr_store['data']
603
+ else:
604
+ # Legacy format: direct array
605
+ self._zarr_array = self._zarr_store
606
+ return self._zarr_array
607
+
608
+ def _get_attrs_source(self):
609
+ """
610
+ Get the object that contains attributes (group for Zarr 3.x, array for legacy).
611
+
612
+ Returns:
613
+ zarr.Group or zarr.Array: The object containing metadata attributes
614
+ """
615
+ if self._zarr_store is None:
616
+ self.load()
617
+ # For Zarr 3.x format, attributes are on the group
618
+ if isinstance(self._zarr_store, zarr.Group) and 'data' in self._zarr_store:
619
+ return self._zarr_store
620
+ # For legacy format, attributes are on the array
604
621
  return self._zarr_array
605
622
 
606
623
  def _create_output_dir(self, output_path: str) -> None:
@@ -858,10 +875,10 @@ class ZarrManager:
858
875
  pandas DataFrame containing metadata if available, None otherwise
859
876
  """
860
877
  if self._metadata is None:
861
- arr = self.load()
862
- if 'metadata' in arr.attrs:
878
+ attrs_source = self._get_attrs_source()
879
+ if 'metadata' in attrs_source.attrs:
863
880
  import pandas as pd
864
- self._metadata = pd.DataFrame(arr.attrs['metadata'])
881
+ self._metadata = pd.DataFrame(attrs_source.attrs['metadata'])
865
882
  return self._metadata
866
883
 
867
884
  def get_ephemeris(self) -> Optional['pd.DataFrame']:
@@ -872,10 +889,11 @@ class ZarrManager:
872
889
  pandas DataFrame containing ephemeris data if available, None otherwise
873
890
  """
874
891
  if self._ephemeris is None:
875
- arr = self.load()
876
- if 'ephemeris' in arr.attrs:
892
+ attrs_source = self._get_attrs_source()
893
+ if 'ephemeris' in attrs_source.attrs:
877
894
  import pandas as pd
878
- self._ephemeris = pd.DataFrame(arr.attrs['ephemeris'])
895
+ self._ephemeris = pd.DataFrame(attrs_source.attrs['ephemeris'])
896
+ return self._ephemeris
879
897
  return self._ephemeris
880
898
 
881
899
  @gc_collect
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sarpyx
3
- Version: 0.1.5
3
+ Version: 0.1.6
4
4
  Summary: A swissknife for SAR processing.
5
5
  Author-email: Roberto Del Prete <roberto.delprete@esa.int>
6
- License: MIT
6
+ License: Apache-2.0
7
7
  Requires-Python: <3.13,>=3.11
8
+ License-File: LICENSE
8
9
  Requires-Dist: matplotlib
9
10
  Requires-Dist: scipy
10
- Requires-Dist: s1isp
11
11
  Requires-Dist: geopandas>=1.1.1
12
12
  Requires-Dist: shapely
13
13
  Requires-Dist: numpy
@@ -15,9 +15,9 @@ Requires-Dist: openpyxl
15
15
  Requires-Dist: h5py
16
16
  Requires-Dist: numba
17
17
  Requires-Dist: jupyter
18
- Requires-Dist: phidown>=0.1.18
18
+ Requires-Dist: phidown>=0.1.24
19
19
  Requires-Dist: rasterio>=1.4.3
20
- Requires-Dist: zarr>=3.0.8
20
+ Requires-Dist: zarr>=3.0.0
21
21
  Requires-Dist: joblib>=1.5.1
22
22
  Requires-Dist: dask>=2025.5.1
23
23
  Requires-Dist: lxml>=5.4.0
@@ -36,3 +36,7 @@ Requires-Dist: tensorboardX>=2.6.4
36
36
  Requires-Dist: wandb>=0.21.3
37
37
  Requires-Dist: scikit-learn>=1.7.2
38
38
  Requires-Dist: geographiclib>=2.1
39
+ Requires-Dist: dotenv>=0.9.9
40
+ Requires-Dist: pyarrow>=23.0.0
41
+ Requires-Dist: fastparquet>=2025.12.0
42
+ Dynamic: license-file
@@ -1,27 +1,32 @@
1
1
  docs/examples/basic_sublook_analysis.py,sha256=1qUlX5D18F6vFRV0DdzKWvTywZ3Ri94F-th1xqWoz0w,11529
2
- docs/examples/advanced/batch_processing.py,sha256=PPMHPktcDgCmlgv8ySn_2ZpDDtpiMHeYVNqh3sRnFGo,41428
3
- docs/examples/advanced/custom_processing_chains.py,sha256=Ye3J1L1HSdcyPrhOfxOXsHXwumxSeEEaSiotzyLUph0,37475
2
+ docs/examples/advanced/batch_processing.py,sha256=LTf1SULZTcWL83Cqhe0e1MSY6IrLsNr-nYozAriVCIk,41432
3
+ docs/examples/advanced/custom_processing_chains.py,sha256=mh4pldE-cz-EFSaQeTZI5XWe5lURKzlBmw7QyXl-f5c,37479
4
4
  docs/examples/advanced/insar_time_series.py,sha256=FMQVs9CdgHynnxM_lKRJ_GpJydJALC9uXQK19AvzrmI,39716
5
- docs/examples/advanced/performance_optimization.py,sha256=hxmZR08_RaKE9qV6Vv4E1y4fyxSFFMUblOYxtCkOJp0,41733
5
+ docs/examples/advanced/performance_optimization.py,sha256=hORCN98gJILBQKiZoxWxHvkNDyCO4N0c3bLl5BcyC_E,41737
6
6
  docs/examples/basic/data_io_examples.py,sha256=CHXlZ-rQ-bajP4UikHQN3r4Q_b69WY0clELJ-taiC8w,21499
7
- docs/examples/basic/snap_integration.py,sha256=NWRZJqR9ZBuRqLb75qL_dqNiHKjhHxWnjOMPsSFwMfs,11599
7
+ docs/examples/basic/snap_integration.py,sha256=poDpmdnoQalMI1Mfr8j2KeU66uqluBTR6E6P2AkGkjY,11603
8
8
  docs/examples/basic/visualization_gallery.py,sha256=tdo5GxI3o9KgJOj9eOZxjhYaP8FhOj6yz1Ja8K_OuBk,22920
9
9
  docs/examples/intermediate/polarimetric_analysis.py,sha256=kQx7i9Wfm_ykxyzUti95f-UuokTL1CLlYZa1Vj4A_dg,31490
10
- docs/examples/intermediate/quality_assessment.py,sha256=V22pDIxjbV8ajyjSaoAqTrwQl2TCJwCGLosz-2L_uKg,34446
10
+ docs/examples/intermediate/quality_assessment.py,sha256=UlvdYTvodnWvMxUdSa8AzGL5qLWEueV0lAgB65tMoRs,34450
11
11
  docs/examples/intermediate/ship_detection_cfar.py,sha256=W-2duOHp3h_PdHmUaLJcUDTj4lxmXYJGXsG6rxvrLRY,38964
12
12
  docs/examples/intermediate/vegetation_monitoring.py,sha256=ENnCyMMzuw04C34Faxoorj5jVtXqF4im9VNXRBlFwws,27686
13
- sarpyx/__init__.py,sha256=fchNm33pwvX7vTDVdlCdQz50f8_OcNjoQ0UArpdot6k,963
13
+ outputs/baseline/20260205-234828/__init__.py,sha256=i4Gs34Wk0L5fVBafr-7Kj1tuV3xsguRxmG4KzKAVZuY,833
14
+ outputs/baseline/20260205-234828/main.py,sha256=f5CkwOd4qEkzy72amOzGZ_t3JR30bycEoXsvr9av9YU,13703
15
+ outputs/final/20260205-234851/__init__.py,sha256=B_bGwcpY66FgpyjZNGR9PvzRFZif0jnvfS6qmBIUos4,833
16
+ outputs/final/20260205-234851/main.py,sha256=uilWF1JZOh_HkvZrXsTSh_T0JXDTzWxTfSD2ZwLWcqc,13703
17
+ sarpyx/__init__.py,sha256=Gsu_bvdPPpnEA10qcDUJrM4fvNUprmmHGZLqg3ZeA3k,964
14
18
  sarpyx/algorithms/AdaptiveThresholding.py,sha256=7ycVmHp2WeXqq1Wb2huDmky_Z1FvbtJ_OLvExzcEGK0,5691
15
- sarpyx/algorithms/__init__.py,sha256=PH9BVBo6TNfXD2wQG_0kiFYy74U4mYVqalM77hL-FdM,452
16
- sarpyx/cli/__init__.py,sha256=NBa8NieSu75JAa-MV4-MqmtjHWfeTYJ_A4_1D-4OMGs,369
19
+ sarpyx/algorithms/__init__.py,sha256=C43iB7s5GAN8EqyJ_7yXt96_Bl4x2QD_xygJ6xFNj5M,453
20
+ sarpyx/cli/__init__.py,sha256=Pd4AUeEVoAI-YuWutb-J5mon66TC9iCnuwW8gPQQS2M,369
17
21
  sarpyx/cli/decode.py,sha256=vQqOifdcexed3tAPL1Qw2xErGLBNHOnNhUPMoAD__NY,5815
18
- sarpyx/cli/focus.py,sha256=p6ZeohUsfQmQSAxrKIaD_6maxPoGqxwtSww6Hpxm8H8,12083
19
- sarpyx/cli/main.py,sha256=gTZZF9ye394-QRKbEXBnAJp9yIxxvVVRhKNqmsOQv1M,10717
20
- sarpyx/cli/shipdet.py,sha256=xfxQVrsT7I4k--4jGpUaU8VwAYUVSxnxEpoGtZycGE8,11072
22
+ sarpyx/cli/focus.py,sha256=gYhVhLSUn55pWKP5g9Pe5cQLeAzjicyRgwKiEcD9LOY,11927
23
+ sarpyx/cli/main.py,sha256=uilWF1JZOh_HkvZrXsTSh_T0JXDTzWxTfSD2ZwLWcqc,13703
24
+ sarpyx/cli/shipdet.py,sha256=RjJ4j4aXSvbthQ5tDuLE6HM6Q2bgjtqp1CjcWVuFX7w,11076
21
25
  sarpyx/cli/unzip.py,sha256=fG2WpJPDZ2AoQk1qrpuYP7hLj1mKnxhUNieZKktkVmk,5340
22
26
  sarpyx/cli/upload.py,sha256=teXpohily8IYeLVYmWbS9ealBXdJwLH83c1KZU-HVQY,4348
23
27
  sarpyx/cli/utils.py,sha256=ewArHsKMB4JEi32fu2gxzouQVwa0afwou0WG6y35o2U,7553
24
- sarpyx/processor/__init__.py,sha256=nCTClOgRy5N6DycldTny4gMmB9MkQHhEWjSskdJ3wUU,832
28
+ sarpyx/cli/worldsar.py,sha256=Yb8mLwpjKuTdWzgsKsqhqG9aRwWA2tRAMdnXNH5nPMk,18445
29
+ sarpyx/processor/__init__.py,sha256=B_bGwcpY66FgpyjZNGR9PvzRFZif0jnvfS6qmBIUos4,833
25
30
  sarpyx/processor/algorithms/__init__.py,sha256=UdXRpIWS_WWFfqGTJIf-YC1cjUKVYHoESeGKxV2SqeQ,410
26
31
  sarpyx/processor/algorithms/backprojection.py,sha256=BSz37I0zrbBcbK8XSnHs1DBzo-jQhfzD9-ZQK1XSFLA,526
27
32
  sarpyx/processor/algorithms/constants.py,sha256=2G3gOaC7qAhbs_g9RkaGnP__wCW5J5azeoa45pJcRRs,12445
@@ -31,13 +36,8 @@ sarpyx/processor/core/__init__.py,sha256=K_RdQ87RPU3duTH1jK_gp8VeOV6thqhqDZucRCG
31
36
  sarpyx/processor/core/aux.py,sha256=9u1uVQpDfXwH6S8hY0aDtrwYa744dr3-kC8ikO8S0Gc,12352
32
37
  sarpyx/processor/core/code2physical.py,sha256=dD0niPGjvvhkkKwGswOOWU8mvZiRj1RyjGILfPj8z08,27044
33
38
  sarpyx/processor/core/constants.py,sha256=2IglEMxVFQqvROm67sXl54X8nzODfXjqTTmnQtEsfJY,3026
34
- sarpyx/processor/core/decode.py,sha256=_36M_ml7ZGk3JvPv9A6J7ScI-_so2o9dehfZw07-2jI,39521
35
- sarpyx/processor/core/decode_v0.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
- sarpyx/processor/core/decode_v1.py,sha256=bvg5t1ZKlWuI5f2VEe4mJJnuNiXXJoKA0XC4qQqzJLk,36094
37
- sarpyx/processor/core/focus.py,sha256=Gf53hitsnNSXLv5KbnQSb-u66pnZK7i8nBcs73TY10A,68998
38
- sarpyx/processor/core/focus_old.py,sha256=76FuP9YUq30cXW46fkCF3qr3th_I1CB253hex9D3wd4,64372
39
- sarpyx/processor/core/focus_v1.py,sha256=0Eww7syNzuYzjOHfxjOzg-HxiiRgYiCsv0ynozTnYz4,65024
40
- sarpyx/processor/core/focus_v2.py,sha256=HBC1RJ2UEyGGAMfBA769YlVtsghgovf1BvkiVMrSTsk,67402
39
+ sarpyx/processor/core/decode.py,sha256=o4oEbUCSrXCVEW1uQ1_Nm73Bgd_u0miWpZ03bGqZMSU,40741
40
+ sarpyx/processor/core/focus.py,sha256=vH022rXX4gg5EOwvGaQfP5MIgCoN0lhoUjly9xqnhNA,71943
41
41
  sarpyx/processor/core/signal.py,sha256=aVlMS5xa-byabjFq_xBKsv-tcYp2DIef484tX_1W1cE,12327
42
42
  sarpyx/processor/core/spectrum.py,sha256=mSG6a-UZu2nRLO8BO5Ethu6SYV4_KT8cN9wKrlBfJz8,36436
43
43
  sarpyx/processor/core/subaperture.py,sha256=1jyofcqVHzQB3oQPzQR5K0nCjMqZE06QsqLuMrZlDRc,19899
@@ -52,29 +52,38 @@ sarpyx/processor/utils/metrics.py,sha256=8wp0yriIQMURmjksRf6lG2kgyIpzS3SVRRdOlqh
52
52
  sarpyx/processor/utils/summary.py,sha256=bn6LuuhYKrdqjhHkwro_4WYrvG4MU9e7SKIwKpG4NiM,526
53
53
  sarpyx/processor/utils/unzip.py,sha256=VvnwPRic42VKmxQm8wlUUuwdlb6z9GOHTqGl9JoVfsI,2131
54
54
  sarpyx/processor/utils/viz.py,sha256=9D2KDhlNckIr88zBhYLOGwgqvsws_hgbPKhvBnqCeq4,3396
55
- sarpyx/science/__init__.py,sha256=CZUcss-4nOZroU2w1RytJgs4n4sdZ5YKxJ_nY-QbdC8,178
55
+ sarpyx/science/__init__.py,sha256=HwTNdKxnSA05GN9xkdcOkzHO5Z4fQzRxoCIVET-abT4,178
56
56
  sarpyx/science/indices.py,sha256=WpsnvvYaK55v8OwmwUakeVHypcYSWUEFMf04zLdh50Y,10428
57
- sarpyx/sla/__init__.py,sha256=pBveJ9h-rMQGvvoLSzkxi2406ymGsTAwTHLYmLjdClo,561
57
+ sarpyx/sla/__init__.py,sha256=wjRHQKn9n3XATQIxCB0y8VQ7oAXV7fBGfOJUNOyIwWk,798
58
+ sarpyx/sla/metrics.py,sha256=yka7gC6S2SA3oqqfawovxjAz6VTTNJQ_yOU48kOwChk,2880
58
59
  sarpyx/sla/utilis.py,sha256=we2VOZM7MtZdD0YaKTjHFchj2Hlu1MP0kNka25170wI,3955
59
60
  sarpyx/sla/core/__init__.py,sha256=ptn8ztthve3VP4JabLc7NurmR26U3ljr1mvZaZ6w9Gk,181
60
61
  sarpyx/sla/core/meta.py,sha256=lMp-F2G9p_wwzquFXNEQPFSx5ajHz4OGezed9sS-i0E,5166
61
62
  sarpyx/sla/core/spectrum.py,sha256=VxVdxxvvHhOD9RnIkZ9383Jr6_0Wgw4Wt04JZPEHmn8,20587
62
- sarpyx/snap/__init__.py,sha256=hQITbG-rIwl4ydrq7VX1in0PJZTbh-N9y5GWkMmG2lg,194
63
- sarpyx/snap/engine.py,sha256=KV-MlkHuseGc2e6haGRuQzLUFqjYxwnRPoLNBMPb5mw,26624
64
- sarpyx/snap/op.py,sha256=PL34A1Q7u1fMiKwdc-pvPM4b9_SlXvHSgeeljBsLS_o,9299
65
- sarpyx/utils/__init__.py,sha256=XkYSeDlAM6m3BP1V6AeTPKhsPIucfigcIT47QW8dAXk,629
63
+ sarpyx/snapflow/__init__.py,sha256=QzV3XO9S4ljH7fOAVaP8Fx6oK3vMV__naQHSO8W_RL0,195
64
+ sarpyx/snapflow/engine.py,sha256=YMq_zdVf2RVEGS9eF6HOKmkq5W09GawE9ZVnLnkrEQU,253288
65
+ sarpyx/snapflow/op.py,sha256=7Vr_49ro0bmLp9zGmNTi2Hwyj39FLgiw9oYen1FOhuY,9277
66
+ sarpyx/utils/__init__.py,sha256=qrlKX92Y8iZOp1bS5zp3T-sjmHbenjJsGEAHcWWmP2g,630
66
67
  sarpyx/utils/complex_losses.py,sha256=RJvWXZ9WMmWqzEIs8VOW6hQFGf5-If_peKrD3uYYXe8,6379
67
68
  sarpyx/utils/executor.py,sha256=Rdk4lVBgrSdaUZZgdDEETrlS-ytiOGqMAce4Urn7Jwo,10960
69
+ sarpyx/utils/geos.py,sha256=RLPn9ynsR3rus6cvvkORPQo2IIrcLHKUkHL5cCaYTEk,23017
70
+ sarpyx/utils/grid.py,sha256=8BGgVsDRXY4aSqGo7mJKYBMxfBgpXHEG9ANmQd_Kt48,11330
68
71
  sarpyx/utils/hf.py,sha256=AG4A7Cd4dBcevcl_C-4OAl_-CXbYUAA11dpGO5TrH0A,3828
69
- sarpyx/utils/io.py,sha256=nw9RWNk_eFpMukXCUDXqG9GCk-YIM6G3BPcL5vZWeiE,18136
72
+ sarpyx/utils/io.py,sha256=TlXezDxNEm4PGysSI13i6b6l40MnBMZCaklBBlZ9btA,20302
70
73
  sarpyx/utils/losses.py,sha256=0DJnZ1dOF33GjPMDH4R5-X27loE07PZkrg2ldmc4M94,88110
74
+ sarpyx/utils/meta.py,sha256=yuw-uekidlxJrI7Fw-68BLPj2JmXkfT6YrUnCPuVVlA,1552
71
75
  sarpyx/utils/metrics.py,sha256=VDz6GNO8HlBQ2A7hlKIfZNPTdd0dcYXmFjMX4d4cdCI,19886
76
+ sarpyx/utils/nisar_utils.py,sha256=VJ5oPb6FDKtYJkWI0Y8c6N53TePT47y_5lWJAnGqWlo,23109
77
+ sarpyx/utils/rfigen.py,sha256=_3v9drsXycjj0SEueoKG3eDgzE4d5hdPs_qr-D0nL-k,4011
72
78
  sarpyx/utils/sar_loss.py,sha256=cqxebOoBqJlYOUe87W6eGK97oiV4lgKIoQL9MkOPR0A,23833
73
79
  sarpyx/utils/up.py,sha256=ApIjips3SYt3rb4aDo7ljyDBuh8i5pY4i9qo__o3tA4,2590
74
80
  sarpyx/utils/viz.py,sha256=2F7T7JtwLbA2E2KtQCE7NnR6U88p9d7W3y10dvzFGzU,3991
75
- sarpyx/utils/zarr_utils.py,sha256=_ZLEJUgRbukRMgoucyPviwsC4kScGK5K4W-dJgABMKQ,64042
76
- sarpyx-0.1.5.dist-info/METADATA,sha256=RTiR9UylBn__F5GqcYqI3qmmJGnQ8gi7wyHsllxybyk,1089
77
- sarpyx-0.1.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
78
- sarpyx-0.1.5.dist-info/entry_points.txt,sha256=KaSUkL_cvQIA-8nodwgik9UfA2h-07nluy2DKgPeE6E,241
79
- sarpyx-0.1.5.dist-info/top_level.txt,sha256=r3uVdADIGkm2RUPUL5ownhpOlbGVYQGUHOA6sMKgQ6o,12
80
- sarpyx-0.1.5.dist-info/RECORD,,
81
+ sarpyx/utils/wkt_utils.py,sha256=Xn4sY2uBWtAnQKfqC0xvnF95RBeR44rAJC-T6skf9zQ,4048
82
+ sarpyx/utils/zarr_utils.py,sha256=fP-7d-3POTUn61BtZyLgswCDYm4ow-CZRdJPx12ZRWA,65276
83
+ sarpyx-0.1.6.dist-info/licenses/LICENSE,sha256=TVOR4tTt739YHIPw1bKRjoeiRBtfcd4L63N17sV98G0,11351
84
+ tests/test_zarr_compat.py,sha256=-0iF-WBy0bzugxHvc2j8M2-AExghrM2Ky-2FyU0FUR8,1217
85
+ sarpyx-0.1.6.dist-info/METADATA,sha256=nfeNI516iuuT1ZkqHuhuR14Tw3bwn3-tJdfzxwn5qZo,1217
86
+ sarpyx-0.1.6.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
87
+ sarpyx-0.1.6.dist-info/entry_points.txt,sha256=KaSUkL_cvQIA-8nodwgik9UfA2h-07nluy2DKgPeE6E,241
88
+ sarpyx-0.1.6.dist-info/top_level.txt,sha256=amk2m5OI2lU-hX4eS5WRP-YoUiT5q77jr1cC3NGi5cU,26
89
+ sarpyx-0.1.6.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5