|
2 | 2 |
|
3 | 3 | import os |
4 | 4 | import shutil |
| 5 | +import warnings |
5 | 6 | from collections.abc import Mapping |
6 | 7 | from glob import glob |
7 | 8 | from itertools import chain |
@@ -96,6 +97,15 @@ def save_yaml(data, file_path): |
96 | 97 | yaml.dump(data, fp) |
97 | 98 |
|
98 | 99 |
|
| 100 | +def dump_yaml_str(data): |
| 101 | + """Serialize *data* to a YAML string (ruamel.yaml safe mode).""" |
| 102 | + import io |
| 103 | + buf = io.StringIO() |
| 104 | + yaml = YAML(typ='safe', pure=True) |
| 105 | + yaml.dump(data, buf) |
| 106 | + return buf.getvalue() |
| 107 | + |
| 108 | + |
99 | 109 | def load_array(file): |
100 | 110 | ext = os.path.splitext(file)[-1] |
101 | 111 | if 'npy' in ext: |
@@ -192,3 +202,51 @@ def create_dir(dirname, backup=False): |
192 | 202 | os.makedirs(dirname) |
193 | 203 | else: |
194 | 204 | assert dirname.is_dir(), f'{dirname} is not a dir' |
| 205 | + |
| 206 | + |
| 207 | +# --------------------------------------------------------------------------- |
| 208 | +# Array shape coercion helpers |
| 209 | +# --------------------------------------------------------------------------- |
| 210 | + |
| 211 | +def coerce_box(arr, nframes, fname="box.npy"): |
| 212 | + """Ensure box array has shape (nframes, 9); accept (nframes, 3, 3).""" |
| 213 | + if arr.shape == (nframes, 3, 3): |
| 214 | + warnings.warn(f"{fname}: got shape {arr.shape}, reshaping to ({nframes}, 9).") |
| 215 | + return arr.reshape(nframes, 9) |
| 216 | + if arr.shape != (nframes, 9): |
| 217 | + raise ValueError(f"{fname}: expected shape ({nframes}, 9), got {arr.shape}.") |
| 218 | + return arr |
| 219 | + |
| 220 | + |
| 221 | +def coerce_energy(arr, nframes, fname="energy.npy"): |
| 222 | + """Ensure energy array has shape (nframes, 1); accept (nframes,).""" |
| 223 | + if arr.shape == (nframes,): |
| 224 | + warnings.warn(f"{fname}: got shape {arr.shape}, reshaping to ({nframes}, 1).") |
| 225 | + return arr.reshape(nframes, 1) |
| 226 | + if arr.shape != (nframes, 1): |
| 227 | + raise ValueError(f"{fname}: expected shape ({nframes}, 1), got {arr.shape}.") |
| 228 | + return arr |
| 229 | + |
| 230 | + |
| 231 | +def coerce_stress(arr, nframes, fname="stress.npy"): |
| 232 | + """Ensure stress array has shape (nframes, 6) upper-triangle (xx,xy,xz,yy,yz,zz). |
| 233 | +
|
| 234 | + Accepted input shapes: |
| 235 | + (nframes, 6) -- already upper-triangle, returned as-is. |
| 236 | + (nframes, 3,3) -- full matrix, reshaped then upper-triangle sliced. |
| 237 | + (nframes, 9) -- full flat, upper-triangle sliced. |
| 238 | + """ |
| 239 | + if arr.shape == (nframes, 6): |
| 240 | + return arr |
| 241 | + if arr.shape == (nframes, 3, 3): |
| 242 | + warnings.warn( |
| 243 | + f"{fname}: got shape {arr.shape}, reshaping to ({nframes}, 9) " |
| 244 | + f"then taking upper-triangle to ({nframes}, 6)." |
| 245 | + ) |
| 246 | + arr = arr.reshape(nframes, 9) |
| 247 | + if arr.shape == (nframes, 9): |
| 248 | + warnings.warn(f"{fname}: got shape {arr.shape}, taking upper-triangle to ({nframes}, 6).") |
| 249 | + return arr[:, [0, 1, 2, 4, 5, 8]] |
| 250 | + raise ValueError( |
| 251 | + f"{fname}: expected ({nframes},6), ({nframes},9), or ({nframes},3,3), got {arr.shape}." |
| 252 | + ) |
0 commit comments