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.
Files changed (130) hide show
  1. reaxkit/__init__.py +0 -0
  2. reaxkit/analysis/__init__.py +0 -0
  3. reaxkit/analysis/composed/RDF_analyzer.py +560 -0
  4. reaxkit/analysis/composed/__init__.py +0 -0
  5. reaxkit/analysis/composed/connectivity_analyzer.py +706 -0
  6. reaxkit/analysis/composed/coordination_analyzer.py +144 -0
  7. reaxkit/analysis/composed/electrostatics_analyzer.py +687 -0
  8. reaxkit/analysis/per_file/__init__.py +0 -0
  9. reaxkit/analysis/per_file/control_analyzer.py +165 -0
  10. reaxkit/analysis/per_file/eregime_analyzer.py +108 -0
  11. reaxkit/analysis/per_file/ffield_analyzer.py +305 -0
  12. reaxkit/analysis/per_file/fort13_analyzer.py +79 -0
  13. reaxkit/analysis/per_file/fort57_analyzer.py +106 -0
  14. reaxkit/analysis/per_file/fort73_analyzer.py +61 -0
  15. reaxkit/analysis/per_file/fort74_analyzer.py +65 -0
  16. reaxkit/analysis/per_file/fort76_analyzer.py +191 -0
  17. reaxkit/analysis/per_file/fort78_analyzer.py +154 -0
  18. reaxkit/analysis/per_file/fort79_analyzer.py +83 -0
  19. reaxkit/analysis/per_file/fort7_analyzer.py +393 -0
  20. reaxkit/analysis/per_file/fort99_analyzer.py +411 -0
  21. reaxkit/analysis/per_file/molfra_analyzer.py +359 -0
  22. reaxkit/analysis/per_file/params_analyzer.py +258 -0
  23. reaxkit/analysis/per_file/summary_analyzer.py +84 -0
  24. reaxkit/analysis/per_file/trainset_analyzer.py +84 -0
  25. reaxkit/analysis/per_file/vels_analyzer.py +95 -0
  26. reaxkit/analysis/per_file/xmolout_analyzer.py +528 -0
  27. reaxkit/cli.py +181 -0
  28. reaxkit/count_loc.py +276 -0
  29. reaxkit/data/alias.yaml +89 -0
  30. reaxkit/data/constants.yaml +27 -0
  31. reaxkit/data/reaxff_input_files_contents.yaml +186 -0
  32. reaxkit/data/reaxff_output_files_contents.yaml +301 -0
  33. reaxkit/data/units.yaml +38 -0
  34. reaxkit/help/__init__.py +0 -0
  35. reaxkit/help/help_index_loader.py +531 -0
  36. reaxkit/help/introspection_utils.py +131 -0
  37. reaxkit/io/__init__.py +0 -0
  38. reaxkit/io/base_handler.py +165 -0
  39. reaxkit/io/generators/__init__.py +0 -0
  40. reaxkit/io/generators/control_generator.py +123 -0
  41. reaxkit/io/generators/eregime_generator.py +341 -0
  42. reaxkit/io/generators/geo_generator.py +967 -0
  43. reaxkit/io/generators/trainset_generator.py +1758 -0
  44. reaxkit/io/generators/tregime_generator.py +113 -0
  45. reaxkit/io/generators/vregime_generator.py +164 -0
  46. reaxkit/io/generators/xmolout_generator.py +304 -0
  47. reaxkit/io/handlers/__init__.py +0 -0
  48. reaxkit/io/handlers/control_handler.py +209 -0
  49. reaxkit/io/handlers/eregime_handler.py +122 -0
  50. reaxkit/io/handlers/ffield_handler.py +812 -0
  51. reaxkit/io/handlers/fort13_handler.py +123 -0
  52. reaxkit/io/handlers/fort57_handler.py +143 -0
  53. reaxkit/io/handlers/fort73_handler.py +145 -0
  54. reaxkit/io/handlers/fort74_handler.py +155 -0
  55. reaxkit/io/handlers/fort76_handler.py +195 -0
  56. reaxkit/io/handlers/fort78_handler.py +142 -0
  57. reaxkit/io/handlers/fort79_handler.py +227 -0
  58. reaxkit/io/handlers/fort7_handler.py +264 -0
  59. reaxkit/io/handlers/fort99_handler.py +128 -0
  60. reaxkit/io/handlers/geo_handler.py +224 -0
  61. reaxkit/io/handlers/molfra_handler.py +184 -0
  62. reaxkit/io/handlers/params_handler.py +137 -0
  63. reaxkit/io/handlers/summary_handler.py +135 -0
  64. reaxkit/io/handlers/trainset_handler.py +658 -0
  65. reaxkit/io/handlers/vels_handler.py +293 -0
  66. reaxkit/io/handlers/xmolout_handler.py +174 -0
  67. reaxkit/utils/__init__.py +0 -0
  68. reaxkit/utils/alias.py +219 -0
  69. reaxkit/utils/cache.py +77 -0
  70. reaxkit/utils/constants.py +75 -0
  71. reaxkit/utils/equation_of_states.py +96 -0
  72. reaxkit/utils/exceptions.py +27 -0
  73. reaxkit/utils/frame_utils.py +175 -0
  74. reaxkit/utils/log.py +43 -0
  75. reaxkit/utils/media/__init__.py +0 -0
  76. reaxkit/utils/media/convert.py +90 -0
  77. reaxkit/utils/media/make_video.py +91 -0
  78. reaxkit/utils/media/plotter.py +812 -0
  79. reaxkit/utils/numerical/__init__.py +0 -0
  80. reaxkit/utils/numerical/extrema_finder.py +96 -0
  81. reaxkit/utils/numerical/moving_average.py +103 -0
  82. reaxkit/utils/numerical/numerical_calcs.py +75 -0
  83. reaxkit/utils/numerical/signal_ops.py +135 -0
  84. reaxkit/utils/path.py +55 -0
  85. reaxkit/utils/units.py +104 -0
  86. reaxkit/webui/__init__.py +0 -0
  87. reaxkit/webui/app.py +0 -0
  88. reaxkit/webui/components.py +0 -0
  89. reaxkit/webui/layouts.py +0 -0
  90. reaxkit/webui/utils.py +0 -0
  91. reaxkit/workflows/__init__.py +0 -0
  92. reaxkit/workflows/composed/__init__.py +0 -0
  93. reaxkit/workflows/composed/coordination_workflow.py +393 -0
  94. reaxkit/workflows/composed/electrostatics_workflow.py +587 -0
  95. reaxkit/workflows/composed/xmolout_fort7_workflow.py +343 -0
  96. reaxkit/workflows/meta/__init__.py +0 -0
  97. reaxkit/workflows/meta/help_workflow.py +136 -0
  98. reaxkit/workflows/meta/introspection_workflow.py +235 -0
  99. reaxkit/workflows/meta/make_video_workflow.py +61 -0
  100. reaxkit/workflows/meta/plotter_workflow.py +601 -0
  101. reaxkit/workflows/per_file/__init__.py +0 -0
  102. reaxkit/workflows/per_file/control_workflow.py +110 -0
  103. reaxkit/workflows/per_file/eregime_workflow.py +267 -0
  104. reaxkit/workflows/per_file/ffield_workflow.py +390 -0
  105. reaxkit/workflows/per_file/fort13_workflow.py +86 -0
  106. reaxkit/workflows/per_file/fort57_workflow.py +137 -0
  107. reaxkit/workflows/per_file/fort73_workflow.py +151 -0
  108. reaxkit/workflows/per_file/fort74_workflow.py +88 -0
  109. reaxkit/workflows/per_file/fort76_workflow.py +188 -0
  110. reaxkit/workflows/per_file/fort78_workflow.py +135 -0
  111. reaxkit/workflows/per_file/fort79_workflow.py +314 -0
  112. reaxkit/workflows/per_file/fort7_workflow.py +592 -0
  113. reaxkit/workflows/per_file/fort83_workflow.py +60 -0
  114. reaxkit/workflows/per_file/fort99_workflow.py +223 -0
  115. reaxkit/workflows/per_file/geo_workflow.py +554 -0
  116. reaxkit/workflows/per_file/molfra_workflow.py +577 -0
  117. reaxkit/workflows/per_file/params_workflow.py +135 -0
  118. reaxkit/workflows/per_file/summary_workflow.py +161 -0
  119. reaxkit/workflows/per_file/trainset_workflow.py +356 -0
  120. reaxkit/workflows/per_file/tregime_workflow.py +79 -0
  121. reaxkit/workflows/per_file/vels_workflow.py +309 -0
  122. reaxkit/workflows/per_file/vregime_workflow.py +75 -0
  123. reaxkit/workflows/per_file/xmolout_workflow.py +678 -0
  124. reaxkit-1.0.0.dist-info/METADATA +128 -0
  125. reaxkit-1.0.0.dist-info/RECORD +130 -0
  126. reaxkit-1.0.0.dist-info/WHEEL +5 -0
  127. reaxkit-1.0.0.dist-info/entry_points.txt +2 -0
  128. reaxkit-1.0.0.dist-info/licenses/AUTHORS.md +20 -0
  129. reaxkit-1.0.0.dist-info/licenses/LICENSE +21 -0
  130. reaxkit-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,343 @@
1
+ """
2
+ xmolout–fort.7 combined workflow for ReaxKit.
3
+
4
+ This workflow provides visualization and analysis tasks that require both
5
+ atomic coordinates from `xmolout` and per-atom properties from `fort.7`
6
+ (e.g. partial charges, bond-order–derived quantities).
7
+
8
+ It supports:
9
+ - 3D scatter visualization of arbitrary fort.7 scalar properties mapped onto
10
+ atomic positions across selected frames.
11
+ - 2D projected heatmaps (xy/xz/yz) of atomic properties or atom counts,
12
+ with flexible spatial binning and aggregation.
13
+
14
+ The workflow is designed for spatially resolved analysis of ReaxFF outputs,
15
+ enabling intuitive inspection of per-atom quantities in real space and
16
+ across time.
17
+ """
18
+
19
+
20
+ from __future__ import annotations
21
+ import argparse
22
+ from pathlib import Path
23
+ from typing import Optional, Sequence, Tuple, Union
24
+
25
+ import numpy as np
26
+
27
+ # Handlers / analyzers
28
+ from reaxkit.io.handlers.xmolout_handler import XmoloutHandler
29
+ from reaxkit.io.handlers.fort7_handler import Fort7Handler
30
+ from reaxkit.analysis.per_file import fort7_analyzer as f7
31
+
32
+ # Utils (NEW: replace local parsers with these)
33
+ from reaxkit.utils.frame_utils import parse_frames, parse_atoms, resolve_indices
34
+
35
+ # Aliases (NEW: accept canonical or alias names like 'charge', 'q', etc.)
36
+ from reaxkit.utils.alias import resolve_alias_from_columns
37
+
38
+ # Plotting
39
+ from reaxkit.utils.media.plotter import scatter3d_points, heatmap2d_from_3d
40
+
41
+
42
+ # ------------------------- internals -------------------------
43
+
44
+ def _indices_from_spec(xh: XmoloutHandler, frames_spec: Optional[Union[slice, Sequence[int]]]) -> list[int]:
45
+ """Turn a frames spec (slice or list) into concrete frame indices for xh."""
46
+ return resolve_indices(xh, frames=frames_spec, iterations=None, step=None)
47
+
48
+
49
+ def _select_atoms(n_atoms: int, atoms: Optional[Sequence[int]]) -> np.ndarray:
50
+ """Return a boolean mask over 0..n_atoms-1 for the selected atom indices."""
51
+ if not atoms:
52
+ return np.ones(n_atoms, dtype=bool)
53
+ mask = np.zeros(n_atoms, dtype=bool)
54
+ for a in atoms:
55
+ if 0 <= int(a) < n_atoms:
56
+ mask[int(a)] = True
57
+ return mask
58
+
59
+
60
+ # ========================= 3D SCATTER (per-frame) =========================
61
+
62
+ def _plot_fort7_property_3d(
63
+ *,
64
+ xmolout_handler: XmoloutHandler,
65
+ fort7_handler: Fort7Handler,
66
+ property_name: str,
67
+ frames_spec: Optional[Union[slice, Sequence[int]]] = None,
68
+ atoms_list: Optional[Sequence[int]] = None,
69
+ save_dir: Optional[Union[str, Path]] = None,
70
+ vmin: Optional[float] = None,
71
+ vmax: Optional[float] = None,
72
+ size: float = 8.0,
73
+ alpha: float = 0.9,
74
+ cmap: str = "coolwarm",
75
+ elev: float = 22.0,
76
+ azim: float = 38.0,
77
+ ) -> None:
78
+ """
79
+ Plot any scalar property (e.g., partial_charge/charge/q) from fort.7 in 3D across frames.
80
+ """
81
+ # Pull all per-atom data we need from fort7 (tidy: frame_idx, iter, atom_idx, <props...>)
82
+ df_all = f7.get_features_atom(fort7_handler, columns=".*", frames=frames_spec, regex=True)
83
+
84
+ # Resolve the requested property via alias map against the columns we actually have
85
+ col = resolve_alias_from_columns(df_all.columns, property_name)
86
+ if col is None:
87
+ raise ValueError(
88
+ f"Column '{property_name}' not found (with alias resolution). "
89
+ f"Available columns include: {list(df_all.columns)[:12]} ..."
90
+ )
91
+
92
+ # Auto color limits if not provided
93
+ if vmin is None:
94
+ vmin = float(np.nanmin(df_all[col].to_numpy(dtype=float)))
95
+ if vmax is None:
96
+ vmax = float(np.nanmax(df_all[col].to_numpy(dtype=float)))
97
+
98
+ # Prep output
99
+ save_dir = Path(save_dir) if save_dir else None
100
+ if save_dir:
101
+ save_dir.mkdir(parents=True, exist_ok=True)
102
+
103
+ # Concrete frame indices to iterate
104
+ idx_list = _indices_from_spec(xmolout_handler, frames_spec)
105
+
106
+ for fi in idx_list:
107
+ # xmolout: geometry + types
108
+ fr = xmolout_handler.frame(int(fi))
109
+ coords = fr["coords"] # (N,3)
110
+ n_atoms = coords.shape[0]
111
+ keep_atoms = _select_atoms(n_atoms, atoms_list)
112
+
113
+ # fort7 values aligned by atom_idx
114
+ sub = df_all[df_all["frame_idx"] == fi][["atom_idx", col]].copy()
115
+ vals = np.full(n_atoms, np.nan, dtype=float)
116
+ if not sub.empty:
117
+ idx = sub["atom_idx"].to_numpy(int, copy=False) # 0-based
118
+ good = (idx >= 0) & (idx < n_atoms)
119
+ vals[idx[good]] = sub[col].to_numpy(float, copy=False)[good]
120
+
121
+ # filter & drop NaNs
122
+ use = keep_atoms & np.isfinite(vals)
123
+ if not np.any(use):
124
+ continue
125
+
126
+ title = f"{col}_3D_frame_{fi}"
127
+ scatter3d_points(
128
+ coords[use],
129
+ vals[use],
130
+ title=title,
131
+ s=size,
132
+ alpha=alpha,
133
+ cmap=cmap,
134
+ vmin=vmin,
135
+ vmax=vmax,
136
+ elev=elev,
137
+ azim=azim,
138
+ save=(save_dir / f"{title}.png" if save_dir else None),
139
+ show_message = False
140
+ )
141
+
142
+
143
+ def _plot_property_task(args: argparse.Namespace) -> int:
144
+ xh = XmoloutHandler(args.xmolout)
145
+ fh = Fort7Handler(args.fort7)
146
+
147
+ frames_spec = parse_frames(args.frames) # NEW
148
+ atoms_list = parse_atoms(args.atoms) # NEW
149
+
150
+ _plot_fort7_property_3d(
151
+ xmolout_handler=xh,
152
+ fort7_handler=fh,
153
+ property_name=args.property,
154
+ frames_spec=frames_spec,
155
+ atoms_list=atoms_list,
156
+ save_dir=args.save,
157
+ vmin=args.vmin,
158
+ vmax=args.vmax,
159
+ size=args.size,
160
+ alpha=args.alpha,
161
+ cmap=args.cmap,
162
+ elev=args.elev,
163
+ azim=args.azim,
164
+ )
165
+ if args.save:
166
+ print(f"[Done] All plots saved in {args.save}")
167
+
168
+ return 0
169
+
170
+
171
+ # ==================== 2D HEATMAP (projection + aggregation) ====================
172
+
173
+ def _parse_bins(bins: str) -> Union[int, Tuple[int, int]]:
174
+ if "," in bins:
175
+ nx, ny = [int(x) for x in bins.split(",")]
176
+ return (nx, ny)
177
+ return int(bins)
178
+
179
+
180
+ def _heatmap2d_task(args: argparse.Namespace) -> int:
181
+ """
182
+ Project 3D coords to 2D (xy/xz/yz), bin into a grid, and aggregate values.
183
+ If --property is provided, aggregate that fort7 scalar; else aggregate point count.
184
+ One PNG per frame is saved if --save is provided; otherwise plots are shown.
185
+ """
186
+ xh = XmoloutHandler(args.xmolout)
187
+ frames_spec = parse_frames(args.frames) # NEW
188
+ idx_list = _indices_from_spec(xh, frames_spec)
189
+
190
+ # Optional scalar from fort7
191
+ use_scalar = args.property is not None
192
+ if use_scalar:
193
+ fh = Fort7Handler(args.fort7)
194
+ df = f7.get_features_atom(fh, columns=".*", frames=frames_spec, regex=True)
195
+ col = resolve_alias_from_columns(df.columns, args.property)
196
+ if col is None:
197
+ raise ValueError(
198
+ f"Column '{args.property}' not found (with alias resolution). "
199
+ f"Available columns include: {list(df.columns)[:12]} ..."
200
+ )
201
+
202
+ bins: Union[int, Tuple[int, int]] = _parse_bins(args.bins)
203
+
204
+ # Output
205
+ save_dir = Path(args.save) if args.save else None
206
+ if save_dir:
207
+ save_dir.mkdir(parents=True, exist_ok=True)
208
+
209
+ for fi in idx_list:
210
+ fr = xh.frame(int(fi))
211
+ coords = fr["coords"]
212
+
213
+ if use_scalar:
214
+ sub = df[df["frame_idx"] == fi][["atom_idx", col]]
215
+ values = np.full(coords.shape[0], np.nan, float)
216
+ if not sub.empty:
217
+ idx = sub["atom_idx"].to_numpy(int, copy=False)
218
+ ok = (idx >= 0) & (idx < coords.shape[0])
219
+ values[idx[ok]] = sub[col].to_numpy(float, copy=False)[ok]
220
+ m = np.isfinite(values)
221
+ c_plot, v_plot = coords[m], values[m]
222
+ agg = args.agg
223
+ label = col
224
+ else:
225
+ c_plot = coords
226
+ v_plot = np.ones(coords.shape[0], float)
227
+ agg = "count"
228
+ label = "count"
229
+
230
+ title = f"{label}_{args.plane}_frame_{fi}"
231
+ out_path = (save_dir / f"{title}.png") if save_dir else None
232
+
233
+ heatmap2d_from_3d(
234
+ c_plot,
235
+ v_plot,
236
+ plane=args.plane,
237
+ bins=bins,
238
+ agg=agg,
239
+ vmin=args.vmin,
240
+ vmax=args.vmax,
241
+ cmap=args.cmap,
242
+ title=title,
243
+ save=out_path,
244
+ show_message = False,
245
+ )
246
+ if args.save:
247
+ print(f"[Done] All plots saved in {args.save}")
248
+
249
+ return 0
250
+
251
+
252
+ # ==================== CLI registration ====================
253
+ def _add_common_xmolout_io_args(
254
+ p: argparse.ArgumentParser,
255
+ *,
256
+ include_plot: bool = False,
257
+ ) -> None:
258
+ p.add_argument("--xmolout", default="xmolout", help="Path to xmolout file.")
259
+ p.add_argument("--fort7", default="fort.7", help="Path to fort.7 file.")
260
+ if include_plot:
261
+ p.add_argument("--plot", action="store_true", help="Show plot interactively.")
262
+
263
+ p.add_argument("--export", default=None, help="Path to export CSV data.")
264
+
265
+
266
+ def register_tasks(subparsers: argparse._SubParsersAction) -> None:
267
+ """
268
+ Register coordination-related CLI subcommands.
269
+
270
+ This function defines the task-level interface for the
271
+ `reaxkit file` workflow and attaches its tasks (i.e., subcommands).
272
+
273
+ Each task may share common input arguments and defines task-specific options as needed.
274
+ """
275
+ # 3D scatter
276
+ p = subparsers.add_parser(
277
+ "plot3d",
278
+ help="3D scatter plot of any fort7 property (aliases allowed: charge/q → partial_charge).",
279
+ description=(
280
+ "Examples:\n"
281
+ " reaxkit xmolfort7 plot3d --property charge --frames 0:20:10 \n"
282
+ ),
283
+ formatter_class=argparse.RawTextHelpFormatter,
284
+ )
285
+ _add_common_xmolout_io_args(p, include_plot=True)
286
+ p.add_argument("--property", required=True,
287
+ help="Column name or alias (e.g., partial_charge, charge, q).")
288
+ p.add_argument("--frames", default=None,
289
+ help='Frames: "0,10,20" or "0:100:5".')
290
+ p.add_argument("--atoms", default=None,
291
+ help='Atom indices: "0,1,2" (0-based).')
292
+ p.add_argument("--vmin", type=float, default=None,
293
+ help="Color scale min (auto if not set).")
294
+ p.add_argument("--vmax", type=float, default=None,
295
+ help="Color scale max (auto if not set).")
296
+ p.add_argument("--size", type=float, default=8.0, help="Marker size.")
297
+ p.add_argument("--alpha", type=float, default=0.9, help="Marker transparency.")
298
+ p.add_argument("--cmap", default="coolwarm", help="Matplotlib colormap.")
299
+ p.add_argument("--elev", type=float, default=22.0, help="3D view elevation.")
300
+ p.add_argument("--azim", type=float, default=38.0, help="3D view azimuth.")
301
+ p.add_argument("--save", default="reaxkit_outputs/xmol_fort7/3D_scatter/", help="Path to save plot image.")
302
+ p.set_defaults(_run=_plot_property_task)
303
+
304
+
305
+
306
+
307
+
308
+ # 2D heatmap
309
+ q = subparsers.add_parser(
310
+ "heatmap2d",
311
+ help="Project 3D atoms to 2D grid (xy/xz/yz) and aggregate values per cell.",
312
+ description=(
313
+ "Examples:\n"
314
+ " reaxkit xmolfort7 heatmap2d --property partial_charge --plane xz "
315
+ "--bins 10 --agg mean --frames 0:300:100\n"
316
+ ),
317
+ formatter_class=argparse.RawTextHelpFormatter,
318
+ )
319
+ _add_common_xmolout_io_args(q, include_plot=True)
320
+ q.add_argument("--frames", default=None,
321
+ help='Frames: "0,10,20" or "0:100:5".')
322
+
323
+ # Projection/grid
324
+ q.add_argument("--plane", default="xy", choices=["xy", "xz", "yz"],
325
+ help="Projection plane.")
326
+ q.add_argument("--bins", default="40",
327
+ help='Grid bins: "N" or "Nx,Ny" (e.g., "10,25").')
328
+ q.add_argument("--agg", default="mean",
329
+ help="Aggregation: mean|max|min|sum|count.")
330
+
331
+ # Optional scalar from fort7
332
+ q.add_argument("--property", default=None,
333
+ help="fort7 column or alias to aggregate (e.g., partial_charge|charge|q).")
334
+
335
+ # Viz
336
+ q.add_argument("--vmin", type=float, default=None,
337
+ help="Color scale min (auto if not set).")
338
+ q.add_argument("--vmax", type=float, default=None,
339
+ help="Color scale max (auto if not set).")
340
+ q.add_argument("--cmap", default="viridis", help="Matplotlib colormap.")
341
+ q.add_argument("--save", default="reaxkit_outputs/xmol_fort7/2D_heatmap/", help="Path to save plot image.")
342
+ q.set_defaults(_run=_heatmap2d_task)
343
+
File without changes
@@ -0,0 +1,136 @@
1
+ """
2
+ Interactive help and discovery workflow for ReaxKit.
3
+
4
+ This workflow provides a search-based help system that maps conceptual,
5
+ human-language queries (e.g. "electric field", "restraint", "bond order")
6
+ to relevant ReaxFF input and output files.
7
+
8
+ It operates as a kind-level command (`reaxkit help`) rather than a task-based
9
+ workflow, and therefore does not define subcommands. Instead, it queries
10
+ curated help indices and ranks matches based on relevance.
11
+
12
+ Optional flags allow users to inspect why a file matched, view example
13
+ ReaxKit commands, and explore core, optional, and derived variables
14
+ associated with each file.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import argparse
20
+ from reaxkit.help.help_index_loader import search_help_indices, _format_hits
21
+
22
+
23
+ def build_parser(p: argparse.ArgumentParser) -> None:
24
+ """
25
+ Define CLI arguments for the kind-level command: `reaxkit help`.
26
+
27
+ This is used by documentation generation to render a stable list of flags
28
+ and defaults, and can also be reused by the CLI entry-point when building
29
+ the parser for `help`.
30
+ """
31
+ p.add_argument(
32
+ "query",
33
+ nargs="?",
34
+ default=None,
35
+ help="Search query (use quotes for multi-word queries).",
36
+ )
37
+
38
+ p.add_argument(
39
+ "--top",
40
+ type=int,
41
+ default=8,
42
+ help="Maximum number of matches to display.",
43
+ )
44
+ p.add_argument(
45
+ "--min-score",
46
+ type=float,
47
+ default=35.0,
48
+ help="Minimum score threshold; lower-scoring matches are hidden.",
49
+ )
50
+
51
+ # Output detail toggles
52
+ p.add_argument("--why", action="store_true", help="Show why each file matched the query.")
53
+ p.add_argument("--file_templates", action="store_true", help="Show one example ReaxKit command per match.")
54
+ p.add_argument("--tags", action="store_true", help="Show tags for each match.")
55
+ p.add_argument("--core-vars", dest="core_vars", action="store_true", help="Show core variables for each match.")
56
+ p.add_argument("--optional-vars", dest="optional_vars", action="store_true", help="Show optional variables.")
57
+ p.add_argument("--derived-vars", dest="derived_vars", action="store_true", help="Show derived variables.")
58
+ p.add_argument("--notes", action="store_true", help="Show notes for each match.")
59
+
60
+ # Convenience flag
61
+ p.add_argument(
62
+ "--all-info",
63
+ dest="all_info",
64
+ action="store_true",
65
+ help="Show why/file_templates/tags/core/optional/derived/notes all at once.",
66
+ )
67
+
68
+
69
+ def run_main(args: argparse.Namespace) -> None:
70
+ """
71
+ Run the `reaxkit help` command.
72
+
73
+ Behavior:
74
+ -----------
75
+ - If no query is provided, prints a short usage message and exits.
76
+ - If a query is provided, searches curated help indices and prints ranked matches.
77
+ - Use `--top` and `--min-score` to control result count and filtering.
78
+ - Use detail flags (`--why`, `--file_templates`, `--tags`, `--core-vars`, `--optional-vars`,
79
+ `--derived-vars`, `--notes`) to expand what is shown per match.
80
+ - `--all-info` enables all detail flags together.
81
+
82
+ Examples
83
+ -----------
84
+ reaxkit help 'restraint'
85
+ reaxkit help 'electric field'
86
+ """
87
+ # Allow: `reaxkit help` (no query)
88
+ if getattr(args, "query", None) is None:
89
+ print("ReaxKit help\n")
90
+ print('Usage:\n reaxkit help "restraint"\n reaxkit help bond\n reaxkit help "electric field"\n')
91
+ print("Tip: put multi-word queries in quotes.")
92
+ return
93
+
94
+ hits = search_help_indices(
95
+ args.query,
96
+ top_k=getattr(args, "top", 8),
97
+ min_score=getattr(args, "min_score", 35.0),
98
+ )
99
+
100
+ if not hits:
101
+ print(f"❌ No matches for: {args.query!r}")
102
+ return
103
+
104
+ all_info = getattr(args, "all_info", False)
105
+
106
+ show_why = all_info or getattr(args, "why", False)
107
+ show_examples = all_info or getattr(args, "file_templates", False)
108
+ show_tags = all_info or getattr(args, "tags", False)
109
+ show_core_vars = all_info or getattr(args, "core_vars", False)
110
+ show_optional_vars = all_info or getattr(args, "optional_vars", False)
111
+ show_derived_vars = all_info or getattr(args, "derived_vars", False)
112
+ show_notes = all_info or getattr(args, "notes", False)
113
+
114
+ print(
115
+ _format_hits(
116
+ hits,
117
+ show_why=show_why,
118
+ show_examples=show_examples,
119
+ show_tags=show_tags,
120
+ show_core_vars=show_core_vars,
121
+ show_optional_vars=show_optional_vars,
122
+ show_derived_vars=show_derived_vars,
123
+ show_notes=show_notes,
124
+ )
125
+ )
126
+
127
+
128
+ def register_tasks(subparsers: argparse._SubParsersAction) -> None:
129
+ """
130
+ Intentionally empty.
131
+
132
+ `help` is a kind-level command (invoked as `reaxkit help "<query>"`), so it does
133
+ not define subcommands via `register_tasks`. The CLI entry-point should call
134
+ `build_parser(...)` and route execution to `run_main(...)`.
135
+ """
136
+ return