|
8 | 8 |
|
9 | 9 | import math |
10 | 10 | import os |
| 11 | +import re |
11 | 12 | import tempfile |
12 | 13 |
|
13 | 14 | import numpy as np |
|
24 | 25 | 'font.family': 'serif', |
25 | 26 | }) |
26 | 27 |
|
| 28 | +# LaTeX-style labels for known MFC variable names |
| 29 | +_LABEL_MAP = { |
| 30 | + 'pres': r'$p$', |
| 31 | + 'rho': r'$\rho$', |
| 32 | + 'E': r'$E$', |
| 33 | + 'T': r'$T$', |
| 34 | + 'D': r'$D$', |
| 35 | + 'c': r'$c$', |
| 36 | + 'gamma': r'$\gamma$', |
| 37 | + 'pi_inf': r'$\pi_\infty$', |
| 38 | + 'pres_inf': r'$p_\infty$', |
| 39 | + 'heat_ratio': r'$\gamma$', |
| 40 | + 'schlieren': r'$|\nabla \rho|$', |
| 41 | + 'psi': r'$\psi$', |
| 42 | + 'n': r'$n$', |
| 43 | + 'qm': r'$q_m$', |
| 44 | + 'Bx': r'$B_x$', 'By': r'$B_y$', 'Bz': r'$B_z$', |
| 45 | + 'voidFraction': r'void fraction', |
| 46 | + 'liutex_mag': r'$|\lambda|$', |
| 47 | + 'damage_state': r'damage', |
| 48 | +} |
| 49 | + |
| 50 | +_INDEXED_PATTERNS = [ |
| 51 | + (r'^vel(\d+)$', lambda m: [r'$u$', r'$v$', r'$w$'][int(m.group(1)) - 1] |
| 52 | + if int(m.group(1)) <= 3 else rf'$v_{m.group(1)}$'), |
| 53 | + (r'^mom(\d+)$', lambda m: rf'$\rho {["u", "v", "w"][int(m.group(1)) - 1]}$' |
| 54 | + if int(m.group(1)) <= 3 else rf'$m_{m.group(1)}$'), |
| 55 | + (r'^alpha(\d+)$', lambda m: rf'$\alpha_{m.group(1)}$'), |
| 56 | + (r'^alpha_rho(\d+)$', lambda m: rf'$\alpha_{m.group(1)}\rho_{m.group(1)}$'), |
| 57 | + (r'^alpha_rho_e(\d+)$', lambda m: rf'$\alpha_{m.group(1)}\rho_{m.group(1)}e_{m.group(1)}$'), |
| 58 | + (r'^omega(\d+)$', lambda m: rf'$\omega_{m.group(1)}$'), |
| 59 | + (r'^tau(\d+)$', lambda m: rf'$\tau_{m.group(1)}$'), |
| 60 | + (r'^xi(\d+)$', lambda m: rf'$\xi_{m.group(1)}$'), |
| 61 | + (r'^flux(\d+)$', lambda m: rf'$F_{m.group(1)}$'), |
| 62 | + (r'^liutex_axis(\d+)$', lambda m: rf'$\lambda_{m.group(1)}$'), |
| 63 | + (r'^rho(\d+)$', lambda m: rf'$\rho_{m.group(1)}$'), |
| 64 | + (r'^Y_(.+)$', lambda m: rf'$Y_{{\mathrm{{{m.group(1)}}}}}$'), |
| 65 | + (r'^nR(\d+)$', lambda m: rf'$nR_{{{m.group(1)}}}$'), |
| 66 | + (r'^nV(\d+)$', lambda m: rf'$nV_{{{m.group(1)}}}$'), |
| 67 | + (r'^nP(\d+)$', lambda m: rf'$nP_{{{m.group(1)}}}$'), |
| 68 | + (r'^nM(\d+)$', lambda m: rf'$nM_{{{m.group(1)}}}$'), |
| 69 | + (r'^color_function(\d+)$', lambda m: rf'color $f_{m.group(1)}$'), |
| 70 | +] |
| 71 | + |
| 72 | + |
| 73 | +def pretty_label(varname): |
| 74 | + """Map an MFC variable name to a LaTeX-style label for plots.""" |
| 75 | + if varname in _LABEL_MAP: |
| 76 | + return _LABEL_MAP[varname] |
| 77 | + for pattern, formatter in _INDEXED_PATTERNS: |
| 78 | + m = re.match(pattern, varname) |
| 79 | + if m: |
| 80 | + return formatter(m) |
| 81 | + return varname |
| 82 | + |
27 | 83 |
|
28 | 84 | def render_1d(x_cc, data, varname, step, output, **opts): # pylint: disable=too-many-arguments,too-many-positional-arguments |
29 | 85 | """Render a 1D line plot and save as PNG.""" |
30 | 86 | fig, ax = plt.subplots(figsize=opts.get('figsize', (10, 6))) |
| 87 | + label = pretty_label(varname) |
31 | 88 | ax.plot(x_cc, data, linewidth=1.5) |
32 | 89 | ax.set_xlabel(r'$x$') |
33 | | - ax.set_ylabel(varname) |
34 | | - ax.set_title(f'{varname} (step {step})') |
| 90 | + ax.set_ylabel(label) |
| 91 | + ax.set_title(f'{label} (step {step})') |
35 | 92 | ax.grid(True, alpha=0.3) |
36 | 93 | ax.ticklabel_format(axis='y', style='sci', scilimits=(-3, 4), useMathText=True) |
37 | 94 |
|
@@ -67,7 +124,7 @@ def render_1d_tiled(x_cc, variables, step, output, **opts): # pylint: disable=t |
67 | 124 | row, col = divmod(idx, ncols) |
68 | 125 | ax = axes[row][col] |
69 | 126 | ax.plot(x_cc, variables[vn], linewidth=1.2) |
70 | | - ax.set_ylabel(vn, fontsize=9) |
| 127 | + ax.set_ylabel(pretty_label(vn), fontsize=9) |
71 | 128 | ax.tick_params(labelsize=8) |
72 | 129 | ax.grid(True, alpha=0.3) |
73 | 130 |
|
@@ -125,10 +182,11 @@ def render_2d(x_cc, y_cc, data, varname, step, output, **opts): # pylint: disab |
125 | 182 | # data shape is (nx, ny), pcolormesh expects (ny, nx) when using x_cc, y_cc |
126 | 183 | pcm = ax.pcolormesh(x_cc, y_cc, data.T, cmap=cmap, vmin=vmin, vmax=vmax, |
127 | 184 | norm=norm, shading='auto') |
128 | | - fig.colorbar(pcm, ax=ax, label=varname) |
| 185 | + label = pretty_label(varname) |
| 186 | + fig.colorbar(pcm, ax=ax, label=label) |
129 | 187 | ax.set_xlabel(r'$x$') |
130 | 188 | ax.set_ylabel(r'$y$') |
131 | | - ax.set_title(f'{varname} (step {step})') |
| 189 | + ax.set_title(f'{label} (step {step})') |
132 | 190 | ax.set_aspect('equal', adjustable='box') |
133 | 191 |
|
134 | 192 | fig.tight_layout() |
@@ -197,11 +255,12 @@ def render_3d_slice(assembled, varname, step, output, slice_axis='z', # pylint: |
197 | 255 | # sliced shape depends on axis: need to transpose appropriately |
198 | 256 | pcm = ax.pcolormesh(x_plot, y_plot, sliced.T, cmap=cmap, vmin=vmin, |
199 | 257 | vmax=vmax, norm=norm, shading='auto') |
200 | | - fig.colorbar(pcm, ax=ax, label=varname) |
| 258 | + label = pretty_label(varname) |
| 259 | + fig.colorbar(pcm, ax=ax, label=label) |
201 | 260 | ax.set_xlabel(xlabel) |
202 | 261 | ax.set_ylabel(ylabel) |
203 | 262 | slice_coord = coord_along[idx] |
204 | | - ax.set_title(f'{varname} (step {step}, {slice_axis}={slice_coord:.4g})') |
| 263 | + ax.set_title(f'{label} (step {step}, {slice_axis}={slice_coord:.4g})') |
205 | 264 | ax.set_aspect('equal', adjustable='box') |
206 | 265 |
|
207 | 266 | fig.tight_layout() |
|
0 commit comments