valyte 0.1.9__py3-none-any.whl → 0.1.11__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.
valyte/cli.py CHANGED
@@ -1,17 +1,5 @@
1
1
  #!/usr/bin/env python3
2
- """
3
- Valyte CLI Tool
4
- ===============
5
-
6
- A post-processing tool for VASP outputs, designed to create publication-quality
7
- plots with a modern aesthetic. Supports DOS and band structure plotting.
8
-
9
- Features:
10
- - DOS plotting with gradient fills
11
- - Band structure plotting
12
- - Smart legend positioning
13
- - Custom font support
14
- """
2
+ """Valyte CLI entry point."""
15
3
 
16
4
  import os
17
5
  import sys
@@ -28,59 +16,51 @@ from valyte.band_plot import plot_band_structure
28
16
  from valyte.dos_plot import load_dos, plot_dos
29
17
  from valyte.kpoints import generate_kpoints_interactive
30
18
  from valyte.potcar import generate_potcar
19
+ from valyte.ipr import run_ipr_interactive
20
+
21
+
22
+ def _normalize_element(symbol: str) -> str:
23
+ if not symbol:
24
+ return symbol
25
+ return symbol[0].upper() + symbol[1:].lower()
26
+
31
27
 
32
28
  def parse_element_selection(inputs):
33
- """
34
- Parses user input for elements and orbitals.
35
-
36
- Args:
37
- inputs (list): List of strings, e.g., ["Ag", "Bi(s)", "O(p)"]
38
-
39
- Returns:
40
- tuple: (elements_to_load, plotting_config)
41
- elements_to_load (list): Elements to extract from VASP data.
42
- plotting_config (list): List of (Element, Orbital) tuples.
43
- """
29
+ """Parse element/orbital selections like "Fe", "Fe(d)", "O(p)"."""
44
30
  if not inputs:
45
31
  return None, None
46
32
 
47
- elements_to_load = set()
33
+ elements_to_load = []
34
+ elements_seen = set()
48
35
  plotting_config = []
49
-
50
- # Regex to match "Element" or "Element(orbital)"
51
- pattern = re.compile(r"^([A-Za-z]+)(?:\(([spdf])\))?$")
52
-
36
+
37
+ pattern = re.compile(r"^([A-Za-z]+)(?:\(([spdf])\))?$", re.IGNORECASE)
38
+
53
39
  for item in inputs:
54
- match = pattern.match(item)
55
- if match:
56
- el = match.group(1)
57
- orb = match.group(2) # None if no orbital specified
58
-
59
- elements_to_load.add(el)
60
- if orb:
61
- plotting_config.append((el, orb))
62
- else:
63
- plotting_config.append((el, 'total'))
64
- else:
65
- print(f"⚠️ Warning: Could not parse '{item}'. Ignoring.")
66
-
40
+ match = pattern.match(item.strip())
41
+ if not match:
42
+ print(f"Warning: could not parse '{item}'. Ignoring.")
43
+ continue
44
+
45
+ el = _normalize_element(match.group(1))
46
+ orb = match.group(2).lower() if match.group(2) else None
67
47
 
68
- return list(elements_to_load), plotting_config
48
+ if el not in elements_seen:
49
+ elements_to_load.append(el)
50
+ elements_seen.add(el)
51
+
52
+ plotting_config.append((el, orb or "total"))
53
+
54
+ return elements_to_load, plotting_config
69
55
 
70
56
 
71
- # ===============================================================
72
- # Main CLI
73
- # ===============================================================
74
57
  def main():
75
- """
76
- Main entry point for the CLI.
77
- """
78
58
  parser = argparse.ArgumentParser(description="Valyte: VASP Post-Processing Tool")
79
59
  subparsers = parser.add_subparsers(dest="command", help="Available commands")
80
60
 
81
- # --- DOS Subcommand ---
61
+ # DOS
82
62
  dos_parser = subparsers.add_parser("dos", help="Plot Density of States (DOS)")
83
- dos_parser.add_argument("filepath", nargs="?", help="Path to vasprun.xml or directory containing it (optional)")
63
+ dos_parser.add_argument("filepath", nargs="?", help="Path to vasprun.xml or directory containing it")
84
64
  dos_parser.add_argument("--vasprun", help="Explicit path to vasprun.xml (alternative to positional argument)")
85
65
  dos_parser.add_argument("-e", "--elements", nargs="+", help="Elements/Orbitals to plot (e.g., 'Fe O' or 'Fe(d) O(p)')")
86
66
  dos_parser.add_argument("-o", "--output", default="valyte_dos.png", help="Output filename")
@@ -92,7 +72,7 @@ def main():
92
72
  dos_parser.add_argument("--legend-cutoff", type=float, default=0.10, help="Threshold for legend visibility (0.0-1.0)")
93
73
  dos_parser.add_argument("--font", default="Arial", help="Font family")
94
74
 
95
- # --- Supercell Subcommand ---
75
+ # Supercell
96
76
  supercell_parser = subparsers.add_parser("supercell", help="Create a supercell")
97
77
  supercell_parser.add_argument("nx", type=int, help="Supercell size x")
98
78
  supercell_parser.add_argument("ny", type=int, help="Supercell size y")
@@ -100,50 +80,51 @@ def main():
100
80
  supercell_parser.add_argument("-i", "--input", default="POSCAR", help="Input POSCAR file")
101
81
  supercell_parser.add_argument("-o", "--output", default="POSCAR_supercell", help="Output filename")
102
82
 
103
- # --- Band Structure Subcommand ---
83
+ # Band
104
84
  band_parser = subparsers.add_parser("band", help="Band structure utilities")
105
85
  band_subparsers = band_parser.add_subparsers(dest="band_command", help="Band commands")
106
86
 
107
- # Band Plotting (default if no subcommand)
108
- # Note: argparse doesn't easily support default subcommands, so we handle this in logic
87
+ # Band plotting (default)
109
88
  band_parser.add_argument("--vasprun", default=".", help="Path to vasprun.xml or directory")
110
89
  band_parser.add_argument("--kpoints", help="Path to KPOINTS file (for labels)")
111
90
  band_parser.add_argument("-o", "--output", default="valyte_band.png", help="Output filename")
112
91
  band_parser.add_argument("--ylim", nargs=2, type=float, help="Energy range (min max)")
113
92
  band_parser.add_argument("--font", default="Arial", help="Font family")
114
93
 
115
- # Band KPOINTS Generation
94
+ # Band KPOINTS generation
116
95
  kpt_gen_parser = band_subparsers.add_parser("kpt-gen", help="Generate KPOINTS for band structure")
117
96
  kpt_gen_parser.add_argument("-i", "--input", default="POSCAR", help="Input POSCAR file")
118
97
  kpt_gen_parser.add_argument("-n", "--npoints", type=int, default=40, help="Points per segment")
119
98
  kpt_gen_parser.add_argument("-o", "--output", default="KPOINTS", help="Output filename")
120
99
  kpt_gen_parser.add_argument("--symprec", type=float, default=0.01, help="Symmetry precision (default: 0.01)")
121
-
122
100
  kpt_gen_parser.add_argument("--mode", default="bradcrack", help="Standardization mode (default: bradcrack)")
123
101
 
124
- # --- K-Point Generation (Interactive) ---
102
+ # KPOINTS (interactive)
125
103
  subparsers.add_parser("kpt", help="Interactive K-Point Generation (SCF)")
126
104
 
127
- # --- POTCAR Generation ---
105
+ # POTCAR
128
106
  potcar_parser = subparsers.add_parser("potcar", help="Generate POTCAR")
129
107
  potcar_parser.add_argument("-i", "--input", default="POSCAR", help="Input POSCAR file")
130
108
  potcar_parser.add_argument("-o", "--output", default="POTCAR", help="Output filename")
131
109
  potcar_parser.add_argument("--functional", default="PBE", help="Functional (default: PBE)")
132
110
 
111
+ # IPR
112
+ subparsers.add_parser("ipr", help="Compute IPR from PROCAR")
113
+
133
114
  args = parser.parse_args()
134
115
 
135
116
  if args.command == "dos":
136
- # Resolve filepath: positional > flag > current dir
137
117
  target_path = args.filepath if args.filepath else args.vasprun
138
118
  if not target_path:
139
119
  target_path = "."
140
-
120
+
141
121
  elements, plotting_config = parse_element_selection(args.elements)
142
-
122
+
143
123
  try:
144
124
  dos_data, pdos_data = load_dos(target_path, elements)
145
125
  plot_dos(
146
- dos_data, pdos_data,
126
+ dos_data,
127
+ pdos_data,
147
128
  out=args.output,
148
129
  xlim=tuple(args.xlim),
149
130
  ylim=tuple(args.ylim) if args.ylim else None,
@@ -152,11 +133,10 @@ def main():
152
133
  show_total=not args.pdos,
153
134
  plotting_config=plotting_config,
154
135
  legend_cutoff=args.legend_cutoff,
155
- scale_factor=args.scale
136
+ scale_factor=args.scale,
156
137
  )
157
- # print(f"✅ DOS plot saved to {args.output}") # Silent mode
158
138
  except Exception as e:
159
- print(f"Error: {e}")
139
+ print(f"Error: {e}")
160
140
  sys.exit(1)
161
141
 
162
142
  elif args.command == "supercell":
@@ -166,17 +146,17 @@ def main():
166
146
  nx=args.nx,
167
147
  ny=args.ny,
168
148
  nz=args.nz,
169
- output=args.output
149
+ output=args.output,
170
150
  )
171
151
  except Exception as e:
172
- print(f"Error: {e}")
152
+ print(f"Error: {e}")
173
153
  sys.exit(1)
174
-
154
+
175
155
  elif args.command == "kpt":
176
156
  try:
177
157
  generate_kpoints_interactive()
178
158
  except Exception as e:
179
- print(f"Error: {e}")
159
+ print(f"Error: {e}")
180
160
  sys.exit(1)
181
161
 
182
162
  elif args.command == "potcar":
@@ -184,10 +164,17 @@ def main():
184
164
  generate_potcar(
185
165
  poscar_path=args.input,
186
166
  functional=args.functional,
187
- output=args.output
167
+ output=args.output,
188
168
  )
189
169
  except Exception as e:
190
- print(f"Error: {e}")
170
+ print(f"Error: {e}")
171
+ sys.exit(1)
172
+
173
+ elif args.command == "ipr":
174
+ try:
175
+ run_ipr_interactive()
176
+ except Exception as e:
177
+ print(f"Error: {e}")
191
178
  sys.exit(1)
192
179
 
193
180
  elif args.command == "band":
@@ -198,23 +185,19 @@ def main():
198
185
  npoints=args.npoints,
199
186
  output=args.output,
200
187
  symprec=args.symprec,
201
- mode=args.mode
188
+ mode=args.mode,
202
189
  )
203
190
  except Exception as e:
204
- print(f"Error: {e}")
191
+ print(f"Error: {e}")
205
192
  sys.exit(1)
206
193
  elif args.band_command == "plot" or args.band_command is None:
207
- # Default behavior for 'valyte band' is plotting
208
194
  try:
209
- # Determine input path: --vasprun > positional > current dir
210
- target_path = args.vasprun or args.filepath or "."
195
+ target_path = args.vasprun or "."
211
196
  if os.path.isdir(target_path):
212
197
  target_path = os.path.join(target_path, "vasprun.xml")
213
-
214
- # Determine KPOINTS path
198
+
215
199
  kpoints_path = args.kpoints
216
200
  if not kpoints_path:
217
- # Try to find KPOINTS in the same directory as vasprun.xml
218
201
  base_dir = os.path.dirname(target_path)
219
202
  potential_kpoints = os.path.join(base_dir, "KPOINTS")
220
203
  if os.path.exists(potential_kpoints):
@@ -225,10 +208,11 @@ def main():
225
208
  kpoints_path=kpoints_path,
226
209
  output=args.output,
227
210
  ylim=tuple(args.ylim) if args.ylim else None,
228
- font=args.font
211
+ font=args.font,
229
212
  )
230
213
  except Exception:
231
214
  import traceback
215
+
232
216
  traceback.print_exc()
233
217
  sys.exit(1)
234
218
  else:
@@ -236,5 +220,6 @@ def main():
236
220
  else:
237
221
  parser.print_help()
238
222
 
223
+
239
224
  if __name__ == "__main__":
240
225
  main()