pynxtools-apm 0.1__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.
- pynxtools_apm/README.md +45 -0
- pynxtools_apm/__init__.py +0 -0
- pynxtools_apm/concepts/__init__.py +0 -0
- pynxtools_apm/concepts/mapping_functors.py +345 -0
- pynxtools_apm/config/eln_cfg.py +189 -0
- pynxtools_apm/config/oasis_cfg.py +94 -0
- pynxtools_apm/reader.py +167 -0
- pynxtools_apm/utils/__init__.py +0 -0
- pynxtools_apm/utils/create_nx_default_plots.py +237 -0
- pynxtools_apm/utils/generate_synthetic_data.py +637 -0
- pynxtools_apm/utils/get_file_checksum.py +33 -0
- pynxtools_apm/utils/get_gitrepo_commit.py +38 -0
- pynxtools_apm/utils/interpret_boolean.py +38 -0
- pynxtools_apm/utils/io_case_logic.py +166 -0
- pynxtools_apm/utils/load_ranging.py +357 -0
- pynxtools_apm/utils/load_reconstruction.py +279 -0
- pynxtools_apm/utils/oasis_config_reader.py +95 -0
- pynxtools_apm/utils/oasis_eln_reader.py +249 -0
- pynxtools_apm/utils/parse_composition_table.py +186 -0
- pynxtools_apm/utils/string_conversions.py +48 -0
- pynxtools_apm/utils/versioning.py +41 -0
- pynxtools_apm-0.1.dist-info/LICENSE +201 -0
- pynxtools_apm-0.1.dist-info/METADATA +106 -0
- pynxtools_apm-0.1.dist-info/RECORD +27 -0
- pynxtools_apm-0.1.dist-info/WHEEL +5 -0
- pynxtools_apm-0.1.dist-info/entry_points.txt +2 -0
- pynxtools_apm-0.1.dist-info/top_level.txt +1 -0
pynxtools_apm/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<!--# APM reader
|
|
2
|
+
|
|
3
|
+
## Getting started - usage related to NOMAD Oasis
|
|
4
|
+
This parser can be used to map numerical data and metadata inside frequently
|
|
5
|
+
used file formats of atom probe tomography and related field-ion microscopy
|
|
6
|
+
software tools into a NeXus HDF5 file which complies with a specific version
|
|
7
|
+
of the NXapm application definition.
|
|
8
|
+
|
|
9
|
+
If you are using a NOMAD Oasis, you can use this tool as follows.
|
|
10
|
+
1. Log-in to a NOMAD Oasis and navigate to the *Create Uploads* tab.
|
|
11
|
+
2. Select apm example from the list of available options.
|
|
12
|
+
3. Drag-and-drop the file with your reconstructed dataset via pos, epos, or apt,
|
|
13
|
+
and add your ranging definitions file via rrng, or rng, or the fig files from
|
|
14
|
+
Peter Felfer's Erlangen atom-probe-toolbox.
|
|
15
|
+
3. Edit the electronic lab notebook (ELN) schema inside the NOMAD Oasis and click the
|
|
16
|
+
save button in the NOMAD Oasis GUI to save the data that you have entered into
|
|
17
|
+
the ELN template. Clicking *save* will trigger the automatic generation
|
|
18
|
+
of an eln_data.yaml file. Second, the clicking will trigger a run of the
|
|
19
|
+
dataconverter/apm parser which generates a NXapm NeXus file based on the data
|
|
20
|
+
in the reconstruction and ranging file and the eln_data.yaml file. Afterwards,
|
|
21
|
+
the file will be displayed in the GUI and show up in the upload section of your Oasis.
|
|
22
|
+
By default the converter performs a strong loss-less compression on the input
|
|
23
|
+
as many of the stack data store integers with a low entropy. The compression may
|
|
24
|
+
take some time. You can inspect the progress of the conversion in the console from
|
|
25
|
+
which you started the NOMAD Oasis appworker.
|
|
26
|
+
4. If successful, a NeXus (nxs) file will appear in your upload. You can explore
|
|
27
|
+
its content with the H5Web tools inside the NOMAD Oasis GUI and click interactively
|
|
28
|
+
through the data including default plots. For atom probe these are a 3D discretized
|
|
29
|
+
view of your reconstruction using 1nm rectangular binning and the mass spectrum
|
|
30
|
+
with a default 0.01 Da binning an no additional corrections.
|
|
31
|
+
If unsuccessful, the console from where you started the NOMAD appworker can help
|
|
32
|
+
you with identifying if problems occurred.
|
|
33
|
+
|
|
34
|
+
## A request to take action by the technology partners
|
|
35
|
+
In fact, while the above-mentioned file formats and corresponding commercial software is routinely
|
|
36
|
+
used by numerous atom probers every day, the actual knowledge about the I/O routines has always
|
|
37
|
+
been on a few developers shoulders. In fact many of the open-source readers for file formats were
|
|
38
|
+
reverse-engineered. This is challenging because the amount of documentation that is available
|
|
39
|
+
for some file formats is neither exhaustive nor documented enough in detail.
|
|
40
|
+
|
|
41
|
+
This limits developers to decide and design how to best implement possible mappings of
|
|
42
|
+
specific binary numerical data and metadata into specifically named fields. We wish that
|
|
43
|
+
intensified exchange between technology partners like AMETEK/Cameca and the atom probe
|
|
44
|
+
community can help to improve the situation. Everybody is very welcomed to leave us
|
|
45
|
+
comments in the issue list (or drop us an email) to exchange specifically about this topic.-->
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright The NOMAD Authors.
|
|
3
|
+
#
|
|
4
|
+
# This file is part of NOMAD. See https://nomad-lab.eu for further info.
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
#
|
|
18
|
+
"""Utilities for working with NeXus concepts encoded as Python dicts in the concepts dir."""
|
|
19
|
+
|
|
20
|
+
from datetime import datetime
|
|
21
|
+
import pytz
|
|
22
|
+
import flatdict as fd
|
|
23
|
+
import numpy as np
|
|
24
|
+
|
|
25
|
+
from pynxtools_apm.utils.string_conversions import string_to_number, rchop
|
|
26
|
+
from pynxtools_apm.utils.interpret_boolean import try_interpret_as_boolean
|
|
27
|
+
from pynxtools_apm.utils.get_file_checksum import get_sha256_of_file_content
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def variadic_path_to_specific_path(path: str, instance_identifier: list):
|
|
31
|
+
"""Transforms a variadic path to an actual path with instances."""
|
|
32
|
+
if (path is not None) and (path != ""):
|
|
33
|
+
narguments = path.count("*")
|
|
34
|
+
if narguments == 0: # path is not variadic
|
|
35
|
+
return path
|
|
36
|
+
if len(instance_identifier) >= narguments:
|
|
37
|
+
tmp = path.split("*")
|
|
38
|
+
if len(tmp) == narguments + 1:
|
|
39
|
+
nx_specific_path = ""
|
|
40
|
+
for idx in range(0, narguments):
|
|
41
|
+
nx_specific_path += f"{tmp[idx]}{instance_identifier[idx]}"
|
|
42
|
+
idx += 1
|
|
43
|
+
nx_specific_path += f"{tmp[-1]}"
|
|
44
|
+
return nx_specific_path
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def add_specific_metadata(
|
|
49
|
+
concept_mapping: dict, orgmeta: fd.FlatDict, identifier: list, template: dict
|
|
50
|
+
) -> dict:
|
|
51
|
+
"""Map specific concept src on specific NeXus concept trg.
|
|
52
|
+
|
|
53
|
+
concept_mapping: translation dict how trg and src are to be mapped
|
|
54
|
+
orgmeta: instance data of src concepts
|
|
55
|
+
identifier: list of identifier to resolve variadic paths
|
|
56
|
+
template: instance data resulting from a resolved src to trg concept mapping
|
|
57
|
+
"""
|
|
58
|
+
if "prefix_trg" in concept_mapping:
|
|
59
|
+
variadic_prefix_trg = concept_mapping["prefix_trg"]
|
|
60
|
+
elif "prefix" in concept_mapping:
|
|
61
|
+
variadic_prefix_trg = concept_mapping["prefix"]
|
|
62
|
+
else:
|
|
63
|
+
raise KeyError(f"Neither prefix nor prefix_trg found in concept_mapping!")
|
|
64
|
+
|
|
65
|
+
if "prefix_src" in concept_mapping:
|
|
66
|
+
prefix_src = concept_mapping["prefix_src"]
|
|
67
|
+
else:
|
|
68
|
+
prefix_src = ""
|
|
69
|
+
|
|
70
|
+
# process all mapping functors
|
|
71
|
+
# (in graphical programming these are also referred to as filters or nodes), i.e.
|
|
72
|
+
# an agent that gets some input does some (maybe abstract mapping) and returns an output
|
|
73
|
+
# as the mapping can be abstract we call it functor
|
|
74
|
+
if "use" in concept_mapping:
|
|
75
|
+
for entry in concept_mapping["use"]:
|
|
76
|
+
if isinstance(entry, tuple):
|
|
77
|
+
if len(entry) == 2:
|
|
78
|
+
if isinstance(entry[1], str) and entry[1] == "":
|
|
79
|
+
continue
|
|
80
|
+
trg = variadic_path_to_specific_path(
|
|
81
|
+
f"{variadic_prefix_trg}/{entry[0]}", identifier
|
|
82
|
+
)
|
|
83
|
+
template[f"{trg}"] = entry[1]
|
|
84
|
+
if "map" in concept_mapping:
|
|
85
|
+
for entry in concept_mapping["map"]:
|
|
86
|
+
if isinstance(entry, str):
|
|
87
|
+
if f"{prefix_src}{entry}" not in orgmeta:
|
|
88
|
+
continue
|
|
89
|
+
if (
|
|
90
|
+
isinstance(orgmeta[f"{prefix_src}{entry}"], str)
|
|
91
|
+
and orgmeta[f"{prefix_src}{entry}"] == ""
|
|
92
|
+
):
|
|
93
|
+
continue
|
|
94
|
+
trg = variadic_path_to_specific_path(
|
|
95
|
+
f"{variadic_prefix_trg}/{entry}", identifier
|
|
96
|
+
)
|
|
97
|
+
template[f"{trg}"] = orgmeta[f"{prefix_src}{entry}"]
|
|
98
|
+
if isinstance(entry, tuple):
|
|
99
|
+
if len(entry) == 2:
|
|
100
|
+
if isinstance(entry[0], str):
|
|
101
|
+
if f"{prefix_src}{entry[1]}" not in orgmeta:
|
|
102
|
+
continue
|
|
103
|
+
if (orgmeta[f"{prefix_src}{entry[1]}"], str) and orgmeta[
|
|
104
|
+
f"{prefix_src}{entry[1]}"
|
|
105
|
+
] == "":
|
|
106
|
+
continue
|
|
107
|
+
trg = variadic_path_to_specific_path(
|
|
108
|
+
f"{variadic_prefix_trg}/{entry[0]}", identifier
|
|
109
|
+
)
|
|
110
|
+
template[f"{trg}"] = orgmeta[f"{prefix_src}{entry[1]}"]
|
|
111
|
+
if "map_to_str" in concept_mapping:
|
|
112
|
+
for entry in concept_mapping["map_to_str"]:
|
|
113
|
+
if isinstance(entry, str):
|
|
114
|
+
if f"{prefix_src}{entry}" not in orgmeta:
|
|
115
|
+
continue
|
|
116
|
+
if (
|
|
117
|
+
isinstance(orgmeta[f"{prefix_src}{entry}"], str)
|
|
118
|
+
and orgmeta[f"{prefix_src}{entry}"] == ""
|
|
119
|
+
):
|
|
120
|
+
continue
|
|
121
|
+
trg = variadic_path_to_specific_path(
|
|
122
|
+
f"{variadic_prefix_trg}/{entry}", identifier
|
|
123
|
+
)
|
|
124
|
+
template[f"{trg}"] = orgmeta[f"{prefix_src}{entry}"]
|
|
125
|
+
if isinstance(entry, tuple):
|
|
126
|
+
if len(entry) == 2:
|
|
127
|
+
if all(isinstance(elem, str) for elem in entry):
|
|
128
|
+
if f"{prefix_src}{entry[1]}" not in orgmeta:
|
|
129
|
+
continue
|
|
130
|
+
if (
|
|
131
|
+
isinstance(orgmeta[f"{prefix_src}{entry[1]}"], str)
|
|
132
|
+
and orgmeta[f"{prefix_src}{entry[1]}"] == ""
|
|
133
|
+
):
|
|
134
|
+
continue
|
|
135
|
+
trg = variadic_path_to_specific_path(
|
|
136
|
+
f"{variadic_prefix_trg}/{entry[0]}", identifier
|
|
137
|
+
)
|
|
138
|
+
template[f"{trg}"] = orgmeta[f"{prefix_src}{entry[1]}"]
|
|
139
|
+
if "map_to_bool" in concept_mapping:
|
|
140
|
+
for entry in concept_mapping["map_to_bool"]:
|
|
141
|
+
if isinstance(entry, str):
|
|
142
|
+
if f"{prefix_src}{entry[0]}" not in orgmeta:
|
|
143
|
+
continue
|
|
144
|
+
trg = variadic_path_to_specific_path(
|
|
145
|
+
f"{variadic_prefix_trg}/{entry[0]}", identifier
|
|
146
|
+
)
|
|
147
|
+
template[f"{trg}"] = try_interpret_as_boolean(
|
|
148
|
+
orgmeta[f"{prefix_src}{entry[0]}"]
|
|
149
|
+
)
|
|
150
|
+
if isinstance(entry, tuple):
|
|
151
|
+
if len(entry) == 2:
|
|
152
|
+
if all(isinstance(elem, str) for elem in entry):
|
|
153
|
+
if f"{prefix_src}{entry[1]}" not in orgmeta:
|
|
154
|
+
continue
|
|
155
|
+
trg = variadic_path_to_specific_path(
|
|
156
|
+
f"{variadic_prefix_trg}/{entry[0]}", identifier
|
|
157
|
+
)
|
|
158
|
+
template[f"{trg}"] = try_interpret_as_boolean(
|
|
159
|
+
orgmeta[f"{prefix_src}{entry[1]}"]
|
|
160
|
+
)
|
|
161
|
+
if "map_to_real" in concept_mapping:
|
|
162
|
+
for entry in concept_mapping["map_to_real"]:
|
|
163
|
+
if isinstance(entry, str):
|
|
164
|
+
if isinstance(entry[0], str):
|
|
165
|
+
if f"{prefix_src}{entry[0]}" not in orgmeta:
|
|
166
|
+
continue
|
|
167
|
+
if (
|
|
168
|
+
isinstance(orgmeta[f"{prefix_src}{entry[0]}"], str)
|
|
169
|
+
and orgmeta[f"{prefix_src}{entry[0]}"] == ""
|
|
170
|
+
):
|
|
171
|
+
continue
|
|
172
|
+
trg = variadic_path_to_specific_path(
|
|
173
|
+
f"{variadic_prefix_trg}/{entry[0]}", identifier
|
|
174
|
+
)
|
|
175
|
+
template[f"{trg}"] = string_to_number(
|
|
176
|
+
orgmeta[f"{prefix_src}{entry[0]}"]
|
|
177
|
+
)
|
|
178
|
+
if isinstance(entry, tuple):
|
|
179
|
+
if len(entry) == 2:
|
|
180
|
+
if all(isinstance(elem, str) for elem in entry):
|
|
181
|
+
if f"{prefix_src}{entry[1]}" not in orgmeta:
|
|
182
|
+
continue
|
|
183
|
+
if (
|
|
184
|
+
isinstance(orgmeta[f"{prefix_src}{entry[0]}"], str)
|
|
185
|
+
and orgmeta[f"{prefix_src}{entry[1]}"] == ""
|
|
186
|
+
):
|
|
187
|
+
continue
|
|
188
|
+
trg = variadic_path_to_specific_path(
|
|
189
|
+
f"{variadic_prefix_trg}/{entry[0]}", identifier
|
|
190
|
+
)
|
|
191
|
+
template[f"{trg}"] = string_to_number(
|
|
192
|
+
orgmeta[f"{prefix_src}{entry[1]}"]
|
|
193
|
+
)
|
|
194
|
+
elif isinstance(entry[0], str) and isinstance(entry[1], list):
|
|
195
|
+
if not all(
|
|
196
|
+
(
|
|
197
|
+
isinstance(value, str)
|
|
198
|
+
and f"{prefix_src}{value}" in orgmeta
|
|
199
|
+
)
|
|
200
|
+
for value in entry[1]
|
|
201
|
+
):
|
|
202
|
+
continue
|
|
203
|
+
if not all(
|
|
204
|
+
(
|
|
205
|
+
isinstance(orgmeta[f"{prefix_src}{value}"], str)
|
|
206
|
+
and orgmeta[f"{prefix_src}{value}"] != ""
|
|
207
|
+
)
|
|
208
|
+
for value in entry[1]
|
|
209
|
+
):
|
|
210
|
+
continue
|
|
211
|
+
trg = variadic_path_to_specific_path(
|
|
212
|
+
f"{variadic_prefix_trg}/{entry[0]}", identifier
|
|
213
|
+
)
|
|
214
|
+
res = []
|
|
215
|
+
for value in entry[1]:
|
|
216
|
+
res.append(
|
|
217
|
+
string_to_number(orgmeta[f"{prefix_src}{value}"])
|
|
218
|
+
)
|
|
219
|
+
template[f"{trg}"] = np.asarray(res, np.float64)
|
|
220
|
+
if "map_to_real_and_multiply" in concept_mapping:
|
|
221
|
+
for entry in concept_mapping["map_to_real_and_multiply"]:
|
|
222
|
+
if isinstance(entry, tuple):
|
|
223
|
+
if len(entry) == 3:
|
|
224
|
+
if (
|
|
225
|
+
isinstance(entry[0], str)
|
|
226
|
+
and isinstance(entry[1], str)
|
|
227
|
+
and isinstance(entry[2], float)
|
|
228
|
+
):
|
|
229
|
+
if f"{prefix_src}{entry[1]}" not in orgmeta:
|
|
230
|
+
continue
|
|
231
|
+
if (
|
|
232
|
+
isinstance(orgmeta[f"{prefix_src}{entry[1]}"], str)
|
|
233
|
+
and orgmeta[f"{prefix_src}{entry[1]}"] == ""
|
|
234
|
+
):
|
|
235
|
+
continue
|
|
236
|
+
trg = variadic_path_to_specific_path(
|
|
237
|
+
f"{variadic_prefix_trg}/{entry[0]}", identifier
|
|
238
|
+
)
|
|
239
|
+
template[f"{trg}"] = entry[2] * string_to_number(
|
|
240
|
+
orgmeta[f"{prefix_src}{entry[1]}"]
|
|
241
|
+
)
|
|
242
|
+
if "map_to_real_and_join" in concept_mapping:
|
|
243
|
+
for entry in concept_mapping["map_to_real_and_join"]:
|
|
244
|
+
if isinstance(entry, tuple):
|
|
245
|
+
if len(entry) == 2:
|
|
246
|
+
if isinstance(entry[0], str) and isinstance(entry[1], list):
|
|
247
|
+
if not all(
|
|
248
|
+
(
|
|
249
|
+
isinstance(value, str)
|
|
250
|
+
and f"{prefix_src}{value}" in orgmeta
|
|
251
|
+
)
|
|
252
|
+
for value in entry[1]
|
|
253
|
+
):
|
|
254
|
+
continue
|
|
255
|
+
if not all(
|
|
256
|
+
(
|
|
257
|
+
isinstance(orgmeta[f"{prefix_src}{value}"], str)
|
|
258
|
+
and orgmeta[f"{prefix_src}{value}"] != ""
|
|
259
|
+
)
|
|
260
|
+
for value in entry[1]
|
|
261
|
+
):
|
|
262
|
+
continue
|
|
263
|
+
res = []
|
|
264
|
+
for value in entry[1]:
|
|
265
|
+
res.append(
|
|
266
|
+
string_to_number(orgmeta[f"{prefix_src}{value}"])
|
|
267
|
+
)
|
|
268
|
+
trg = variadic_path_to_specific_path(
|
|
269
|
+
f"{variadic_prefix_trg}/{entry[0]}", identifier
|
|
270
|
+
)
|
|
271
|
+
template[f"{trg}"] = np.asarray(res)
|
|
272
|
+
# we may need to be more specific with the return datatype here, currently default python float
|
|
273
|
+
if "unix_to_iso8601" in concept_mapping:
|
|
274
|
+
for entry in concept_mapping["unix_to_iso8601"]:
|
|
275
|
+
if isinstance(entry, tuple):
|
|
276
|
+
if (
|
|
277
|
+
2 <= len(entry) <= 3
|
|
278
|
+
): # trg, src, timestamp or empty string (meaning utc)
|
|
279
|
+
if all(isinstance(elem, str) for elem in entry):
|
|
280
|
+
if f"{prefix_src}{entry[1]}" not in orgmeta:
|
|
281
|
+
continue
|
|
282
|
+
if (
|
|
283
|
+
isinstance(orgmeta[f"{prefix_src}{entry[1]}"], str)
|
|
284
|
+
and orgmeta[f"{prefix_src}{entry[1]}"] == ""
|
|
285
|
+
):
|
|
286
|
+
continue
|
|
287
|
+
tzone = "UTC"
|
|
288
|
+
if len(entry) == 3:
|
|
289
|
+
# if not isinstance(entry[2], str):
|
|
290
|
+
# raise TypeError(f"{tzone} needs to be of type string!")
|
|
291
|
+
tzone = entry[2]
|
|
292
|
+
if tzone not in pytz.all_timezones:
|
|
293
|
+
raise ValueError(
|
|
294
|
+
f"{tzone} is not a timezone in pytz.all_timezones!"
|
|
295
|
+
)
|
|
296
|
+
trg = variadic_path_to_specific_path(
|
|
297
|
+
f"{variadic_prefix_trg}/{entry[0]}", identifier
|
|
298
|
+
)
|
|
299
|
+
template[f"{trg}"] = datetime.fromtimestamp(
|
|
300
|
+
int(orgmeta[f"{prefix_src}{entry[1]}"]),
|
|
301
|
+
tz=pytz.timezone(tzone),
|
|
302
|
+
).isoformat()
|
|
303
|
+
if "join_str" in concept_mapping: # currently also joining empty strings
|
|
304
|
+
for entry in concept_mapping["join_str"]:
|
|
305
|
+
if isinstance(entry, tuple):
|
|
306
|
+
if len(entry) == 2:
|
|
307
|
+
if isinstance(entry[0], str) and isinstance(entry[1], list):
|
|
308
|
+
if not all(
|
|
309
|
+
(
|
|
310
|
+
isinstance(value, str)
|
|
311
|
+
and f"{prefix_src}{value}" in orgmeta
|
|
312
|
+
)
|
|
313
|
+
for value in entry[1]
|
|
314
|
+
):
|
|
315
|
+
continue
|
|
316
|
+
trg = variadic_path_to_specific_path(
|
|
317
|
+
f"{variadic_prefix_trg}/{entry[0]}", identifier
|
|
318
|
+
)
|
|
319
|
+
res = []
|
|
320
|
+
for value in entry[1]:
|
|
321
|
+
res.append(orgmeta[f"{prefix_src}{value}"])
|
|
322
|
+
template[f"{trg}"] = " ".join(res)
|
|
323
|
+
if "sha256" in concept_mapping:
|
|
324
|
+
for entry in concept_mapping["sha256"]:
|
|
325
|
+
if isinstance(entry, tuple):
|
|
326
|
+
if len(entry) == 2:
|
|
327
|
+
if not all(isinstance(elem, str) for elem in entry):
|
|
328
|
+
continue
|
|
329
|
+
if f"{prefix_src}{entry[1]}" not in orgmeta:
|
|
330
|
+
continue
|
|
331
|
+
if orgmeta[f"{prefix_src}{entry[1]}"] == "":
|
|
332
|
+
continue
|
|
333
|
+
trg = variadic_path_to_specific_path(
|
|
334
|
+
f"{variadic_prefix_trg}/{entry[0]}", identifier
|
|
335
|
+
)
|
|
336
|
+
with open(orgmeta[f"{prefix_src}{entry[1]}"], "rb") as fp:
|
|
337
|
+
template[f"{rchop(trg, 'checksum')}checksum"] = (
|
|
338
|
+
get_sha256_of_file_content(fp)
|
|
339
|
+
)
|
|
340
|
+
template[f"{rchop(trg, 'checksum')}type"] = "file"
|
|
341
|
+
template[f"{rchop(trg, 'checksum')}path"] = orgmeta[
|
|
342
|
+
f"{prefix_src}{entry[1]}"
|
|
343
|
+
]
|
|
344
|
+
template[f"{rchop(trg, 'checksum')}algorithm"] = "sha256"
|
|
345
|
+
return template
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright The NOMAD Authors.
|
|
3
|
+
#
|
|
4
|
+
# This file is part of NOMAD. See https://nomad-lab.eu for further info.
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
#
|
|
18
|
+
"""Dict mapping custom schema instances from eln_data.yaml file on concepts in NXapm."""
|
|
19
|
+
|
|
20
|
+
APM_ENTRY_TO_NEXUS = {
|
|
21
|
+
"prefix_trg": "/ENTRY[entry*]",
|
|
22
|
+
"prefix_src": "entry/",
|
|
23
|
+
"map_to_str": [
|
|
24
|
+
"run_number",
|
|
25
|
+
"operation_mode",
|
|
26
|
+
"start_time",
|
|
27
|
+
"end_time",
|
|
28
|
+
"experiment_description",
|
|
29
|
+
("experiment_alias", "run_number"),
|
|
30
|
+
],
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
APM_SAMPLE_TO_NEXUS = {
|
|
35
|
+
"prefix_trg": "/ENTRY[entry*]/sample",
|
|
36
|
+
"prefix_src": "sample/",
|
|
37
|
+
"map": [
|
|
38
|
+
("grain_diameter", "grain_diameter/value"),
|
|
39
|
+
("grain_diameter_error", "grain_diameter_error/value"),
|
|
40
|
+
("heat_treatment_temperature", "heat_treatment_temperature/value"),
|
|
41
|
+
("heat_treatment_temperature_error", "heat_treatment_temperature_error/value"),
|
|
42
|
+
("heat_treatment_quenching_rate", "heat_treatment_quenching_rate/value"),
|
|
43
|
+
(
|
|
44
|
+
"heat_treatment_quenching_rate_error",
|
|
45
|
+
"heat_treatment_quenching_rate_error/value",
|
|
46
|
+
),
|
|
47
|
+
],
|
|
48
|
+
"map_to_str": [
|
|
49
|
+
"alias",
|
|
50
|
+
"description",
|
|
51
|
+
"method",
|
|
52
|
+
("grain_diameter/@units", "grain_diameter/unit"),
|
|
53
|
+
("grain_diameter_error/@units", "grain_diameter/unit"),
|
|
54
|
+
("heat_treatment_temperature/@units", "heat_treatment_temperature/unit"),
|
|
55
|
+
(
|
|
56
|
+
"heat_treatment_temperature_error/@units",
|
|
57
|
+
"heat_treatment_temperature_error/unit",
|
|
58
|
+
),
|
|
59
|
+
("heat_treatment_quenching_rate/@units", "heat_treatment_quenching_rate/unit"),
|
|
60
|
+
(
|
|
61
|
+
"heat_treatment_quenching_rate_error/@units",
|
|
62
|
+
"heat_treatment_quenching_rate_error/unit",
|
|
63
|
+
),
|
|
64
|
+
],
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
APM_SPECIMEN_TO_NEXUS = {
|
|
69
|
+
"prefix_trg": "/ENTRY[entry*]/specimen",
|
|
70
|
+
"prefix_src": "specimen/",
|
|
71
|
+
"map": [
|
|
72
|
+
("initial_radius", "initial_radius/value"),
|
|
73
|
+
("shank_angle", "shank_angle/value"),
|
|
74
|
+
],
|
|
75
|
+
"map_to_bool": ["is_polycrystalline", "is_amorphous"],
|
|
76
|
+
"map_to_str": [
|
|
77
|
+
"alias",
|
|
78
|
+
"preparation_date",
|
|
79
|
+
"description",
|
|
80
|
+
"method",
|
|
81
|
+
("initial_radius/@units", "initial_radius/unit"),
|
|
82
|
+
("shank_angle/@units", "shank_angle/unit"),
|
|
83
|
+
],
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
APM_INSTRUMENT_STATIC_TO_NEXUS = {
|
|
88
|
+
"prefix_trg": "/ENTRY[entry*]/measurement/instrument",
|
|
89
|
+
"prefix_src": "atom_probe/",
|
|
90
|
+
"map": [("analysis_chamber/flight_path", "nominal_flight_path/value")],
|
|
91
|
+
"map_to_str": [
|
|
92
|
+
"status",
|
|
93
|
+
"instrument_name",
|
|
94
|
+
"location",
|
|
95
|
+
("FABRICATION[fabrication]/vendor", "fabrication_vendor"),
|
|
96
|
+
("FABRICATION[fabrication]/model", "fabrication_model"),
|
|
97
|
+
("FABRICATION[fabrication]/identifier", "fabrication_identifier"),
|
|
98
|
+
("reflectron/status", "reflectron_status"),
|
|
99
|
+
("local_electrode/name", "local_electrode_name"),
|
|
100
|
+
("pulser/pulse_mode", "pulser/pulse_mode"),
|
|
101
|
+
("analysis_chamber/flight_path/@units", "nominal_flight_path/unit"),
|
|
102
|
+
],
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
APM_INSTRUMENT_DYNAMIC_TO_NEXUS = {
|
|
107
|
+
"prefix_trg": "/ENTRY[entry*]/measurement/event_data_apm_set/EVENT_DATA_APM[event_data_apm]/instrument",
|
|
108
|
+
"prefix_src": "atom_probe/",
|
|
109
|
+
"use": [("control/target_detection_rate/@units", "ions/pulse")],
|
|
110
|
+
"map": [
|
|
111
|
+
("control/target_detection_rate", "target_detection_rate"),
|
|
112
|
+
("pulser/pulse_frequency", "pulser/pulse_frequency/value"),
|
|
113
|
+
("pulser/pulse_fraction", "pulser/pulse_fraction"),
|
|
114
|
+
("analysis_chamber/chamber_pressure", "chamber_pressure/value"),
|
|
115
|
+
("stage_lab/base_temperature", "base_temperature/value"),
|
|
116
|
+
],
|
|
117
|
+
"map_to_str": [
|
|
118
|
+
("control/evaporation_control", "evaporation_control"),
|
|
119
|
+
("pulser/pulse_frequency/@units", "pulser/pulse_frequency/unit"),
|
|
120
|
+
("analysis_chamber/chamber_pressure/@units", "chamber_pressure/unit"),
|
|
121
|
+
("stage_lab/base_temperature/@units", "base_temperature/unit"),
|
|
122
|
+
],
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
APM_RANGE_TO_NEXUS = {
|
|
127
|
+
"prefix_trg": "/ENTRY[entry*]/atom_probe/ranging",
|
|
128
|
+
"prefix_src": "ranging/",
|
|
129
|
+
"map_to_str": [
|
|
130
|
+
("programID[program1]/program", "program"),
|
|
131
|
+
("programID[program1]/program/@version", "program_version"),
|
|
132
|
+
],
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
APM_RECON_TO_NEXUS = {
|
|
137
|
+
"prefix_trg": "/ENTRY[entry*]/atom_probe/reconstruction",
|
|
138
|
+
"prefix_src": "reconstruction/",
|
|
139
|
+
"map": [("field_of_view", "field_of_view/value")],
|
|
140
|
+
"map_to_str": [
|
|
141
|
+
"protocol_name",
|
|
142
|
+
"crystallographic_calibration",
|
|
143
|
+
"parameter",
|
|
144
|
+
("programID[program1]/program", "program"),
|
|
145
|
+
("programID[program1]/program/@version", "program_version"),
|
|
146
|
+
("field_of_view/@units", "field_of_view/unit"),
|
|
147
|
+
],
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
APM_WORKFLOW_TO_NEXUS = {
|
|
152
|
+
"prefix_trg": "/ENTRY[entry*]/atom_probe",
|
|
153
|
+
"prefix_src": "workflow/",
|
|
154
|
+
"sha256": [
|
|
155
|
+
("raw_data/SERIALIZED[serialized]/checksum", "raw_dat_file"),
|
|
156
|
+
("hit_finding/SERIALIZED[serialized]/checksum", "hit_dat_file"),
|
|
157
|
+
("reconstruction/config/checksum", "recon_cfg_file"),
|
|
158
|
+
],
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
# NeXus concept specific mapping tables which require special treatment as the current
|
|
162
|
+
# NOMAD Oasis custom schema implementation delivers them as a list of dictionaries instead
|
|
163
|
+
# of a directly flattenable list of key, value pairs
|
|
164
|
+
|
|
165
|
+
APM_USER_TO_NEXUS = {
|
|
166
|
+
"prefix_trg": "/ENTRY[entry*]/USER[user*]",
|
|
167
|
+
"map_to_str": [
|
|
168
|
+
"name",
|
|
169
|
+
"affiliation",
|
|
170
|
+
"address",
|
|
171
|
+
"email",
|
|
172
|
+
"telephone_number",
|
|
173
|
+
"role",
|
|
174
|
+
"social_media_name",
|
|
175
|
+
"social_media_platform",
|
|
176
|
+
],
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
APM_IDENTIFIER_TO_NEXUS = {
|
|
181
|
+
"prefix_trg": "/ENTRY[entry*]/USER[user*]",
|
|
182
|
+
"use": [
|
|
183
|
+
("IDENTIFIER[identifier]/is_persistent", False),
|
|
184
|
+
("IDENTIFIER[identifier]/service", "orcid"),
|
|
185
|
+
],
|
|
186
|
+
"map_to_str": [
|
|
187
|
+
("IDENTIFIER[identifier]/identifier", "orcid"),
|
|
188
|
+
],
|
|
189
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright The NOMAD Authors.
|
|
3
|
+
#
|
|
4
|
+
# This file is part of NOMAD. See https://nomad-lab.eu for further info.
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
#
|
|
18
|
+
"""Dict mapping values for a specifically configured NOMAD Oasis."""
|
|
19
|
+
|
|
20
|
+
# currently by virtue of design NOMAD Oasis specific examples show how different tools and
|
|
21
|
+
# services can be specifically coupled and implemented so that they work together
|
|
22
|
+
# currently we assume that the ELN provides all those pieces of information to instantiate
|
|
23
|
+
# a NeXus data artifact which technology-partner-specific files or database blobs can not
|
|
24
|
+
# deliver. Effectively a reader uses the eln_data.yaml generic ELN output to fill in these
|
|
25
|
+
# missing pieces of information while typically heavy data (tensors etc) are translated
|
|
26
|
+
# and written from the technology-partner files
|
|
27
|
+
# for large application definitions this can lead to a practical inconvenience:
|
|
28
|
+
# the ELN that has to be exposed to the user is complex and has many fields to fill in
|
|
29
|
+
# just to assure that all information are included in the ELN output and thus consumable
|
|
30
|
+
# by the dataconverter
|
|
31
|
+
# taking the perspective of a specific lab where a specific version of an ELN provided by
|
|
32
|
+
# or running in addition to NOMAD Oasis is used many pieces of information might not change
|
|
33
|
+
# or administrators do not wish to expose this via the end user ELN in an effort to reduce
|
|
34
|
+
# the complexity for end users and make entering of repetitiv information obsolete
|
|
35
|
+
|
|
36
|
+
# this is the scenario for which deployment_specific mapping shines
|
|
37
|
+
# parsing of deployment specific details in the apm reader is currently implemented
|
|
38
|
+
# such that it executes after reading generic ELN data (eventually available entries)
|
|
39
|
+
# in the template get overwritten
|
|
40
|
+
|
|
41
|
+
import datetime as dt
|
|
42
|
+
|
|
43
|
+
from pynxtools_apm.utils.versioning import NX_APM_ADEF_NAME
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
APM_OASISCONFIG_TO_NEXUS = {
|
|
47
|
+
"prefix_trg": "/ENTRY[entry*]",
|
|
48
|
+
"use": [
|
|
49
|
+
("definition", f"{NX_APM_ADEF_NAME}"),
|
|
50
|
+
(
|
|
51
|
+
"start_time",
|
|
52
|
+
f"{dt.datetime.now(dt.timezone.utc).isoformat().replace('+00:00', 'Z')}",
|
|
53
|
+
),
|
|
54
|
+
],
|
|
55
|
+
"map_to_str": [("operation_mode")],
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
APM_CSYS_MCSTASLIKE_TO_NEXUS = {
|
|
60
|
+
"prefix_trg": "/ENTRY[entry*]/coordinate_system_set/COORDINATE_SYSTEM[coordinate_system]",
|
|
61
|
+
"use": [
|
|
62
|
+
(
|
|
63
|
+
"alias",
|
|
64
|
+
"Following the idea of McStas that the z-axis points along the direction of an ion leaving the apex along the longest direction of the specimen",
|
|
65
|
+
),
|
|
66
|
+
("type", "cartesian"),
|
|
67
|
+
("handedness", "right_handed"),
|
|
68
|
+
(
|
|
69
|
+
"x_direction",
|
|
70
|
+
"Direction 1 that is perpendicular to the z_direction for a right_handed cartesian",
|
|
71
|
+
),
|
|
72
|
+
("x_alias", "x-axis"),
|
|
73
|
+
(
|
|
74
|
+
"y_direction",
|
|
75
|
+
"Direction 2 that is perpendicular to the x_direction and the z_direction for a right_handed cartesian",
|
|
76
|
+
),
|
|
77
|
+
("y_alias", "y-axis"),
|
|
78
|
+
(
|
|
79
|
+
"z_direction",
|
|
80
|
+
"Direction of an ion travelling hypothetically exactly along the assumed axis that is parallel to the longest direction of the specimen",
|
|
81
|
+
),
|
|
82
|
+
("z_alias", "z-axis"),
|
|
83
|
+
(
|
|
84
|
+
"origin",
|
|
85
|
+
"E.g. a characteristic point e.g. initial apex or center of the base of the specimen or something else",
|
|
86
|
+
),
|
|
87
|
+
],
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
APM_EXAMPLE_TO_NEXUS = {
|
|
92
|
+
"prefix_trg": "/ENTRY[entry*]/CITE[cite*]",
|
|
93
|
+
"map_to_str": [("doi"), ("description")],
|
|
94
|
+
}
|