reaxkit 1.0.0__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.
- reaxkit/__init__.py +0 -0
- reaxkit/analysis/__init__.py +0 -0
- reaxkit/analysis/composed/RDF_analyzer.py +560 -0
- reaxkit/analysis/composed/__init__.py +0 -0
- reaxkit/analysis/composed/connectivity_analyzer.py +706 -0
- reaxkit/analysis/composed/coordination_analyzer.py +144 -0
- reaxkit/analysis/composed/electrostatics_analyzer.py +687 -0
- reaxkit/analysis/per_file/__init__.py +0 -0
- reaxkit/analysis/per_file/control_analyzer.py +165 -0
- reaxkit/analysis/per_file/eregime_analyzer.py +108 -0
- reaxkit/analysis/per_file/ffield_analyzer.py +305 -0
- reaxkit/analysis/per_file/fort13_analyzer.py +79 -0
- reaxkit/analysis/per_file/fort57_analyzer.py +106 -0
- reaxkit/analysis/per_file/fort73_analyzer.py +61 -0
- reaxkit/analysis/per_file/fort74_analyzer.py +65 -0
- reaxkit/analysis/per_file/fort76_analyzer.py +191 -0
- reaxkit/analysis/per_file/fort78_analyzer.py +154 -0
- reaxkit/analysis/per_file/fort79_analyzer.py +83 -0
- reaxkit/analysis/per_file/fort7_analyzer.py +393 -0
- reaxkit/analysis/per_file/fort99_analyzer.py +411 -0
- reaxkit/analysis/per_file/molfra_analyzer.py +359 -0
- reaxkit/analysis/per_file/params_analyzer.py +258 -0
- reaxkit/analysis/per_file/summary_analyzer.py +84 -0
- reaxkit/analysis/per_file/trainset_analyzer.py +84 -0
- reaxkit/analysis/per_file/vels_analyzer.py +95 -0
- reaxkit/analysis/per_file/xmolout_analyzer.py +528 -0
- reaxkit/cli.py +181 -0
- reaxkit/count_loc.py +276 -0
- reaxkit/data/alias.yaml +89 -0
- reaxkit/data/constants.yaml +27 -0
- reaxkit/data/reaxff_input_files_contents.yaml +186 -0
- reaxkit/data/reaxff_output_files_contents.yaml +301 -0
- reaxkit/data/units.yaml +38 -0
- reaxkit/help/__init__.py +0 -0
- reaxkit/help/help_index_loader.py +531 -0
- reaxkit/help/introspection_utils.py +131 -0
- reaxkit/io/__init__.py +0 -0
- reaxkit/io/base_handler.py +165 -0
- reaxkit/io/generators/__init__.py +0 -0
- reaxkit/io/generators/control_generator.py +123 -0
- reaxkit/io/generators/eregime_generator.py +341 -0
- reaxkit/io/generators/geo_generator.py +967 -0
- reaxkit/io/generators/trainset_generator.py +1758 -0
- reaxkit/io/generators/tregime_generator.py +113 -0
- reaxkit/io/generators/vregime_generator.py +164 -0
- reaxkit/io/generators/xmolout_generator.py +304 -0
- reaxkit/io/handlers/__init__.py +0 -0
- reaxkit/io/handlers/control_handler.py +209 -0
- reaxkit/io/handlers/eregime_handler.py +122 -0
- reaxkit/io/handlers/ffield_handler.py +812 -0
- reaxkit/io/handlers/fort13_handler.py +123 -0
- reaxkit/io/handlers/fort57_handler.py +143 -0
- reaxkit/io/handlers/fort73_handler.py +145 -0
- reaxkit/io/handlers/fort74_handler.py +155 -0
- reaxkit/io/handlers/fort76_handler.py +195 -0
- reaxkit/io/handlers/fort78_handler.py +142 -0
- reaxkit/io/handlers/fort79_handler.py +227 -0
- reaxkit/io/handlers/fort7_handler.py +264 -0
- reaxkit/io/handlers/fort99_handler.py +128 -0
- reaxkit/io/handlers/geo_handler.py +224 -0
- reaxkit/io/handlers/molfra_handler.py +184 -0
- reaxkit/io/handlers/params_handler.py +137 -0
- reaxkit/io/handlers/summary_handler.py +135 -0
- reaxkit/io/handlers/trainset_handler.py +658 -0
- reaxkit/io/handlers/vels_handler.py +293 -0
- reaxkit/io/handlers/xmolout_handler.py +174 -0
- reaxkit/utils/__init__.py +0 -0
- reaxkit/utils/alias.py +219 -0
- reaxkit/utils/cache.py +77 -0
- reaxkit/utils/constants.py +75 -0
- reaxkit/utils/equation_of_states.py +96 -0
- reaxkit/utils/exceptions.py +27 -0
- reaxkit/utils/frame_utils.py +175 -0
- reaxkit/utils/log.py +43 -0
- reaxkit/utils/media/__init__.py +0 -0
- reaxkit/utils/media/convert.py +90 -0
- reaxkit/utils/media/make_video.py +91 -0
- reaxkit/utils/media/plotter.py +812 -0
- reaxkit/utils/numerical/__init__.py +0 -0
- reaxkit/utils/numerical/extrema_finder.py +96 -0
- reaxkit/utils/numerical/moving_average.py +103 -0
- reaxkit/utils/numerical/numerical_calcs.py +75 -0
- reaxkit/utils/numerical/signal_ops.py +135 -0
- reaxkit/utils/path.py +55 -0
- reaxkit/utils/units.py +104 -0
- reaxkit/webui/__init__.py +0 -0
- reaxkit/webui/app.py +0 -0
- reaxkit/webui/components.py +0 -0
- reaxkit/webui/layouts.py +0 -0
- reaxkit/webui/utils.py +0 -0
- reaxkit/workflows/__init__.py +0 -0
- reaxkit/workflows/composed/__init__.py +0 -0
- reaxkit/workflows/composed/coordination_workflow.py +393 -0
- reaxkit/workflows/composed/electrostatics_workflow.py +587 -0
- reaxkit/workflows/composed/xmolout_fort7_workflow.py +343 -0
- reaxkit/workflows/meta/__init__.py +0 -0
- reaxkit/workflows/meta/help_workflow.py +136 -0
- reaxkit/workflows/meta/introspection_workflow.py +235 -0
- reaxkit/workflows/meta/make_video_workflow.py +61 -0
- reaxkit/workflows/meta/plotter_workflow.py +601 -0
- reaxkit/workflows/per_file/__init__.py +0 -0
- reaxkit/workflows/per_file/control_workflow.py +110 -0
- reaxkit/workflows/per_file/eregime_workflow.py +267 -0
- reaxkit/workflows/per_file/ffield_workflow.py +390 -0
- reaxkit/workflows/per_file/fort13_workflow.py +86 -0
- reaxkit/workflows/per_file/fort57_workflow.py +137 -0
- reaxkit/workflows/per_file/fort73_workflow.py +151 -0
- reaxkit/workflows/per_file/fort74_workflow.py +88 -0
- reaxkit/workflows/per_file/fort76_workflow.py +188 -0
- reaxkit/workflows/per_file/fort78_workflow.py +135 -0
- reaxkit/workflows/per_file/fort79_workflow.py +314 -0
- reaxkit/workflows/per_file/fort7_workflow.py +592 -0
- reaxkit/workflows/per_file/fort83_workflow.py +60 -0
- reaxkit/workflows/per_file/fort99_workflow.py +223 -0
- reaxkit/workflows/per_file/geo_workflow.py +554 -0
- reaxkit/workflows/per_file/molfra_workflow.py +577 -0
- reaxkit/workflows/per_file/params_workflow.py +135 -0
- reaxkit/workflows/per_file/summary_workflow.py +161 -0
- reaxkit/workflows/per_file/trainset_workflow.py +356 -0
- reaxkit/workflows/per_file/tregime_workflow.py +79 -0
- reaxkit/workflows/per_file/vels_workflow.py +309 -0
- reaxkit/workflows/per_file/vregime_workflow.py +75 -0
- reaxkit/workflows/per_file/xmolout_workflow.py +678 -0
- reaxkit-1.0.0.dist-info/METADATA +128 -0
- reaxkit-1.0.0.dist-info/RECORD +130 -0
- reaxkit-1.0.0.dist-info/WHEEL +5 -0
- reaxkit-1.0.0.dist-info/entry_points.txt +2 -0
- reaxkit-1.0.0.dist-info/licenses/AUTHORS.md +20 -0
- reaxkit-1.0.0.dist-info/licenses/LICENSE +21 -0
- reaxkit-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
"""
|
|
2
|
+
fort.7 analysis utilities.
|
|
3
|
+
|
|
4
|
+
This module provides functions for extracting atom-level and iteration-level
|
|
5
|
+
features from a parsed ReaxFF ``fort.7`` file, as well as higher-level
|
|
6
|
+
coordination analysis when combined with ``xmolout``.
|
|
7
|
+
|
|
8
|
+
Typical use cases include:
|
|
9
|
+
|
|
10
|
+
- extracting per-atom quantities such as partial charges or bond-order sums
|
|
11
|
+
- extracting per-iteration (summary) quantities from the simulation table
|
|
12
|
+
- classifying atomic coordination (under / proper / over) across frames
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
import re
|
|
18
|
+
import pandas as pd
|
|
19
|
+
from collections.abc import Mapping
|
|
20
|
+
|
|
21
|
+
from reaxkit.utils.frame_utils import resolve_indices
|
|
22
|
+
from typing import Iterable, List, Sequence, Union
|
|
23
|
+
from reaxkit.io.handlers.xmolout_handler import XmoloutHandler
|
|
24
|
+
from reaxkit.analysis.composed.coordination_analyzer import (
|
|
25
|
+
classify_coordination_for_frame,
|
|
26
|
+
status_label,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
Indexish = Union[int, Iterable[int], None]
|
|
30
|
+
|
|
31
|
+
# --------------------------- frame/column helpers ---------------------------
|
|
32
|
+
def _resolve_columns(
|
|
33
|
+
df_example: pd.DataFrame,
|
|
34
|
+
columns: Union[str, Sequence[str]],
|
|
35
|
+
regex: bool = False,
|
|
36
|
+
must_exist: bool = True,
|
|
37
|
+
) -> List[str]:
|
|
38
|
+
"""
|
|
39
|
+
Map requested column name(s) or regex pattern(s) to real DataFrame columns.
|
|
40
|
+
"""
|
|
41
|
+
if isinstance(columns, str):
|
|
42
|
+
columns = [columns]
|
|
43
|
+
|
|
44
|
+
resolved: List[str] = []
|
|
45
|
+
cols = list(df_example.columns)
|
|
46
|
+
|
|
47
|
+
for spec in columns:
|
|
48
|
+
if regex:
|
|
49
|
+
pat = re.compile(spec)
|
|
50
|
+
matches = [c for c in cols if pat.search(c)]
|
|
51
|
+
resolved.extend(matches)
|
|
52
|
+
else:
|
|
53
|
+
if spec in cols:
|
|
54
|
+
resolved.append(spec)
|
|
55
|
+
elif not must_exist:
|
|
56
|
+
# skip silently
|
|
57
|
+
pass
|
|
58
|
+
else:
|
|
59
|
+
raise KeyError(f"Column '{spec}' not found. Example columns: {cols[:10]} ...")
|
|
60
|
+
|
|
61
|
+
# de-dup preserving order
|
|
62
|
+
out, seen = [], set()
|
|
63
|
+
for c in resolved:
|
|
64
|
+
if c not in seen:
|
|
65
|
+
out.append(c)
|
|
66
|
+
seen.add(c)
|
|
67
|
+
|
|
68
|
+
if must_exist and not out:
|
|
69
|
+
raise KeyError("No columns matched the request.")
|
|
70
|
+
return out
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# --------------------------- atom-level features ---------------------------
|
|
74
|
+
|
|
75
|
+
def get_fort7_data_per_atom(
|
|
76
|
+
handler,
|
|
77
|
+
columns: Union[str, Sequence[str]],
|
|
78
|
+
frames: Indexish = None,
|
|
79
|
+
iterations: Indexish = None,
|
|
80
|
+
regex: bool = False,
|
|
81
|
+
add_index_cols: bool = True,
|
|
82
|
+
) -> pd.DataFrame:
|
|
83
|
+
"""Extract per-atom feature columns across selected frames.
|
|
84
|
+
|
|
85
|
+
Works on
|
|
86
|
+
--------
|
|
87
|
+
Fort7Handler — ``fort.7``
|
|
88
|
+
|
|
89
|
+
Parameters
|
|
90
|
+
----------
|
|
91
|
+
handler : Fort7Handler
|
|
92
|
+
Parsed ``fort.7`` handler.
|
|
93
|
+
columns : str or sequence of str
|
|
94
|
+
Atom-level column name(s) to extract (e.g. ``partial_charge``,
|
|
95
|
+
``sum_BOs``). Regex patterns are allowed if ``regex=True``.
|
|
96
|
+
frames : int or iterable of int, optional
|
|
97
|
+
Frame indices to include.
|
|
98
|
+
iterations : int or iterable of int, optional
|
|
99
|
+
Iteration numbers to include.
|
|
100
|
+
regex : bool, default=False
|
|
101
|
+
Whether ``columns`` should be interpreted as regular expressions.
|
|
102
|
+
add_index_cols : bool, default=True
|
|
103
|
+
If True, include ``frame_idx``, ``iter``, and ``atom_idx`` columns.
|
|
104
|
+
|
|
105
|
+
Returns
|
|
106
|
+
-------
|
|
107
|
+
pandas.DataFrame
|
|
108
|
+
Tidy table with one row per atom per frame, including requested
|
|
109
|
+
feature columns and index metadata.
|
|
110
|
+
|
|
111
|
+
Examples
|
|
112
|
+
--------
|
|
113
|
+
>>> df = get_fort7_data_per_atom(f7, "partial_charge", frames=0)
|
|
114
|
+
>>> df = get_fort7_data_per_atom(f7, r"^atom_cnn\\d+$", regex=True)
|
|
115
|
+
"""
|
|
116
|
+
sim_df = handler.dataframe()
|
|
117
|
+
idx_list = resolve_indices(handler, frames, iterations)
|
|
118
|
+
|
|
119
|
+
out_frames = []
|
|
120
|
+
for fi in idx_list:
|
|
121
|
+
atoms = handler._frames[fi]
|
|
122
|
+
cols = _resolve_columns(atoms, columns, regex=regex, must_exist=True)
|
|
123
|
+
part = atoms[cols].copy()
|
|
124
|
+
if add_index_cols:
|
|
125
|
+
part.insert(0, "atom_idx", range(len(part)))
|
|
126
|
+
part.insert(0, "iter", int(sim_df.iloc[fi]["iter"]))
|
|
127
|
+
part.insert(0, "frame_idx", fi)
|
|
128
|
+
out_frames.append(part)
|
|
129
|
+
|
|
130
|
+
if not out_frames:
|
|
131
|
+
return pd.DataFrame(columns=(["frame_idx", "iter", "atom_idx"] if add_index_cols else []) + (columns if isinstance(columns, list) else [columns]))
|
|
132
|
+
return pd.concat(out_frames, ignore_index=True)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
# ------------------------- iter-level features -------------------------
|
|
136
|
+
|
|
137
|
+
def get_fort7_data_summaries(
|
|
138
|
+
handler,
|
|
139
|
+
columns: Union[str, Sequence[str]],
|
|
140
|
+
frames: Indexish = None,
|
|
141
|
+
iterations: Indexish = None,
|
|
142
|
+
regex: bool = False,
|
|
143
|
+
add_index_cols: bool = True,
|
|
144
|
+
) -> pd.DataFrame:
|
|
145
|
+
"""Extract per-iteration (summary) feature columns from a ``fort.7`` file.
|
|
146
|
+
|
|
147
|
+
Works on
|
|
148
|
+
--------
|
|
149
|
+
Fort7Handler — ``fort.7``
|
|
150
|
+
|
|
151
|
+
Parameters
|
|
152
|
+
----------
|
|
153
|
+
handler : Fort7Handler
|
|
154
|
+
Parsed ``fort.7`` handler.
|
|
155
|
+
columns : str or sequence of str
|
|
156
|
+
Summary-level column name(s) to extract.
|
|
157
|
+
frames : int or iterable of int, optional
|
|
158
|
+
Frame indices to include.
|
|
159
|
+
iterations : int or iterable of int, optional
|
|
160
|
+
Iteration numbers to include.
|
|
161
|
+
regex : bool, default=False
|
|
162
|
+
Whether ``columns`` should be interpreted as regular expressions.
|
|
163
|
+
add_index_cols : bool, default=True
|
|
164
|
+
If True, include ``frame_idx`` and ``iter`` columns.
|
|
165
|
+
|
|
166
|
+
Returns
|
|
167
|
+
-------
|
|
168
|
+
pandas.DataFrame
|
|
169
|
+
Table with one row per selected frame containing summary quantities.
|
|
170
|
+
|
|
171
|
+
Examples
|
|
172
|
+
--------
|
|
173
|
+
>>> df = get_fort7_data_summaries(f7, ["num_bonds", "total_BO"])
|
|
174
|
+
>>> df = get_fort7_data_summaries(f7, r"^total_.*$", regex=True)
|
|
175
|
+
"""
|
|
176
|
+
sim_df = handler.dataframe()
|
|
177
|
+
idx_list = resolve_indices(handler, frames, iterations)
|
|
178
|
+
|
|
179
|
+
if len(sim_df) == 0:
|
|
180
|
+
return pd.DataFrame()
|
|
181
|
+
|
|
182
|
+
cols = _resolve_columns(sim_df, columns, regex=regex, must_exist=True)
|
|
183
|
+
part = sim_df.iloc[idx_list][cols].reset_index(drop=True)
|
|
184
|
+
|
|
185
|
+
if add_index_cols and "iter" not in part.columns:
|
|
186
|
+
# Provide iter + frame_idx for context if the user didn't request iter
|
|
187
|
+
meta_df = sim_df.loc[idx_list, ["iter"]].reset_index(drop=True)
|
|
188
|
+
meta_df.insert(0, "frame_idx", idx_list)
|
|
189
|
+
part = pd.concat([meta_df, part], axis=1)
|
|
190
|
+
elif add_index_cols and "iter" in part.columns:
|
|
191
|
+
part.insert(0, "frame_idx", idx_list)
|
|
192
|
+
|
|
193
|
+
return part
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
# ---------------------------- convenience slices ----------------------------
|
|
197
|
+
|
|
198
|
+
def get_partial_charges_conv_fnc(
|
|
199
|
+
handler,
|
|
200
|
+
frames: Indexish = None,
|
|
201
|
+
iterations: Indexish = None,
|
|
202
|
+
) -> pd.DataFrame:
|
|
203
|
+
"""
|
|
204
|
+
Convenience function to extract per-atom partial charges across selected frames.
|
|
205
|
+
|
|
206
|
+
Works on
|
|
207
|
+
--------
|
|
208
|
+
Fort7Handler — ``fort.7``
|
|
209
|
+
|
|
210
|
+
Parameters
|
|
211
|
+
----------
|
|
212
|
+
handler : Fort7Handler
|
|
213
|
+
Parsed ``fort.7`` handler.
|
|
214
|
+
frames, iterations
|
|
215
|
+
Frame indices or iteration numbers to include.
|
|
216
|
+
|
|
217
|
+
Returns
|
|
218
|
+
-------
|
|
219
|
+
pandas.DataFrame
|
|
220
|
+
Per-atom partial charges with frame and atom indices.
|
|
221
|
+
|
|
222
|
+
Examples
|
|
223
|
+
--------
|
|
224
|
+
>>> df = get_partial_charges_conv_fnc(f7, frames=0)
|
|
225
|
+
"""
|
|
226
|
+
return get_fort7_data_per_atom(handler, "partial_charge", frames=frames, iterations=iterations)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def get_all_atoms_cnn_conv_fnc(
|
|
230
|
+
handler,
|
|
231
|
+
frames: Indexish = None,
|
|
232
|
+
iterations: Indexish = None,
|
|
233
|
+
) -> pd.DataFrame:
|
|
234
|
+
"""
|
|
235
|
+
Convenience function to extract all ``atom_cnn*`` connectivity columns across selected frames.
|
|
236
|
+
|
|
237
|
+
Works on
|
|
238
|
+
--------
|
|
239
|
+
Fort7Handler — ``fort.7``
|
|
240
|
+
|
|
241
|
+
Parameters
|
|
242
|
+
----------
|
|
243
|
+
handler : Fort7Handler
|
|
244
|
+
Parsed ``fort.7`` handler.
|
|
245
|
+
frames, iterations
|
|
246
|
+
Frame indices or iteration numbers to include.
|
|
247
|
+
|
|
248
|
+
Returns
|
|
249
|
+
-------
|
|
250
|
+
pandas.DataFrame
|
|
251
|
+
Per-atom connectivity values with frame and atom indices.
|
|
252
|
+
|
|
253
|
+
Examples
|
|
254
|
+
--------
|
|
255
|
+
>>> df = get_all_atoms_cnn_conv_fnc(f7)
|
|
256
|
+
"""
|
|
257
|
+
return get_fort7_data_per_atom(handler, r"^atom_cnn\d+$", frames=frames, iterations=iterations, regex=True)
|
|
258
|
+
|
|
259
|
+
def get_sum_bos_conv_fnc(
|
|
260
|
+
handler,
|
|
261
|
+
frames: Indexish = None,
|
|
262
|
+
iterations: Indexish = None,
|
|
263
|
+
) -> pd.DataFrame:
|
|
264
|
+
"""
|
|
265
|
+
Convenience function to extract per-atom total bond order (``sum_BOs``) across selected frames.
|
|
266
|
+
|
|
267
|
+
Works on
|
|
268
|
+
--------
|
|
269
|
+
Fort7Handler — ``fort.7``
|
|
270
|
+
|
|
271
|
+
Parameters
|
|
272
|
+
----------
|
|
273
|
+
handler : Fort7Handler
|
|
274
|
+
Parsed ``fort.7`` handler.
|
|
275
|
+
frames, iterations
|
|
276
|
+
Frame indices or iteration numbers to include.
|
|
277
|
+
|
|
278
|
+
Returns
|
|
279
|
+
-------
|
|
280
|
+
pandas.DataFrame
|
|
281
|
+
Tidy table with columns: ``frame_idx``, ``iter``, ``atom_idx``,
|
|
282
|
+
and ``sum_BOs``.
|
|
283
|
+
|
|
284
|
+
Examples
|
|
285
|
+
--------
|
|
286
|
+
>>> df = get_sum_bos_conv_fnc(f7)
|
|
287
|
+
"""
|
|
288
|
+
return get_fort7_data_per_atom(
|
|
289
|
+
handler,
|
|
290
|
+
columns="sum_BOs",
|
|
291
|
+
frames=frames,
|
|
292
|
+
iterations=iterations,
|
|
293
|
+
regex=False,
|
|
294
|
+
add_index_cols=True,
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
# --- Coordination classification using features_atom("sum_BOs") --------------
|
|
299
|
+
def per_atom_coordination_status_over_frames(
|
|
300
|
+
f7_handler,
|
|
301
|
+
xh: XmoloutHandler,
|
|
302
|
+
*,
|
|
303
|
+
valences: Mapping[str, float],
|
|
304
|
+
threshold: float = 0.9,
|
|
305
|
+
frames: Indexish = None,
|
|
306
|
+
iterations: Indexish = None,
|
|
307
|
+
require_all_valences: bool = True,
|
|
308
|
+
) -> pd.DataFrame:
|
|
309
|
+
"""Classify atomic coordination status across frames using bond-order sums.
|
|
310
|
+
|
|
311
|
+
Works on
|
|
312
|
+
--------
|
|
313
|
+
Fort7Handler + XmoloutHandler — ``fort.7`` + ``xmolout``
|
|
314
|
+
|
|
315
|
+
Parameters
|
|
316
|
+
----------
|
|
317
|
+
f7_handler : Fort7Handler
|
|
318
|
+
Parsed ``fort.7`` handler providing bond-order information.
|
|
319
|
+
xh : XmoloutHandler
|
|
320
|
+
Parsed ``xmolout`` handler providing atom types per frame.
|
|
321
|
+
valences : mapping of str to float
|
|
322
|
+
Reference valence values for each atom type.
|
|
323
|
+
threshold : float, default=0.9
|
|
324
|
+
Tolerance window for under/over-coordination classification.
|
|
325
|
+
frames, iterations
|
|
326
|
+
Frame indices or iteration numbers to include.
|
|
327
|
+
require_all_valences : bool, default=True
|
|
328
|
+
If True, raise an error when a valence is missing for any atom type.
|
|
329
|
+
|
|
330
|
+
Returns
|
|
331
|
+
-------
|
|
332
|
+
pandas.DataFrame
|
|
333
|
+
One row per atom per frame with columns including:
|
|
334
|
+
``frame_index``, ``iter``, ``atom_id``, ``atom_type``,
|
|
335
|
+
``sum_BOs``, ``valence``, ``delta``, ``status``, ``status_label``.
|
|
336
|
+
|
|
337
|
+
Examples
|
|
338
|
+
--------
|
|
339
|
+
>>> df = per_atom_coordination_status_over_frames(
|
|
340
|
+
... f7, xh, valences={"C": 4.0, "H": 1.0}
|
|
341
|
+
... )
|
|
342
|
+
"""
|
|
343
|
+
# Pull sum_BOs in tidy form (frame_idx, iter, atom_idx, sum_BOs)
|
|
344
|
+
df_sum = get_sum_bos_conv_fnc(f7_handler, frames=frames, iterations=iterations)
|
|
345
|
+
if df_sum.empty:
|
|
346
|
+
return pd.DataFrame(columns=[
|
|
347
|
+
"frame_index","iter","atom_id","atom_type","sum_BOs",
|
|
348
|
+
"valence","delta","status","status_label"
|
|
349
|
+
])
|
|
350
|
+
|
|
351
|
+
# Group by frame and classify
|
|
352
|
+
rows = []
|
|
353
|
+
for fi, g in df_sum.groupby("frame_idx", sort=True):
|
|
354
|
+
g = g.sort_values("atom_idx")
|
|
355
|
+
sum_vals = g["sum_BOs"].to_numpy(dtype=float)
|
|
356
|
+
|
|
357
|
+
# Atom types for this frame come from xmolout
|
|
358
|
+
fr = xh.frame(int(fi))
|
|
359
|
+
atom_types = fr["atom_types"]
|
|
360
|
+
if len(sum_vals) != len(atom_types):
|
|
361
|
+
raise ValueError(
|
|
362
|
+
f"Length mismatch at frame {fi}: sum_BOs({len(sum_vals)}) vs atom_types({len(atom_types)})"
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
per_atom = classify_coordination_for_frame(
|
|
366
|
+
sum_bos=sum_vals,
|
|
367
|
+
atom_types=atom_types,
|
|
368
|
+
valences=valences,
|
|
369
|
+
threshold=threshold,
|
|
370
|
+
require_all_valences=require_all_valences,
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
# Attach frame metadata
|
|
374
|
+
iter = int(g["iter"].iloc[0]) if "iter" in g.columns else int(fi)
|
|
375
|
+
per_atom.insert(0, "iter", iter)
|
|
376
|
+
per_atom.insert(0, "frame_index", int(fi))
|
|
377
|
+
|
|
378
|
+
# Friendly label
|
|
379
|
+
per_atom["status_label"] = status_label(per_atom["status"])
|
|
380
|
+
|
|
381
|
+
rows.append(per_atom)
|
|
382
|
+
|
|
383
|
+
out = pd.concat(rows, ignore_index=True)
|
|
384
|
+
out = out.sort_values(["frame_index", "atom_id"], kind="mergesort").reset_index(drop=True)
|
|
385
|
+
return out
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
|