surfacetopography 0.91.2__py3.6-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 +96 -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 +358 -0
- SurfaceTopography/Converters.py +197 -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 +139 -0
- SurfaceTopography/IO/OPDx.py +885 -0
- SurfaceTopography/IO/Reader.py +389 -0
- SurfaceTopography/IO/__init__.py +241 -0
- SurfaceTopography/IO/__pycache__/DI.cpython-36.pyc +0 -0
- SurfaceTopography/IO/__pycache__/FromFile.cpython-36.pyc +0 -0
- SurfaceTopography/IO/__pycache__/H5.cpython-36.pyc +0 -0
- SurfaceTopography/IO/__pycache__/IBW.cpython-36.pyc +0 -0
- SurfaceTopography/IO/__pycache__/MI.cpython-36.pyc +0 -0
- SurfaceTopography/IO/__pycache__/Matlab.cpython-36.pyc +0 -0
- SurfaceTopography/IO/__pycache__/NC.cpython-36.pyc +0 -0
- SurfaceTopography/IO/__pycache__/NPY.cpython-36.pyc +0 -0
- SurfaceTopography/IO/__pycache__/OPDx.cpython-36.pyc +0 -0
- SurfaceTopography/IO/__pycache__/Reader.cpython-36.pyc +0 -0
- SurfaceTopography/IO/__pycache__/__init__.cpython-36.pyc +0 -0
- SurfaceTopography/Interpolation.py +30 -0
- SurfaceTopography/Nonuniform/Autocorrelation.py +161 -0
- SurfaceTopography/Nonuniform/Detrending.py +87 -0
- SurfaceTopography/Nonuniform/PowerSpectrum.py +178 -0
- SurfaceTopography/Nonuniform/ScalarParameters.py +140 -0
- SurfaceTopography/Nonuniform/VariableBandwidth.py +155 -0
- SurfaceTopography/Nonuniform/__init__.py +28 -0
- SurfaceTopography/Nonuniform/__pycache__/Autocorrelation.cpython-36.pyc +0 -0
- SurfaceTopography/Nonuniform/__pycache__/Detrending.cpython-36.pyc +0 -0
- SurfaceTopography/Nonuniform/__pycache__/PowerSpectrum.cpython-36.pyc +0 -0
- SurfaceTopography/Nonuniform/__pycache__/ScalarParameters.cpython-36.pyc +0 -0
- SurfaceTopography/Nonuniform/__pycache__/VariableBandwidth.cpython-36.pyc +0 -0
- SurfaceTopography/Nonuniform/__pycache__/__init__.cpython-36.pyc +0 -0
- SurfaceTopography/Nonuniform/__pycache__/common.cpython-36.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-36.pyc +0 -0
- SurfaceTopography/Tools/__pycache__/common.cpython-36.pyc +0 -0
- SurfaceTopography/Tools/common.py +75 -0
- SurfaceTopography/Uniform/Autocorrelation.py +211 -0
- SurfaceTopography/Uniform/Detrending.py +155 -0
- SurfaceTopography/Uniform/Filtering.py +226 -0
- SurfaceTopography/Uniform/Interpolation.py +159 -0
- SurfaceTopography/Uniform/PowerSpectrum.py +197 -0
- SurfaceTopography/Uniform/ScalarParameters.py +173 -0
- SurfaceTopography/Uniform/VariableBandwidth.py +169 -0
- SurfaceTopography/Uniform/__init__.py +28 -0
- SurfaceTopography/Uniform/__pycache__/Autocorrelation.cpython-36.pyc +0 -0
- SurfaceTopography/Uniform/__pycache__/Detrending.cpython-36.pyc +0 -0
- SurfaceTopography/Uniform/__pycache__/Filtering.cpython-36.pyc +0 -0
- SurfaceTopography/Uniform/__pycache__/Interpolation.cpython-36.pyc +0 -0
- SurfaceTopography/Uniform/__pycache__/PowerSpectrum.cpython-36.pyc +0 -0
- SurfaceTopography/Uniform/__pycache__/ScalarParameters.cpython-36.pyc +0 -0
- SurfaceTopography/Uniform/__pycache__/VariableBandwidth.cpython-36.pyc +0 -0
- SurfaceTopography/Uniform/__pycache__/__init__.cpython-36.pyc +0 -0
- SurfaceTopography/Uniform/__pycache__/common.cpython-36.pyc +0 -0
- SurfaceTopography/Uniform/common.py +260 -0
- SurfaceTopography/UniformLineScanAndTopography.py +887 -0
- SurfaceTopography/__init__.py +62 -0
- SurfaceTopography/__pycache__/Converters.cpython-36.pyc +0 -0
- SurfaceTopography/__pycache__/Generation.cpython-36.pyc +0 -0
- SurfaceTopography/__pycache__/HeightContainer.cpython-36.pyc +0 -0
- SurfaceTopography/__pycache__/Interpolation.cpython-36.pyc +0 -0
- SurfaceTopography/__pycache__/NonuniformLineScan.cpython-36.pyc +0 -0
- SurfaceTopography/__pycache__/Special.cpython-36.pyc +0 -0
- SurfaceTopography/__pycache__/UniformLineScanAndTopography.cpython-36.pyc +0 -0
- SurfaceTopography/__pycache__/__init__.cpython-36.pyc +0 -0
- SurfaceTopography/__pycache__/common.cpython-36.pyc +0 -0
- SurfaceTopography/common.py +111 -0
- _SurfaceTopography.cpython-36m-x86_64-linux-gnu.so +0 -0
- _SurfaceTopography.py +8 -0
- __pycache__/_SurfaceTopography.cpython-36.pyc +0 -0
- test/IO/__init__.py +28 -0
- test/IO/__pycache__/__init__.cpython-36.pyc +0 -0
- test/IO/__pycache__/test_ibw.cpython-36.pyc +0 -0
- test/IO/__pycache__/test_io.cpython-36.pyc +0 -0
- test/IO/__pycache__/test_mi.cpython-36.pyc +0 -0
- test/IO/__pycache__/test_netcdf.cpython-36.pyc +0 -0
- test/IO/__pycache__/test_npy.cpython-36.pyc +0 -0
- test/IO/__pycache__/test_opdx.cpython-36.pyc +0 -0
- test/IO/test_ibw.py +178 -0
- test/IO/test_io.py +401 -0
- test/IO/test_mi.py +103 -0
- test/IO/test_netcdf.py +134 -0
- test/IO/test_npy.py +135 -0
- test/IO/test_opdx.py +441 -0
- test/__init__.py +26 -0
- test/__pycache__/__init__.cpython-36.pyc +0 -0
- test/__pycache__/compare-orientation-with-gwyddion.cpython-36.pyc +0 -0
- test/__pycache__/conftest.cpython-36.pyc +0 -0
- test/__pycache__/test_autocorrelation.cpython-36.pyc +0 -0
- test/__pycache__/test_bicubic.cpython-36.pyc +0 -0
- test/__pycache__/test_filtering.cpython-36.pyc +0 -0
- test/__pycache__/test_generation.cpython-36.pyc +0 -0
- test/__pycache__/test_import.cpython-36.pyc +0 -0
- test/__pycache__/test_make_sphere.cpython-36.pyc +0 -0
- test/__pycache__/test_power_spectrum.cpython-36.pyc +0 -0
- test/__pycache__/test_scalar_parameters.cpython-36.pyc +0 -0
- test/__pycache__/test_topography1.cpython-36.pyc +0 -0
- test/__pycache__/test_topography2.cpython-36.pyc +0 -0
- test/__pycache__/test_variable_bandwidth.cpython-36.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_filtering.py +69 -0
- test/test_generation.py +259 -0
- test/test_import.py +54 -0
- test/test_make_sphere.py +108 -0
- test/test_power_spectrum.py +259 -0
- test/test_scalar_parameters.py +176 -0
- test/test_topography1.py +1287 -0
- test/test_topography2.py +328 -0
- test/test_variable_bandwidth.py +107 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2019-2020 Lars Pastewka
|
|
3
|
+
# 2019-2020 Antoine Sanner
|
|
4
|
+
# 2019-2020 Michael Röttger
|
|
5
|
+
# 2019 Kai Haase
|
|
6
|
+
#
|
|
7
|
+
# ### MIT license
|
|
8
|
+
#
|
|
9
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
11
|
+
# in the Software without restriction, including without limitation the rights
|
|
12
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
14
|
+
# furnished to do so, subject to the following conditions:
|
|
15
|
+
#
|
|
16
|
+
# The above copyright notice and this permission notice shall be included in
|
|
17
|
+
# all copies or substantial portions of the Software.
|
|
18
|
+
#
|
|
19
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25
|
+
# SOFTWARE.
|
|
26
|
+
#
|
|
27
|
+
|
|
28
|
+
import abc
|
|
29
|
+
import warnings
|
|
30
|
+
|
|
31
|
+
import numpy as np
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ChannelInfo:
|
|
35
|
+
"""
|
|
36
|
+
Information on topography channels contained within a file. The interface
|
|
37
|
+
is identical to :obj:`HeightContainer` and subclasses.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(self, reader, index, name=None, dim=None, nb_grid_pts=None,
|
|
41
|
+
physical_sizes=None, periodic=None,
|
|
42
|
+
info={}):
|
|
43
|
+
"""
|
|
44
|
+
Initialize the channel. Use as many information from the file as
|
|
45
|
+
possible by passing it in the keyword arguments.
|
|
46
|
+
|
|
47
|
+
Arguments
|
|
48
|
+
---------
|
|
49
|
+
reader: ReaderBase
|
|
50
|
+
Reader instance this channel is coming from.
|
|
51
|
+
index: int
|
|
52
|
+
Index of channel in the file, where zero is the first channel.
|
|
53
|
+
name: str
|
|
54
|
+
Name of the channel. If no name is given, "channel <index>" will
|
|
55
|
+
be used, where "<index>" is replaced with the index.
|
|
56
|
+
dim: int
|
|
57
|
+
Number of dimensions.
|
|
58
|
+
nb_grid_pts: tuple of ints
|
|
59
|
+
Number grid points in each dimension.
|
|
60
|
+
physical_sizes: tuple of floats
|
|
61
|
+
Physical dimensions.
|
|
62
|
+
periodic: bool
|
|
63
|
+
Wether the SurfaceTopography should be interpreted as one period of
|
|
64
|
+
a periodic surface. This will affect the PSD and autocorrelation
|
|
65
|
+
calculations (windowing).
|
|
66
|
+
info: dict
|
|
67
|
+
Meta data found in the file.
|
|
68
|
+
"""
|
|
69
|
+
self._reader = reader
|
|
70
|
+
self._index = int(index)
|
|
71
|
+
self._name = "channel {}".format(self._index) \
|
|
72
|
+
if name is None else str(name)
|
|
73
|
+
self._dim = dim
|
|
74
|
+
self._nb_grid_pts = None \
|
|
75
|
+
if nb_grid_pts is None else tuple(np.ravel(nb_grid_pts))
|
|
76
|
+
self._physical_sizes = None \
|
|
77
|
+
if physical_sizes is None else tuple(np.ravel(physical_sizes))
|
|
78
|
+
self._periodic = periodic
|
|
79
|
+
self._info = info.copy()
|
|
80
|
+
|
|
81
|
+
def topography(self, physical_sizes=None,
|
|
82
|
+
height_scale_factor=None, info={},
|
|
83
|
+
periodic=False,
|
|
84
|
+
subdomain_locations=None, nb_subdomain_grid_pts=None):
|
|
85
|
+
"""
|
|
86
|
+
Returns an instance of a subclass of :obj:`HeightContainer` that
|
|
87
|
+
contains the topography data. The method allows to override data
|
|
88
|
+
found in the data file.
|
|
89
|
+
|
|
90
|
+
Arguments
|
|
91
|
+
---------
|
|
92
|
+
physical_sizes : tuple of floats
|
|
93
|
+
Physical size of the topography. It is necessary to specify this
|
|
94
|
+
if no physical size is found in the data file. If there is a
|
|
95
|
+
physical size, then this parameter will override the physical
|
|
96
|
+
size found in the data file.
|
|
97
|
+
height_scale_factor : float
|
|
98
|
+
Override height scale factor found in the data file.
|
|
99
|
+
info : dict
|
|
100
|
+
This dictionary will be appended to the info dictionary returned
|
|
101
|
+
by the reader.
|
|
102
|
+
periodic: bool
|
|
103
|
+
Wether the SurfaceTopography should be interpreted as one period of
|
|
104
|
+
a periodic surface. This will affect the PSD and autocorrelation
|
|
105
|
+
calculations (windowing)
|
|
106
|
+
subdomain_locations : tuple of ints
|
|
107
|
+
Origin (location) of the subdomain handled by the present MPI
|
|
108
|
+
process.
|
|
109
|
+
nb_subdomain_grid_pts : tuple of ints
|
|
110
|
+
Number of grid points within the subdomain handled by the present
|
|
111
|
+
MPI process.
|
|
112
|
+
|
|
113
|
+
Returns
|
|
114
|
+
-------
|
|
115
|
+
topography : subclass of :obj:`HeightContainer`
|
|
116
|
+
The object containing the actual topography data.
|
|
117
|
+
"""
|
|
118
|
+
return self._reader.topography(
|
|
119
|
+
channel_index=self._index,
|
|
120
|
+
physical_sizes=physical_sizes,
|
|
121
|
+
height_scale_factor=height_scale_factor,
|
|
122
|
+
info=info,
|
|
123
|
+
periodic=periodic,
|
|
124
|
+
subdomain_locations=subdomain_locations,
|
|
125
|
+
nb_subdomain_grid_pts=nb_subdomain_grid_pts)
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def index(self):
|
|
129
|
+
"""Unique integer channel index."""
|
|
130
|
+
return self._index
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def name(self):
|
|
134
|
+
'''
|
|
135
|
+
Name of the channel.
|
|
136
|
+
Can be used in a UI for identifying a channel.
|
|
137
|
+
'''
|
|
138
|
+
return self._name
|
|
139
|
+
|
|
140
|
+
@property
|
|
141
|
+
def dim(self):
|
|
142
|
+
"""
|
|
143
|
+
1 for line scans and 2 for topography maps.
|
|
144
|
+
"""
|
|
145
|
+
return self._dim
|
|
146
|
+
|
|
147
|
+
@property
|
|
148
|
+
def nb_grid_pts(self):
|
|
149
|
+
"""
|
|
150
|
+
Number of grid points in each direction, either 1 or 2 elements
|
|
151
|
+
depending on the dimension of the topography.
|
|
152
|
+
"""
|
|
153
|
+
return self._nb_grid_pts
|
|
154
|
+
|
|
155
|
+
@property
|
|
156
|
+
def physical_sizes(self):
|
|
157
|
+
"""
|
|
158
|
+
If the physical size can be determined from the file, a tuple is
|
|
159
|
+
returned. The tuple has 1 or 2 elements (size_x, size_y), depending
|
|
160
|
+
on the dimension of the topography.
|
|
161
|
+
|
|
162
|
+
If the physical size can not be determined from the file, then
|
|
163
|
+
None is returned.
|
|
164
|
+
|
|
165
|
+
Note that the physical sizes obtained from the file can be
|
|
166
|
+
overwritten by passing a `physical_sizes` argument to the
|
|
167
|
+
`topography` method that returns the topography object.
|
|
168
|
+
"""
|
|
169
|
+
return self._physical_sizes
|
|
170
|
+
|
|
171
|
+
@property
|
|
172
|
+
def is_periodic(self):
|
|
173
|
+
"""
|
|
174
|
+
Return whether the topography is periodically repeated at the
|
|
175
|
+
boundaries.
|
|
176
|
+
"""
|
|
177
|
+
return self._periodic
|
|
178
|
+
|
|
179
|
+
@property
|
|
180
|
+
def pixel_size(self):
|
|
181
|
+
"""
|
|
182
|
+
The pixel size is returned as the phyiscal size divided by the number
|
|
183
|
+
of grid points. If the physical size can be determined from the file,
|
|
184
|
+
a tuple is returned. The tuple has 1 or 2 elements (size_x, size_y),
|
|
185
|
+
depending on the dimension of the topography.
|
|
186
|
+
|
|
187
|
+
If the physical size can not be determined from the file, then
|
|
188
|
+
None is returned.
|
|
189
|
+
|
|
190
|
+
Note that the physical sizes obtained from the file can be overwritten
|
|
191
|
+
by passing a `physical_sizes` argument to the `topography` method that
|
|
192
|
+
returns the topography object. Overriding the physical size will also
|
|
193
|
+
affect the pixel size.
|
|
194
|
+
"""
|
|
195
|
+
if self._physical_sizes is None or self._nb_grid_pts is None:
|
|
196
|
+
return None
|
|
197
|
+
else:
|
|
198
|
+
return tuple(np.array(self._physical_sizes) /
|
|
199
|
+
np.array(self._nb_grid_pts))
|
|
200
|
+
|
|
201
|
+
@property
|
|
202
|
+
def area_per_pt(self):
|
|
203
|
+
"""
|
|
204
|
+
The area per point is returned as the product over the pixel size
|
|
205
|
+
tuple. If `pixel_size` returns None, than also `area_per_pt` returns
|
|
206
|
+
None.s
|
|
207
|
+
"""
|
|
208
|
+
if self.pixel_size is None:
|
|
209
|
+
return None
|
|
210
|
+
else:
|
|
211
|
+
return np.prod(self.pixel_size)
|
|
212
|
+
|
|
213
|
+
@property
|
|
214
|
+
def info(self):
|
|
215
|
+
"""
|
|
216
|
+
A dictionary containing additional information (metadata) not used by
|
|
217
|
+
PyCo itself, but required by third-party application.
|
|
218
|
+
|
|
219
|
+
Presently, the following entries have been standardized:
|
|
220
|
+
'unit':
|
|
221
|
+
This is the unit of the physical size (if given in the file) and
|
|
222
|
+
the units of the heights.
|
|
223
|
+
'height_scale_factor':
|
|
224
|
+
Factor which was used to scale the raw numbers from file (which
|
|
225
|
+
can be voltages or some other quantity actually acquired in the
|
|
226
|
+
measurement technique) to heights with the given 'unit'.
|
|
227
|
+
"""
|
|
228
|
+
return self._info
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class ReaderBase(metaclass=abc.ABCMeta):
|
|
232
|
+
"""
|
|
233
|
+
Base class for topography readers. These are object that allow to open a
|
|
234
|
+
file (from filename or stream object), inspect its metadata and then
|
|
235
|
+
request to load a topography from it. Metadata is typically extracted
|
|
236
|
+
without reading the full file.
|
|
237
|
+
"""
|
|
238
|
+
|
|
239
|
+
_format = None
|
|
240
|
+
_name = None
|
|
241
|
+
_description = None
|
|
242
|
+
|
|
243
|
+
_default_channel_index = 0
|
|
244
|
+
|
|
245
|
+
@classmethod
|
|
246
|
+
def format(cls):
|
|
247
|
+
"""
|
|
248
|
+
String identifier for this file format. Identifier must be unique and
|
|
249
|
+
is typically equal to the file extension of this format.
|
|
250
|
+
"""
|
|
251
|
+
if cls._format is None:
|
|
252
|
+
raise RuntimeError('Reader does not provide a format string')
|
|
253
|
+
return cls._format
|
|
254
|
+
|
|
255
|
+
@classmethod
|
|
256
|
+
def name(cls):
|
|
257
|
+
"""
|
|
258
|
+
Short name of this file format.
|
|
259
|
+
"""
|
|
260
|
+
if cls._name is None:
|
|
261
|
+
raise RuntimeError('Reader does not provide a name')
|
|
262
|
+
return cls._name
|
|
263
|
+
|
|
264
|
+
@classmethod
|
|
265
|
+
def description(cls):
|
|
266
|
+
"""
|
|
267
|
+
Long description of this file format. Should be formatted as markdown.
|
|
268
|
+
"""
|
|
269
|
+
if cls._description is None:
|
|
270
|
+
raise RuntimeError('Reader does not provide a description string')
|
|
271
|
+
return cls._description
|
|
272
|
+
|
|
273
|
+
def __enter__(self):
|
|
274
|
+
return self
|
|
275
|
+
|
|
276
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
277
|
+
self.close()
|
|
278
|
+
|
|
279
|
+
def close(self):
|
|
280
|
+
pass
|
|
281
|
+
|
|
282
|
+
@property
|
|
283
|
+
@abc.abstractmethod
|
|
284
|
+
def channels(self):
|
|
285
|
+
"""
|
|
286
|
+
Returns a list of :obj:`ChannelInfo`s describing the available data
|
|
287
|
+
channels.
|
|
288
|
+
"""
|
|
289
|
+
raise NotImplementedError
|
|
290
|
+
|
|
291
|
+
@property
|
|
292
|
+
def default_channel(self):
|
|
293
|
+
"""Return the default channel. This is often the first channel with
|
|
294
|
+
height information."""
|
|
295
|
+
return self.channels[self._default_channel_index]
|
|
296
|
+
|
|
297
|
+
@classmethod
|
|
298
|
+
def _check_physical_sizes(self, physical_sizes_from_arg,
|
|
299
|
+
physical_sizes=None):
|
|
300
|
+
if physical_sizes is None:
|
|
301
|
+
if physical_sizes_from_arg is None:
|
|
302
|
+
raise ValueError("physical_sizes could not be extracted from "
|
|
303
|
+
"file, you should provide it")
|
|
304
|
+
else:
|
|
305
|
+
if physical_sizes_from_arg is None:
|
|
306
|
+
physical_sizes_from_arg = physical_sizes
|
|
307
|
+
elif tuple(physical_sizes_from_arg) != tuple(physical_sizes):
|
|
308
|
+
warnings.warn(
|
|
309
|
+
"A physical size different from the value specified when "
|
|
310
|
+
"calling the reader was present in the file. We will "
|
|
311
|
+
"ignore the value given in the file. Specified values: "
|
|
312
|
+
"{}; Values from file: {}".format(
|
|
313
|
+
physical_sizes,
|
|
314
|
+
physical_sizes_from_arg))
|
|
315
|
+
return physical_sizes_from_arg
|
|
316
|
+
|
|
317
|
+
@abc.abstractmethod
|
|
318
|
+
def topography(self, channel_index=None, physical_sizes=None,
|
|
319
|
+
height_scale_factor=None, info={},
|
|
320
|
+
periodic=False,
|
|
321
|
+
subdomain_locations=None, nb_subdomain_grid_pts=None):
|
|
322
|
+
"""
|
|
323
|
+
Returns an instance of a subclass of :obj:`HeightContainer` that
|
|
324
|
+
contains the topography data. The method allows to override data
|
|
325
|
+
found in the data file.
|
|
326
|
+
|
|
327
|
+
Arguments
|
|
328
|
+
---------
|
|
329
|
+
channel_index : int
|
|
330
|
+
Index of the channel to load. See also `channels` method.
|
|
331
|
+
(Default: None, which load the default channel)
|
|
332
|
+
physical_sizes : tuple of floats
|
|
333
|
+
Physical size of the topography. It is necessary to specify this
|
|
334
|
+
if no physical size is found in the data file. If there is a
|
|
335
|
+
physical size, then this parameter will override the physical
|
|
336
|
+
size found in the data file.
|
|
337
|
+
height_scale_factor : float
|
|
338
|
+
Override height scale factor found in the data file.
|
|
339
|
+
info : dict
|
|
340
|
+
This dictionary will be appended to the info dictionary returned
|
|
341
|
+
by the reader.
|
|
342
|
+
periodic: bool
|
|
343
|
+
Wether the SurfaceTopography should be interpreted as one period of
|
|
344
|
+
a periodic surface. This will affect the PSD and autocorrelation
|
|
345
|
+
calculations (windowing)
|
|
346
|
+
subdomain_locations : tuple of ints
|
|
347
|
+
Origin (location) of the subdomain handled by the present MPI
|
|
348
|
+
process.
|
|
349
|
+
nb_subdomain_grid_pts : tuple of ints
|
|
350
|
+
Number of grid points within the subdomain handled by the present
|
|
351
|
+
MPI process.
|
|
352
|
+
|
|
353
|
+
Returns
|
|
354
|
+
-------
|
|
355
|
+
topography : subclass of :obj:`HeightContainer`
|
|
356
|
+
The object containing the actual topography data.
|
|
357
|
+
"""
|
|
358
|
+
raise NotImplementedError
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
class ReadFileError(Exception):
|
|
362
|
+
pass
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
class UnknownFileFormatGiven(ReadFileError):
|
|
366
|
+
pass
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
class CannotDetectFileFormat(ReadFileError):
|
|
370
|
+
"""
|
|
371
|
+
Raised when no reader is able to open_topography the file
|
|
372
|
+
"""
|
|
373
|
+
pass
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
class FileFormatMismatch(ReadFileError):
|
|
377
|
+
"""
|
|
378
|
+
Raised when the reader cannot interpret the file at all
|
|
379
|
+
(obvious for txt vs binary, but holds also for a header)
|
|
380
|
+
"""
|
|
381
|
+
pass
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
class CorruptFile(ReadFileError):
|
|
385
|
+
"""
|
|
386
|
+
Raised when the reader identifies the file format as matching,
|
|
387
|
+
but there is a mistake, for example the number of points doesn't match
|
|
388
|
+
"""
|
|
389
|
+
pass
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2019-2020 Lars Pastewka
|
|
3
|
+
# 2020 Michael Röttger
|
|
4
|
+
# 2019 Kai Haase
|
|
5
|
+
# 2019 Antoine Sanner
|
|
6
|
+
#
|
|
7
|
+
# ### MIT license
|
|
8
|
+
#
|
|
9
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
11
|
+
# in the Software without restriction, including without limitation the rights
|
|
12
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
14
|
+
# furnished to do so, subject to the following conditions:
|
|
15
|
+
#
|
|
16
|
+
# The above copyright notice and this permission notice shall be included in
|
|
17
|
+
# all copies or substantial portions of the Software.
|
|
18
|
+
#
|
|
19
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25
|
+
# SOFTWARE.
|
|
26
|
+
#
|
|
27
|
+
|
|
28
|
+
import os
|
|
29
|
+
|
|
30
|
+
# Old-style readers
|
|
31
|
+
from .FromFile import AscReader, HGTReader, OPDReader, X3PReader, XYZReader
|
|
32
|
+
|
|
33
|
+
# New-style readers
|
|
34
|
+
from .DI import DIReader
|
|
35
|
+
from .H5 import H5Reader
|
|
36
|
+
from .IBW import IBWReader
|
|
37
|
+
from .Matlab import MatReader
|
|
38
|
+
from .MI import MIReader
|
|
39
|
+
from .NC import NCReader
|
|
40
|
+
from .NPY import NPYReader
|
|
41
|
+
from .OPDx import OPDxReader
|
|
42
|
+
|
|
43
|
+
from .Reader import UnknownFileFormatGiven, CannotDetectFileFormat, \
|
|
44
|
+
FileFormatMismatch, CorruptFile, ReaderBase # noqa: F401
|
|
45
|
+
|
|
46
|
+
readers = [
|
|
47
|
+
AscReader,
|
|
48
|
+
DIReader,
|
|
49
|
+
MatReader,
|
|
50
|
+
OPDReader,
|
|
51
|
+
OPDxReader,
|
|
52
|
+
X3PReader,
|
|
53
|
+
XYZReader,
|
|
54
|
+
IBWReader,
|
|
55
|
+
MIReader,
|
|
56
|
+
NCReader,
|
|
57
|
+
# NCReader must come before H5Reader, because NC4 *is* a specialized form
|
|
58
|
+
# of HDF5
|
|
59
|
+
H5Reader,
|
|
60
|
+
NPYReader,
|
|
61
|
+
HGTReader,
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
lookup_reader_by_format = {}
|
|
65
|
+
for reader in readers:
|
|
66
|
+
lookup_reader_by_format[reader.format()] = reader
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def detect_format(fobj, comm=None):
|
|
70
|
+
"""
|
|
71
|
+
Detect file format based on its content.
|
|
72
|
+
|
|
73
|
+
Arguments
|
|
74
|
+
---------
|
|
75
|
+
fobj : filename or file object
|
|
76
|
+
comm : mpi communicator, optional
|
|
77
|
+
"""
|
|
78
|
+
msg = ""
|
|
79
|
+
for reader in readers:
|
|
80
|
+
try:
|
|
81
|
+
if comm is not None:
|
|
82
|
+
reader(fobj, comm)
|
|
83
|
+
else:
|
|
84
|
+
reader(fobj)
|
|
85
|
+
return reader.format()
|
|
86
|
+
except Exception as err:
|
|
87
|
+
msg += "tried {}: \n {}\n\n".format(reader.__name__, err)
|
|
88
|
+
finally:
|
|
89
|
+
if hasattr(fobj, 'seek'):
|
|
90
|
+
# if the reader crashes the cursor in the file-like object
|
|
91
|
+
# has to be set back to the top of the file
|
|
92
|
+
fobj.seek(0)
|
|
93
|
+
raise CannotDetectFileFormat(msg)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def open_topography(fobj, format=None, communicator=None):
|
|
97
|
+
r"""
|
|
98
|
+
Returns a reader object for the file `fobj`. The reader interface mirrors
|
|
99
|
+
the topography interface and can be used to extract meta data (number of
|
|
100
|
+
grid points, physical sizes, etc.) without reading the full topography in
|
|
101
|
+
memory.
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
fobj : str or filelike object
|
|
106
|
+
path of the file or filelike object
|
|
107
|
+
format : str, optional
|
|
108
|
+
specify in which format the file should be interpreted
|
|
109
|
+
communicator : mpi4py or NuMPI communicator object
|
|
110
|
+
MPI communicator handling inter-process communication
|
|
111
|
+
|
|
112
|
+
Returns
|
|
113
|
+
-------
|
|
114
|
+
Instance of a :obj:`ReaderBase` subclass according to the format.
|
|
115
|
+
|
|
116
|
+
Examples
|
|
117
|
+
--------
|
|
118
|
+
Simplest read workflow:
|
|
119
|
+
|
|
120
|
+
>>> reader = open_topography("filename")
|
|
121
|
+
>>> top = reader.topography()
|
|
122
|
+
|
|
123
|
+
The first topography in file is returned, independently of whether
|
|
124
|
+
the file has multiple channels or not.
|
|
125
|
+
|
|
126
|
+
You can always check the channels and their metadata with
|
|
127
|
+
`reader.channels()`. This returns a list of dicts containing attributes `name`,
|
|
128
|
+
`physical_sizes`, `nb_grid_pts`, ``unit` and `height_scale_factor:
|
|
129
|
+
|
|
130
|
+
>>> reader.channels
|
|
131
|
+
[{'name': 'ZSensor',
|
|
132
|
+
'nb_grid_pts': (256, 256),
|
|
133
|
+
'physical_sizes': (9999.999999999998, 9999.999999999998),
|
|
134
|
+
'unit': 'nm',
|
|
135
|
+
'height_scale_factor': 0.29638271279074097},
|
|
136
|
+
{'name': 'AmplitudeError',
|
|
137
|
+
'nb_grid_pts': (256, 256),
|
|
138
|
+
'physical_sizes': (10.0, 10.0),
|
|
139
|
+
'unit': ('µm', None),
|
|
140
|
+
'height_scale_factor': 0.04577566528320313}]
|
|
141
|
+
|
|
142
|
+
Here the channel 'ZSensor' offers a topography with sizes of
|
|
143
|
+
10000 nm in each dimension.
|
|
144
|
+
|
|
145
|
+
You can choose it by giving the index 0 to channel
|
|
146
|
+
(you would use `channel=1` for the second):
|
|
147
|
+
|
|
148
|
+
>>> top = reader.topography(channel=0)
|
|
149
|
+
|
|
150
|
+
The returned topography has the physical sizes found in the file.
|
|
151
|
+
|
|
152
|
+
You can also prescribe some attributes when reading the topography:
|
|
153
|
+
|
|
154
|
+
>>> top = reader.topography(channel=0, physical_sizes=(10.,10.), info={"unit":"µm"})
|
|
155
|
+
|
|
156
|
+
In order to plot the topography with matplotlib, you can use
|
|
157
|
+
|
|
158
|
+
>>> plt.pcolormesh(*top.positions_and_heights())
|
|
159
|
+
|
|
160
|
+
with origin in the lower left and correct tick labels at x and y axes, or
|
|
161
|
+
|
|
162
|
+
>>> plt.imshow(top.heights().T)
|
|
163
|
+
|
|
164
|
+
with origin in the upper left (inverted y axis).
|
|
165
|
+
""" # noqa: E501
|
|
166
|
+
if communicator is not None:
|
|
167
|
+
kwargs = {"communicator": communicator}
|
|
168
|
+
else:
|
|
169
|
+
kwargs = {}
|
|
170
|
+
|
|
171
|
+
if not hasattr(fobj, 'read'): # fobj is a path
|
|
172
|
+
if not os.path.isfile(fobj):
|
|
173
|
+
raise FileExistsError("file {} not found".format(fobj))
|
|
174
|
+
|
|
175
|
+
if format is None:
|
|
176
|
+
msg = ""
|
|
177
|
+
for reader in readers:
|
|
178
|
+
try:
|
|
179
|
+
return reader(fobj, **kwargs)
|
|
180
|
+
except Exception as err:
|
|
181
|
+
msg += "tried {}: \n {}\n\n".format(reader.__name__, err)
|
|
182
|
+
finally:
|
|
183
|
+
if hasattr(fobj, 'seek'):
|
|
184
|
+
# if the reader crashes the cursor in the file-like object
|
|
185
|
+
# has to be set back to the top of the file
|
|
186
|
+
fobj.seek(0)
|
|
187
|
+
raise CannotDetectFileFormat(msg)
|
|
188
|
+
else:
|
|
189
|
+
if format not in lookup_reader_by_format.keys():
|
|
190
|
+
raise UnknownFileFormatGiven(
|
|
191
|
+
"{} not in registered file formats {}".format(
|
|
192
|
+
fobj, lookup_reader_by_format.keys()))
|
|
193
|
+
return lookup_reader_by_format[format](fobj, **kwargs)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def read_topography(fn, format=None, communicator=None, **kwargs):
|
|
197
|
+
r"""
|
|
198
|
+
Returns a topography object representing the topograpgy in the file `fobj`.
|
|
199
|
+
If there are multiple data channels within this file, the default channel
|
|
200
|
+
is returned. The default channel depends on the file format; see
|
|
201
|
+
documentation of the respective reader on this.
|
|
202
|
+
|
|
203
|
+
Parameters
|
|
204
|
+
----------
|
|
205
|
+
fobj : str or filelike object
|
|
206
|
+
path of the file or filelike object
|
|
207
|
+
format : str, optional
|
|
208
|
+
specify in which format the file should be interpreted
|
|
209
|
+
communicator : mpi4py or NuMPI communicator object
|
|
210
|
+
MPI communicator handling inter-process communication
|
|
211
|
+
channel : int
|
|
212
|
+
Number of the channel to load. See also `channels` method.
|
|
213
|
+
physical_sizes : tuple of floats
|
|
214
|
+
Physical size of the topography. It is necessary to specify this
|
|
215
|
+
if no physical size is found in the data file. If there is a
|
|
216
|
+
physical size, then this parameter will override the physical
|
|
217
|
+
size found in the data file.
|
|
218
|
+
height_scale_factor : float
|
|
219
|
+
Override height scale factor found in the data file.
|
|
220
|
+
info : dict
|
|
221
|
+
This dictionary will be appended to the info dictionary returned
|
|
222
|
+
by the reader.
|
|
223
|
+
periodic: bool
|
|
224
|
+
Wether the SurfaceTopography should be interpreted as one period of a
|
|
225
|
+
periodic surface. This will affect the PSD and autocorrelation
|
|
226
|
+
calculations (windowing)
|
|
227
|
+
subdomain_locations : tuple of ints
|
|
228
|
+
Origin (location) of the subdomain handled by the present MPI process.
|
|
229
|
+
nb_subdomain_grid_pts : tuple of ints
|
|
230
|
+
Number of grid points within the subdomain handled by the present
|
|
231
|
+
MPI process.
|
|
232
|
+
|
|
233
|
+
Returns
|
|
234
|
+
-------
|
|
235
|
+
topography : subclass of :obj:`HeightContainer`
|
|
236
|
+
The object containing the actual topography data.
|
|
237
|
+
"""
|
|
238
|
+
with open_topography(fn, format=format,
|
|
239
|
+
communicator=communicator) as reader:
|
|
240
|
+
t = reader.topography(**kwargs)
|
|
241
|
+
return t
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 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
|
+
Interpolation module
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from _SurfaceTopography import Bicubic # noqa: F401
|