Updated scripts for post-processing data.

This commit is contained in:
Kenneth Jao 2022-03-25 17:10:26 -04:00
parent de65751b48
commit 87be8908e3
14 changed files with 1314 additions and 83 deletions

424
scripts/aspect_diagrams.py Normal file
View File

@ -0,0 +1,424 @@
from __future__ import annotations
from typing import List, Tuple, Dict
import argparse, math, numpy as np, os
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
from multiprocessing import Pool, cpu_count
from pathlib import Path
import squish.ordered as order
from squish import Simulation, DomainParams
from squish.common import OUTPUT_DIR
def order_process(domain: DomainParams) -> Tuple[float, float, float]:
energies, isoparams = [], []
configs = order.configurations(domain)
for config in configs:
rbar = order.avg_radius(domain, config)
area = domain.w * domain.h / domain.n
energies.append(
2 * domain.w * domain.h
+ 2 * math.pi * domain.n * (domain.r ** 2 - 2 * domain.r * rbar)
)
isoparams.append(math.pi * rbar ** 2 / area)
return (domain.w, min(energies), max(energies), min(isoparams), max(isoparams))
def get_ordered_energies(orig_domain: DomainParams, widths: np.ndarray) -> Dict:
data = {}
domains = []
for w in widths:
aspect = w
domains.append(
DomainParams(
orig_domain.n,
math.sqrt(orig_domain.n * aspect),
math.sqrt(orig_domain.n / aspect),
orig_domain.r,
)
)
# domains = [
# DomainParams(orig_domain.n, w, orig_domain.h, orig_domain.r) for w in widths
# ]
with Pool(cpu_count()) as pool:
energy_mins, energy_maxes, isoparam_mins, isoparam_maxes = {}, {}, {}, {}
for i, res in enumerate(pool.imap_unordered(order_process, domains)):
energy_mins[res[0]] = res[1]
energy_maxes[res[0]] = res[2]
isoparam_mins[res[0]] = res[3]
isoparam_maxes[res[0]] = res[4]
hashes = int(21 * i / len(widths))
print(
f'Generating at width {res[0]:.02f}... |{"#"*hashes}{" "*(20-hashes)}|'
+ f" {i+1}/{len(widths)} completed.",
flush=True,
end="\r",
)
print(flush=True)
data["energy_min"] = list([x[1] for x in sorted(energy_mins.items())])
data["energy_max"] = list([x[1] for x in sorted(energy_maxes.items())])
data["isoparam_min"] = list([x[1] for x in sorted(isoparam_mins.items())])
data["isoparam_max"] = list([x[1] for x in sorted(isoparam_maxes.items())])
return data
def eq_file_process(file: Path) -> Tuple[float, List[float], List[float]]:
sim, frames = Simulation.load(file)
alls = []
for frame_info in frames:
alls.append(
[
frame_info["energy"],
np.var(frame_info["stats"]["avg_radius"]) <= 1e-8,
np.count_nonzero(frame_info["stats"]["site_edge_count"] != 6),
sum(frame_info["stats"]["site_energies"][: sim.domain.n]),
]
)
sim, frames = Simulation.load(file)
sim.frames = list(frames)
counts = sim.get_distinct()
distincts = []
for j, frame_info in enumerate(sim.frames):
distincts.append(
[
frame_info["energy"],
np.var(frame_info["stats"]["avg_radius"]) <= 1e-8,
np.count_nonzero(frame_info["stats"]["site_edge_count"] != 6),
sum(frame_info["stats"]["site_energies"][: sim.domain.n]),
counts[j],
]
)
return sim.domain.w / sim.domain.h, alls, distincts
def get_equilibria_data(filepath: Path) -> Tuple[Dict, numpy.ndarray, DomainParams]:
data = {"all": {}, "distinct": {}}
files = list(Path(filepath).iterdir())
with Pool(cpu_count()) as pool:
for i, res in enumerate(pool.imap_unordered(eq_file_process, files)):
data["all"][res[0]] = res[1]
data["distinct"][res[0]] = res[2]
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)
sim, frames = Simulation.load(files[0])
widths = np.asarray(sorted(data["all"]))
domain = DomainParams(sim.domain.n, widths[-1], sim.domain.h, sim.domain.r)
return data, widths, domain
def axis_settings(ax, widths):
ax.grid(zorder=0)
ax.set_xticks([round(w, 2) for w in widths[::2]])
ax.set_xticklabels([f"{round(w, 3):.2f}" for w in widths[::2]], rotation=90)
plt.subplots_adjust(0.07, 0.12, 0.97, 0.9)
def probability_of_disorder(data, widths, domain):
fig, ax = plt.subplots(figsize=(16, 8))
all_disorder_count = []
for width in widths:
equal_shape = list([c[1] for c in data["all"][width]])
all_disorder_count.append(
100 * equal_shape.count(False) / len(data["all"][width])
)
ax.plot(widths, all_disorder_count)
axis_settings(ax, widths)
ax.yaxis.set_major_formatter(mtick.PercentFormatter())
ax.title.set_text(f"Probability of Disorder - N{domain.n}")
ax.set_xlabel("Aspect Ratio")
ax.set_ylabel("Disordered Equilibria")
boa_y_min = round(min(all_disorder_count) / 20) * 20 - 5
ax.set_yticks(np.arange(boa_y_min, 100.01, 2.5))
return fig
def density_of_states(data, widths, domain):
fig, ax = plt.subplots(figsize=(16, 8))
distinct_ordered, distinct_unordered = [], []
for width in widths:
equal_shape = list([c[1] for c in data["distinct"][width]])
distinct_ordered.append(equal_shape.count(True))
distinct_unordered.append(equal_shape.count(False))
ax2 = ax.twinx()
ax.plot(widths, distinct_unordered, label="Unordered Equilibria", color="C0")
ax2.plot(widths, distinct_ordered, label="Ordered Equilibria", color="C1")
axis_settings(ax, widths)
plt.subplots_adjust(0.07, 0.12, 0.92, 0.9)
ax.title.set_text(f"Density of States - N{domain.n}")
ax.set_xlabel("Aspect Ratio")
ax.set_ylabel("Number of States (Disordered)", color="C0")
ax2.set_ylabel("Number of States (Ordered)", color="C1")
dos_y_max_unorder = 1.05 * max(distinct_unordered)
dos_y_max_order = 1.05 * max(distinct_ordered)
ax.set_yticks(np.linspace(0, dos_y_max_unorder, 20).astype(int))
# ax.set_yticks(np.arange(0, dos_y_max_unorder, round(dos_y_max_unorder/200, 1)*10))
ax2.set_yticks(np.arange(0, dos_y_max_order))
return fig
def defect_density(data, widths, domain):
fig, ax = plt.subplots(figsize=(16, 8))
defects = []
for width in widths:
defects.append(
sum([c[2] for c in data["all"][width] if not c[1]])
/ len(data["all"][width])
)
ax.plot(widths, defects)
axis_settings(ax, widths)
ax.title.set_text(f"Average Defects - N{domain.n}")
ax.set_xlabel("Aspect Ratio")
ax.set_ylabel("Defects")
ax.set_yticks(np.arange(0, 1 + max(defects), 0.5))
return fig
def circle_isoparam(data, widths, order_data, domain):
fig, ax = plt.subplots(figsize=(16, 8))
ax2 = ax.twinx()
axis_settings(ax, widths)
plt.subplots_adjust(0.07, 0.12, 0.92, 0.9)
ax.title.set_text(f"Circular Isoparametric Ratio - N{domain.n}")
ax.set_xlabel("Aspect Ratio")
ax.set_ylabel("Maximum Ratio", color="C0")
ax2.set_ylabel("Minimum Ratio", color="C1")
ax.plot(widths, order_data["isoparam_max"], label="Maximum", color="C0")
ax2.plot(widths, order_data["isoparam_min"], label="Minimum", color="C1")
return fig
def reduced_energy(data, widths, order_data, domain):
fig, ax = plt.subplots(figsize=(16, 8))
ordered_energies, unordered_energies = [], []
for width in widths:
ordered_energies.append([c[0] for c in data["distinct"][width] if c[1]])
unordered_energies.append([c[0] for c in data["distinct"][width] if not c[1]])
for i in range(len(order_data["energy_min"])):
ordered_energies[i].append(order_data["energy_min"][i])
ordered_energies[i].append(order_data["energy_max"][i])
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])
offset = np.array(min_order)
min_unorder_off = min_unorder - offset
max_unorder_off = max_unorder - offset
ax.plot(widths, min_order - offset, color="C1")
# ax.plot(widths, max_order - offset, color='C1', linestyle='dotted')
ax.plot(widths, min_unorder_off, color="C0")
ax.plot(widths, max_unorder_off, color="C0", linestyle="dotted")
axis_settings(ax, widths)
ax.title.set_text(f"Reduced Energy vs. Width - N{domain.n}")
ax.set_xlabel("Aspect Ratio")
ax.set_ylabel("Reduced Energy")
bif_y_max = np.max(np.abs(np.concatenate((min_unorder_off, max_unorder_off))))
bif_top = np.arange(
0, bif_y_max, round(bif_y_max / 20, -math.floor(math.log10(bif_y_max / 20)))
)
ax.set_yticks(np.concatenate((-bif_top[1:][::-1], bif_top)))
return fig
def defect_energy(data, widths, order_data, domain):
fig, ax = plt.subplots(figsize=(16, 8))
ordered_energies, unordered_energies = [], []
for width in widths:
ordered_energies.append([c[0] for c in data["distinct"][width] if c[1]])
unordered_energies.append([c[0] for c in data["distinct"][width] if not c[1]])
for i in range(len(order_data["energy_min"])):
ordered_energies[i].append(order_data["energy_min"][i])
ordered_energies[i].append(order_data["energy_max"][i])
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])
offset = np.array(min_order)
defect_a, defect_b = [], []
for width in widths:
num_defects = [c[2] for c in data["all"][width]]
defect_energy = [c[3] for c in data["all"][width]]
m, b = np.polyfit(num_defects, defect_energy, 1)
defect_a.append(m)
defect_b.append(b)
ax2 = ax.twinx()
ax.plot(widths, defect_a, label="Energy per Defect", color="C0")
ax2.plot(widths, defect_b - offset, label="Relative Initial Energy", color="C1")
axis_settings(ax, widths)
plt.subplots_adjust(0.07, 0.12, 0.92, 0.9)
ax.title.set_text(f"Defect Energy - N{domain.n}")
ax.set_xlabel("Aspect Ratio")
ax.set_ylabel("Energy per Defect", color="C0")
ax2.set_ylabel("Relative Initial Energy", color="C1")
return fig
def excess_energy(data, widths, order_data, domain):
fig, ax = plt.subplots(figsize=(16, 8))
ordered_energies, unordered_energies = [], []
for width in widths:
ordered_energies.append([c[0] for c in data["distinct"][width] if c[1]])
unordered_energies.append([c[0] for c in data["distinct"][width] if not c[1]])
for i in range(len(order_data["energy_min"])):
ordered_energies[i].append(order_data["energy_min"][i])
ordered_energies[i].append(order_data["energy_max"][i])
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])
# Energy of regular hexagon with area 1
offset = (
2
- 2 * domain.r * (6 * 3 ** (-0.25) * math.sqrt(2) * math.atanh(0.5))
+ 2 * math.pi * domain.r ** 2
)
min_order_off = min_order / domain.n - offset
min_unorder_off = min_unorder / domain.n - offset
max_unorder_off = max_unorder / domain.n - offset
ax.plot(widths, min_order_off, color="C1", label="Minimum Ordered")
ax.plot(widths, min_unorder_off, color="C0", label="Minimum Disordered")
ax.plot(
widths,
max_unorder_off,
color="C0",
linestyle="dotted",
label="Maximum Disordered",
)
# ax.plot(
# [min(widths), max(widths)],
# [offset, offset],
# color="C1",
# linestyle="dotted",
# label="Regular Energy",
# )
axis_settings(ax, widths)
ax.title.set_text(f"Energy at Aspect Ratios - N{domain.n}")
ax.set_xlabel("Aspect Ratio")
ax.set_ylabel("Excess Energy per Site")
ax.legend()
start, end = ax.get_ylim()
ax.set_yticks(np.linspace(0, end, 20))
ax.ticklabel_format(axis="y", style="sci")
return fig
def main():
# Loading arguments.
parser = argparse.ArgumentParser("Outputs width search data into diagrams")
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()
# Obtain data from simulation files and generate single shape data.
data, widths, domain = get_equilibria_data(Path(args.sims_path))
order_data = get_ordered_energies(domain, widths)
fig_folder = OUTPUT_DIR / Path(f"AspectDiagrams - N{domain.n}")
fig_folder.mkdir(exist_ok=True)
# Generating diagrams.
probability_of_disorder(data, widths, domain).savefig(
fig_folder / "Probability of Disorder.png"
)
density_of_states(data, widths, domain).savefig(
fig_folder / "Density Of States.png"
)
defect_density(data, widths, domain).savefig(fig_folder / "Defects.png")
reduced_energy(data, widths, order_data, domain).savefig(
fig_folder / "Reduced Energy.png"
)
defect_energy(data, widths, order_data, domain).savefig(
fig_folder / "Defect Energy.png"
)
circle_isoparam(data, widths, order_data, domain).savefig(
fig_folder / "Circular Isoparametric Ratio.png"
)
excess_energy(data, widths, order_data, domain).savefig(
fig_folder / "Excess Energy.png"
)
print(f"Wrote to {fig_folder}.")
if __name__ == "__main__":
os.environ["QT_LOGGING_RULES"] = "*=false"
try:
main()
except KeyboardInterrupt:
print("Program terminated by user.")

113
scripts/coercivity.py Normal file
View File

@ -0,0 +1,113 @@
from __future__ import annotations
from typing import List, Tuple, Dict
import argparse, math, numpy as np, os, pickle
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
from multiprocessing import Pool, cpu_count
from pathlib import Path
import squish.ordered as order
from squish import Simulation, DomainParams
from squish.common import Energy, OUTPUT_DIR
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)
plt.subplots_adjust(0.07, 0.12, 0.97, 0.9)
def main():
# Loading arguments.
parser = argparse.ArgumentParser("Outputs ordered equilibria lowest eigenvalues.")
parser.add_argument(
"n_objects",
metavar="N",
type=int,
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 = np.round(np.linspace(3.0, 10.0, 141), 2)
values = []
with open("coercivity_eigs.pkl", "rb") as f:
store_data = pickle.load(f)
for width in widths:
eig_vals = []
for config, eigs in store_data[width].items():
zero_ind = np.where(np.isclose(eigs, 0, atol=1e-4))[0][0]
if zero_ind == 0:
eig_vals.append(eigs[2])
else:
eig_vals.append(eigs[0])
values.append(min(eig_vals))
# for i, width in enumerate(widths):
# domain = DomainParams(args.n_objects, width, 10, 4.0)
# eig_vals = []
# store_data[width] = {}
# configs = order.configurations(domain)
# for j, config in enumerate(configs):
# if config == (1,0):
# continue
# points = order.sites(domain, config)
# hess = Energy("radial-t").mode(*domain, points).hessian(10e-5)
# eigs = np.sort(np.linalg.eig(hess)[0])[::-1]
# store_data[width][config] = eigs
# zero_ind = np.where(np.isclose(eigs, 0))[0][0]
# if zero_ind == 0:
# eig_vals.append(eigs[2])
# else:
# eig_vals.append(eigs[0])
# hashes = int(21*j/len(widths))
# print(f'Generating at {width}, {i+1}/{len(widths)}... |{"#"*hashes}{" "*(20-hashes)}|' + \
# f' {j+1}/{len(configs)} configs done.', flush=True, end='\r')
# print(flush=True)
# with open("coercivity_eigs.pkl", "wb") as f:
# pickle.dump(store_data, f, pickle.HIGHEST_PROTOCOL)
# return
fig, ax = plt.subplots(figsize=(12, 8))
plt.subplots_adjust(0.07, 0.12, 0.97, 0.9)
ax.plot(widths, values)
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)
fig.suptitle("Coercivity")
# ax.set_xlim([0, 5])
ax.set_xlabel("Width")
ax.set_ylabel("Eigenvalue")
fig.savefig(OUTPUT_DIR / "Coercivity.png")
print(f"Wrote to {OUTPUT_DIR / 'Coercivity.png'}")
if __name__ == "__main__":
os.environ["QT_LOGGING_RULES"] = "*=false"
try:
main()
except KeyboardInterrupt:
print("Program terminated by user.")

View File

@ -17,14 +17,6 @@ def main():
metavar="path/to/data",
help="folder that contains simulation files at various step sizes.",
)
parser.add_argument(
"-q",
"--quiet",
dest="quiet",
action="store_true",
default=False,
help="suppress all normal output",
)
args = parser.parse_args()
data = {}

View File

@ -72,20 +72,20 @@ def main():
for i, count in enumerate(counts):
my_cool_data[i + 1].append(count)
ax.plot(
100 * vees[: index + 1],
counts[: index + 1],
label=f"N={domain.n}",
color=f"C{j}",
)
ax.plot(
100 * vees[index:],
counts[index:],
label=f"_nolegend_",
linestyle="dotted",
color=f"C{j}",
)
ax.plot(100*vees, counts, label=f"N={domain.n}")
#ax.plot(
# 100 * vees[: index + 1],
# counts[: index + 1],
# label=f"N={domain.n}",
# color=f"C{j}",
#)
#ax.plot(
# 100 * vees[index:],
# counts[index:],
# label=f"_nolegend_",
# linestyle="dotted",
# color=f"C{j}",
#)
with open("cumulative-vee.csv", "w") as csvfile:
writer = csv.writer(csvfile)

View File

@ -167,8 +167,6 @@ def main():
pad = 100
alpha_prob_dens = {}
for alpha, avg in alpha_avgs.items():
if alpha == 1.0:
continue
mov_avgs = np.array(
[np.mean(avg[max(0, i - pad) : i + pad]) for i in range(len(avg))]
)
@ -184,17 +182,21 @@ def main():
d_avgs = np.gradient(mov_avgs, vees[1] - vees[0])
a1_prob_dens[n] = d_avgs / (np.sum(d_avgs) * (vees[1] - vees[0]))
print(list(alpha_prob_dens.keys()))
for alpha, prob_dens in sorted(alpha_prob_dens.items()):
if alpha in [0.3, 0.5, 0.7, 0.9, 1.0]:
continue
# continue
ax.plot(100 * vees, prob_dens, label=fr"$\alpha={alpha:.1f}$")
ax.plot(100*vees, a1_prob_dens[395], zorder=50, label=r"$\alpha = 1.0$", color="black")
for n, prob_dens in sorted(a1_prob_dens.items()):
if n in [255, 315, 335, 355, 375]:
ax.plot(100 * vees, prob_dens, label=f"N={n}")
if n == 395:
ax.plot(100 * vees, prob_dens, label=f"N={n}", color="black")
# ax.plot(100 * vees, prob_dens, label=r"$\alpha = 1.0$", zorder=50, color="black")
# Probability densities of alpha=1 across N
#for n, prob_dens in sorted(a1_prob_dens.items()):
# if n in [255, 315, 335, 355, 375]:
# ax.plot(100 * vees, prob_dens, label=f"N={n}")
# if n == 395:
# ax.plot(100 * vees, prob_dens, label=f"N={n}", color="black")
# # ax.plot(100 * vees, prob_dens, label=r"$\alpha = 1.0$", zorder=50, color="black")
# ax.plot(100 * vees, avgs[395], zorder=50, color="black")
ax.set_xlim(0, 6.3)

39
scripts/defectenergy.py Normal file
View File

@ -0,0 +1,39 @@
from squish import Simulation
import matplotlib.pyplot as plt
import os, numpy as np
def main():
sim, frames = Simulation.load(
"squish_output/Radial[T]Search - N11-400 - 10.00x10.00 - 500/Radial[T]Search - N397 - 10.00x10.00"
)
defect, energy = [], []
for frame_info in frames:
defect.append(np.count_nonzero(frame_info["stats"]["site_edge_count"] != 6))
energy.append(sum(frame_info["stats"]["site_energies"][:400]))
fig, ax = plt.subplots(1, figsize=(8, 8))
plt.subplots_adjust(0.1, 0.12, 0.97, 0.9)
fig.suptitle("Defects vs. Energy")
ax.set_xlabel("Defects")
ax.set_ylabel("Energy")
ax.grid(zorder=0)
ax.set_xticks(np.arange(0, 64, 2))
ax.scatter(defect, energy, zorder=3, color="C0", marker="*")
m, b = np.polyfit(defect, energy, 1)
ax.plot(
defect, np.array(defect) * m + b, zorder=3, color="C1", label=f"Slope: {m:.4f}"
)
ax.legend()
fig.savefig("DefectEnergyN397-10.00.png")
if __name__ == "__main__":
os.environ["QT_LOGGING_RULES"] = "*=false"
try:
main()
except KeyboardInterrupt:
print("Program terminated by user.")

108
scripts/defects.py Normal file
View File

@ -0,0 +1,108 @@
from __future__ import annotations
from typing import List
import argparse, pickle, numpy as np, os
from pathlib import Path
import matplotlib.pyplot as plt
from squish import Simulation
from squish.common import OUTPUT_DIR
def main():
parser = argparse.ArgumentParser("Graphs average defects at N.")
parser.add_argument(
"sims_path",
metavar="path/to/data",
help="folder that contains simulation files at various Ns.",
)
parser.add_argument(
"-q",
"--quiet",
dest="quiet",
action="store_true",
default=False,
help="suppress all normal output",
)
args = parser.parse_args()
data = {}
files = list(Path(args.sims_path).iterdir())
for i, file in enumerate(files):
sim, frames = Simulation.load(file)
avg_defects = 0
count = 0
for frame in frames:
if np.var(frame["stats"]["avg_radius"]) > 1e-8:
avg_defects += np.count_nonzero(frame["stats"]["site_edge_count"] != 6)
count += 1
avg_defects /= 1 if count == 0 else count
data[sim.domain.n] = avg_defects
hashes = int(21 * i / len(files))
print(
f'Processed N={sim.domain.n:03} |{"#"*hashes}{" "*(20-hashes)}|'
+ f" {i+1}/{len(files)} simulations processed.",
flush=True,
end="\r",
)
print(flush=True)
data = sorted(data.items())
ns, defects = np.array([x[0] for x in data]), np.array([x[1] for x in data])
corrected = []
for i, x in enumerate(defects):
if x == 0:
corrected.append(defects[i + 1])
else:
corrected.append(x)
fig, ax = plt.subplots(1, 2, figsize=(16, 8))
plt.subplots_adjust(0.07, 0.12, 0.97, 0.9)
fig.suptitle("Defects vs. Number of Sites (N)")
m0, b0 = np.polyfit(ns, defects, 1)
ax[0].plot(ns, defects)
ax[0].plot(ns, m0 * ns + b0, label=f"Slope: {m0:.5f}")
ax[0].grid(zorder=0)
ax[0].legend()
ax[0].set_xlabel("N")
ax[0].set_ylabel("Average Defects")
x, y = np.log(ns), np.log(corrected)
m, b = np.polyfit(x, y, 1)
x2, y2 = x[40:], np.log(defects[40:])
m2, b2 = np.polyfit(x2, y2, 1)
ax[1].plot(x, y, linestyle="dotted", color="C0")
ax[1].plot(x, np.log(defects))
# ax[1].plot(x, m*x+b, label=f"All N: {m:.5f}")
ax[1].plot(x2, m2 * x2 + b2, label=f"N $\\geq$ 40: {m2:.5f}")
ax[1].grid(zorder=0)
ax[1].legend()
ax[1].set_xticks(np.arange(3.75, 6.25, 0.25))
ax[1].set_yticks(np.arange(0, 4.5, 0.5))
ax[1].set_xlim(3.75, 6)
ax[1].set_ylim(0, 4)
ax[1].set_xlabel("$\\ln$ N")
ax[1].set_ylabel("$\\ln$ Average Defects")
fig.savefig(OUTPUT_DIR / "DefectsN.png")
print(f"Wrote to {OUTPUT_DIR / 'DefectsN.png'}")
if __name__ == "__main__":
os.environ["QT_log10GING_RULES"] = "*=false"
try:
main()
except KeyboardInterrupt:
print("Program terminated by user.")

View File

@ -102,21 +102,21 @@ def main():
)
ax.plot(ns, m0 * ns + b0, color="C0", linestyle="dashed")
lns2 = ax.plot(
ns, 100 * epds, color="C1", alpha=0.5, label=r"$\zeta_1 \times 10^{4}$"
)
lns3 = ax.plot(
ns,
10 * avg_defects * epds,
color="C2",
alpha=0.5,
label=r"$\mathcal{F} \times 10^{3}$",
)
#lns2 = ax.plot(
# ns, 100 * epds, color="C1", alpha=0.5, label=r"$\zeta_1 \times 10^{4}$"
#)
#
#lns3 = ax.plot(
# ns,
# 10 * avg_defects * epds,
# color="C2",
# alpha=0.5,
# label=r"$\mathcal{F} \times 10^{3}$",
#)
# ax3.plot(ns, 100*(m1 * ns + b1) / 10, color="C2", linestyle="dashed")
ax.set_xlim(93, 407)
ax.set_ylim(3, 37)
ax.set_ylim(3, 36)
ax.set_yticks(np.arange(5, 40, 5))
# ax2.set_ylim(-3 * 0.4, 18 + 3 * 0.4)
@ -131,9 +131,9 @@ def main():
# labs = [l.get_label() for l in lns]
ax.grid(zorder=0)
# ax.legend(lns, labs, loc="lower right")
ax.legend()
#ax.legend()
ax.set_xlabel("N")
# ax.set_ylabel(r"$\langle \mathrm{D} \rangle$")
ax.set_ylabel(r"$\langle \mathrm{D} \rangle$")
# ax2.set_ylabel("VEE")
# ax2.set_ylabel(r"$\zeta \left[\times 10^{4} \right]$", color="C1")
# ax3.set_ylabel(r"Defect Energy $\left[\times 10^{3} \right]$", color="C2")

302
scripts/heatmap.py Normal file
View File

@ -0,0 +1,302 @@
from __future__ import annotations
from typing import List, Tuple, Dict
import argparse, math, numpy as np, os, pickle
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
from scipy.optimize import curve_fit
from multiprocessing import Pool, cpu_count
from pathlib import Path
import squish.ordered as order
from squish import Simulation, DomainParams
from squish.common import OUTPUT_DIR
def order_process(domain: DomainParams) -> Tuple[float, float, float]:
energies, isoparams = [], []
configs = order.configurations(domain)
for config in configs:
rbar = order.avg_radius(domain, config)
area = domain.w * domain.h / domain.n
energies.append(
2 * domain.w * domain.h
+ 2 * math.pi * domain.n * (domain.r ** 2 - 2 * domain.r * rbar)
)
isoparams.append(math.pi * rbar ** 2 / area)
return domain.w, min(energies), max(energies), min(isoparams), max(isoparams)
def get_ordered_energies(orig_domain: DomainParams, widths: np.ndarray) -> Dict:
data = {}
domains = []
for w in widths:
aspect = w
domains.append(
DomainParams(
orig_domain.n,
math.sqrt(orig_domain.n * aspect),
math.sqrt(orig_domain.n / aspect),
orig_domain.r,
)
)
# domains = [
# DomainParams(orig_domain.n, w, orig_domain.h, orig_domain.r) for w in widths
# ]
with Pool(cpu_count()) as pool:
energy_mins, energy_maxes, isoparam_mins, isoparam_maxes = {}, {}, {}, {}
for i, res in enumerate(pool.imap_unordered(order_process, domains)):
energy_mins[res[0]] = res[1]
energy_maxes[res[0]] = res[2]
isoparam_mins[res[0]] = res[3]
isoparam_maxes[res[0]] = res[4]
hashes = int(21 * i / len(widths))
print(
f'Generating at width {res[0]:.02f}... |{"#"*hashes}{" "*(20-hashes)}|'
+ f" {i+1}/{len(widths)} completed.",
flush=True,
end="\r",
)
print(flush=True)
data["energy_min"] = list([x[1] for x in sorted(energy_mins.items())])
data["energy_max"] = list([x[1] for x in sorted(energy_maxes.items())])
data["isoparam_min"] = list([x[1] for x in sorted(isoparam_mins.items())])
data["isoparam_max"] = list([x[1] for x in sorted(isoparam_maxes.items())])
return data
def eq_file_process(file: Path) -> Tuple[float, List[float], List[float]]:
sim, frames = Simulation.load(file)
alls = []
for frame_info in frames:
alls.append(
[
frame_info["energy"],
np.var(frame_info["stats"]["avg_radius"]) <= 1e-8,
np.count_nonzero(frame_info["stats"]["site_edge_count"] != 6),
sum(frame_info["stats"]["site_energies"][: sim.domain.n]),
]
)
sim, frames = Simulation.load(file)
sim.frames = list(frames)
counts = sim.get_distinct()
distincts = []
for j, frame_info in enumerate(sim.frames):
distincts.append(
[
frame_info["energy"],
np.var(frame_info["stats"]["avg_radius"]) <= 1e-8,
np.count_nonzero(frame_info["stats"]["site_edge_count"] != 6),
sum(frame_info["stats"]["site_energies"][: sim.domain.n]),
counts[j],
]
)
return sim.domain.w / sim.domain.h, alls, distincts
def get_equilibria_data(filepath: Path) -> Tuple[Dict, numpy.ndarray, DomainParams]:
data = {"all": {}, "distinct": {}}
files = list(Path(filepath).iterdir())
with Pool(cpu_count()) as pool:
for i, res in enumerate(pool.imap_unordered(eq_file_process, files)):
data["all"][res[0]] = res[1]
data["distinct"][res[0]] = res[2]
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)
sim, frames = Simulation.load(files[0])
widths = np.asarray(sorted(data["all"]))
domain = DomainParams(sim.domain.n, widths[-1], sim.domain.h, sim.domain.r)
return data, widths, domain
def probability_of_disorder(data, widths, domain):
fig, ax = plt.subplots(figsize=(16, 8))
all_disorder_count = []
for width in widths:
equal_shape = list([c[1] for c in data["all"][width]])
all_disorder_count.append(
100 * equal_shape.count(False) / len(data["all"][width])
)
return all_disorder_count
def excess_energy(data, widths, order_data, domain):
fig, ax = plt.subplots(figsize=(16, 8))
ordered_energies, unordered_energies = [], []
for width in widths:
ordered_energies.append([c[0] for c in data["distinct"][width] if c[1]])
unordered_energies.append([c[0] for c in data["distinct"][width] if not c[1]])
for i in range(len(order_data["energy_min"])):
ordered_energies[i].append(order_data["energy_min"][i])
ordered_energies[i].append(order_data["energy_max"][i])
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])
return min_order - min_unorder
def sigmoid(x, x0, k):
return 100 / (1 + np.exp(-k * (x - x0)))
def main():
# Loading arguments.
parser = argparse.ArgumentParser("Outputs width search data into diagrams")
parser.add_argument(
"sims_path",
metavar="path/to/data",
help="folder that contains simulation files of all searches for all N.",
)
parser.add_argument(
"-q",
"--quiet",
dest="quiet",
action="store_true",
default=False,
help="suppress all normal output",
)
args = parser.parse_args()
fig_folder = OUTPUT_DIR
fig_folder.mkdir(exist_ok=True)
store = Path(args.sims_path) / "EEvsPoD.pkl"
if store.is_file():
with open(store, "rb") as f:
horiz, vert = pickle.load(f)
else:
horiz = []
vert = []
for file in Path(args.sims_path).iterdir():
# Obtain data from simulation files and generate single shape data.
data, widths, domain = get_equilibria_data(file)
order_data = get_ordered_energies(domain, widths)
vert.append(probability_of_disorder(data, widths, domain))
horiz.append(excess_energy(data, widths, order_data, domain))
horiz, vert = np.concatenate(horiz), np.concatenate(vert)
with open(store, "wb") as f:
pickle.dump((horiz, vert), f, pickle.HIGHEST_PROTOCOL)
fig, ax = plt.subplots(figsize=(10, 10))
for i in range(2):
ax.scatter(
horiz[i * 141 : (i + 1) * 141],
vert[i * 141 : (i + 1) * 141],
alpha=0.5,
color=f"C{i}",
s=5,
)
start, end = ax.get_xlim()
# popt, pcov = curve_fit(sigmoid, horiz, vert)
# x = np.linspace(start, end, 100)
# y = sigmoid(x, *popt)
# y = sigmoid(x, -1.35, 3)
# ax.plot(x, y, color="C1")
plt.subplots_adjust(0.1, 0.1, 0.97, 0.93)
ax.set_xticks(np.linspace(start, end, 10))
ax.set_yticks(np.arange(0, 105, 5))
ax.grid()
ax.yaxis.set_major_formatter(mtick.PercentFormatter())
ax.title.set_text("Excess Energy Difference vs. PoD")
ax.set_xlabel("Excess Energy Difference")
ax.set_ylabel("Probability of Disorder")
fig.savefig(OUTPUT_DIR / "Energy Diff and Probability")
return
# with open("testing.pkl", "rb") as f:
# disorder_dict = pickle.load(f)
# widths = np.linspace(3.0, 10.0, 141)
# min_n, max_n = 60, 80
disorder_dict = {}
for file in Path(args.sims_path).iterdir():
sim_data, widths, domain = get_equilibria_data(file)
disorder_count = []
for width in widths:
equal_shape = list([c[1] for c in sim_data["all"][width]])
disorder_count.append(
100 * equal_shape.count(False) / len(sim_data["all"][width])
)
disorder_dict[domain.n] = disorder_count
min_n, max_n = min(disorder_dict), max(disorder_dict)
filepath = f"Disorder Heatmap N{min_n}-{max_n}"
# with open("testing.pkl", "wb") as f:
# pickle.dump(disorder_dict, f, pickle.HIGHEST_PROTOCOL)
disorder_arr = np.zeros((max_n - min_n + 1, len(widths)))
for key, value in disorder_dict.items():
disorder_arr[key - min_n] = np.asarray(value)
fig, ax = plt.subplots(figsize=(12, 8))
extent = [min(widths), max(widths), min_n, max_n + 1]
ax.imshow(
disorder_arr,
cmap="plasma",
interpolation="nearest",
aspect="auto",
extent=extent,
)
ax.invert_xaxis()
ax.set_xticks([round(w, 2) for w in widths[::-2]])
ax.set_xticklabels(ax.get_xticks(), rotation=90)
ax.set_yticks(list(range(min_n, max_n + 1)))
plt.subplots_adjust(0.07, 0.12, 0.97, 0.9)
ax.title.set_text(filepath)
ax.set_xlabel("Width")
ax.set_ylabel("Number of Sites")
fig.savefig(OUTPUT_DIR / filepath)
print(f"Wrote to {OUTPUT_DIR / filepath}.")
if __name__ == "__main__":
os.environ["QT_LOGGING_RULES"] = "*=false"
try:
main()
except KeyboardInterrupt:
print("Program terminated by user.")

View File

@ -1,5 +1,6 @@
import numpy as np, os, math
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from multiprocessing import Pool, cpu_count
from squish import Simulation, ordered, DomainParams
@ -64,17 +65,32 @@ def main():
data["Config"],
)
print(min_order, min_config)
fig = plt.figure(figsize=(20, 15))
gs = fig.add_gridspec(1, 1)
ax = fig.add_subplot(gs[0])
ax.scatter(ns, min_order)
pad = 5
mov_avgs = np.array(
[np.mean(min_order[max(0, i - pad) : i + pad]) for i in range(len(min_order))]
)
ax.scatter(ns, mov_avgs, s=8)
log_slope, _ = np.polyfit(np.log10(ns), np.log10(mov_avgs), 1)
print(log_slope)
def g(x, k):
return k * (x ** log_slope)
# return a * np.e ** (-b * (x - c))
params, covs = curve_fit(g, ns, min_order, p0=[5000])
ax.plot(np.arange(500, 5500), g(np.arange(500, 5500), *params), color="C1")
print(params)
ax.grid(zorder=0)
# ax.set_xlim(1000, 5000)
ax.set_xlim(800, 5200)
ax.set_xlabel("N")
ax.set_ylabel(r"VEE $\left[\times 10^{2}\right]$")

115
scripts/near_neighbors.py Normal file
View File

@ -0,0 +1,115 @@
import numpy as np, os
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
from squish import Simulation, DomainParams, ordered
from squish.common import OUTPUT_DIR
from script_tools import RC_SETTINGS, get_args, get_data
NAME = "NearNeighbors"
second_neigh = True
def main():
sims_path, regen = get_args(
"Probability distribution of near neighbrs at distances",
"simulation folder of equilibriums to plot",
)
dists = np.linspace(0, 5, 25000)
def f():
all_data = {}
for n in [400]:
if second_neigh:
sim = Simulation.from_file(sims_path / f"Radial[T]Search - N{n} - 2500")
print("Loaded simulation.")
else:
sim, frames = Simulation.load(
sims_path / f"Radial[T]Search - N{n} - 2500"
)
counts = np.empty(dists.shape, dtype=float)
total_dists = np.array([], dtype=float)
if second_neigh:
for i, frame in enumerate(sim.frames):
if np.count_nonzero(frame.stats["site_edge_count"] != 6) != 6:
continue
total_dists = np.append(total_dists, frame.stats["site_distances"])
snn = frame.second_near_neighbor()
snn_dists = np.empty((sum([len(x) for x in snn])), dtype=float)
ind = 0
for j, site_snn in enumerate(snn):
site_snn_dists = ordered.toroidal_distance(
sim.domain,
frame.site_arr[site_snn],
np.ones((len(site_snn), 2)) * frame.site_arr[j],
)
snn_dists[ind : ind + len(site_snn_dists)] = site_snn_dists
ind += len(site_snn_dists)
total_dists = np.append(total_dists, snn_dists)
hashes = int(21 * i / len(sim))
print(
f'Processing N={n} at frame {i}... |{"#"*hashes}{" "*(20-hashes)}|'
+ f" {i+1}/{len(sim)} completed.",
flush=True,
end="\r",
)
print(flush=True)
else:
for frame in frames:
if (
np.count_nonzero(frame["stats"]["site_edge_count"] != 6) / n
< 0.08
):
continue
total_dists = np.append(
total_dists, frame["stats"]["site_distances"]
)
for i, dist in enumerate(dists):
counts[i] = np.count_nonzero(total_dists <= dist)
counts = 100 * counts / len(total_dists)
pad = 20
counts = np.array(
[np.mean(counts[max(0, i - pad) : i + pad]) for i in range(len(counts))]
)
grad = np.gradient(counts, dists[1] - dists[0])
all_data[n] = grad / (np.sum(grad) * (dists[1] - dists[0]))
return all_data
all_data = get_data(sims_path / "NearNeighborsD6.pkl", f, regen=regen)
data_2 = get_data(sims_path / "NearNeighborsD60.pkl", f, regen=regen)
plt.rcParams.update(RC_SETTINGS)
fig = plt.figure(figsize=(15, 15))
gs = fig.add_gridspec(1, 1)
ax = fig.add_subplot(gs[0])
for n, counts in sorted(all_data.items()):
ax.plot(dists, counts, label=f"D=6")
for n, counts in sorted(data_2.items()):
ax.plot(dists, counts, label=f"D=60")
ax.set_xlim(0, 3)
ax.set_xlabel(r"Distance")
# ax.set_ylabel("Percent of Distances")
ax.grid(zorder=0)
ax.legend()
fig.savefig(OUTPUT_DIR / (NAME + ".png"))
print(f"Wrote to {OUTPUT_DIR / (NAME + '.png')}")
if __name__ == "__main__":
main()

View File

@ -2,11 +2,14 @@ import argparse, numpy as np, os
from pathlib import Path
import matplotlib.pyplot as plt
from squish import DomainParams, Simulation, ordered
from squish.common import OUTPUT_DIR
from squish import ordered
from squish.common import OUTPUT_DIR, DomainParams, Energy
from squish.simulation import Simulation, Flow
from script_tools import RC_SETTINGS, get_data, format_data
NAME = "Perturbations"
NAME2 = "MinimumEscapeVEE"
def main():
@ -14,9 +17,7 @@ def main():
description="Graphs perturbation graphs for a collection of simulations."
)
parser.add_argument(
"sims_path",
metavar="sim_dir",
help="folder that contains of perturbations from an equilibrium",
"sim_store_path", metavar="sim_dir", help="folder to save simulations to"
)
parser.add_argument(
"end_path",
@ -32,41 +33,122 @@ def main():
)
args = parser.parse_args()
sims_path = Path(args.sims_path)
out_fol = Path(args.sim_store_path)
end_sim = Simulation.from_file(args.end_path)
(OUTPUT_DIR / out_fol).mkdir(exist_ok=True)
end_eq = Simulation.from_file(args.end_path)
e_hex = ordered.e_hex(end_eq.domain)
def f():
data = {}
for file in sims_path.iterdir():
if "k" not in file.name or file.is_file():
continue
k = float(file.name.split("k")[-1])
delta = 10 ** k
all_data = []
for j in range(50):
pert_out_fol = out_fol / f"Vector{j:03}"
(OUTPUT_DIR / pert_out_fol).mkdir(exist_ok=True)
sim, frames = Simulation.load(file)
data[delta] = {"norm": [], "time": [], "k": k}
perturb = np.random.random_sample(end_eq.frames[0].site_arr.shape)
perturb /= np.linalg.norm(perturb)
for i, frame in enumerate(frames):
adjusted = frame["arr"] + (
end_sim.frames[0].site_arr[0] - frame["arr"][0]
)
data = {}
k = -4
same_eq = True
while same_eq:
print(f"Testing k={k} on vector {j:03}")
k_out_fol = pert_out_fol / f"EQk{k}"
delta = 10 ** k
data[delta] = {"norm": [], "time": [], "vee": [], "k": k}
if not pert_out_fol.is_dir():
this_pert = perturb * delta
sim = Flow(
end_eq.domain,
end_eq.energy,
end_eq.step_size,
end_eq.thres,
True,
name=k_out_fol,
)
sim.run(True, True, 50, end_eq.frames[0].site_arr + this_pert)
data[delta]["norm"].append(
np.linalg.norm(
ordered.toroidal_distance(
end_sim.domain, adjusted, end_sim.frames[0].site_arr
sim, frames = Simulation.load(OUTPUT_DIR / k_out_fol)
for i, frame in enumerate(frames):
adjusted = frame["arr"] + (
end_eq.frames[0].site_arr[0] - frame["arr"][0]
)
data[delta]["norm"].append(
np.linalg.norm(
ordered.toroidal_distance(
end_eq.domain, adjusted, end_eq.frames[0].site_arr
)
)
)
)
data[delta]["time"].append(sim.step_size * i)
data[delta]["time"].append(sim.step_size * i)
data[delta]["vee"].append(frame["energy"] / sim.domain.n - e_hex)
return data
k += 1 if k < 0 else 0.25
m, _ = np.polyfit(data[delta]["time"], data[delta]["norm"], 1)
same_eq = m < 0
data = get_data(sims_path / "PerturbData.pkl", f, regen=args.regen)
all_data.append({"vec": perturb, "data": data})
return all_data
all_data = get_data(OUTPUT_DIR / out_fol / "PerturbData.pkl", f, regen=args.regen)
end_vee = end_eq.frames[0].energy / end_eq.domain.n - e_hex
print(end_vee)
vees = []
for dat in all_data:
for k, v in sorted(dat["data"].items()):
if v["norm"][-1] > 1e-3:
vees.append(dat["data"][k]["vee"][0])
break
eigs = np.sort(np.linalg.eigvalsh(end_eq.frames[0].hessian))
zero_ind = np.where(np.isclose(eigs, 0, atol=1e-8))[0]
if len(zero_ind) == 0:
coer = eigs[0]
elif zero_ind[0] == 0:
coer = eigs[2]
else:
coer = eigs[0]
plt.rcParams.update(RC_SETTINGS)
fig = plt.figure(figsize=(15, 15))
gs = fig.add_gridspec(1, 1)
ax = fig.add_subplot(gs[0])
ax.hist(vees, bins=np.linspace(0, 1, 30))
ax.grid(zorder=0)
props = dict(boxstyle="round", facecolor="white", alpha=0.8, zorder=20)
ax.text(
0.60,
0.96,
f"Min Escape = {min(vees):.6f}",
transform=ax.transAxes,
verticalalignment="top",
bbox=props,
)
ax.text(
0.62,
0.89,
f"Coercivity = {coer:.6f}",
transform=ax.transAxes,
verticalalignment="top",
bbox=props,
)
out = OUTPUT_DIR / f"{NAME2} - {args.sim_store_path}.png"
fig.savefig(out)
print(f"Wrote to {out}")
return
fig = plt.figure(figsize=(30, 8))
gs = fig.add_gridspec(1, 1)
ax = fig.add_subplot(gs[0])

View File

@ -117,11 +117,6 @@ def torus_region(c, verts, height):
v = np.hstack((v, height * np.ones((len(v), 1))))
return v, f, v_inds[sd - 1]
centers = np.array([[c[0], c[1], heights[i]]])
v_top = np.hstack((verts, heights[i] * np.ones((len(verts), 1))))
face_verts = np.concatenate((centers, v_top))
def main():
parser = argparse.ArgumentParser(description="Generates 3D model for equilibrium.")
@ -136,7 +131,7 @@ def main():
args = parser.parse_args()
torus = args.torus
size = args.size
size = args.size * 10
# Get desired frame and load.
sim, frames = Simulation.load(args.sims_path)

43
scripts/vor_test.py Normal file
View File

@ -0,0 +1,43 @@
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import Voronoi, voronoi_plot_2d
from squish import ordered, DomainParams
from script_tools import RC_SETTINGS
from pathlib import Path
N = 64
C = (0, 0)
out_fol = Path(f"N{N}C{C}")
out_fol.mkdir(exist_ok=True)
def render(i, dom, vor):
plt.rcParams.update(RC_SETTINGS)
fig = plt.figure(figsize=(15, 15))
gs = fig.add_gridspec(1, 1)
ax = fig.add_subplot(gs[0])
voronoi_plot_2d(vor, ax=ax, show_points=True, show_vertices=False)
ax.set_xlim(0, dom.w)
ax.set_ylim(0, dom.h)
fig.savefig(out_fol / f"{i:03}.png")
def get_full_points(dom, points):
SYMM = np.array(
[[0, 0], [1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1], [0, -1], [1, -1]]
)
return np.concatenate([points + dom.dim * s for s in SYMM])
def main():
d = DomainParams(N, 8, 8, 4)
# init = get_full_points(d, ordered.sites(d, C))
init = get_full_points(d, np.random.random_sample((64, 2)) * d.dim)
for i in range(10):
vor = Voronoi(init if i == 0 else vor.vertices)
render(i, d, vor)
if __name__ == "__main__":
main()