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,110 @@
1
+ """
2
+ Control-file workflow for ReaxKit.
3
+
4
+ This workflow provides utilities for inspecting and generating ReaxFF
5
+ `control` files, which define global simulation settings such as
6
+ MD/energy-minimization parameters, output frequencies, and algorithmic options.
7
+
8
+ It supports:
9
+ - Querying individual control keys (e.g. `nmdit`, `iout2`) from an existing
10
+ control file, with optional section filtering.
11
+ - Generating a complete default control file containing all standard sections
12
+ and recommended default values.
13
+
14
+ The workflow is designed to make control-file management transparent,
15
+ scriptable, and reproducible from the command line.
16
+ """
17
+
18
+
19
+ from __future__ import annotations
20
+ import argparse
21
+
22
+ from reaxkit.io.handlers.control_handler import ControlHandler
23
+ from reaxkit.analysis.per_file.control_analyzer import get_control_data
24
+ from reaxkit.io.generators.control_generator import write_control_template
25
+
26
+ def _format_value(value):
27
+ """
28
+ Format numeric values with commas (e.g., 150000 -> 150,000).
29
+ Works for int or float-like inputs.
30
+ """
31
+ # Try integer first
32
+ try:
33
+ iv = int(value)
34
+ return f"{iv:,}"
35
+ except (ValueError, TypeError):
36
+ pass
37
+
38
+ # Try float next (only apply formatting if large enough)
39
+ try:
40
+ fv = float(value)
41
+ # Only add commas to the integer part for large floats
42
+ if abs(fv) >= 1000:
43
+ int_part, dot, frac = f"{fv}".partition(".")
44
+ int_part = f"{int(int_part):,}"
45
+ return int_part + (("." + frac) if frac else "")
46
+ return value
47
+ except (ValueError, TypeError):
48
+ return value
49
+
50
+
51
+ def _control_get_task(args: argparse.Namespace) -> int:
52
+ """CLI task: get a single control key value (e.g., nmdit)."""
53
+ handler = ControlHandler(args.file)
54
+ value = get_control_data(handler, args.key, section=args.section, default=None)
55
+
56
+ if value is None:
57
+ print(f"❌ Key '{args.key}' not found in control file '{args.file}'.")
58
+ return 1
59
+
60
+ formatted = _format_value(value)
61
+ print(f'{args.key} = {formatted}')
62
+ return 0
63
+
64
+ def _control_make_task(args: argparse.Namespace) -> int:
65
+ """
66
+ CLI task: generate a default control file with all sections and default values.
67
+ """
68
+ output = write_control_template(args.output)
69
+ print(f"[Done] control file written to {output}")
70
+ return 0
71
+
72
+ def register_tasks(subparsers: argparse._SubParsersAction) -> None:
73
+ # --- get ---
74
+ p = subparsers.add_parser(
75
+ "get",
76
+ help="Get the value of a control key (e.g. nmdit)",
77
+ description=(
78
+ "Examples:\n"
79
+ " reaxkit control get nmdit\n"
80
+ ),
81
+ formatter_class=argparse.RawTextHelpFormatter,
82
+ )
83
+ p.add_argument("key", help="Control key to look up, e.g. 'nmdit'.")
84
+ p.add_argument(
85
+ "--file", default="control",
86
+ help="Path to control file (default: 'control').",
87
+ )
88
+ p.add_argument(
89
+ "--section", default=None,
90
+ help="Optional control section (general, md, mm, ff, outdated).",
91
+ )
92
+ p.set_defaults(_run=_control_get_task)
93
+
94
+ # --- make ---
95
+ m = subparsers.add_parser(
96
+ "make",
97
+ help="Generate a default control file with all sections and default values",
98
+ description=(
99
+ "Examples:\n"
100
+ " reaxkit control make\n"
101
+ " reaxkit control make --output control\n"
102
+ ),
103
+ formatter_class=argparse.RawTextHelpFormatter,
104
+ )
105
+ m.add_argument(
106
+ "--output",
107
+ default="reaxkit_generated_inputs/control",
108
+ help="Output path for the generated control file (default: 'control').",
109
+ )
110
+ m.set_defaults(_run=_control_make_task)
@@ -0,0 +1,267 @@
1
+ """
2
+ Electric-field regime (eregime) workflow for ReaxKit.
3
+
4
+ This workflow provides tools to read, analyze, visualize, and generate
5
+ `eregime.in` files, which define time- or iteration-dependent electric-field
6
+ schedules in ReaxFF simulations.
7
+
8
+ It supports:
9
+ - Extracting electric-field components (e.g. E1, E2) versus iteration, frame,
10
+ or physical time, with optional plotting and CSV export.
11
+ - Selecting subsets of data by frame ranges for focused analysis.
12
+ - Generating new `eregime.in` files using standard field profiles, including
13
+ sinusoidal waves, smooth pulses, or user-defined analytic functions.
14
+
15
+ The workflow is designed to bridge ReaxFF electric-field protocols with
16
+ analysis and visualization, enabling reproducible setup and interpretation
17
+ of field-driven simulations.
18
+ """
19
+
20
+ from __future__ import annotations
21
+ import argparse
22
+ from pathlib import Path
23
+ from typing import Callable, Dict, Any
24
+ from reaxkit.utils.units import unit_for
25
+
26
+ from reaxkit.io.handlers.eregime_handler import EregimeHandler
27
+ from reaxkit.analysis.per_file.eregime_analyzer import get_eregime_data
28
+ from reaxkit.utils.media.plotter import single_plot
29
+ from reaxkit.io.generators.eregime_generator import (
30
+ write_eregime_sinusoidal,
31
+ write_eregime_smooth_pulse,
32
+ write_eregime_from_function,
33
+ )
34
+ from reaxkit.utils.alias import normalize_choice
35
+ from reaxkit.utils.frame_utils import parse_frames, select_frames
36
+ from reaxkit.utils.path import resolve_output_path
37
+
38
+
39
+ # ====================================================================
40
+ # GET (read/plot/export)
41
+ # ====================================================================
42
+
43
+ def _eregime_get_task(args: argparse.Namespace) -> int:
44
+ """
45
+ Parse eregime.in and return Y vs chosen X axis (iter/frame/time), with optional plotting/export.
46
+ """
47
+ handler = EregimeHandler(args.file)
48
+
49
+ # Build series with alias-aware resolver and x-axis conversion (iter/frame/time)
50
+ df = get_eregime_data(
51
+ handler,
52
+ y=args.column,
53
+ xaxis=args.xaxis,
54
+ control_file=args.control, # used when xaxis='time'
55
+ ) # -> DataFrame with columns [<x_label>, <y (as requested)>]
56
+
57
+ # Optional row selection via frames (position-based)
58
+ frames = parse_frames(args.frames)
59
+ df = select_frames(df, frames)
60
+
61
+ x_label = df.columns[0]
62
+ y_label = df.columns[1]
63
+ canonical_label = normalize_choice(args.column) # resolve like E1 → field1
64
+ unit = unit_for(canonical_label) or unit_for(y_label) or ""
65
+ title = f"{canonical_label} vs {x_label}"
66
+
67
+ workflow_name = args.kind
68
+ # Export CSV
69
+ if args.export:
70
+ out = resolve_output_path(args.export, workflow_name)
71
+ out.parent.mkdir(parents=True, exist_ok=True)
72
+ df.to_csv(out, index=False)
73
+ print(f"[Done] Exported data to {out}")
74
+
75
+ # Save static plot
76
+ if args.save:
77
+ out = resolve_output_path(args.save, workflow_name)
78
+ single_plot(
79
+ df[x_label], df[y_label],
80
+ title=title, xlabel=x_label, ylabel=f"{canonical_label} ({unit})", save=out
81
+ )
82
+
83
+ # Show interactive plot
84
+ if args.plot:
85
+ single_plot(
86
+ df[x_label], df[y_label],
87
+ title=title, xlabel=x_label, ylabel=f"{canonical_label} ({unit})", save=None
88
+ )
89
+
90
+ # Guidance if no action flags
91
+ if not (args.export or args.save or args.plot):
92
+ print("ℹ️ No action chosen. Add one or more of: --plot, --save PATH, --export PATH")
93
+ print(f"Available columns in file: {', '.join(df.columns)}")
94
+
95
+ return 0
96
+
97
+ # ====================================================================
98
+ # GENERATORS (using official API)
99
+ # ====================================================================
100
+
101
+ def _task_gen_sin(args: argparse.Namespace) -> int:
102
+ write_eregime_sinusoidal(
103
+ args.output,
104
+ max_magnitude=args.max_magnitude,
105
+ step_angle=args.step_angle,
106
+ iteration_step=args.iteration_step,
107
+ num_cycles=args.num_cycles,
108
+ direction=args.direction,
109
+ voltage_idx=args.V,
110
+ phase=args.phase,
111
+ dc_offset=args.dc_offset,
112
+ start_iter=args.start_iter,
113
+ )
114
+ print(f" This file is saved in {Path(args.output).resolve()}")
115
+ return 0
116
+
117
+
118
+ def _task_gen_pulse(args: argparse.Namespace) -> int:
119
+ write_eregime_smooth_pulse(
120
+ args.output,
121
+ amplitude=args.amplitude,
122
+ width=args.width,
123
+ period=args.period,
124
+ slope=args.slope,
125
+ iteration_step=args.iteration_step,
126
+ num_of_cycles=args.num_cycles,
127
+ step_size=args.step_size,
128
+ direction=args.direction,
129
+ voltage_idx=args.V,
130
+ baseline=args.baseline,
131
+ start_iter=args.start_iter,
132
+ )
133
+ print(f" This file is saved in {Path(args.output).resolve()}")
134
+ return 0
135
+
136
+
137
+ def _safe_build_func(expr: str) -> Callable[[float], float]:
138
+ """
139
+ Build func(t) from a simple expression like '0.003*sin(2*pi*t/100) + 0.0005'.
140
+ Allowed names: from math + numpy as (optional) 'np'.
141
+ """
142
+ import math, numpy as np
143
+ allowed: Dict[str, Any] = {k: getattr(math, k) for k in dir(math) if not k.startswith("_")}
144
+ allowed["np"] = np
145
+ code = compile(expr, "<func-expr>", "eval")
146
+
147
+ def f(t: float) -> float:
148
+ return float(eval(code, {"__builtins__": {}}, {**allowed, "t": float(t)}))
149
+
150
+ return f
151
+
152
+
153
+ def _task_gen_func(args: argparse.Namespace) -> int:
154
+ func = _safe_build_func(args.expr)
155
+ write_eregime_from_function(
156
+ args.output,
157
+ func=func,
158
+ t_end=args.t_end,
159
+ dt=args.dt,
160
+ iteration_step=args.iteration_step,
161
+ direction=args.direction,
162
+ voltage_idx=args.V,
163
+ start_iter=args.start_iter,
164
+ )
165
+ print(f" This file is saved in {Path(args.output).resolve()}")
166
+ return 0
167
+
168
+
169
+ # ====================================================================
170
+ # CLI WIRING (single entry)
171
+ # ====================================================================
172
+
173
+ def register_tasks(subparsers: argparse._SubParsersAction) -> None:
174
+ """
175
+ Wire subcommands under the *existing* 'eregime' command provided by the top-level CLI.
176
+ """
177
+ # ---- 'get' ----
178
+ p_get = subparsers.add_parser(
179
+ "get",
180
+ help="Get a column (like E1) vs iter/frame/time and optionally plot, save, or export it.\n",
181
+ description=(
182
+ "Examples:\n"
183
+ " reaxkit eregime get --column E1 --xaxis time --export eregime_E1_vs_time.csv "
184
+ "--save eregime_E1_vs_time.png\n"
185
+ ),
186
+ formatter_class=argparse.RawTextHelpFormatter,
187
+ )
188
+ p_get.add_argument("--file", default="eregime.in", help="Path to eregime.in file")
189
+ p_get.add_argument("--column", required=True,
190
+ help="Y column to extract (aliases supported, e.g., E, E1, E2, direction, direction1, direction2)"
191
+ )
192
+ p_get.add_argument("--xaxis", default="iter", choices=("iter", "frame", "time"),
193
+ help="X axis for the output: 'iter' (default), 'frame', or 'time' (needs --control)"
194
+ )
195
+ p_get.add_argument("--control", default="control",
196
+ help="Control file used to convert iteration → time when --xaxis time (default: control)"
197
+ )
198
+ p_get.add_argument("--frames", default=None,
199
+ help="Row selector (position-based): 'start:stop[:step]' or 'i,j,k' (default: all rows)"
200
+ )
201
+ p_get.add_argument("--plot", action="store_true", help="Show the plot interactively.")
202
+ p_get.add_argument("--save", default=None, help="Save the plot image to this path.")
203
+ p_get.add_argument("--export", default=None, help="Export data CSV to this path.")
204
+ p_get.set_defaults(_run=_eregime_get_task)
205
+
206
+
207
+ # ---- 'gen' parent ----
208
+ p_gen = subparsers.add_parser(
209
+ "gen",
210
+ help="Generate eregime.in via official generators (sin, pulse, func).\n",
211
+ description=(
212
+ "Examples:\n"
213
+ " reaxkit eregime gen sin --output eregime_sin.in --max-magnitude 0.004 --step-angle 0.05 "
214
+ "--iteration-step 500 --num-cycles 2 --direction z --V 1\n"
215
+ " reaxkit eregime gen pulse --output eregime_pulse.in --amplitude 0.003 --width 50 "
216
+ "--period 200 --slope 20 --iteration-step 250 --num-cycles 5 --direction z --V 1\n"
217
+ " reaxkit eregime gen func --output eregime_func.in --expr '0.003*cos(2*pi*t/100)' "
218
+ "--t-end 1000 --dt 1 --iteration-step 250 --direction z --V 1"
219
+ ),
220
+ formatter_class=argparse.RawTextHelpFormatter,
221
+ )
222
+ gen = p_gen.add_subparsers(dest="gen_cmd", required=True)
223
+
224
+ # gen sin (make_eregime_sinusoidal)
225
+ p_sin = gen.add_parser("sin")
226
+ p_sin.add_argument("--output", default="eregime.in", help="Output file path.")
227
+ p_sin.add_argument("--max-magnitude", type=float, required=True, help="Peak amplitude (V/Å).")
228
+ p_sin.add_argument("--step-angle", type=float, required=True, help="Sampling step (radians).")
229
+ p_sin.add_argument("--iteration-step", type=int, required=True, help="Iterations between samples.")
230
+ p_sin.add_argument("--num-cycles", type=float, required=True, help="Number of cycles.")
231
+ p_sin.add_argument("--direction", default="z", help="x|y|z")
232
+ p_sin.add_argument("--V", type=int, default=1, help="Voltage index (integer).")
233
+ p_sin.add_argument("--phase", type=float, default=0.0, help="Phase offset (radians).")
234
+ p_sin.add_argument("--dc-offset", type=float, default=0.0, help="DC offset (V/Å).")
235
+ p_sin.add_argument("--start-iter", type=int, default=0, help="Starting iteration.")
236
+ p_sin.set_defaults(_run=_task_gen_sin)
237
+
238
+ # gen pulse (make_eregime_smooth_pulse)
239
+ p_pulse = gen.add_parser("pulse")
240
+ p_pulse.add_argument("--output", default="eregime.in", help="Output file path.")
241
+ p_pulse.add_argument("--amplitude", type=float, required=True, help="Peak amplitude (V/Å).")
242
+ p_pulse.add_argument("--width", type=float, required=True, help="Flat-top width (time units).")
243
+ p_pulse.add_argument("--period", type=float, required=True, help="Full-cycle period (time units).")
244
+ p_pulse.add_argument("--slope", type=float, required=True, help="Ramp duration up/down (time units).")
245
+ p_pulse.add_argument("--iteration-step", type=int, required=True, help="Iterations per sample.")
246
+ p_pulse.add_argument("--num-cycles", type=float, required=True, help="Number of cycles.")
247
+ p_pulse.add_argument("--step-size", type=float, default=0.1, help="Temporal resolution.")
248
+ p_pulse.add_argument("--direction", default="z", help="x|y|z")
249
+ p_pulse.add_argument("--V", type=int, default=1, help="Voltage index (integer).")
250
+ p_pulse.add_argument("--baseline", type=float, default=0.0, help="Baseline (V/Å).")
251
+ p_pulse.add_argument("--start-iter", type=int, default=0, help="Starting iteration.")
252
+ p_pulse.set_defaults(_run=_task_gen_pulse)
253
+
254
+ # gen func (make_eregime_from_function)
255
+ p_func = gen.add_parser("func")
256
+ p_func.add_argument("--output", default="eregime.in", help="Output file path.")
257
+ p_func.add_argument(
258
+ "--expr", required=True,
259
+ help="Python expression in t (math + np available), e.g. '0.003*sin(2*pi*t/100) + 0.0005'"
260
+ )
261
+ p_func.add_argument("--t-end", type=float, required=True, help="End time.")
262
+ p_func.add_argument("--dt", type=float, required=True, help="Time step.")
263
+ p_func.add_argument("--iteration-step", type=int, required=True, help="Iterations per sample.")
264
+ p_func.add_argument("--direction", default="z", help="x|y|z")
265
+ p_func.add_argument("--V", type=int, default=1, help="Voltage index (integer).")
266
+ p_func.add_argument("--start-iter", type=int, default=0, help="Starting iteration.")
267
+ p_func.set_defaults(_run=_task_gen_func)