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,106 @@
|
|
|
1
|
+
"""
|
|
2
|
+
fort.57 (geometry / convergence) analysis utilities.
|
|
3
|
+
|
|
4
|
+
This module provides helpers for extracting selected convergence and
|
|
5
|
+
geometry-related quantities from a parsed ReaxFF ``fort.57`` file
|
|
6
|
+
via ``Fort57Handler``.
|
|
7
|
+
|
|
8
|
+
Typical use cases include:
|
|
9
|
+
|
|
10
|
+
- selecting canonical fort.57 columns with alias support
|
|
11
|
+
- exporting convergence metrics such as RMSG or potential energy
|
|
12
|
+
- attaching a geometry descriptor for multi-structure workflows
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from typing import Sequence
|
|
19
|
+
|
|
20
|
+
import pandas as pd
|
|
21
|
+
|
|
22
|
+
from reaxkit.io.handlers.fort57_handler import Fort57Handler
|
|
23
|
+
from reaxkit.utils.alias import normalize_choice, resolve_alias_from_columns
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
_F57_CANONICAL = ("iter", "E_pot", "T", "T_set", "RMSG", "nfc")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def get_fort57_data(
|
|
30
|
+
*,
|
|
31
|
+
fort57_handler: Fort57Handler,
|
|
32
|
+
cols: Sequence[str] | None = None,
|
|
33
|
+
include_geo_descriptor: bool = False,
|
|
34
|
+
) -> pd.DataFrame:
|
|
35
|
+
"""
|
|
36
|
+
Extract selected columns from a ``fort.57`` file as a DataFrame.
|
|
37
|
+
|
|
38
|
+
Works on
|
|
39
|
+
--------
|
|
40
|
+
Fort57Handler — ``fort.57``
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
fort57_handler : Fort57Handler
|
|
45
|
+
Parsed ``fort.57`` handler.
|
|
46
|
+
cols : sequence of str, optional
|
|
47
|
+
Columns to extract using canonical names or aliases
|
|
48
|
+
(e.g. ``iter``, ``E_pot``, ``T``, ``T_set``, ``RMSG``, ``nfc``).
|
|
49
|
+
If None, all available columns are returned.
|
|
50
|
+
include_geo_descriptor : bool, default=False
|
|
51
|
+
If True, prepend a ``geo_descriptor`` column identifying
|
|
52
|
+
the geometry associated with this data.
|
|
53
|
+
|
|
54
|
+
Returns
|
|
55
|
+
-------
|
|
56
|
+
pandas.DataFrame
|
|
57
|
+
Table containing the requested columns. Column names are
|
|
58
|
+
normalized to canonical fort.57 keys.
|
|
59
|
+
|
|
60
|
+
Examples
|
|
61
|
+
--------
|
|
62
|
+
>>> from reaxkit.io.handlers.fort57_handler import Fort57Handler
|
|
63
|
+
>>> from reaxkit.analysis.per_file.fort57_analyzer import get_fort57_data
|
|
64
|
+
>>> h = Fort57Handler("fort.57")
|
|
65
|
+
>>> df = get_fort57_data(fort57_handler=h, cols=["iter", "RMSG"])
|
|
66
|
+
"""
|
|
67
|
+
df = fort57_handler.dataframe()
|
|
68
|
+
|
|
69
|
+
# default: all canonical columns (if present)
|
|
70
|
+
if cols is None or len(cols) == 0:
|
|
71
|
+
out = df.copy()
|
|
72
|
+
else:
|
|
73
|
+
# 1) Normalize user requests to canonical keys (via alias.py)
|
|
74
|
+
wanted_canon = [normalize_choice(c, domain="fort57.md") for c in cols]
|
|
75
|
+
|
|
76
|
+
# 2) Resolve those canonical keys to actual dataframe columns
|
|
77
|
+
# (usually identical, but this keeps it robust)
|
|
78
|
+
resolved_cols: list[str] = []
|
|
79
|
+
available = list(df.columns)
|
|
80
|
+
|
|
81
|
+
for canon in wanted_canon:
|
|
82
|
+
if canon not in _F57_CANONICAL:
|
|
83
|
+
raise ValueError(
|
|
84
|
+
f"Unknown fort.57 column '{canon}'. "
|
|
85
|
+
f"Allowed: {', '.join(_F57_CANONICAL)}"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
actual = resolve_alias_from_columns(available, canon)
|
|
89
|
+
if actual is None:
|
|
90
|
+
raise KeyError(
|
|
91
|
+
f"Column '{canon}' not found (and no alias matched). "
|
|
92
|
+
f"Available: {', '.join(available)}"
|
|
93
|
+
)
|
|
94
|
+
resolved_cols.append(actual)
|
|
95
|
+
|
|
96
|
+
out = df.loc[:, resolved_cols].copy()
|
|
97
|
+
|
|
98
|
+
# Optional: rename resolved columns back to canonical names
|
|
99
|
+
# so downstream code always sees iter/E_pot/T/T_set/RMSG/nfc
|
|
100
|
+
rename_map = dict(zip(resolved_cols, wanted_canon))
|
|
101
|
+
out = out.rename(columns=rename_map)
|
|
102
|
+
|
|
103
|
+
if include_geo_descriptor:
|
|
104
|
+
out.insert(0, "geo_descriptor", fort57_handler.geo_descriptor)
|
|
105
|
+
|
|
106
|
+
return out
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Energy output analysis utilities (fort.73, energylog, fort.58).
|
|
3
|
+
|
|
4
|
+
This module provides a lightweight interface for accessing energy-related
|
|
5
|
+
output written by ReaxFF during MD, MM, or optimization runs. It supports
|
|
6
|
+
``fort.73``, ``energylog``, and ``fort.58`` files via a common handler interface.
|
|
7
|
+
|
|
8
|
+
Typical use cases include:
|
|
9
|
+
|
|
10
|
+
- extracting selected energy terms versus iteration
|
|
11
|
+
- exporting energy components for plotting or post-processing
|
|
12
|
+
- working uniformly with fort.73, energylog, and fort.58 outputs
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
from typing import List, Optional
|
|
18
|
+
import pandas as pd
|
|
19
|
+
|
|
20
|
+
from reaxkit.io.base_handler import BaseHandler
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_fort73_data(handler: BaseHandler, columns: Optional[List[str]] = None) -> pd.DataFrame:
|
|
24
|
+
"""
|
|
25
|
+
Extract energy data from a ReaxFF energy output file as a DataFrame.
|
|
26
|
+
|
|
27
|
+
Works on
|
|
28
|
+
--------
|
|
29
|
+
Fort73Handler / EnergylogHandler / Fort58Handler — ``fort.73``, ``energylog``, ``fort.58``
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
----------
|
|
33
|
+
handler : TemplateHandler
|
|
34
|
+
Parsed handler instance for ``fort.73``, ``energylog``, or ``fort.58``.
|
|
35
|
+
columns : list[str], optional
|
|
36
|
+
Energy columns to extract (e.g. ``["iter", "Ebond", "Evdw"]``).
|
|
37
|
+
If None, all available columns are returned.
|
|
38
|
+
|
|
39
|
+
Returns
|
|
40
|
+
-------
|
|
41
|
+
pandas.DataFrame
|
|
42
|
+
Energy table indexed by iteration, containing the requested
|
|
43
|
+
energy components.
|
|
44
|
+
|
|
45
|
+
Examples
|
|
46
|
+
--------
|
|
47
|
+
>>> from reaxkit.io.handlers.fort73_handler import Fort73Handler
|
|
48
|
+
>>> from reaxkit.analysis.per_file.fort73_analyzer import get_fort73_data
|
|
49
|
+
>>> h = Fort73Handler("fort.73")
|
|
50
|
+
>>> df = get_fort73_data(h, columns=["iter", "Ebond", "Evdw"])
|
|
51
|
+
"""
|
|
52
|
+
df = handler.dataframe().copy()
|
|
53
|
+
|
|
54
|
+
if columns is not None:
|
|
55
|
+
# Validate requested columns
|
|
56
|
+
missing = set(columns) - set(df.columns)
|
|
57
|
+
if missing:
|
|
58
|
+
raise KeyError(f"Requested columns not found in fort.73 DataFrame: {missing}")
|
|
59
|
+
df = df[columns]
|
|
60
|
+
|
|
61
|
+
return df
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""
|
|
2
|
+
fort.74 (thermodynamic summary) analysis utilities.
|
|
3
|
+
|
|
4
|
+
This module provides helpers for accessing and sorting thermodynamic
|
|
5
|
+
summary data produced by ReaxFF in ``fort.74`` files via ``Fort74Handler``.
|
|
6
|
+
|
|
7
|
+
Typical use cases include:
|
|
8
|
+
|
|
9
|
+
- retrieving formation energies, volumes, or densities
|
|
10
|
+
- sorting structures by energy or iteration
|
|
11
|
+
- exporting fort.74 data for post-processing or plotting
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
import pandas as pd
|
|
17
|
+
from typing import Optional
|
|
18
|
+
|
|
19
|
+
from reaxkit.io.handlers.fort74_handler import Fort74Handler
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def get_fort74_data(
|
|
23
|
+
handler: Fort74Handler,
|
|
24
|
+
*,
|
|
25
|
+
sort: Optional[str] = None,
|
|
26
|
+
ascending: bool = True
|
|
27
|
+
) -> pd.DataFrame:
|
|
28
|
+
"""
|
|
29
|
+
Retrieve thermodynamic summary data from a ``fort.74`` file.
|
|
30
|
+
|
|
31
|
+
Works on
|
|
32
|
+
--------
|
|
33
|
+
Fort74Handler — ``fort.74``
|
|
34
|
+
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
handler : Fort74Handler
|
|
38
|
+
Parsed ``fort.74`` handler.
|
|
39
|
+
sort : str, optional
|
|
40
|
+
Column name or alias to sort by (e.g. ``Emin``, ``Hf``, ``iter``).
|
|
41
|
+
If None, rows are returned in file order.
|
|
42
|
+
ascending : bool, default=True
|
|
43
|
+
Sort order when ``sort`` is specified.
|
|
44
|
+
|
|
45
|
+
Returns
|
|
46
|
+
-------
|
|
47
|
+
pandas.DataFrame
|
|
48
|
+
Table containing thermodynamic and structural summary quantities
|
|
49
|
+
from ``fort.74``.
|
|
50
|
+
|
|
51
|
+
Examples
|
|
52
|
+
--------
|
|
53
|
+
>>> from reaxkit.io.handlers.fort74_handler import Fort74Handler
|
|
54
|
+
>>> from reaxkit.analysis.per_file.fort74_analyzer import get_fort74_data
|
|
55
|
+
>>> h = Fort74Handler("fort.74")
|
|
56
|
+
>>> df = get_fort74_data(h, sort="Emin")
|
|
57
|
+
"""
|
|
58
|
+
df = handler.dataframe().copy()
|
|
59
|
+
|
|
60
|
+
# No sorting → return as-is
|
|
61
|
+
if not sort:
|
|
62
|
+
return df
|
|
63
|
+
|
|
64
|
+
# Sort and return
|
|
65
|
+
return df.sort_values(by=sort, ascending=ascending).reset_index(drop=True)
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"""
|
|
2
|
+
fort.76 (restraint monitor) analysis utilities.
|
|
3
|
+
|
|
4
|
+
This module provides helpers for extracting and organizing restraint-related
|
|
5
|
+
quantities written by ReaxFF into ``fort.76`` files via ``Fort76Handler``.
|
|
6
|
+
|
|
7
|
+
Typical use cases include:
|
|
8
|
+
|
|
9
|
+
- extracting target and actual values for specific restraints
|
|
10
|
+
- selecting subsets of restraint columns with alias support
|
|
11
|
+
- preparing clean tables for plotting or downstream analysis
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from typing import List, Sequence
|
|
18
|
+
import pandas as pd
|
|
19
|
+
|
|
20
|
+
from reaxkit.io.handlers.fort76_handler import Fort76Handler
|
|
21
|
+
from reaxkit.utils.alias import _resolve_alias, available_keys
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# ---------- Internal helpers ----------
|
|
25
|
+
|
|
26
|
+
def _resolve_fort76_column(handler: Fort76Handler, requested: str) -> str:
|
|
27
|
+
"""
|
|
28
|
+
Resolve a user-requested column name to a canonical fort.76 DataFrame column.
|
|
29
|
+
|
|
30
|
+
Resolution order:
|
|
31
|
+
1) Restraint columns: "restraint 1 target", "r1_actual", etc.
|
|
32
|
+
2) Standard columns via alias.py: iter, E_res, E_pot
|
|
33
|
+
3) Exact column name fallback
|
|
34
|
+
"""
|
|
35
|
+
df = handler.dataframe()
|
|
36
|
+
cols = list(df.columns)
|
|
37
|
+
|
|
38
|
+
key = requested.strip().lower()
|
|
39
|
+
|
|
40
|
+
# ---- 1) restraint columns (simple parsing, no regex) ----
|
|
41
|
+
# accepted file_templates:
|
|
42
|
+
# "restraint 1 target value"
|
|
43
|
+
# "restraint 1 actual"
|
|
44
|
+
# "r1_target"
|
|
45
|
+
# "r2 actual"
|
|
46
|
+
if "restraint" in key or key.startswith("r"):
|
|
47
|
+
parts = key.replace("_", " ").split()
|
|
48
|
+
|
|
49
|
+
# find index
|
|
50
|
+
idx = None
|
|
51
|
+
for p in parts:
|
|
52
|
+
if p.isdigit():
|
|
53
|
+
idx = int(p)
|
|
54
|
+
break
|
|
55
|
+
|
|
56
|
+
if idx is not None:
|
|
57
|
+
if "target" in parts:
|
|
58
|
+
col = f"r{idx}_target"
|
|
59
|
+
elif "actual" in parts:
|
|
60
|
+
col = f"r{idx}_actual"
|
|
61
|
+
else:
|
|
62
|
+
raise KeyError(
|
|
63
|
+
f"Restraint column must specify target or actual: '{requested}'"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
if col not in cols:
|
|
67
|
+
raise KeyError(
|
|
68
|
+
f"Resolved '{requested}' → '{col}', but column not found. "
|
|
69
|
+
f"Available restraint columns: {[c for c in cols if c.startswith('r')]}"
|
|
70
|
+
)
|
|
71
|
+
return col
|
|
72
|
+
|
|
73
|
+
# ---- 2) standard columns via alias.py ----
|
|
74
|
+
try:
|
|
75
|
+
return _resolve_alias(df, requested)
|
|
76
|
+
except KeyError:
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
# ---- 3) exact match fallback ----
|
|
80
|
+
if requested in cols:
|
|
81
|
+
return requested
|
|
82
|
+
|
|
83
|
+
raise KeyError(
|
|
84
|
+
f"Could not resolve requested column '{requested}'. "
|
|
85
|
+
f"Available columns / aliases: {available_keys(cols)}"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
# ---------- Public API ----------
|
|
90
|
+
|
|
91
|
+
def get_fort76_data(
|
|
92
|
+
handler: Fort76Handler,
|
|
93
|
+
columns: Sequence[str],
|
|
94
|
+
dropna_rows: bool = False,
|
|
95
|
+
copy: bool = True,
|
|
96
|
+
) -> pd.DataFrame:
|
|
97
|
+
"""
|
|
98
|
+
Extract user-requested columns from a ``fort.76`` file.
|
|
99
|
+
|
|
100
|
+
Works on
|
|
101
|
+
--------
|
|
102
|
+
Fort76Handler — ``fort.76``
|
|
103
|
+
|
|
104
|
+
Parameters
|
|
105
|
+
----------
|
|
106
|
+
handler : Fort76Handler
|
|
107
|
+
Parsed ``fort.76`` handler.
|
|
108
|
+
columns : sequence of str
|
|
109
|
+
Column names to extract. Aliases are supported, including
|
|
110
|
+
restraint specifications such as ``"restraint 1 target"``
|
|
111
|
+
or ``"r2_actual"``.
|
|
112
|
+
dropna_rows : bool, default=False
|
|
113
|
+
If True, drop rows where all selected non-``iter`` columns are NaN.
|
|
114
|
+
copy : bool, default=True
|
|
115
|
+
If True, return a copy of the DataFrame.
|
|
116
|
+
|
|
117
|
+
Returns
|
|
118
|
+
-------
|
|
119
|
+
pandas.DataFrame
|
|
120
|
+
Table containing only the requested columns, in the order specified.
|
|
121
|
+
|
|
122
|
+
Examples
|
|
123
|
+
--------
|
|
124
|
+
>>> from reaxkit.io.handlers.fort76_handler import Fort76Handler
|
|
125
|
+
>>> from reaxkit.analysis.per_file.fort76_analyzer import get_fort76_data
|
|
126
|
+
>>> h = Fort76Handler("fort.76")
|
|
127
|
+
>>> df = get_fort76_data(
|
|
128
|
+
... h,
|
|
129
|
+
... ["iter", "restraint 1 target value", "restraint 1 actual value"]
|
|
130
|
+
... )
|
|
131
|
+
"""
|
|
132
|
+
df = handler.dataframe()
|
|
133
|
+
|
|
134
|
+
resolved: List[str] = [
|
|
135
|
+
_resolve_fort76_column(handler, col) for col in columns
|
|
136
|
+
]
|
|
137
|
+
|
|
138
|
+
out = df.loc[:, resolved]
|
|
139
|
+
|
|
140
|
+
if dropna_rows:
|
|
141
|
+
non_iter = [c for c in out.columns if c.lower() != "iter"]
|
|
142
|
+
if non_iter:
|
|
143
|
+
out = out.dropna(axis=0, how="all", subset=non_iter)
|
|
144
|
+
|
|
145
|
+
return out.copy() if copy else out
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def get_fort76_restraint_pairs(
|
|
149
|
+
handler: Fort76Handler,
|
|
150
|
+
restraint_index: int,
|
|
151
|
+
include_iter: bool = True,
|
|
152
|
+
) -> pd.DataFrame:
|
|
153
|
+
"""
|
|
154
|
+
Extract target and actual values for a single restraint.
|
|
155
|
+
|
|
156
|
+
Works on
|
|
157
|
+
--------
|
|
158
|
+
Fort76Handler — ``fort.76``
|
|
159
|
+
|
|
160
|
+
Parameters
|
|
161
|
+
----------
|
|
162
|
+
handler : Fort76Handler
|
|
163
|
+
Parsed ``fort.76`` handler.
|
|
164
|
+
restraint_index : int
|
|
165
|
+
Index of the restraint (1-based, as in the ReaxFF input).
|
|
166
|
+
include_iter : bool, default=True
|
|
167
|
+
If True, include the ``iter`` column.
|
|
168
|
+
|
|
169
|
+
Returns
|
|
170
|
+
-------
|
|
171
|
+
pandas.DataFrame
|
|
172
|
+
Table with columns ``["iter", "rN_target", "rN_actual"]`` if
|
|
173
|
+
``include_iter=True``, otherwise ``["rN_target", "rN_actual"]``.
|
|
174
|
+
|
|
175
|
+
Examples
|
|
176
|
+
--------
|
|
177
|
+
>>> from reaxkit.io.handlers.fort76_handler import Fort76Handler
|
|
178
|
+
>>> from reaxkit.analysis.per_file.fort76_analyzer import get_fort76_restraint_pairs
|
|
179
|
+
>>> h = Fort76Handler("fort.76")
|
|
180
|
+
>>> df = get_fort76_restraint_pairs(h, restraint_index=1)
|
|
181
|
+
"""
|
|
182
|
+
req: List[str] = []
|
|
183
|
+
if include_iter:
|
|
184
|
+
req.append("iter")
|
|
185
|
+
|
|
186
|
+
req += [
|
|
187
|
+
f"restraint {restraint_index} target value",
|
|
188
|
+
f"restraint {restraint_index} actual value",
|
|
189
|
+
]
|
|
190
|
+
|
|
191
|
+
return get_fort76_data(handler, req)
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""
|
|
2
|
+
fort.78 (external field schedule) analysis utilities.
|
|
3
|
+
|
|
4
|
+
This module provides helpers for extracting and aligning electric-field
|
|
5
|
+
schedule data written by ReaxFF into ``fort.78`` files via ``Fort78Handler``.
|
|
6
|
+
|
|
7
|
+
Typical use cases include:
|
|
8
|
+
|
|
9
|
+
- extracting electric-field components versus iteration
|
|
10
|
+
- matching field values to other outputs sampled at ``iout2`` frequency
|
|
11
|
+
- preparing aligned field profiles for plotting with xmolout or summaries
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
from typing import Sequence
|
|
17
|
+
import pandas as pd
|
|
18
|
+
|
|
19
|
+
from reaxkit.io.handlers.fort78_handler import Fort78Handler
|
|
20
|
+
from reaxkit.utils.alias import resolve_alias_from_columns, load_default_alias_map
|
|
21
|
+
from reaxkit.io.handlers.control_handler import ControlHandler
|
|
22
|
+
from reaxkit.analysis.per_file.control_analyzer import get_control_data
|
|
23
|
+
|
|
24
|
+
def get_fort78_data(handler: Fort78Handler, variables: str | Sequence[str]) -> pd.DataFrame:
|
|
25
|
+
"""Extract iteration versus one or more variables from a ``fort.78`` file.
|
|
26
|
+
|
|
27
|
+
Works on
|
|
28
|
+
--------
|
|
29
|
+
Fort78Handler — ``fort.78``
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
----------
|
|
33
|
+
handler : Fort78Handler
|
|
34
|
+
Parsed ``fort.78`` handler.
|
|
35
|
+
variables : str or sequence of str
|
|
36
|
+
Field variable name(s) to extract. Aliases are supported
|
|
37
|
+
(e.g. ``E_field_z``, ``field_z``). Output columns are named
|
|
38
|
+
exactly as requested.
|
|
39
|
+
|
|
40
|
+
Returns
|
|
41
|
+
-------
|
|
42
|
+
pandas.DataFrame
|
|
43
|
+
Table with columns ``["iter", <variables...>]`` where
|
|
44
|
+
``<variables>`` correspond to the requested names.
|
|
45
|
+
|
|
46
|
+
Examples
|
|
47
|
+
--------
|
|
48
|
+
>>> from reaxkit.io.handlers.fort78_handler import Fort78Handler
|
|
49
|
+
>>> from reaxkit.analysis.per_file.fort78_analyzer import get_fort78_data
|
|
50
|
+
>>> h = Fort78Handler("fort.78")
|
|
51
|
+
>>> df = get_fort78_data(h, variables=["E_field_z", "E_field_x"])
|
|
52
|
+
"""
|
|
53
|
+
df = handler.dataframe()
|
|
54
|
+
cols = list(df.columns)
|
|
55
|
+
|
|
56
|
+
if isinstance(variables, str):
|
|
57
|
+
variables = [variables]
|
|
58
|
+
|
|
59
|
+
# Resolve iter, then always expose as 'iter'
|
|
60
|
+
iter_hit = resolve_alias_from_columns(cols, "iter", load_default_alias_map())
|
|
61
|
+
if iter_hit is None:
|
|
62
|
+
raise KeyError(f"'iter' column not found. Available: {cols}")
|
|
63
|
+
|
|
64
|
+
out = df[[iter_hit]].copy()
|
|
65
|
+
if iter_hit != "iter":
|
|
66
|
+
out = out.rename(columns={iter_hit: "iter"})
|
|
67
|
+
|
|
68
|
+
# Resolve and rename each requested var to the *requested name*
|
|
69
|
+
for var in variables:
|
|
70
|
+
hit = resolve_alias_from_columns(cols, var, load_default_alias_map())
|
|
71
|
+
if hit is None:
|
|
72
|
+
raise KeyError(f"Variable '{var}' not found. Available: {cols}")
|
|
73
|
+
# attach numeric-ified column using the requested alias name
|
|
74
|
+
ser = pd.to_numeric(df[hit], errors="coerce")
|
|
75
|
+
out[var] = ser
|
|
76
|
+
|
|
77
|
+
# Ensure iter is numeric/int
|
|
78
|
+
out["iter"] = pd.to_numeric(out["iter"], errors="coerce").astype("Int64")
|
|
79
|
+
out = out.dropna(subset=["iter"])
|
|
80
|
+
out["iter"] = out["iter"].astype(int)
|
|
81
|
+
|
|
82
|
+
return out
|
|
83
|
+
|
|
84
|
+
# ----------------------------------------------------------------------------------------
|
|
85
|
+
# matching electric fields data to iout2, which is used to get plots of summary,
|
|
86
|
+
# xmolout, polarization, or etc. along with electric field profile
|
|
87
|
+
# ----------------------------------------------------------------------------------------
|
|
88
|
+
|
|
89
|
+
def match_electric_field_to_iout2(
|
|
90
|
+
f78: Fort78Handler,
|
|
91
|
+
ctrl: ControlHandler,
|
|
92
|
+
target_iters: Sequence[int],
|
|
93
|
+
field_var: str = "E_field_z",
|
|
94
|
+
) -> pd.Series:
|
|
95
|
+
"""
|
|
96
|
+
Match electric-field values from ``fort.78`` to target iterations.
|
|
97
|
+
|
|
98
|
+
The matching follows a piecewise-constant rule:
|
|
99
|
+
for each target iteration, the last available fort.78 value with
|
|
100
|
+
``iter <= target_iter`` is used. By convention, ``iter = 0`` maps to 0.0.
|
|
101
|
+
|
|
102
|
+
Works on
|
|
103
|
+
--------
|
|
104
|
+
Fort78Handler + ControlHandler — ``fort.78`` + ``control``
|
|
105
|
+
|
|
106
|
+
Parameters
|
|
107
|
+
----------
|
|
108
|
+
f78 : Fort78Handler
|
|
109
|
+
Parsed ``fort.78`` handler providing the field schedule.
|
|
110
|
+
ctrl : ControlHandler
|
|
111
|
+
Parsed control handler (used to access ``iout2`` for consistency).
|
|
112
|
+
target_iters : sequence of int
|
|
113
|
+
Iteration numbers to which the electric field should be matched.
|
|
114
|
+
field_var : str, default="E_field_z"
|
|
115
|
+
Electric-field component to use (aliases supported).
|
|
116
|
+
|
|
117
|
+
Returns
|
|
118
|
+
-------
|
|
119
|
+
pandas.Series
|
|
120
|
+
Series indexed by ``target_iters`` containing matched electric-field
|
|
121
|
+
values (same units as ``fort.78``, typically V/Å).
|
|
122
|
+
|
|
123
|
+
Examples
|
|
124
|
+
--------
|
|
125
|
+
>>> field = match_electric_field_to_iout2(
|
|
126
|
+
... f78, ctrl, target_iters=[0, 80, 160], field_var="E_field_z"
|
|
127
|
+
... )
|
|
128
|
+
"""
|
|
129
|
+
# Access iout2 from control (not strictly needed for the matching logic,
|
|
130
|
+
# but useful for consistency/sanity checks with xmolout/summary output rate).
|
|
131
|
+
iout2 = get_control_data(ctrl, "iout2", section="md", default=1)
|
|
132
|
+
_ = iout2 # currently not used explicitly, but kept for future use/logging
|
|
133
|
+
|
|
134
|
+
df_E = get_fort78_data(f78, variables=field_var) # columns: ['iter', field_var]
|
|
135
|
+
if df_E.empty:
|
|
136
|
+
raise ValueError("fort.78 has no usable data.")
|
|
137
|
+
|
|
138
|
+
df_E = df_E.sort_values("iter").reset_index(drop=True)
|
|
139
|
+
mapping = pd.Series(df_E[field_var].values, index=df_E["iter"].values)
|
|
140
|
+
sorted_iters = list(mapping.index)
|
|
141
|
+
|
|
142
|
+
out_vals = []
|
|
143
|
+
for it in target_iters:
|
|
144
|
+
it = int(it)
|
|
145
|
+
if it == 0:
|
|
146
|
+
out_vals.append(0.0)
|
|
147
|
+
continue
|
|
148
|
+
# all fort.78 iters <= this iter
|
|
149
|
+
valid = [f for f in sorted_iters if f <= it]
|
|
150
|
+
if not valid:
|
|
151
|
+
raise ValueError(f"No fort.78 iteration ≤ {it}")
|
|
152
|
+
out_vals.append(float(mapping[max(valid)]))
|
|
153
|
+
|
|
154
|
+
return pd.Series(out_vals, index=list(target_iters), name=field_var)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""
|
|
2
|
+
fort.79 (parameter sensitivity) analysis utilities.
|
|
3
|
+
|
|
4
|
+
This module provides helpers for analyzing force-field parameter
|
|
5
|
+
sensitivity information written by ReaxFF into ``fort.79`` files
|
|
6
|
+
via ``Fort79Handler``.
|
|
7
|
+
|
|
8
|
+
Typical use cases include:
|
|
9
|
+
|
|
10
|
+
- computing relative sensitivities of force-field error to parameter changes
|
|
11
|
+
- identifying parameters with the strongest impact on total error
|
|
12
|
+
- post-processing sensitivity tables for ranking or visualization
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
import pandas as pd
|
|
17
|
+
from reaxkit.io.handlers.fort79_handler import Fort79Handler
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_fort79_data_with_diff_sensitivities(handler: Fort79Handler) -> pd.DataFrame:
|
|
21
|
+
"""
|
|
22
|
+
Compute relative force-field error sensitivities from a ``fort.79`` file.
|
|
23
|
+
|
|
24
|
+
Sensitivities are computed by normalizing ``diff1``, ``diff2``, and
|
|
25
|
+
(optionally) ``diff4`` by ``diff3``, which represents the error obtained
|
|
26
|
+
using the current value of each parameter.
|
|
27
|
+
|
|
28
|
+
Works on
|
|
29
|
+
--------
|
|
30
|
+
Fort79Handler — ``fort.79``
|
|
31
|
+
|
|
32
|
+
Parameters
|
|
33
|
+
----------
|
|
34
|
+
handler : Fort79Handler
|
|
35
|
+
Parsed ``fort.79`` handler containing sensitivity data.
|
|
36
|
+
|
|
37
|
+
Returns
|
|
38
|
+
-------
|
|
39
|
+
pandas.DataFrame
|
|
40
|
+
Sensitivity table with columns:
|
|
41
|
+
- ``identifier``: parameter identifier
|
|
42
|
+
- ``sensitivity1/3``: ``diff1 / diff3``
|
|
43
|
+
- ``sensitivity2/3``: ``diff2 / diff3``
|
|
44
|
+
- ``sensitivity4/3``: ``diff4 / diff3`` (NaN if ``diff4`` is absent)
|
|
45
|
+
- ``min_sensitivity``: minimum sensitivity across available diffs
|
|
46
|
+
- ``max_sensitivity``: maximum sensitivity across available diffs
|
|
47
|
+
|
|
48
|
+
Examples
|
|
49
|
+
--------
|
|
50
|
+
>>> from reaxkit.io.handlers.fort79_handler import Fort79Handler
|
|
51
|
+
>>> from reaxkit.analysis.per_file.fort79_analyzer import get_fort79_data_with_diff_sensitivities
|
|
52
|
+
>>> h = Fort79Handler("fort.79")
|
|
53
|
+
>>> df = get_fort79_data_with_diff_sensitivities(h)
|
|
54
|
+
"""
|
|
55
|
+
df = handler.dataframe() if hasattr(handler, "dataframe") else handler._parse()[0]
|
|
56
|
+
|
|
57
|
+
# ensure numeric and safe division
|
|
58
|
+
result = pd.DataFrame()
|
|
59
|
+
|
|
60
|
+
result['identider'] = df['identifier']
|
|
61
|
+
|
|
62
|
+
if "diff1" in df and "diff3" in df:
|
|
63
|
+
result["sensitivity1/3"] = df["diff1"] / df["diff3"]
|
|
64
|
+
else:
|
|
65
|
+
result["sensitivity1/3"] = pd.Series(dtype=float)
|
|
66
|
+
|
|
67
|
+
if "diff2" in df and "diff3" in df:
|
|
68
|
+
result["sensitivity2/3"] = df["diff2"] / df["diff3"]
|
|
69
|
+
else:
|
|
70
|
+
result["sensitivity2/3"] = pd.Series(dtype=float)
|
|
71
|
+
|
|
72
|
+
# optional diff4 handling
|
|
73
|
+
if "diff4" in df and "diff3" in df:
|
|
74
|
+
result["sensitivity4/3"] = df["diff4"] / df["diff3"]
|
|
75
|
+
else:
|
|
76
|
+
result["sensitivity4/3"] = pd.Series([float("nan")] * len(result))
|
|
77
|
+
|
|
78
|
+
result["min_sensitivity"] = result[["sensitivity1/3", "sensitivity2/3", "sensitivity4/3"]].min(axis=1)
|
|
79
|
+
result["max_sensitivity"] = result[["sensitivity1/3", "sensitivity2/3", "sensitivity4/3"]].max(axis=1)
|
|
80
|
+
|
|
81
|
+
return result
|
|
82
|
+
|
|
83
|
+
|