surfacetopography 0.92.0__py3.8-linux-x86_64.egg
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.
- EGG-INFO/PKG-INFO +11 -0
- EGG-INFO/SOURCES.txt +99 -0
- EGG-INFO/dependency_links.txt +1 -0
- EGG-INFO/native_libs.txt +1 -0
- EGG-INFO/not-zip-safe +1 -0
- EGG-INFO/requires.txt +6 -0
- EGG-INFO/top_level.txt +3 -0
- SurfaceTopography/ChangeLog.md +387 -0
- SurfaceTopography/Converters.py +197 -0
- SurfaceTopography/FFTTricks.py +79 -0
- SurfaceTopography/Generation.py +440 -0
- SurfaceTopography/HeightContainer.py +315 -0
- SurfaceTopography/IO/DI.py +261 -0
- SurfaceTopography/IO/FromFile.py +802 -0
- SurfaceTopography/IO/H5.py +79 -0
- SurfaceTopography/IO/IBW.py +176 -0
- SurfaceTopography/IO/MI.py +307 -0
- SurfaceTopography/IO/Matlab.py +106 -0
- SurfaceTopography/IO/NC.py +228 -0
- SurfaceTopography/IO/NPY.py +140 -0
- SurfaceTopography/IO/OPDx.py +885 -0
- SurfaceTopography/IO/Reader.py +389 -0
- SurfaceTopography/IO/__init__.py +241 -0
- SurfaceTopography/IO/__pycache__/DI.cpython-38.pyc +0 -0
- SurfaceTopography/IO/__pycache__/FromFile.cpython-38.pyc +0 -0
- SurfaceTopography/IO/__pycache__/H5.cpython-38.pyc +0 -0
- SurfaceTopography/IO/__pycache__/IBW.cpython-38.pyc +0 -0
- SurfaceTopography/IO/__pycache__/MI.cpython-38.pyc +0 -0
- SurfaceTopography/IO/__pycache__/Matlab.cpython-38.pyc +0 -0
- SurfaceTopography/IO/__pycache__/NC.cpython-38.pyc +0 -0
- SurfaceTopography/IO/__pycache__/NPY.cpython-38.pyc +0 -0
- SurfaceTopography/IO/__pycache__/OPDx.cpython-38.pyc +0 -0
- SurfaceTopography/IO/__pycache__/Reader.cpython-38.pyc +0 -0
- SurfaceTopography/IO/__pycache__/__init__.cpython-38.pyc +0 -0
- SurfaceTopography/Interpolation.py +30 -0
- SurfaceTopography/Nonuniform/Autocorrelation.py +161 -0
- SurfaceTopography/Nonuniform/Detrending.py +87 -0
- SurfaceTopography/Nonuniform/PowerSpectrum.py +191 -0
- SurfaceTopography/Nonuniform/ScalarParameters.py +140 -0
- SurfaceTopography/Nonuniform/VariableBandwidth.py +155 -0
- SurfaceTopography/Nonuniform/__init__.py +28 -0
- SurfaceTopography/Nonuniform/__pycache__/Autocorrelation.cpython-38.pyc +0 -0
- SurfaceTopography/Nonuniform/__pycache__/Detrending.cpython-38.pyc +0 -0
- SurfaceTopography/Nonuniform/__pycache__/PowerSpectrum.cpython-38.pyc +0 -0
- SurfaceTopography/Nonuniform/__pycache__/ScalarParameters.cpython-38.pyc +0 -0
- SurfaceTopography/Nonuniform/__pycache__/VariableBandwidth.cpython-38.pyc +0 -0
- SurfaceTopography/Nonuniform/__pycache__/__init__.cpython-38.pyc +0 -0
- SurfaceTopography/Nonuniform/__pycache__/common.cpython-38.pyc +0 -0
- SurfaceTopography/Nonuniform/common.py +95 -0
- SurfaceTopography/NonuniformLineScan.py +310 -0
- SurfaceTopography/Special.py +225 -0
- SurfaceTopography/Tools/__init__.py +28 -0
- SurfaceTopography/Tools/__pycache__/__init__.cpython-38.pyc +0 -0
- SurfaceTopography/Tools/__pycache__/common.cpython-38.pyc +0 -0
- SurfaceTopography/Tools/common.py +75 -0
- SurfaceTopography/Uniform/Autocorrelation.py +212 -0
- SurfaceTopography/Uniform/Detrending.py +155 -0
- SurfaceTopography/Uniform/Filtering.py +321 -0
- SurfaceTopography/Uniform/Interpolation.py +202 -0
- SurfaceTopography/Uniform/PowerSpectrum.py +174 -0
- SurfaceTopography/Uniform/ScalarParameters.py +185 -0
- SurfaceTopography/Uniform/VariableBandwidth.py +169 -0
- SurfaceTopography/Uniform/__init__.py +28 -0
- SurfaceTopography/Uniform/__pycache__/Autocorrelation.cpython-38.pyc +0 -0
- SurfaceTopography/Uniform/__pycache__/Detrending.cpython-38.pyc +0 -0
- SurfaceTopography/Uniform/__pycache__/Filtering.cpython-38.pyc +0 -0
- SurfaceTopography/Uniform/__pycache__/Interpolation.cpython-38.pyc +0 -0
- SurfaceTopography/Uniform/__pycache__/PowerSpectrum.cpython-38.pyc +0 -0
- SurfaceTopography/Uniform/__pycache__/ScalarParameters.cpython-38.pyc +0 -0
- SurfaceTopography/Uniform/__pycache__/VariableBandwidth.cpython-38.pyc +0 -0
- SurfaceTopography/Uniform/__pycache__/__init__.cpython-38.pyc +0 -0
- SurfaceTopography/Uniform/__pycache__/common.cpython-38.pyc +0 -0
- SurfaceTopography/Uniform/common.py +381 -0
- SurfaceTopography/UniformLineScanAndTopography.py +887 -0
- SurfaceTopography/__init__.py +62 -0
- SurfaceTopography/__pycache__/Converters.cpython-38.pyc +0 -0
- SurfaceTopography/__pycache__/FFTTricks.cpython-38.pyc +0 -0
- SurfaceTopography/__pycache__/Generation.cpython-38.pyc +0 -0
- SurfaceTopography/__pycache__/HeightContainer.cpython-38.pyc +0 -0
- SurfaceTopography/__pycache__/Interpolation.cpython-38.pyc +0 -0
- SurfaceTopography/__pycache__/NonuniformLineScan.cpython-38.pyc +0 -0
- SurfaceTopography/__pycache__/Special.cpython-38.pyc +0 -0
- SurfaceTopography/__pycache__/UniformLineScanAndTopography.cpython-38.pyc +0 -0
- SurfaceTopography/__pycache__/__init__.cpython-38.pyc +0 -0
- SurfaceTopography/__pycache__/common.cpython-38.pyc +0 -0
- SurfaceTopography/common.py +111 -0
- _SurfaceTopography.cpython-38-x86_64-linux-gnu.so +0 -0
- _SurfaceTopography.py +7 -0
- __pycache__/_SurfaceTopography.cpython-38.pyc +0 -0
- test/IO/__init__.py +28 -0
- test/IO/__pycache__/__init__.cpython-38.pyc +0 -0
- test/IO/__pycache__/test_h5.cpython-38.pyc +0 -0
- test/IO/__pycache__/test_hgt.cpython-38.pyc +0 -0
- test/IO/__pycache__/test_ibw.cpython-38.pyc +0 -0
- test/IO/__pycache__/test_io.cpython-38.pyc +0 -0
- test/IO/__pycache__/test_mat.cpython-38.pyc +0 -0
- test/IO/__pycache__/test_mi.cpython-38.pyc +0 -0
- test/IO/__pycache__/test_netcdf.cpython-38.pyc +0 -0
- test/IO/__pycache__/test_npy.cpython-38.pyc +0 -0
- test/IO/__pycache__/test_opd.cpython-38.pyc +0 -0
- test/IO/__pycache__/test_opdx.cpython-38.pyc +0 -0
- test/IO/__pycache__/test_x3p.cpython-38.pyc +0 -0
- test/IO/__pycache__/test_xyz.cpython-38.pyc +0 -0
- test/IO/test_h5.py +31 -0
- test/IO/test_hgt.py +16 -0
- test/IO/test_ibw.py +205 -0
- test/IO/test_io.py +436 -0
- test/IO/test_mat.py +21 -0
- test/IO/test_mi.py +103 -0
- test/IO/test_netcdf.py +134 -0
- test/IO/test_npy.py +176 -0
- test/IO/test_opd.py +28 -0
- test/IO/test_opdx.py +441 -0
- test/IO/test_x3p.py +43 -0
- test/IO/test_xyz.py +19 -0
- test/__init__.py +26 -0
- test/__pycache__/__init__.cpython-38.pyc +0 -0
- test/__pycache__/compare-orientation-with-gwyddion.cpython-38.pyc +0 -0
- test/__pycache__/conftest.cpython-38.pyc +0 -0
- test/__pycache__/test_autocorrelation.cpython-38.pyc +0 -0
- test/__pycache__/test_bicubic.cpython-38.pyc +0 -0
- test/__pycache__/test_derivatives.cpython-38.pyc +0 -0
- test/__pycache__/test_filtering.cpython-38.pyc +0 -0
- test/__pycache__/test_generation.cpython-38.pyc +0 -0
- test/__pycache__/test_import.cpython-38.pyc +0 -0
- test/__pycache__/test_make_sphere.cpython-38.pyc +0 -0
- test/__pycache__/test_pipeline.cpython-38.pyc +0 -0
- test/__pycache__/test_power_spectrum.cpython-38.pyc +0 -0
- test/__pycache__/test_scalar_parameters.cpython-38.pyc +0 -0
- test/__pycache__/test_topography.cpython-38.pyc +0 -0
- test/__pycache__/test_variable_bandwidth.cpython-38.pyc +0 -0
- test/compare-orientation-with-gwyddion.py +102 -0
- test/conftest.py +80 -0
- test/test_autocorrelation.py +311 -0
- test/test_bicubic.py +190 -0
- test/test_derivatives.py +88 -0
- test/test_filtering.py +160 -0
- test/test_generation.py +259 -0
- test/test_import.py +54 -0
- test/test_make_sphere.py +111 -0
- test/test_pipeline.py +151 -0
- test/test_power_spectrum.py +283 -0
- test/test_scalar_parameters.py +216 -0
- test/test_topography.py +1151 -0
- test/test_variable_bandwidth.py +107 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2019-2020 Lars Pastewka
|
|
3
|
+
# 2019 Antoine Sanner
|
|
4
|
+
#
|
|
5
|
+
# ### MIT license
|
|
6
|
+
#
|
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
# furnished to do so, subject to the following conditions:
|
|
13
|
+
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be included in
|
|
15
|
+
# all copies or substantial portions of the Software.
|
|
16
|
+
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
# SOFTWARE.
|
|
24
|
+
#
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
Utility function for conversion between uniform and nonuniform
|
|
28
|
+
representations.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
import numpy as np
|
|
32
|
+
|
|
33
|
+
from .HeightContainer import DecoratedTopography, UniformTopographyInterface, \
|
|
34
|
+
NonuniformLineScanInterface
|
|
35
|
+
from .NonuniformLineScan import NonuniformLineScan
|
|
36
|
+
from .UniformLineScanAndTopography import UniformLineScan
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class WrapAsNonuniformLineScan(DecoratedTopography,
|
|
40
|
+
NonuniformLineScanInterface):
|
|
41
|
+
"""
|
|
42
|
+
Wrap a uniform topography into a nonuniform one.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def __init__(self, topography, info={}):
|
|
46
|
+
"""
|
|
47
|
+
Parameters
|
|
48
|
+
----------
|
|
49
|
+
topography : :obj:`NonuniformLineScan`
|
|
50
|
+
SurfaceTopography to wrap.
|
|
51
|
+
"""
|
|
52
|
+
super().__init__(topography, info=info)
|
|
53
|
+
|
|
54
|
+
# This is populated with functions from the nonuniform topography, but
|
|
55
|
+
# this is a uniform topography
|
|
56
|
+
self._functions = NonuniformLineScan._functions
|
|
57
|
+
|
|
58
|
+
# Implement abstract methods of AbstractHeightContainer
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def dim(self):
|
|
62
|
+
return 1
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def physical_sizes(self):
|
|
66
|
+
s, = self.parent_topography.physical_sizes
|
|
67
|
+
p, = self.parent_topography.pixel_size
|
|
68
|
+
return s - p,
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def is_periodic(self):
|
|
72
|
+
return False
|
|
73
|
+
|
|
74
|
+
# Implement nonuniform line scan interface
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def nb_grid_pts(self):
|
|
78
|
+
return self.parent_topography.nb_grid_pts
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def x_range(self):
|
|
82
|
+
s, = self.parent_topography.physical_sizes
|
|
83
|
+
p, = self.parent_topography.pixel_size
|
|
84
|
+
return 0, s - p
|
|
85
|
+
|
|
86
|
+
def positions(self):
|
|
87
|
+
"""
|
|
88
|
+
Returns array containing the lateral positions.
|
|
89
|
+
"""
|
|
90
|
+
r, = self.parent_topography.nb_grid_pts
|
|
91
|
+
p, = self.parent_topography.pixel_size
|
|
92
|
+
return np.arange(r) * p
|
|
93
|
+
|
|
94
|
+
def heights(self):
|
|
95
|
+
"""
|
|
96
|
+
Returns array containing the topography data.
|
|
97
|
+
"""
|
|
98
|
+
return self.parent_topography.heights()
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class UniformlyInterpolatedLineScan(DecoratedTopography,
|
|
102
|
+
UniformTopographyInterface):
|
|
103
|
+
"""
|
|
104
|
+
Interpolate a topography onto a uniform grid.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
def __init__(self, topography, nb_points, padding, info={}):
|
|
108
|
+
"""
|
|
109
|
+
Parameters
|
|
110
|
+
----------
|
|
111
|
+
topography : :obj:`SurfaceTopography` or :obj:`UniformLineScan`
|
|
112
|
+
SurfaceTopography to interpolate.
|
|
113
|
+
nb_points : int
|
|
114
|
+
Number of equidistant grid points.
|
|
115
|
+
padding : int
|
|
116
|
+
Number of padding grid points, zeros appended to the data.
|
|
117
|
+
"""
|
|
118
|
+
super().__init__(topography, info=info)
|
|
119
|
+
self.nb_points = nb_points
|
|
120
|
+
self.padding = padding
|
|
121
|
+
|
|
122
|
+
# This is populated with functions from the nonuniform topography, but
|
|
123
|
+
# this is a uniform topography
|
|
124
|
+
self._functions = UniformLineScan._functions
|
|
125
|
+
|
|
126
|
+
def __getstate__(self):
|
|
127
|
+
""" is called and the returned object is pickled as the contents for
|
|
128
|
+
the instance
|
|
129
|
+
"""
|
|
130
|
+
state = super().__getstate__(), self.nb_points, self.padding
|
|
131
|
+
return state
|
|
132
|
+
|
|
133
|
+
def __setstate__(self, state):
|
|
134
|
+
""" Upon unpickling, it is called with the unpickled state
|
|
135
|
+
Keyword Arguments:
|
|
136
|
+
state -- result of __getstate__
|
|
137
|
+
"""
|
|
138
|
+
superstate, self.nb_points, self.padding = state
|
|
139
|
+
super().__setstate__(superstate)
|
|
140
|
+
|
|
141
|
+
# Implement abstract methods of AbstractHeightContainer
|
|
142
|
+
|
|
143
|
+
@property
|
|
144
|
+
def dim(self):
|
|
145
|
+
return 1
|
|
146
|
+
|
|
147
|
+
@property
|
|
148
|
+
def physical_sizes(self):
|
|
149
|
+
s, = self.parent_topography.physical_sizes
|
|
150
|
+
return s * (self.nb_points + self.padding) / self.nb_points,
|
|
151
|
+
|
|
152
|
+
@property
|
|
153
|
+
def is_periodic(self):
|
|
154
|
+
return False
|
|
155
|
+
|
|
156
|
+
@property
|
|
157
|
+
def is_uniform(self):
|
|
158
|
+
return True
|
|
159
|
+
|
|
160
|
+
# Implement uniform line scan interface
|
|
161
|
+
|
|
162
|
+
@property
|
|
163
|
+
def nb_grid_pts(self):
|
|
164
|
+
"""Return nb_grid_pts, i.e. number of pixels, of the topography."""
|
|
165
|
+
return self.nb_points + self.padding,
|
|
166
|
+
|
|
167
|
+
@property
|
|
168
|
+
def pixel_size(self):
|
|
169
|
+
return (s / r for s, r in zip(self.physical_sizes, self.nb_grid_pts))
|
|
170
|
+
|
|
171
|
+
@property
|
|
172
|
+
def area_per_pt(self):
|
|
173
|
+
return self.pixel_size
|
|
174
|
+
|
|
175
|
+
@property
|
|
176
|
+
def has_undefined_data(self):
|
|
177
|
+
return False
|
|
178
|
+
|
|
179
|
+
def positions(self):
|
|
180
|
+
left, right = self.parent_topography.x_range
|
|
181
|
+
size = right - left
|
|
182
|
+
return np.linspace(left - size * self.padding / (2 * self.nb_points),
|
|
183
|
+
right + size * self.padding / (2 * self.nb_points),
|
|
184
|
+
self.nb_points + self.padding)
|
|
185
|
+
|
|
186
|
+
def heights(self):
|
|
187
|
+
""" Computes the rescaled profile.
|
|
188
|
+
"""
|
|
189
|
+
x = self.positions()
|
|
190
|
+
return np.interp(x, *self.parent_topography.positions_and_heights())
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
# Register pipeline functions from this module
|
|
194
|
+
UniformTopographyInterface.register_function('to_nonuniform',
|
|
195
|
+
WrapAsNonuniformLineScan)
|
|
196
|
+
NonuniformLineScanInterface.register_function('to_uniform',
|
|
197
|
+
UniformlyInterpolatedLineScan)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import muFFT
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def make_fft(topography, fft='mpi'):
|
|
7
|
+
"""
|
|
8
|
+
Instantiate a muFFT object that can compute the Fourier transform of the
|
|
9
|
+
topography and has the same decomposition layout (or raise an error if
|
|
10
|
+
this is not the case).
|
|
11
|
+
|
|
12
|
+
Parameters
|
|
13
|
+
----------
|
|
14
|
+
topography : :obj:`SurfaceTopography`
|
|
15
|
+
Container storing the topography map.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
# We only initialize this once and attach it to the topography object
|
|
19
|
+
if hasattr(topography, '_mufft'):
|
|
20
|
+
return topography._mufft
|
|
21
|
+
|
|
22
|
+
if topography.is_domain_decomposed:
|
|
23
|
+
fft = muFFT.FFT(topography.nb_grid_pts, fft=fft, communicator=topography.communicator)
|
|
24
|
+
if fft.subdomain_locations != topography.subdomain_locations or \
|
|
25
|
+
fft.nb_subdomain_grid_pts != topography.nb_subdomain_grid_pts:
|
|
26
|
+
raise RuntimeError('muFFT suggested a domain decomposition that '
|
|
27
|
+
'differs from the decomposition of the topography.')
|
|
28
|
+
else:
|
|
29
|
+
fft = muFFT.FFT(topography.nb_grid_pts)
|
|
30
|
+
topography._mufft = fft
|
|
31
|
+
return fft
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def get_window_2D(window, nx, ny, physical_sizes=None):
|
|
35
|
+
"""
|
|
36
|
+
Construct a rotationally symmetric window for windowing two-dimensional
|
|
37
|
+
signals (fields).
|
|
38
|
+
|
|
39
|
+
Parameters
|
|
40
|
+
----------
|
|
41
|
+
window : str or np.ndarray
|
|
42
|
+
If window is an np.ndarray, it is just passed through (i.e.
|
|
43
|
+
immediately returned) from this function. If window is a string,
|
|
44
|
+
then a corresponding window will be constructed. Currently the only
|
|
45
|
+
support window is 'hann'.
|
|
46
|
+
nx : int
|
|
47
|
+
Number of grid points of the signal in x-direction
|
|
48
|
+
ny : int
|
|
49
|
+
Number of grid points of the signal in y-direction
|
|
50
|
+
physical_sizes : tuple of float
|
|
51
|
+
The physical size of the underlying signal. If None, then the number
|
|
52
|
+
of grid points nx, ny are used as the physical size. This parameter
|
|
53
|
+
is used to adjust the aspect ratio of the signal. (Default: None)
|
|
54
|
+
|
|
55
|
+
Returns
|
|
56
|
+
-------
|
|
57
|
+
window : np.ndarray
|
|
58
|
+
Numerical window, multiply the signal with this window
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
if isinstance(window, np.ndarray):
|
|
62
|
+
if window.shape != (nx, ny):
|
|
63
|
+
raise TypeError('Window shape (= {0}x{1}) must match the number of points of the signal (={2}x{3})'
|
|
64
|
+
.format(*window.shape, nx, ny))
|
|
65
|
+
return window
|
|
66
|
+
|
|
67
|
+
if physical_sizes is None:
|
|
68
|
+
sx, sy = nx, ny
|
|
69
|
+
else:
|
|
70
|
+
sx, sy = physical_sizes
|
|
71
|
+
if window == 'hann':
|
|
72
|
+
maxr = min(sx, sy) / 2
|
|
73
|
+
r = np.sqrt((sx * (np.arange(nx).reshape(-1, 1) - nx // 2) / nx) ** 2 +
|
|
74
|
+
(sy * (np.arange(ny).reshape(1, -1) - ny // 2) / ny) ** 2)
|
|
75
|
+
win = 0.5 + 0.5 * np.cos(np.pi * r / maxr)
|
|
76
|
+
win[r > maxr] = 0.0
|
|
77
|
+
return win
|
|
78
|
+
else:
|
|
79
|
+
raise ValueError("Unknown window type '{}'".format(window))
|