1717
1818class LatLonFilter (Filter ):
1919 """
20- A filter class for data based on regular latitude and longitude grids using NumPy arrays.
21-
22- Methods
23- -------
24- many_compute(n: int, k: float, data: Union[np.ndarray, List[np.ndarray]]) -> List[np.ndarray]:
25- Placeholder method to compute filtering on multiple datasets. Not implemented yet.
26-
27- compute_velocity(n: int, k: float, ux: np.ndarray, vy: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
28- Computes the filtered velocity fields.
29-
30- compute(n: int, k: float, data: np.ndarray) → np.ndarray:
31- Computes the filtered data.
32-
20+ Filter implementation for regular latitude-longitude grids.
21+
22+ This class provides implicit filtering capabilities for data on structured
23+ lat-lon grids. It supports both Cartesian and spherical coordinate systems
24+ with configurable boundary conditions and land-sea masks.
25+
26+ Parameters
27+ ----------
28+ See Filter class for inherited parameters.
29+
30+ Attributes
31+ ----------
32+ _e2d : int
33+ Total number of grid points (nx * ny)
34+ _nx : int
35+ Number of longitude points
36+ _ny : int
37+ Number of latitude points
38+ _ss : np.ndarray
39+ Non-zero values of sparse filter matrix
40+ _ii : np.ndarray
41+ Row indices for sparse matrix entries
42+ _jj : np.ndarray
43+ Column indices for sparse matrix entries
44+ _area : np.ndarray
45+ Area associated with each grid cell
46+ _backend : str
47+ Computational backend ('cpu' or 'gpu')
48+ _mask_n : np.ndarray
49+ Boolean mask for valid grid points (False indicates land)
3350 """
34-
3551 def __init__ (self , * initial_data , ** kwargs ):
36- """
37- Initializes the LatLonNumpyFilter with the given data and keyword arguments.
38-
39- Parameters
40- ----------
41- initial_data : tuple
42- Initial data to be passed to the parent class.
43- kwargs : dict
44- Additional keyword arguments.
45-
46- """
4752 super ().__init__ (initial_data , ** kwargs )
4853 it = lambda ar : int (ar )
4954 ar = lambda ar : np .array (ar )
@@ -67,24 +72,37 @@ def prepare(
6772 longitude : np .ndarray ,
6873 cartesian : bool = False ,
6974 local : bool = True ,
75+ cyclic_length : float = 2 * math .pi ,
7076 mask : np .ndarray | None = None ,
7177 gpu : bool = False ,
7278 ):
7379 """
74- Prepares the filter for latitude and longitude grids regular grids
80+ Configure filter for a latitude-longitude grid.
81+
82+ Computes grid topology, geometric properties, and assembles the filter
83+ operator matrix. Must be called before any filtering operations.
7584
7685 Parameters
7786 ----------
78- latitude: np.ndarray
79- 1D np.ndarray of floats with latitude values
80- longitude: np.ndarray
81- 1D np.ndarray of floats with longitude values
82- cartesian: bool
83- If true, the conversion from degrees to km should assume that mesh is cartesian.
84- local: bool
85- If true, neighborhood calculation doesn't wrap around an East/West direction
87+ latitude : np.ndarray
88+ Latitude values in degrees (1D array)
89+ longitude : np.ndarray
90+ Longitude values in degrees (1D array)
91+ cartesian : bool, optional
92+ True for Cartesian coordinates, False for spherical (default)
93+ local : bool, optional
94+ True for 4-point local neighborhood, False for 8-point global (default: True)
95+ cyclic_length : float, optional
96+ Cyclic domain length in radians (default: 2π).
97+ mask : np.ndarray, optional
98+ Land-sea mask where True indicates land (default: all ocean)
99+ gpu : bool, optional
100+ True to enable GPU acceleration (default: False)
101+
102+ Notes
103+ -----
104+ - Land points are masked using Neumann boundary conditions
86105 """
87-
88106 nx = len (longitude )
89107 ny = len (latitude )
90108 e2d = nx * ny
@@ -123,10 +141,7 @@ def prepare(
123141 hh = np .ones ((4 , e2d )) # Edge lengths
124142 hc = np .ones ((4 , e2d )) # Distance to next cell centers
125143 r_earth = 6400.0
126- cyclic_length = (
127- 360 # in degrees; if not cyclic, take it larger than zonal size
128- )
129- cyclic_length = cyclic_length * math .pi / 180
144+
130145 # Fill ee_pos, arrangement is W;N;E;S
131146 for i in range (e2d ):
132147 if ee_pos [1 , i ] == i :
@@ -204,9 +219,29 @@ def prepare(
204219 self .set_backend ("gpu" if gpu else "cpu" )
205220
206221 def get_backend (self ) -> str :
222+ """
223+ Get current computational backend.
224+
225+ Returns
226+ -------
227+ str
228+ Current backend ('cpu' or 'gpu').
229+ """
207230 return self ._backend
208231
209232 def set_backend (self , backend : str ):
233+ """
234+ Set computational backend for filtering operations.
235+
236+ Parameters
237+ ----------
238+ backend : str
239+ Desired backend ('cpu' or 'gpu').
240+
241+ Notes
242+ -----
243+ Configures appropriate sparse linear algebra functions for the backend.
244+ """
210245 self .csc_matrix , self .identity , self .cg , self .convers , self .tonumpy = (
211246 get_backend (backend )
212247 )
@@ -247,6 +282,28 @@ def _compute(
247282 return self .tonumpy (tts )
248283
249284 def compute (self , n : int , k : float , data : np .ndarray ) -> np .ndarray :
285+ """
286+ Apply filter to scalar field on lat-lon grid.
287+
288+ Parameters
289+ ----------
290+ n : int
291+ Filter order (must be positive).
292+ k : float
293+ Filter wavelength in spatial units.
294+ data : np.ndarray
295+ Scalar field values on grid (shape: (nx, ny)).
296+
297+ Returns
298+ -------
299+ np.ndarray
300+ Filtered scalar field (shape: (nx, ny)).
301+
302+ Raises
303+ ------
304+ ValueError
305+ If filter order n < 1.
306+ """
250307 if n < 1 :
251308 raise ValueError ("Filter order must be positive" )
252309
@@ -257,6 +314,30 @@ def compute(self, n: int, k: float, data: np.ndarray) -> np.ndarray:
257314 def compute_velocity (
258315 self , n : int , k : float , ux : np .ndarray , vy : np .ndarray
259316 ) -> Tuple [np .ndarray , np .ndarray ]:
317+ """
318+ Apply filter to velocity components on lat-lon grid.
319+
320+ Parameters
321+ ----------
322+ n : int
323+ Filter order (must be positive).
324+ k : float
325+ Filter wavelength in spatial units.
326+ ux : np.ndarray
327+ Eastward velocity component (shape: (nx, ny)).
328+ vy : np.ndarray
329+ Northward velocity component (shape: (nx, ny)).
330+
331+ Returns
332+ -------
333+ Tuple[np.ndarray, np.ndarray]
334+ Filtered velocity components (ux_filt, vy_filt) each with shape (nx, ny).
335+
336+ Raises
337+ ------
338+ ValueError
339+ If filter order n < 1.
340+ """
260341 if n < 1 :
261342 raise ValueError ("Filter order must be positive" )
262343
@@ -276,6 +357,27 @@ def compute_spectra_scalar(
276357 data : np .ndarray ,
277358 mask : np .ndarray | None = None ,
278359 ) -> np .ndarray :
360+ """
361+ Compute power spectra for scalar field at specified wavelengths.
362+
363+ Parameters
364+ ----------
365+ n : int
366+ Filter order (must be positive).
367+ k : Iterable | np.ndarray
368+ Target wavelengths for spectral analysis.
369+ data : np.ndarray
370+ Scalar field values on grid (shape: (nx, ny)).
371+ mask : np.ndarray, optional
372+ Boolean mask where True excludes points from spectra computation.
373+
374+ Returns
375+ -------
376+ np.ndarray
377+ Power spectral density at wavelengths [0, k0, k1, ...]:
378+ [0] : Total variance
379+ [1:] : Variance at each wavelength k
380+ """
279381 nr = len (k )
280382 tt = np .reshape (data , self ._e2d )
281383 spectra = np .zeros (nr + 1 )
@@ -309,34 +411,29 @@ def compute_spectra_velocity(
309411 mask : np .ndarray | None = None ,
310412 ) -> np .ndarray :
311413 """
312- Computes power spectra for given wavelengths.
313- Data must be placed on mesh nodes
414+ Compute power spectra for velocity field at specified wavelengths.
314415
315- For details refer to https://arxiv.org/abs/2404.07398
316- Parameters:
317- -----------
416+ Parameters
417+ ----------
318418 n : int
319- Order of filter, one is recommended
320-
419+ Filter order (must be positive).
321420 k : Iterable | np.ndarray
322- List of wavelengths to be filtered.
323-
421+ Target wavelengths for spectral analysis.
324422 ux : np.ndarray
325- NumPy array containing an eastward velocity component to be filtered.
326-
423+ Eastward velocity component (shape: (nx, ny)).
327424 vy : np.ndarray
328- NumPy array containing a northwards velocity component to be filtered.
329-
330- mask : np.ndarray | None
331- Mask applied to data while computing spectra.
332- True means selected data won't be used for computing spectra.
333- This mask won't be used during filtering.
334-
335- Returns:
336- --------
337- np.ndarray:
338- Array containing power spectra for given wavelengths.
425+ Northward velocity component (shape: (nx, ny)).
426+ mask : np.ndarray, optional
427+ Boolean mask where True excludes points from spectra computation.
428+
429+ Returns
430+ -------
431+ np.ndarray
432+ Kinetic energy spectral density at wavelengths [0, k0, k1, ...]:
433+ [0] : Total kinetic energy
434+ [1:] : Kinetic energy at each wavelength k
339435 """
436+
340437 nr = len (k )
341438 unod = np .reshape (ux , self ._e2d )
342439 vnod = np .reshape (vy , self ._e2d )
0 commit comments