220 lines
7.6 KiB
Python
220 lines
7.6 KiB
Python
from __future__ import annotations
|
|
from typing import List
|
|
import os, argparse, numpy as np, pickle
|
|
import matplotlib.pyplot as plt
|
|
from pathlib import Path
|
|
|
|
from simulation import Diagram, Simulation
|
|
from packsim_core import AreaEnergy, RadialALEnergy, RadialTEnergy
|
|
|
|
ENERGY_R_STR = {AreaEnergy: "Area", RadialALEnergy: "Radial[AL]", RadialTEnergy: "Radial[T]"}
|
|
ENERGY_I_STR = {AreaEnergy: "area", RadialALEnergy: "radial-al", RadialTEnergy: "radial-t"}
|
|
I_TO_R = {"area": "Area","radial-t": "Radial[AL]", "radial-t": "Radial[T]"}
|
|
|
|
def get_torus_config_energies(n: int, widths: np.ndarray, h: float, r: float,
|
|
energy: str) -> Tuple:
|
|
sim_file = SIM_FOLDER / f"{I_TO_R[energy]} - TorusConfigEnergy - N{n}.data"
|
|
if sim_file.is_file():
|
|
with open(sim_file, "rb") as data:
|
|
return pickle.load(data)
|
|
|
|
torus_min_energies, torus_max_energies = np.empty(widths.shape), np.empty(widths.shape)
|
|
torus_min_configs, torus_max_configs = [None]*len(widths), [None]*len(widths)
|
|
|
|
for i, w in enumerate(widths):
|
|
sim = Simulation(n, w, h, r, energy)
|
|
configs = []
|
|
|
|
for j in range(1):
|
|
for c in range(1,n): # Ignore 0, tends to error.
|
|
config = (1,c) if j == 0 else (c,1)
|
|
sim.add_frame(torus=config)
|
|
configs.append(config)
|
|
|
|
# eigs = np.sort(np.linalg.eig(sim.frames[-1].hessian(10e-5))[0])
|
|
# if eigs[0] > 1e-4:
|
|
# del sim.frames[-1]
|
|
# del config[-1]
|
|
|
|
hashes = int(21*i/len(widths))
|
|
print(f'Generating at width {w:.02f}... ' + \
|
|
f'|{"#"*hashes}{" "*(20-hashes)}| {i+1}/{len(widths)}, ' + \
|
|
f'{c + (n-1)*j}/{2*(n-1)} completed.', flush=True, end='\r')
|
|
|
|
pair = list(zip(configs,[frame.energy for frame in sim.frames]))
|
|
torus_min_configs[i], torus_min_energies[i] = min(pair, key=lambda x: x[1])
|
|
torus_max_configs[i], torus_max_energies[i] = max(pair, key=lambda x: x[1])
|
|
|
|
print(flush=True)
|
|
|
|
out_tup = (torus_min_energies, torus_max_energies, torus_min_configs, torus_max_configs)
|
|
with open(sim_file, "wb") as output:
|
|
pickle.dump(out_tup, output)
|
|
|
|
return out_tup
|
|
|
|
|
|
def get_equilibria_data(filepath: Path):
|
|
if filepath.is_file():
|
|
with open(filepath, "rb") as data:
|
|
return pickle.load(data)
|
|
|
|
sims = []
|
|
files = list(Path(filepath).iterdir())
|
|
|
|
for i, file in enumerate(files):
|
|
sims.append(Simulation.load(file))
|
|
|
|
hashes = int(21*i/len(files))
|
|
print(f'Loading simulations... |{"#"*hashes}{" "*(20-hashes)}|' + \
|
|
f' {i+1}/{len(files)} simulations loaded.', flush=True, end='\r')
|
|
print(flush=True)
|
|
sims.sort(key=lambda x: x.w)
|
|
|
|
widths = np.asarray([sim.w for sim in sims])
|
|
|
|
pairs_at_widths = []
|
|
for sim in sims:
|
|
pairs_at_widths.append([(frame.energy, np.var(frame.stats["avg_radius"]) <= 1e-8) \
|
|
for frame in sim.frames])
|
|
|
|
# min_frames = [min(sim.frames, key=lambda x: x.energy) for sim in sims]
|
|
# max_frames = [max(sim.frames, key=lambda x: x.energy) for sim in sims]
|
|
|
|
# min_energies = np.asarray([frame.energy for frame in min_frames])
|
|
# max_energies = np.asarray([frame.energy for frame in max_frames])
|
|
|
|
# min_markers = [np.var(frame.stats["avg_radius"]) <= 1e-8 for frame in min_frames]
|
|
# max_markers = [np.var(frame.stats["avg_radius"]) <= 1e-8 for frame in max_frames]
|
|
|
|
n, h, r, energy = sims[0].n, sims[0].h, sims[0].r, sims[0].energy
|
|
|
|
sim_file = SIM_FOLDER / f"{ENERGY_R_STR[energy]} - EquilibriaData - N{n}.data"
|
|
out_tup = (widths, pairs_at_widths, n, h, r, ENERGY_I_STR[energy])
|
|
with open(sim_file, "wb") as output:
|
|
pickle.dump(out_tup, output)
|
|
|
|
return out_tup
|
|
|
|
def axis_settings(ax, widths):
|
|
ax.invert_xaxis()
|
|
ax.grid(zorder=0)
|
|
ax.set_xticks([round(w,2) for w in widths[::-2]])
|
|
ax.set_xticklabels(ax.get_xticks(), rotation = 90)
|
|
|
|
|
|
def main():
|
|
# Loading arguments.
|
|
parser = argparse.ArgumentParser("Compiles the equilibriums for each width into a diagram.")
|
|
parser.add_argument('sims_path', metavar='path/to/data',
|
|
help="folder that contains simulation files, or cached data file.")
|
|
parser.add_argument('-q', '--quiet', dest='quiet', action='store_true', default=False,
|
|
help="suppress all normal output")
|
|
|
|
args = parser.parse_args()
|
|
|
|
widths, energy_shape_tups, n, h, r, energy = get_equilibria_data(Path(args.sims_path))
|
|
|
|
torus_min_energies, torus_max_energies, _, _ = get_torus_config_energies(
|
|
n, widths, h, r, energy
|
|
)
|
|
|
|
fig_folder = Path(f"figures/ShrinkEnergyComparison - N{n}")
|
|
fig_folder.mkdir(exist_ok=True)
|
|
|
|
# Torus minimum energies used as reference.
|
|
plt.tight_layout()
|
|
# Density of States diagram.
|
|
fig, ax = plt.subplots(figsize=(16, 8))
|
|
|
|
distinct_ordered, distinct_unordered = [], []
|
|
for energy_shapes in energy_shape_tups:
|
|
equal_shape = list([tup[1] for tup in energy_shapes])
|
|
distinct_ordered.append(equal_shape.count(True))
|
|
distinct_unordered.append(equal_shape.count(False))
|
|
|
|
ax.plot(widths, distinct_unordered, label="Unordered Equilibria")
|
|
ax.plot(widths, distinct_ordered, label="Ordered Equilibria")
|
|
ax.legend()
|
|
axis_settings(ax, widths)
|
|
ax.title.set_text('Density of States')
|
|
ax.set_xlabel("Width")
|
|
ax.set_ylabel("Number of States")
|
|
fig.savefig(fig_folder / "Density Of States.png")
|
|
|
|
# Bifurcation diagram
|
|
fig, ax = plt.subplots(figsize=(16, 8))
|
|
|
|
ordered_energies, unordered_energies = [], []
|
|
for energy_shapes in energy_shape_tups:
|
|
order_width, unorder_width = [], []
|
|
for pair in energy_shapes:
|
|
if pair[1]:
|
|
order_width.append(pair[0])
|
|
else:
|
|
unorder_width.append(pair[0])
|
|
ordered_energies.append(order_width)
|
|
unordered_energies.append(unorder_width)
|
|
|
|
|
|
for i in range(len(torus_min_energies)):
|
|
ordered_energies[i].append(torus_min_energies[i])
|
|
ordered_energies[i].append(torus_max_energies[i])
|
|
|
|
|
|
null_unorder = []
|
|
for i, width in enumerate(unordered_energies):
|
|
if len(width) == 0:
|
|
null_unorder.append(i)
|
|
for x in unordered_energies[i-1]:
|
|
width.append(x)
|
|
#width = unordered_energies[i-1]
|
|
#width.append(max(unordered_energies[i-1]))
|
|
|
|
min_order = np.asarray([min(width) for width in ordered_energies])
|
|
max_order = np.asarray([max(width) for width in ordered_energies])
|
|
min_unorder = np.asarray([min(width) for width in unordered_energies])
|
|
max_unorder = np.asarray([max(width) for width in unordered_energies])
|
|
|
|
ax.plot(widths, min_order - torus_min_energies, color='C1')
|
|
#ax.plot(widths, max_order - torus_min_energies, color='C1', linestyle='dotted')
|
|
ax.plot(widths, min_unorder - torus_min_energies, color='C0')
|
|
ax.plot(widths, max_unorder - torus_min_energies, color='C0', linestyle='dotted')
|
|
axis_settings(ax, widths)
|
|
|
|
for i in null_unorder:
|
|
ax.scatter(widths[i], min_unorder[i] - torus_min_energies[i],
|
|
marker='X', color="blue", s=50, zorder=4)
|
|
ax.scatter(widths[i], max_unorder[i] - torus_min_energies[i],
|
|
marker='X', edgecolors="blue", facecolors='none', s=100, zorder=4)
|
|
|
|
# for i, marker in enumerate(min_markers):
|
|
# if marker:
|
|
# ax.scatter(widths[i], min_energies[i]-torus_min_energies[i],
|
|
# marker='H', color="orange", s=20, zorder=4)
|
|
# else:
|
|
# ax.scatter(widths[i], min_energies[i]-torus_min_energies[i],
|
|
# marker='d', color="blue", s=20, zorder=4)
|
|
|
|
# for i, marker in enumerate(max_markers):
|
|
# if marker:
|
|
# ax.scatter(widths[i], max_energies[i]-torus_min_energies[i],
|
|
# marker='H', edgecolors="orange", s=20, facecolors='none', zorder=4)
|
|
# else:
|
|
# ax.scatter(widths[i], max_energies[i]-torus_min_energies[i],
|
|
# marker='d', edgecolors="blue", s=20, facecolors='none', zorder=4)
|
|
|
|
ax.title.set_text('Reduced Energy vs. Width')
|
|
ax.set_xlabel("Width")
|
|
ax.set_ylabel("Reduced Energy")
|
|
|
|
fig.savefig(fig_folder / "Bifurcation.png")
|
|
|
|
if __name__ == "__main__":
|
|
os.environ["QT_LOGGING_RULES"] = "*=false"
|
|
SIM_FOLDER = Path(f"simulations/ShrinkEnergyComparison")
|
|
SIM_FOLDER.mkdir(exist_ok=True)
|
|
try:
|
|
main()
|
|
except KeyboardInterrupt:
|
|
print("Program terminated by user.") |