import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from pathlib import Path
ASM_US = {
'39': {'V0': 29.68, 'V1': 6.19, 'V2': 1.84},
'118': {'V0': 101.8, 'V1': 16.71, 'V2': 6.03},
'9241': {'V0': 13745, 'V1': 4635, 'V2': 641},
}
KLU_US = {
'39': 3.64 + 0.76, '118': 8.73 + 1.82, '9241': 2889 + 353, }
SYSTEMS = ['39', '118', '9241']
VERSIONS = ['V0', 'V1', 'V2']
SYS_TITLE = {'39': 'IEEE 39', '118': 'IEEE 118', '9241': 'PEGASE 9241'}
iter_ms = {}
for s in SYSTEMS:
iter_ms[s] = {}
for v in VERSIONS:
asm = ASM_US[s][v] / 1000.0 lu = KLU_US[s] / 1000.0
iter_ms[s][v] = {'asm': asm, 'lu': lu, 'total': asm + lu}
STYLE_ASM = dict(facecolor='0.20', hatch='', edgecolor='0.30')
STYLE_LU = dict(facecolor='0.82', hatch='', edgecolor='0.40')
VER_LABEL_FULL = {
'V0': 'V0 (MATPOWER)',
'V1': "V1 (Sch\xe4fer '18)",
'V2': 'V2 (Proposed)',
}
VER_LABEL_SHORT = {'V0': 'V0', 'V1': 'V1', 'V2': 'V2'}
plt.rcParams.update({
'font.family': 'serif',
'font.size': 8,
'axes.linewidth': 0.55,
'xtick.major.width': 0.55,
'ytick.major.width': 0.55,
'xtick.major.size': 3,
'hatch.linewidth': 0.55,
})
fig, axes = plt.subplots(1, 3, figsize=(7.1, 2.6))
fig.subplots_adjust(wspace=0.32, bottom=0.32)
BAR_H = 0.50
Y = {'V0': 2, 'V1': 1, 'V2': 0}
for idx, (ax, s) in enumerate(zip(axes, SYSTEMS)):
x_max = iter_ms[s]['V0']['total']
v0_total = iter_ms[s]['V0']['total']
if v0_total >= 0.5: unit, scale = 'ms', 1.0
else: unit, scale = 'μs', 1000.0
for v in VERSIONS:
y = Y[v]
asm = iter_ms[s][v]['asm']
lu = iter_ms[s][v]['lu']
ax.barh(y, asm, height=BAR_H, left=0,
facecolor=STYLE_ASM['facecolor'], hatch=STYLE_ASM['hatch'],
edgecolor=STYLE_ASM['edgecolor'], linewidth=0.0, zorder=3)
ax.barh(y, lu, height=BAR_H, left=asm,
facecolor=STYLE_LU['facecolor'], hatch=STYLE_LU['hatch'],
edgecolor=STYLE_LU['edgecolor'], linewidth=0.6, zorder=3)
ax.barh(y, asm + lu, height=BAR_H,
facecolor='none', edgecolor='0.30', linewidth=0.6, zorder=4)
pct = asm / (asm + lu) * 100
if asm > x_max * 0.10:
ax.text(asm / 2, y, f'{pct:.0f}%',
ha='center', va='center', fontsize=5.8,
color='white', fontweight='bold', zorder=5)
total = asm + lu
val = total * scale
ax.text(total + x_max * 0.015, y, f'{val:.3g} {unit}',
ha='left', va='center', fontsize=5.5, color='0.25', zorder=5)
ax.set_title(SYS_TITLE[s], fontsize=8.5, fontweight='bold', pad=3)
ax.set_yticks([0, 1, 2])
if idx == 0:
ax.set_yticklabels(
[VER_LABEL_FULL['V2'], VER_LABEL_FULL['V1'], VER_LABEL_FULL['V0']],
fontsize=6.8)
else:
ax.set_yticklabels(
[VER_LABEL_SHORT['V2'], VER_LABEL_SHORT['V1'], VER_LABEL_SHORT['V0']],
fontsize=7)
ax.set_xlabel('Per-iteration time (ms)', fontsize=8)
ax.tick_params(axis='x', labelsize=7)
ax.set_ylim(-0.55, 2.55)
ax.set_xlim(0, x_max * 1.28)
ax.grid(axis='x', linestyle=':', linewidth=0.4, color='0.65', zorder=0)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
h_asm = mpatches.Patch(
facecolor=STYLE_ASM['facecolor'], hatch=STYLE_ASM['hatch'], edgecolor='0.40',
linewidth=0.55, label='Jacobian assembly')
h_lu = mpatches.Patch(
facecolor=STYLE_LU['facecolor'], hatch=STYLE_LU['hatch'], edgecolor='0.40',
linewidth=0.55, label='KLU re-factorisation (constant across V0/V1/V2)')
fig.legend(handles=[h_asm, h_lu], loc='lower center', ncol=2, fontsize=6.8,
frameon=False, bbox_to_anchor=(0.5, 0.04),
columnspacing=1.2, handlelength=2.4, handletextpad=0.6)
out = Path('paper/time_breakdown')
fig.savefig(str(out) + '.pdf', bbox_inches='tight', dpi=300)
fig.savefig(str(out) + '.png', bbox_inches='tight', dpi=300)
print(f'Saved {out}.pdf and {out}.png')
print()
print('Assembly fraction per version (directly instrumented):')
for s in SYSTEMS:
fracs = {v: iter_ms[s][v]["asm"] / iter_ms[s][v]["total"] * 100 for v in VERSIONS}
print(f' {SYS_TITLE[s]}: V0={fracs["V0"]:.0f}% V1={fracs["V1"]:.0f}% V2={fracs["V2"]:.0f}%')