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,151 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Energy-output workflow for ReaxKit (fort.73 / energylog / fort.58).
|
|
3
|
+
|
|
4
|
+
This workflow provides tools for reading, visualizing, and exporting energy
|
|
5
|
+
and thermodynamic data produced by ReaxFF simulations, as stored in
|
|
6
|
+
`fort.73`, `energylog`, or `fort.58` files.
|
|
7
|
+
|
|
8
|
+
It supports:
|
|
9
|
+
- Extracting individual or all available energy terms (e.g. Ebond, Eangle,
|
|
10
|
+
Etot) as functions of iteration, frame index, or physical time.
|
|
11
|
+
- Converting the x-axis between iteration, frame, and time using the
|
|
12
|
+
associated control file.
|
|
13
|
+
- Plotting selected energy components or saving them as image files.
|
|
14
|
+
- Exporting energy data to CSV for downstream analysis or comparison
|
|
15
|
+
across simulation runs.
|
|
16
|
+
|
|
17
|
+
The workflow is designed for rapid inspection of ReaxFF energy evolution,
|
|
18
|
+
stability, and convergence behavior.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import argparse, os
|
|
25
|
+
import pandas as pd
|
|
26
|
+
|
|
27
|
+
from reaxkit.io.handlers.fort73_handler import Fort73Handler
|
|
28
|
+
from reaxkit.analysis.per_file.fort73_analyzer import get_fort73_data
|
|
29
|
+
from reaxkit.utils.media.convert import convert_xaxis
|
|
30
|
+
from reaxkit.utils.media.plotter import single_plot
|
|
31
|
+
from reaxkit.utils.path import resolve_output_path
|
|
32
|
+
|
|
33
|
+
def _fort73_get_task(args: argparse.Namespace) -> int:
|
|
34
|
+
DEFAULT_FILES = {
|
|
35
|
+
"fort73": "fort.73",
|
|
36
|
+
"energylog": "energylog",
|
|
37
|
+
"fort58": "fort.58",
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
default_file = DEFAULT_FILES.get(args.kind, "fort.73")
|
|
41
|
+
|
|
42
|
+
file_path = args.file or default_file
|
|
43
|
+
|
|
44
|
+
handler = Fort73Handler(file_path)
|
|
45
|
+
df = get_fort73_data(handler)
|
|
46
|
+
|
|
47
|
+
if "iter" not in df.columns:
|
|
48
|
+
raise KeyError("Column 'iter' not found in fort.73 DataFrame.")
|
|
49
|
+
|
|
50
|
+
# --- X-axis conversion ---
|
|
51
|
+
iters = df["iter"].to_numpy()
|
|
52
|
+
x_vals, x_label = convert_xaxis(iters, args.xaxis, control_file=args.control)
|
|
53
|
+
|
|
54
|
+
# --- Y columns selection ---
|
|
55
|
+
if args.yaxis.lower() == "all":
|
|
56
|
+
y_cols = [c for c in df.columns if c != "iter"]
|
|
57
|
+
if not y_cols:
|
|
58
|
+
raise ValueError("No energy columns found in fort.73 DataFrame.")
|
|
59
|
+
else:
|
|
60
|
+
if args.yaxis not in df.columns:
|
|
61
|
+
raise KeyError(f"Requested y-axis column '{args.yaxis}' not found in fort.73 DataFrame.")
|
|
62
|
+
y_cols = [args.yaxis]
|
|
63
|
+
|
|
64
|
+
workflow_name = args.kind
|
|
65
|
+
|
|
66
|
+
# --- Export CSV (optional, data only) ---
|
|
67
|
+
if args.export:
|
|
68
|
+
out = resolve_output_path(args.export, workflow_name)
|
|
69
|
+
export_df = pd.DataFrame({"x": x_vals})
|
|
70
|
+
for col in y_cols:
|
|
71
|
+
export_df[col] = df[col].values
|
|
72
|
+
export_df.to_csv(out, index=False)
|
|
73
|
+
print(f"[Done] Exported fort.73 data to {out}")
|
|
74
|
+
|
|
75
|
+
# --- Plot / Save (independent flags) ---
|
|
76
|
+
if args.plot or args.save:
|
|
77
|
+
save_base = None
|
|
78
|
+
base_is_dir = False
|
|
79
|
+
|
|
80
|
+
if args.save:
|
|
81
|
+
# Resolve to reaxkit_out/... using same helper as export
|
|
82
|
+
save_base = resolve_output_path(args.save, workflow_name)
|
|
83
|
+
|
|
84
|
+
# Decide if save_base acts like a directory or a file
|
|
85
|
+
if len(y_cols) > 1:
|
|
86
|
+
# Multiple columns → treat as directory unless clearly a file name
|
|
87
|
+
base_is_dir = os.path.isdir(save_base) or "." not in os.path.basename(save_base)
|
|
88
|
+
else:
|
|
89
|
+
base_is_dir = os.path.isdir(save_base)
|
|
90
|
+
|
|
91
|
+
if base_is_dir:
|
|
92
|
+
os.makedirs(save_base, exist_ok=True)
|
|
93
|
+
else:
|
|
94
|
+
parent = os.path.dirname(save_base)
|
|
95
|
+
if parent:
|
|
96
|
+
os.makedirs(parent, exist_ok=True)
|
|
97
|
+
|
|
98
|
+
for col in y_cols:
|
|
99
|
+
y = df[col].values
|
|
100
|
+
|
|
101
|
+
# Decide per-column save path (or None)
|
|
102
|
+
save_path = None
|
|
103
|
+
if save_base:
|
|
104
|
+
if len(y_cols) == 1:
|
|
105
|
+
# Single column: allow explicit filename or directory
|
|
106
|
+
if base_is_dir:
|
|
107
|
+
save_path = os.path.join(save_base, f"{col}.png")
|
|
108
|
+
else:
|
|
109
|
+
save_path = save_base
|
|
110
|
+
else:
|
|
111
|
+
# Multiple columns: directory or filename with suffix
|
|
112
|
+
if base_is_dir:
|
|
113
|
+
save_path = os.path.join(save_base, f"{col}.png")
|
|
114
|
+
else:
|
|
115
|
+
root, ext = os.path.splitext(save_base)
|
|
116
|
+
if not ext:
|
|
117
|
+
ext = ".png"
|
|
118
|
+
save_path = f"{root}_{col}{ext}"
|
|
119
|
+
|
|
120
|
+
# single_plot handles both “show only” (save=None) and “save to file”
|
|
121
|
+
single_plot(
|
|
122
|
+
x_vals,
|
|
123
|
+
y,
|
|
124
|
+
title=f"{col} vs {x_label}",
|
|
125
|
+
xlabel=x_label,
|
|
126
|
+
ylabel=f"{col} (kcal/mole)",
|
|
127
|
+
save=save_path,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
return 0
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def register_tasks(subparsers: argparse._SubParsersAction) -> None:
|
|
134
|
+
p_get = subparsers.add_parser(
|
|
135
|
+
"get",
|
|
136
|
+
help="Extract and plot energy data from fort.73\n",
|
|
137
|
+
description=(
|
|
138
|
+
"Examples:\n"
|
|
139
|
+
" reaxkit fort73 get --yaxis Ebond --xaxis time --plot \n"
|
|
140
|
+
" reaxkit fort73 get --yaxis all --xaxis time --save reaxkit_outputs/fort73/ \n"
|
|
141
|
+
),
|
|
142
|
+
formatter_class=argparse.RawTextHelpFormatter,
|
|
143
|
+
)
|
|
144
|
+
p_get.add_argument("--file", default=None, help="Path to fort.73 / energylog file")
|
|
145
|
+
p_get.add_argument("--yaxis", required=True, help="Energy column (e.g. Ebond) or 'all'")
|
|
146
|
+
p_get.add_argument("--xaxis", default="iter", choices=["iter", "frame", "time"], help="X-axis type")
|
|
147
|
+
p_get.add_argument("--control", default="control", help="Control file (used when xaxis=time)")
|
|
148
|
+
p_get.add_argument("--export", default=None, help="Path to export CSV (x + selected y columns)")
|
|
149
|
+
p_get.add_argument("--save", default=None, help="Path to save plot image (suffix _<col> if yaxis=all)")
|
|
150
|
+
p_get.add_argument("--plot", action="store_true", help="If set, generate plot(s).")
|
|
151
|
+
p_get.set_defaults(_run=_fort73_get_task)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""
|
|
2
|
+
fort.74 summary-table workflow for ReaxKit.
|
|
3
|
+
|
|
4
|
+
This workflow provides utilities for reading and exporting data from ReaxFF
|
|
5
|
+
`fort.74` files, which contain per-structure or per-configuration summary
|
|
6
|
+
quantities produced during force-field training or evaluation runs.
|
|
7
|
+
|
|
8
|
+
It supports:
|
|
9
|
+
- Exporting all available columns from a `fort.74` file to CSV.
|
|
10
|
+
- Selecting and exporting a single column (with optional alias resolution,
|
|
11
|
+
e.g. `Density` → `D`) while always preserving the structure identifier.
|
|
12
|
+
- Writing outputs to a standardized ReaxKit output directory for
|
|
13
|
+
reproducible data organization.
|
|
14
|
+
|
|
15
|
+
The workflow is designed for lightweight inspection and downstream analysis
|
|
16
|
+
of ReaxFF summary metrics such as energies, volumes, and densities.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import argparse
|
|
22
|
+
|
|
23
|
+
from reaxkit.io.handlers.fort74_handler import Fort74Handler
|
|
24
|
+
from reaxkit.analysis.per_file.fort74_analyzer import get_fort74_data
|
|
25
|
+
from reaxkit.utils.path import resolve_output_path
|
|
26
|
+
from reaxkit.utils.alias import normalize_choice, resolve_alias_from_columns
|
|
27
|
+
|
|
28
|
+
def _get_task(args: argparse.Namespace) -> int:
|
|
29
|
+
handler = Fort74Handler(args.file)
|
|
30
|
+
df = get_fort74_data(handler)
|
|
31
|
+
|
|
32
|
+
col_raw = (args.col or "all").strip()
|
|
33
|
+
|
|
34
|
+
if col_raw != "all":
|
|
35
|
+
canonical = normalize_choice(col_raw) # e.g., "Density" -> "D"
|
|
36
|
+
resolved = resolve_alias_from_columns(df.columns, canonical)
|
|
37
|
+
if resolved is None:
|
|
38
|
+
raise SystemExit(
|
|
39
|
+
f"❌ Column '{col_raw}' not found (and no alias matched). "
|
|
40
|
+
f"Available: {', '.join(df.columns)}"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
cols = []
|
|
44
|
+
if "identifier" in df.columns:
|
|
45
|
+
cols.append("identifier")
|
|
46
|
+
if resolved != "identifier":
|
|
47
|
+
cols.append(resolved)
|
|
48
|
+
|
|
49
|
+
out_df = df[cols].copy()
|
|
50
|
+
|
|
51
|
+
# Optional: make exported header match what user asked for
|
|
52
|
+
if resolved != col_raw:
|
|
53
|
+
out_df = out_df.rename(columns={resolved: col_raw})
|
|
54
|
+
else:
|
|
55
|
+
out_df = df
|
|
56
|
+
|
|
57
|
+
out_path = resolve_output_path(args.export, workflow="fort74.md")
|
|
58
|
+
out_df.to_csv(out_path, index=False)
|
|
59
|
+
print(f"[Done] Successfully exported the requested data to {out_path}")
|
|
60
|
+
return 0
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def register_tasks(subparsers: argparse._SubParsersAction) -> None:
|
|
66
|
+
p = subparsers.add_parser(
|
|
67
|
+
"get",
|
|
68
|
+
help="Export one column or all columns from fort.74 to CSV.",
|
|
69
|
+
description=(
|
|
70
|
+
"Examples:\n"
|
|
71
|
+
" reaxkit fort74.md get --export fort74_all_data.csv\n"
|
|
72
|
+
" reaxkit fort74.md get --col Emin --export fort74_all_Emin_data.csv\n"
|
|
73
|
+
),
|
|
74
|
+
formatter_class=argparse.RawTextHelpFormatter,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
p.add_argument("--file", default="fort.74", help="Path to fort.74 file.")
|
|
78
|
+
p.add_argument("--col", default="all", help="Column to export, or 'all'.")
|
|
79
|
+
p.add_argument(
|
|
80
|
+
"--export",
|
|
81
|
+
required=True,
|
|
82
|
+
help=(
|
|
83
|
+
"CSV output path. If a bare filename is given, it will be saved under "
|
|
84
|
+
"reaxkit_outputs/fort74.md/ (via path.resolve_output_path)."
|
|
85
|
+
),
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
p.set_defaults(_run=_get_task)
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"""
|
|
2
|
+
fort.76 restraint-analysis workflow for ReaxKit.
|
|
3
|
+
|
|
4
|
+
This workflow provides tools for reading, visualizing, and exporting data from
|
|
5
|
+
ReaxFF `fort.76` files, which record restraint targets and actual values during
|
|
6
|
+
MD or minimization runs.
|
|
7
|
+
|
|
8
|
+
It supports:
|
|
9
|
+
- Extracting and plotting a single restraint-related column versus iteration,
|
|
10
|
+
frame index, or physical time.
|
|
11
|
+
- Comparing restraint target and actual values for a selected restraint index
|
|
12
|
+
as a function of iteration, frame, or time.
|
|
13
|
+
- Converting the x-axis between iteration, frame, and time using the associated
|
|
14
|
+
control file.
|
|
15
|
+
- Saving plots to disk or exporting data to CSV using standardized output paths.
|
|
16
|
+
|
|
17
|
+
The workflow is intended for diagnosing restraint behavior, convergence, and
|
|
18
|
+
stability in constrained ReaxFF simulations.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import argparse
|
|
25
|
+
|
|
26
|
+
import pandas as pd
|
|
27
|
+
|
|
28
|
+
from reaxkit.io.handlers.fort76_handler import Fort76Handler
|
|
29
|
+
from reaxkit.analysis.per_file.fort76_analyzer import get_fort76_data, get_fort76_restraint_pairs
|
|
30
|
+
from reaxkit.utils.media.convert import convert_xaxis
|
|
31
|
+
from reaxkit.utils.media.plotter import single_plot
|
|
32
|
+
from reaxkit.utils.path import resolve_output_path
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _fort76_get_task(args: argparse.Namespace) -> int:
|
|
36
|
+
"""
|
|
37
|
+
Handle: reaxkit fort76 get ...
|
|
38
|
+
Plot/save/export ONE column vs iter/frame/time (derived from iter).
|
|
39
|
+
"""
|
|
40
|
+
handler = Fort76Handler(args.file)
|
|
41
|
+
handler._parse()
|
|
42
|
+
|
|
43
|
+
df = get_fort76_data(handler, ["iter", args.ycol], dropna_rows=True).copy()
|
|
44
|
+
|
|
45
|
+
xvals, xlabel = convert_xaxis(df["iter"].to_numpy(), args.xaxis, control_file=args.control)
|
|
46
|
+
x = pd.Series(xvals)
|
|
47
|
+
|
|
48
|
+
y_name = df.columns[1]
|
|
49
|
+
y = df[y_name]
|
|
50
|
+
|
|
51
|
+
workflow_name = args.kind # same pattern as fort13_workflow :contentReference[oaicite:4]{index=4}
|
|
52
|
+
|
|
53
|
+
# Export
|
|
54
|
+
if args.export:
|
|
55
|
+
out = resolve_output_path(args.export, workflow_name)
|
|
56
|
+
pd.DataFrame({xlabel: x, y_name: y}).to_csv(out, index=False)
|
|
57
|
+
print(f"[Done] Exported data to {out}.")
|
|
58
|
+
|
|
59
|
+
# Plot / Save
|
|
60
|
+
if args.plot:
|
|
61
|
+
single_plot(
|
|
62
|
+
x=x,
|
|
63
|
+
y=y,
|
|
64
|
+
title=args.title or f"{y_name} vs {args.xaxis}",
|
|
65
|
+
xlabel=args.xlabel or xlabel,
|
|
66
|
+
ylabel=args.ylabel or y_name,
|
|
67
|
+
save=None,
|
|
68
|
+
)
|
|
69
|
+
elif args.save:
|
|
70
|
+
out = resolve_output_path(args.save, workflow_name)
|
|
71
|
+
single_plot(
|
|
72
|
+
x=x,
|
|
73
|
+
y=y,
|
|
74
|
+
title=args.title or f"{y_name} vs {args.xaxis}",
|
|
75
|
+
xlabel=args.xlabel or xlabel,
|
|
76
|
+
ylabel=args.ylabel or y_name,
|
|
77
|
+
save=out,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
if not (args.plot or args.save or args.export):
|
|
81
|
+
print("ℹ️ Nothing to do. Use --plot, --save <path>, --export <csv>.")
|
|
82
|
+
return 0
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _fort76_respair_task(args: argparse.Namespace) -> int:
|
|
86
|
+
"""
|
|
87
|
+
Handle: reaxkit fort76 respair ...
|
|
88
|
+
Plot/save/export restraint target+actual vs iter/frame/time.
|
|
89
|
+
"""
|
|
90
|
+
handler = Fort76Handler(args.file)
|
|
91
|
+
handler._parse()
|
|
92
|
+
|
|
93
|
+
df = get_fort76_restraint_pairs(handler, args.restraint, include_iter=True).copy()
|
|
94
|
+
target_col = df.columns[1]
|
|
95
|
+
actual_col = df.columns[2]
|
|
96
|
+
|
|
97
|
+
xvals, xlabel = convert_xaxis(df["iter"].to_numpy(), args.xaxis, control_file=args.control)
|
|
98
|
+
x = pd.Series(xvals)
|
|
99
|
+
|
|
100
|
+
workflow_name = args.kind
|
|
101
|
+
|
|
102
|
+
# Export
|
|
103
|
+
if args.export:
|
|
104
|
+
out = resolve_output_path(args.export, workflow_name)
|
|
105
|
+
pd.DataFrame(
|
|
106
|
+
{xlabel: x, target_col: df[target_col], actual_col: df[actual_col]}
|
|
107
|
+
).to_csv(out, index=False)
|
|
108
|
+
print(f"Successfully exported data to {out}.")
|
|
109
|
+
|
|
110
|
+
# Plot / Save
|
|
111
|
+
if args.plot:
|
|
112
|
+
single_plot(
|
|
113
|
+
series=[
|
|
114
|
+
{"x": x, "y": df[target_col], "label": target_col},
|
|
115
|
+
{"x": x, "y": df[actual_col], "label": actual_col},
|
|
116
|
+
],
|
|
117
|
+
title=args.title or f"Restraint {args.restraint}: target vs actual ({args.xaxis})",
|
|
118
|
+
xlabel=args.xlabel or xlabel,
|
|
119
|
+
ylabel=args.ylabel or "Value",
|
|
120
|
+
legend=True,
|
|
121
|
+
save=None,
|
|
122
|
+
)
|
|
123
|
+
elif args.save:
|
|
124
|
+
out = resolve_output_path(args.save, workflow_name)
|
|
125
|
+
single_plot(
|
|
126
|
+
series=[
|
|
127
|
+
{"x": x, "y": df[target_col], "label": target_col},
|
|
128
|
+
{"x": x, "y": df[actual_col], "label": actual_col},
|
|
129
|
+
],
|
|
130
|
+
title=args.title or f"Restraint {args.restraint}: target vs actual ({args.xaxis})",
|
|
131
|
+
xlabel=args.xlabel or xlabel,
|
|
132
|
+
ylabel=args.ylabel or "Value",
|
|
133
|
+
legend=True,
|
|
134
|
+
save=out,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
if not (args.plot or args.save or args.export):
|
|
138
|
+
print("ℹ️ Nothing to do. Use --plot, --save <path>, --export <csv>.")
|
|
139
|
+
return 0
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _add_common_fort76_io_args(
|
|
143
|
+
p: argparse.ArgumentParser,
|
|
144
|
+
*,
|
|
145
|
+
include_plot: bool = False,
|
|
146
|
+
) -> None:
|
|
147
|
+
p.add_argument("--file", default="fort.76", help="Path to fort.76 file.")
|
|
148
|
+
p.add_argument("--xaxis", default="iter", choices=["iter", "frame", "time"])
|
|
149
|
+
p.add_argument("--control", default="control", help="Needed for --xaxis time.")
|
|
150
|
+
if include_plot:
|
|
151
|
+
p.add_argument("--plot", action="store_true", help="Show plot interactively.")
|
|
152
|
+
p.add_argument("--save", default=None, help="Path to save plot image.")
|
|
153
|
+
p.add_argument("--export", default=None, help="Path to export CSV data.")
|
|
154
|
+
p.add_argument("--title", default=None)
|
|
155
|
+
p.add_argument("--xlabel", default=None)
|
|
156
|
+
p.add_argument("--ylabel", default=None)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def register_tasks(subparsers: argparse._SubParsersAction) -> None:
|
|
160
|
+
# --- get ---
|
|
161
|
+
p = subparsers.add_parser(
|
|
162
|
+
"get",
|
|
163
|
+
help="Plot, export, or save one fort.76 column vs iter/frame/time.\n",
|
|
164
|
+
description=(
|
|
165
|
+
"Examples:\n"
|
|
166
|
+
" reaxkit fort76 get --ycol E_res --xaxis time --save E_res_vs_time.png\n"
|
|
167
|
+
" reaxkit fort76 get --ycol r1_actual --xaxis frame --export r1_actual_vs_frame.csv\n"
|
|
168
|
+
),
|
|
169
|
+
formatter_class=argparse.RawTextHelpFormatter,
|
|
170
|
+
)
|
|
171
|
+
_add_common_fort76_io_args(p, include_plot=True)
|
|
172
|
+
p.add_argument("--ycol", required=True, help="Column to plot/export (aliases allowed).")
|
|
173
|
+
p.set_defaults(_run=_fort76_get_task)
|
|
174
|
+
|
|
175
|
+
# --- respair ---
|
|
176
|
+
p2 = subparsers.add_parser(
|
|
177
|
+
"respair",
|
|
178
|
+
help="Plot, export, or save restraint target+actual vs iter/frame/time.\n",
|
|
179
|
+
description=(
|
|
180
|
+
"Examples:\n"
|
|
181
|
+
" reaxkit fort76 respair --restraint 2 --xaxis time --control control --save r2_vs_time.png\n"
|
|
182
|
+
),
|
|
183
|
+
formatter_class=argparse.RawTextHelpFormatter,
|
|
184
|
+
)
|
|
185
|
+
_add_common_fort76_io_args(p2, include_plot=True)
|
|
186
|
+
p2.add_argument("--restraint", type=int, required=True, help="Restraint index (1-based).")
|
|
187
|
+
p2.set_defaults(_run=_fort76_respair_task)
|
|
188
|
+
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""
|
|
2
|
+
fort.78 electric-field output workflow for ReaxKit.
|
|
3
|
+
|
|
4
|
+
This workflow provides tools for reading, visualizing, and exporting data from
|
|
5
|
+
ReaxFF `fort.78` files, which record time-dependent electric-field–related
|
|
6
|
+
quantities during simulations with applied external fields.
|
|
7
|
+
|
|
8
|
+
It supports:
|
|
9
|
+
- Extracting a single electric-field or related scalar component (e.g.
|
|
10
|
+
`E_field_x`) as a function of iteration, frame index, or physical time.
|
|
11
|
+
- Converting the x-axis between iteration, frame, and time using the associated
|
|
12
|
+
control file when required.
|
|
13
|
+
- Plotting the selected quantity, saving figures to disk, or exporting the data
|
|
14
|
+
to CSV using standardized output paths.
|
|
15
|
+
|
|
16
|
+
The workflow is intended for analysis of electric-field protocols, field-driven
|
|
17
|
+
responses, and post-processing of ReaxFF simulations involving external fields.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
import argparse
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from reaxkit.utils.units import unit_for
|
|
24
|
+
from reaxkit.io.handlers.fort78_handler import Fort78Handler
|
|
25
|
+
from reaxkit.analysis.per_file.fort78_analyzer import get_fort78_data
|
|
26
|
+
from reaxkit.utils.media.plotter import single_plot
|
|
27
|
+
from reaxkit.utils.media.convert import convert_xaxis
|
|
28
|
+
from reaxkit.utils.path import resolve_output_path
|
|
29
|
+
|
|
30
|
+
def _export_csv(x, x_label: str, y, y_label: str, path: str) -> None:
|
|
31
|
+
import pandas as pd
|
|
32
|
+
df = pd.DataFrame({x_label: x, y_label: y})
|
|
33
|
+
out = Path(path)
|
|
34
|
+
out.parent.mkdir(parents=True, exist_ok=True)
|
|
35
|
+
df.to_csv(out, index=False)
|
|
36
|
+
print(f"[Done] exported data to {out}")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _get_task(args: argparse.Namespace) -> int:
|
|
40
|
+
"""
|
|
41
|
+
Get/plot/export a single yaxis from fort.78 vs iter/frame/time.
|
|
42
|
+
"""
|
|
43
|
+
handler = Fort78Handler(args.file)
|
|
44
|
+
|
|
45
|
+
# Pull requested yaxis from fort.78 summary.
|
|
46
|
+
# Analyzer will *rename* the output yaxis to the *requested alias*.
|
|
47
|
+
ykey: str = args.yaxis.strip()
|
|
48
|
+
df = get_fort78_data(handler, [ykey]) # DataFrame: columns ['iter', ykey]
|
|
49
|
+
|
|
50
|
+
if ykey not in df.columns:
|
|
51
|
+
raise KeyError(f"❌ yaxis '{ykey}' not found in fort.78 data.")
|
|
52
|
+
|
|
53
|
+
# Select and sanitize x/y
|
|
54
|
+
import pandas as pd
|
|
55
|
+
iters = pd.to_numeric(df["iter"], errors="coerce")
|
|
56
|
+
iters = iters.dropna().to_numpy()
|
|
57
|
+
|
|
58
|
+
xvals, xlabel = convert_xaxis(iters, args.xaxis, control_file=args.control)
|
|
59
|
+
|
|
60
|
+
yvals = pd.to_numeric(df[ykey], errors="coerce").to_numpy()
|
|
61
|
+
|
|
62
|
+
workflow_name = args.kind
|
|
63
|
+
# Export CSV if requested
|
|
64
|
+
if args.export:
|
|
65
|
+
out = resolve_output_path(args.export, workflow_name)
|
|
66
|
+
_export_csv(xvals, xlabel, yvals, ykey, out)
|
|
67
|
+
|
|
68
|
+
# Plot and/or save plot
|
|
69
|
+
if args.plot or args.save:
|
|
70
|
+
# Ensure plain numeric arrays before plotting
|
|
71
|
+
import numpy as np
|
|
72
|
+
x_plot = np.asarray(xvals, dtype=float)
|
|
73
|
+
y_plot = np.asarray(yvals, dtype=float)
|
|
74
|
+
|
|
75
|
+
u = unit_for(args.yaxis) or unit_for(ykey)
|
|
76
|
+
if args.save:
|
|
77
|
+
out = resolve_output_path(args.save, workflow_name)
|
|
78
|
+
single_plot(
|
|
79
|
+
x=x_plot,
|
|
80
|
+
y=y_plot,
|
|
81
|
+
title=f"{ykey} vs {xlabel}",
|
|
82
|
+
xlabel=xlabel,
|
|
83
|
+
ylabel=f"{ykey} ({u})" if u else ykey,
|
|
84
|
+
save=out,
|
|
85
|
+
legend=False,
|
|
86
|
+
)
|
|
87
|
+
elif args.plot:
|
|
88
|
+
single_plot(
|
|
89
|
+
x=x_plot,
|
|
90
|
+
y=y_plot,
|
|
91
|
+
title=f"{ykey} vs {xlabel}",
|
|
92
|
+
xlabel=xlabel,
|
|
93
|
+
ylabel=f"{ykey} ({u})" if u else ykey,
|
|
94
|
+
legend=False,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# If neither plot nor export was requested, print a short tip
|
|
98
|
+
if not (args.plot or args.save or args.export or args.head):
|
|
99
|
+
print("ℹ️ Nothing plotted or exported. Use --plot, --save <path>, --export <csv>, or --head N to preview rows.")
|
|
100
|
+
|
|
101
|
+
return 0
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def register_tasks(subparsers: argparse._SubParsersAction) -> None:
|
|
105
|
+
"""
|
|
106
|
+
Register only one task under the already-created 'fort78' workflow:
|
|
107
|
+
reaxkit fort78 get ...
|
|
108
|
+
"""
|
|
109
|
+
g = subparsers.add_parser(
|
|
110
|
+
"get",
|
|
111
|
+
help="Get/plot/export a single yaxis from fort.78 vs iter/frame/time.\n",
|
|
112
|
+
description=(
|
|
113
|
+
"Examples:\n"
|
|
114
|
+
" reaxkit fort78 get --xaxis time --yaxis E_field_x --save E_field_x.png --export E_field_x.csv\n"
|
|
115
|
+
),
|
|
116
|
+
formatter_class=argparse.RawTextHelpFormatter,
|
|
117
|
+
)
|
|
118
|
+
g.add_argument("--file", default="fort.78", help="Path to fort.78 file")
|
|
119
|
+
g.add_argument("--yaxis",
|
|
120
|
+
required=True,
|
|
121
|
+
help="Name of the fort.78 yaxis to extract (e.g., 'E_field_x')",
|
|
122
|
+
)
|
|
123
|
+
g.add_argument("--xaxis",
|
|
124
|
+
choices=("iter", "frame", "time"), default="iter",
|
|
125
|
+
help="X-axis for plotting/export (default: iter). 'time' may require a control file.",
|
|
126
|
+
)
|
|
127
|
+
g.add_argument("--control", default="control",
|
|
128
|
+
help="Path to control file (only used when --xaxis time).",
|
|
129
|
+
)
|
|
130
|
+
# Output options
|
|
131
|
+
g.add_argument("--plot", action="store_true", help="Show a plot in a window")
|
|
132
|
+
g.add_argument("--save", default=None, help="Save plot to a path or directory")
|
|
133
|
+
g.add_argument("--export", default=None, help="Export data to CSV at this path")
|
|
134
|
+
|
|
135
|
+
g.set_defaults(_run=_get_task)
|