Updated scripts to stuse standardized commands and automatic data caching

This commit is contained in:
Kenneth Jao 2022-01-28 16:32:50 -05:00
parent 612e0f0c58
commit 583615ba4b
19 changed files with 1554 additions and 1193 deletions

View File

@ -1,424 +0,0 @@
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.")

View File

@ -1,113 +0,0 @@
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.")

97
scripts/cumulative_vee.py Normal file
View File

@ -0,0 +1,97 @@
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,
get_simulation_data,
get_ordered_data,
)
NAME = "Cumulative-VEE"
ALPHA = 1.0
def main():
sims_path, regen = get_args(
"Anti-cumulative distribution of VEE and percent of equilibria for fixed alpha",
"folders that contains various N simulations to plot",
)
packages = []
for fol in sims_path.iterdir():
if fol.is_file():
continue
data, n, r = get_data(
fol / "package.pkl", get_simulation_data, args=(fol,), regen=regen
)
domain, alphas = DomainParams(n, 1, 1, r), data["all"]["alpha"]
ordered_data = get_data(
OUTPUT_DIR / "OrderedCache" / f"{n}.pkl",
get_ordered_data,
args=(domain, alphas),
regen=regen,
)
packages.append([data, ordered_data, domain])
packages.sort(key=lambda x: x[2].n)
plt.rcParams.update(RC_SETTINGS)
fig = plt.figure(figsize=(15, 15))
gs = fig.add_gridspec(1, 1)
ax = fig.add_subplot(gs[0])
for j, package in enumerate(packages):
data, ordered_data, domain = package
e_hex = ordered.e_hex(domain)
alpha_index = np.where(data["all"]["alpha"] == ALPHA)[0][0]
energies = data["all"]["Energy"][alpha_index] / domain.n - e_hex
min_order = ordered_data["Energy"][alpha_index][0] / domain.n - e_hex
vees = np.linspace(0, 0.06, 10000)
index = np.argmin(np.abs(vees - min_order))
counts = np.empty(vees.shape, dtype=float)
for i, vee in enumerate(vees):
counts[i] = np.count_nonzero(energies >= vee)
counts = 100 * counts / len(energies)
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.set_xlim(0, 6.3)
ax.yaxis.set_major_formatter(mtick.PercentFormatter())
ax.set_xlabel(r"VEE $\left[\times 10^{2}\right]$")
ax.set_ylabel("Percent of Equilibria")
ax.grid(zorder=0)
ax.legend()
fig.savefig(OUTPUT_DIR / (NAME + ".png"))
print(f"Wrote to {OUTPUT_DIR / (NAME + '.png')}")
if __name__ == "__main__":
main()

101
scripts/defect_energy.py Normal file
View File

@ -0,0 +1,101 @@
import numpy as np, os
import matplotlib.pyplot as plt
from squish import Simulation, ordered
from squish.common import OUTPUT_DIR
from script_tools import RC_SETTINGS, get_args, get_data, format_data
NAME = "DefectEnergy"
def main():
sims_path, regen = get_args(
"Generates graph for Average Defects and Energy per Defect.",
"folder that contains simulations at various N",
)
def f():
data = {}
files = list(sims_path.iterdir())
for i, file in enumerate(files):
sim, frames = Simulation.load(file)
domain = sim.domain
e_hex = ordered.e_hex(domain)
defects, energy = [], []
for frame in frames:
if np.var(frame["stats"]["avg_radius"]) > 1e-8:
defects.append(
np.count_nonzero(frame["stats"]["site_edge_count"] != 6)
)
energy.append(100 * frame["energy"] / domain.n)
avg_defects = sum(defects) / (1 if len(defects) == 0 else len(defects))
m, b = np.polyfit(defects, energy, 1)
data[sim.domain.n] = [avg_defects, m]
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)
return format_data(
data, key_name="N", col_names=["Average Defects", "Energy Per Defect"]
)
plt.rcParams.update(RC_SETTINGS)
data = get_data(sims_path / (NAME + ".pkl"), f, regen=regen)
ns, defects, epds = data["N"], data["Average Defects"], data["Energy Per Defect"]
epds *= 100
fig = plt.figure(figsize=(18, 15))
gs = fig.add_gridspec(1, 1)
ax = fig.add_subplot(gs[0])
ax2 = ax.twinx()
ax3 = ax.twinx()
m0, b0 = np.polyfit(ns, defects, 1)
m1, b1 = np.polyfit(ns, defects * epds, 1)
ax.plot(ns, defects, color="C0", alpha=0.5)
ax.plot(ns, m0 * ns + b0, color="C0", linestyle="dashed")
ax2.plot(ns, epds, color="C1", alpha=0.5)
ax3.plot(ns, defects * epds / 10, color="C2", alpha=0.5)
ax3.plot(ns, (m1 * ns + b1) / 10, color="C2", linestyle="dashed")
ax.set_ylim(3, 37)
ax.set_yticks(np.arange(5, 40, 5))
ax2.set_ylim(-3 * 0.4, 18 + 3 * 0.4)
ax2.set_yticks(np.arange(0, 20, 3))
ax3.set_ylim(-3 * 0.5, 18 + 3 * 0.4)
ax3.set_yticks([])
ax3.spines["right"].set_visible(False)
ax3.spines.right.set_position(("axes", 1.11))
ax.grid(zorder=0)
ax.set_xlabel("N")
ax.set_ylabel("Average Defects", color="C0")
ax2.set_ylabel(r"Energy per Defect $\left[\times 10^{4} \right]$", color="C1")
ax3.set_ylabel(r"Defect Energy $\left[\times 10^{3} \right]$", color="C2")
fig.savefig(OUTPUT_DIR / (NAME + ".png"))
print(f"Wrote to {OUTPUT_DIR / (NAME + '.png')}")
if __name__ == "__main__":
os.environ["QT_log10GING_RULES"] = "*=false"
try:
main()
except KeyboardInterrupt:
print("Program terminated by user.")

View File

@ -1,39 +0,0 @@
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.")

View File

@ -1,108 +0,0 @@
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

@ -0,0 +1,96 @@
from __future__ import annotations
from typing import List, Tuple, Dict
import argparse, math, numpy as np, os, pickle, itertools
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
from pathlib import Path
from squish import Simulation, DomainParams
from squish.common import OUTPUT_DIR
def main():
# Loading arguments.
parser = argparse.ArgumentParser("Outputs width search data into diagrams")
parser.add_argument(
"sims_path",
metavar="path/to/data",
help="Path to simulation folders with generated data.pkl from aspect_diagrams.py",
)
packages = []
args = parser.parse_args()
for fol in Path(args.sims_path).iterdir():
if fol.is_file():
continue
store = fol / "data.pkl"
if store.is_file():
with open(store, "rb") as f:
packages.append(pickle.load(f))
else:
print(
f"{store} not found! Use aspect_diagrams.py to generate this file first."
)
if len(packages) == []:
print("No data.pkl files found, terminating")
return
plt.rcParams.update(
{
"axes.titlesize": 45,
"axes.labelsize": 45,
"xtick.labelsize": 40,
"ytick.labelsize": 40,
"xtick.major.width": 2,
"ytick.major.width": 2,
"xtick.major.size": 5,
"ytick.major.size": 5,
"xtick.minor.width": 1,
"ytick.minor.width": 1,
"xtick.minor.size": 3,
"ytick.minor.size": 3,
"legend.fontsize": 40,
"lines.linewidth": 3.5,
"font.family": "cm",
"font.size": 40,
"text.usetex": True,
"text.latex.preamble": r"\usepackage{amsmath}",
"figure.constrained_layout.use": True,
}
)
fig = plt.figure(figsize=(18, 15))
gs = fig.add_gridspec(1, 1)
ax = fig.add_subplot(gs[0])
packages.sort(key=lambda x: x[0].n)
for j, package in enumerate(packages):
domain, data, order_data, widths = package
distinct_unordered = []
for width in widths:
equal_shape = list([c[1] for c in data["distinct"][width]])
distinct_unordered.append(equal_shape.count(False))
ax.plot(widths, distinct_unordered, label=f"N={domain.n}")
widths = packages[0][3]
ax.set_xticks([round(w, 2) for w in widths[::10]])
ax.set_xticklabels([f"{round(w, 3):.2f}" for w in widths[::10]], rotation=90)
ax.set_xlim(0.3, 1.0)
ax.set_xlabel("Aspect Ratio")
ax.set_ylabel("Number of Distinct Equilibria")
ax.grid(zorder=0)
ax.legend(loc="center right", fancybox=True, bbox_to_anchor=(1.34, 0.5))
fig.savefig(OUTPUT_DIR / "DoS.png")
print(f"Wrote to {OUTPUT_DIR / 'DoS.png'}")
if __name__ == "__main__":
main()

View File

@ -1,302 +0,0 @@
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.")

89
scripts/hexagon_alpha.py Normal file
View File

@ -0,0 +1,89 @@
import argparse, numpy as np, os
from multiprocessing import Pool, cpu_count
import matplotlib.pyplot as plt
from squish import ordered
from squish.common import OUTPUT_DIR
from script_tools import RC_SETTINGS, get_data, format_data
NAME = "RegHexTessRatios"
def get_ratios(n: int):
return (n, ordered.hexagon_alpha(n))
def main():
parser = argparse.ArgumentParser(
description="Generates graph for regular hexagonal tessellation ratios"
)
parser.add_argument(
"max_n", metavar="N", type=int, help="maximum N of which to calculate"
)
parser.add_argument(
"--regenerate",
dest="regen",
action="store_true",
help="regenerates the cache file for processed data",
)
args = parser.parse_args()
def f():
data = {"alpha": [], "N": []}
with Pool(cpu_count()) as pool:
for i, res in enumerate(
pool.imap_unordered(get_ratios, range(2, args.max_n + 1))
):
for ratio in res[1]:
data["N"].append(res[0])
data["alpha"].append(ratio)
hashes = int(21 * i / (args.max_n - 1))
print(
f'Processed N={res[0]} |{"#"*hashes}{" "*(20-hashes)}|'
+ f" {i+1}/{args.max_n-1}",
flush=True,
end="\r",
)
print(flush=True)
return data
data = get_data(OUTPUT_DIR / "OrderedCache" / (NAME + ".pkl"), f, regen=args.regen)
plt.rcParams.update(RC_SETTINGS)
fig = plt.figure(figsize=(15, 15))
gs = fig.add_gridspec(1, 1)
ax = fig.add_subplot(gs[0])
alphas, ns = [], []
for alpha, n in zip(data["alpha"], data["N"]):
if n <= args.max_n:
alphas.append(alpha)
ns.append(n)
ax.scatter(alphas, ns, s=5)
ax.set_xlim(-0.01, 1.1)
ax.set_xticks(np.arange(0, 1.01, 0.1))
ax.set_ylim(0, args.max_n)
ax.set_ylabel(r"$N$")
ax.set_xlabel("Aspect Ratio")
ax.grid(zorder=0)
fig.savefig(OUTPUT_DIR / (NAME + ".png"))
print(f"Wrote to {OUTPUT_DIR / (NAME + '.png')}")
if __name__ == "__main__":
os.environ["QT_log10GING_RULES"] = "*=false"
try:
main()
except KeyboardInterrupt:
print("Program terminated by user.")

View File

@ -1,73 +1,102 @@
from __future__ import annotations
from typing import List
import argparse, pickle, numpy as np, os
import argparse, numpy as np, os
from pathlib import Path
import matplotlib.pyplot as plt
from squish import Simulation
from squish import DomainParams, Simulation
from squish.common import OUTPUT_DIR
from script_tools import RC_SETTINGS, get_data, format_data
NAME = "Perturbations"
def toroidal_distance(domain: DomainParams, x: np.ndarray, y: np.ndarray) -> float:
dim = np.array([domain.w, domain.h])
absdist = np.abs(y - x)
wrap = dim * (absdist >= np.array([domain.w, domain.h]) / 2)
return np.linalg.norm(wrap - absdist)
def main():
parser = argparse.ArgumentParser(
"Graphs perturbation graphs for a collection of simulations."
description="Graphs perturbation graphs for a collection of simulations."
)
parser.add_argument(
"sims_path",
metavar="path/to/data",
help="folder that contains simulations of perturbations from an equilibrium.",
metavar="sim_dir",
help="folder that contains of perturbations from an equilibrium",
)
parser.add_argument(
"end_path",
metavar="path/to/equilbrium",
help="NumPy binary (.npy) file that contains the equilibrium to compare to.",
metavar="eq_path",
help="simulation that contains the equilibrium to compare to.",
)
parser.add_argument(
"-q",
"--quiet",
dest="quiet",
"--regenerate",
dest="regen",
action="store_true",
default=False,
help="suppress all normal output",
help="regenerates the cache file for processed data",
)
args = parser.parse_args()
sims_path = Path(args.sims_path)
end = np.load(args.end_path)
end_sim = Simulation.from_file(args.end_path)
data = {}
for file in Path(args.sims_path).iterdir():
k = float(file.name.split("k")[-1])
delta = 10 ** k
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
sim, frames = Simulation.load(file)
data[delta] = {"norm": [], "time": [], "k": k}
sim, frames = Simulation.load(file)
data[delta] = {"norm": [], "time": [], "k": k}
for i, frame in enumerate(frames):
adjusted = frame["arr"] + (end[0] - frame["arr"][0])
for i, frame in enumerate(frames):
adjusted = frame["arr"] + (
end_sim.frames[0].site_arr[0] - frame["arr"][0]
)
data[delta]["norm"].append(np.linalg.norm(adjusted - end))
data[delta]["time"].append(sim.step_size * i)
data[delta]["norm"].append(
toroidal_distance(
end_sim.domain, adjusted, end_sim.frames[0].site_arr
)
)
data[delta]["time"].append(sim.step_size * i)
fig, ax = plt.subplots(figsize=(12, 8))
plt.subplots_adjust(0.07, 0.12, 0.97, 0.9)
return data
data = get_data(sims_path / "PerturbData.pkl", f, regen=args.regen)
plt.rcParams.update(RC_SETTINGS)
fig = plt.figure(figsize=(30, 8))
gs = fig.add_gridspec(1, 1)
ax = fig.add_subplot(gs[0])
for delta in sorted(data):
ax.plot(
np.log10(np.array(data[delta]["time"]) + 1),
np.log10(data[delta]["norm"]),
np.array(data[delta]["time"]),
np.array(data[delta]["norm"]),
label=f"k = {data[delta]['k']}",
)
fig.suptitle("Equilibrium Perturbations")
ax.grid(zorder=0)
# ax.set_xlim([0, 5])
ax.legend()
ax.set_xlabel("$\\log_{10}$ Time")
ax.set_ylabel("$\\log_{10}$ L2 Norm of Difference")
ax.set_title(r"Relaxation of Perturbations")
fig.savefig(OUTPUT_DIR / "Equilibrium Perturbations.png")
print(f"Wrote to {OUTPUT_DIR / 'Equilibrium Perturbations.png'}")
ax.set_xlim([0, 60])
ax.set_yscale("log")
ax.set_xlabel(r"Time")
ax.set_ylabel(r"$\|\mathbf{x}-\mathbf{x_e}\|_2$")
h, l = ax.get_legend_handles_labels()
ax.legend(h[::-1], l[::-1])
ax.grid(zorder=0)
fig.savefig(OUTPUT_DIR / (NAME + ".png"))
print(f"Wrote to {OUTPUT_DIR / (NAME + '.png')}")
if __name__ == "__main__":

View File

@ -0,0 +1,117 @@
import numpy as np, os
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
from squish import Simulation, DomainParams, Energy, ordered
from squish.common import OUTPUT_DIR
from script_tools import (
RC_SETTINGS,
get_args,
get_data,
get_simulation_data,
get_ordered_data,
)
NAME = "PoD"
def main():
sims_path, regen = get_args(
"Various graphs for single N data.",
"folder that contains simulation data at various aspect ratios for some N",
)
data, n, r = get_data(
sims_path / "package.pkl", get_simulation_data, args=(sims_path,), regen=regen
)
domain, alphas = DomainParams(n, 1, 1, r), data["all"]["alpha"]
ordered_data = get_data(
OUTPUT_DIR / "OrderedCache" / f"{n}.pkl",
get_ordered_data,
args=(domain, alphas),
regen=regen,
)
min_disorder, max_disorder = [], []
for i, energies in enumerate(data["distinct"]["Energy"]):
disorder_energies = []
for j, energy in enumerate(energies):
if not data["distinct"]["Ordered"][i][j]:
disorder_energies.append(energy)
min_disorder.append(min(disorder_energies))
max_disorder.append(max(disorder_energies))
min_order = []
for i, energies in enumerate(ordered_data["Energy"]):
min_order.append(energies[0])
e_hex = ordered.e_hex(domain)
min_disorder = np.array(min_disorder) / domain.n - e_hex
max_disorder = np.array(max_disorder) / domain.n - e_hex
min_order = np.array(min_order) / domain.n - e_hex
all_disorder_count = []
for disorders in data["all"]["Ordered"]:
all_disorder_count.append(
100 * np.count_nonzero(disorders == False) / len(disorders)
)
plt.rcParams.update(RC_SETTINGS)
fig = plt.figure(figsize=(15, 15))
gs = fig.add_gridspec(1, 1)
ax = fig.add_subplot(gs[0])
ax2 = ax.twinx()
ax.plot(alphas, 100 * (min_order - min_disorder), color="C2")
ax2.plot(alphas, all_disorder_count, color="C4")
ax.set_xlim(0.3, 1)
ax.set_xticks(np.arange(0.3, 1.01, 0.1))
start, end = ax.get_ylim()
# space = np.linspace(0, end, 20)
space = np.arange(-2.3, 3.3, 0.5)
ax.set_ylim(-2.5, 3.4)
ax.set_yticks(space)
ax.ticklabel_format(axis="y", style="sci")
# start, end = ax2.get_ylim()
# space = np.linspace(start, end, 20)
# space += 100 - space[-2]
space = np.linspace(50, 100, len(space))
ax2.set_ylim(
space[0] - (space[1] - space[0]) * 0.4, space[-1] + (space[1] - space[0]) * 0.6
)
ax2.set_yticks(space)
# ax2.set_ylim(start, space[-1])
# ax2.set_yticks(space[1:-1])
ax2.yaxis.set_major_formatter(mtick.PercentFormatter())
ax.set_xlabel("Aspect Ratio")
ax.set_ylabel(r"VEE $\left[\times 10^{2}\right]$", color="C2")
ax2.set_ylabel("Percent of Disordered Equilibria", color="C4")
# ax.legend(loc=(0.23, 0.5))
ax.grid(zorder=0)
props = dict(boxstyle="round", facecolor="white", alpha=0.8, zorder=20)
ax.text(
0.873,
0.97,
f"N={domain.n}",
transform=ax.transAxes,
verticalalignment="top",
bbox=props,
)
out = OUTPUT_DIR / f"{NAME}-N{domain.n}.png"
fig.savefig(out)
print(f"Wrote to {out}.")
if __name__ == "__main__":
os.environ["QT_LOGGING_RULES"] = "*=false"
try:
main()
except KeyboardInterrupt:
print("Program terminated by user.")

206
scripts/script_tools.py Normal file
View File

@ -0,0 +1,206 @@
from __future__ import annotations
from typing import List
import argparse, pickle, numpy as np, math
from pathlib import Path
from multiprocessing import Pool, cpu_count
import matplotlib.pyplot as plt
from squish import DomainParams, Simulation, Energy, ordered
from squish.common import OUTPUT_DIR
RC_SETTINGS = {
"axes.titlesize": 45,
"axes.labelsize": 45,
"xtick.labelsize": 40,
"ytick.labelsize": 40,
"xtick.major.width": 2,
"ytick.major.width": 2,
"xtick.major.size": 5,
"ytick.major.size": 5,
"xtick.minor.width": 1,
"ytick.minor.width": 1,
"xtick.minor.size": 3,
"ytick.minor.size": 3,
"legend.fontsize": 40,
"lines.linewidth": 3,
"font.family": "cm",
"font.size": 40,
"text.usetex": True,
"text.latex.preamble": r"\usepackage{amsmath}",
"figure.constrained_layout.use": True,
}
def get_args(
script_desc: str, path_desc: str, cache_file: bool = True
) -> Tuple[Path, bool]:
parser = argparse.ArgumentParser(description=script_desc)
parser.add_argument("sims_path", metavar="sim_dir", help=path_desc)
parser.add_argument(
"--regenerate",
dest="regen",
action="store_true",
help="regenerates the cache file for processed data",
)
args = parser.parse_args()
return (Path(args.sims_path), args.regen)
def get_data(
path: Path, func: Callable[Any, Any], args: Tuple[Any] = (), regen: bool = False
) -> Any:
if path.is_file() and not regen:
with open(path, "rb") as f:
return pickle.load(f)
else:
data = func(*args)
with open(path, "wb") as f:
pickle.dump(data, f, pickle.HIGHEST_PROTOCOL)
return data
def format_data(
data: Dict[Any, Any], key_name: str, col_names=List[str]
) -> Dict[Any, Any]:
data = sorted(data.items())
new_data = {}
new_data[key_name] = np.array([x[0] for x in data])
for i, col_name in enumerate(col_names):
if type(data[0][1][i]) is list:
new_data[col_name] = [np.array(x[1][i]) for x in data]
else:
new_data[col_name] = np.array([x[1][i] for x in data])
return new_data
def get_ordered_data(orig_domain: DomainParams, asps: np.ndarray) -> Dict:
data = {}
domains = []
for alpha in asps:
domains.append(
[
DomainParams(
orig_domain.n,
math.sqrt(orig_domain.n * alpha),
math.sqrt(orig_domain.n / alpha),
orig_domain.r,
),
alpha,
]
)
with Pool(cpu_count()) as pool:
for i, res in enumerate(pool.imap_unordered(ordered_data_proc, domains)):
data[res[0]] = res[1:]
hashes = int(21 * i / len(asps))
print(
f'Generating at width {res[0]:.02f}... |{"#"*hashes}{" "*(20-hashes)}|'
+ f" {i+1}/{len(asps)} completed.",
flush=True,
end="\r",
)
print(flush=True)
return format_data(data, key_name="alpha", col_names=["Energy", "Coercivity"])
def ordered_data_proc(
dom_tup: Tuple[DomainParams, float]
) -> Tuple[float, float, float, float]:
domain, alpha = dom_tup
energies, coercivities = [], []
e_hex = ordered.e_hex(domain)
configs = ordered.configurations(domain)
for config in configs:
# Causes errors, so ignore.
if config[0] == 0 or config[1] == 0:
continue
# rbar = ordered.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)
sites = ordered.sites(domain, config)
frame = Energy("radial-t").mode(*domain, sites)
energies.append(frame.energy)
eigs = np.sort(np.linalg.eigvalsh(frame.hessian))
zero_ind = np.where(np.isclose(eigs, 0, atol=1e-8))[0]
if len(zero_ind) == 0:
coercivities.append(eigs[0])
elif zero_ind[0] == 0:
coercivities.append(eigs[2])
else:
coercivities.append(eigs[0])
return (alpha, sorted(energies), sorted(coercivities)[::-1])
def get_simulation_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(simulation_data_proc, 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)
data["all"] = format_data(
data["all"], key_name="alpha", col_names=["Energy", "Ordered", "Defects"]
)
data["distinct"] = format_data(
data["distinct"],
key_name="alpha",
col_names=["Energy", "Ordered", "Defects", "Hits"],
)
sim, frames = Simulation.load(files[0])
return data, sim.domain.n, sim.domain.r
def simulation_data_proc(file: Path) -> Tuple[float, List[float], List[float]]:
sim, frames = Simulation.load(file)
alls = [[], [], []]
for frame_info in frames:
alls[0].append(frame_info["energy"])
alls[1].append(np.var(frame_info["stats"]["avg_radius"]) <= 1e-8)
alls[2].append(np.count_nonzero(frame_info["stats"]["site_edge_count"] != 6))
sim, frames = Simulation.load(file)
sim.frames = list(frames)
counts = sim.get_distinct()
distincts = [[], [], []]
for j, frame_info in enumerate(sim.frames):
distincts[0].append(frame_info["energy"])
distincts[1].append(np.var(frame_info["stats"]["avg_radius"]) <= 1e-8)
distincts[2].append(
np.count_nonzero(frame_info["stats"]["site_edge_count"] != 6)
)
distincts.append(counts)
return sim.domain.w / sim.domain.h, alls, distincts

103
scripts/torus.py Normal file
View File

@ -0,0 +1,103 @@
import numpy as np
import matplotlib.pyplot as plt
def torus_mesh(n, c, a):
theta = np.linspace(0, 2 * np.pi, n)
phi = np.linspace(0, 2 * np.pi, n)
theta, phi = np.meshgrid(theta, phi)
x = (c + a * np.cos(theta)) * np.cos(phi)
y = (c + a * np.cos(theta)) * np.sin(phi)
z = a * np.sin(theta)
return x, y, z
def torus_line(n, c, a, u, v):
phi = np.linspace(0, 2 * np.pi * u, n)
theta = (v / u) * phi
theta, phi = theta % (2 * np.pi), phi % (2 * np.pi)
x = (c + a * np.cos(theta)) * np.cos(phi)
y = (c + a * np.cos(theta)) * np.sin(phi)
z = a * np.sin(theta)
line = np.column_stack([x, y, z])
x, y, z = c * np.cos(phi), c * np.sin(phi), 0 * phi
norm = line - np.column_stack([x, y, z])
return line, norm
def torus_points(c, a, u, v, k):
phi = np.linspace(0, 2 * np.pi * u, k + 1)
theta = (v / u) * phi
theta, phi = theta % (2 * np.pi), phi % (2 * np.pi)
x = (c + a * np.cos(theta)) * np.cos(phi)
y = (c + a * np.cos(theta)) * np.sin(phi)
z = a * np.sin(theta)
return x, y, z
def get_obscure_segs(arr):
bounds = [0, 0]
seg = 1
for i in range(1, len(arr)):
if arr[i] != arr[i - 1]:
bounds[seg] = i
bounds.append(i)
seg += 1
return bounds + [len(arr) - 1]
def main():
fig = plt.figure(figsize=(10, 10), constrained_layout=True)
ax = fig.add_subplot(projection="3d")
ax.set_zlim(-2, 2)
ax.set_axis_off()
azim, elev = 0, 40
c, a = 2, 1
u, v = 4, 1
k = 10
ax.view_init(elev, azim)
ax.plot_surface(
*torus_mesh(100, c, a), rcount=200, ccount=200, color="white", alpha=0.4
)
# Calculate when surface is facing or away and apply dotted vs solid lines.
az, el = azim * np.pi / 180 - np.pi, elev * np.pi / 180 - np.pi / 2
camera_vec = np.array(
[np.sin(el) * np.cos(az), np.sin(el) * np.sin(az), np.cos(el)]
)
line, norm = torus_line(500, c, a, u, v)
cond = np.dot(norm, camera_vec) >= 0
bounds = get_obscure_segs(cond)
# Did not account for normal vectors intersecting with main body, so
# we have manual overrides...
print(bounds)
bounds[3] = 220
print(bounds)
for i in range(len(bounds) - 1):
seg = line[bounds[i] : bounds[i + 1] + 1, :]
lx, ly, lz = seg[:, 0], seg[:, 1], seg[:, 2]
style = "solid" if cond[bounds[i]] else "dashed"
if i == 3:
style = "dashed"
if i == 4:
style = "dashed"
ax.plot(lx, ly, lz, color="blue", linewidth=2, linestyle=style)
# Display points.
ax.scatter(*torus_points(c, a, u, v, k), color="purple", s=50)
# ax.plot(*torus_line(200, 2, 1, 2, 1), color="orange", linewidth=3)
plt.savefig(f"Torus - N{k}({u},{v}).png", bbox_inches="tight")
if __name__ == "__main__":
main()

112
scripts/vee.py Normal file
View File

@ -0,0 +1,112 @@
import numpy as np, os
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
from squish import Simulation, DomainParams, Energy, ordered
from squish.common import OUTPUT_DIR
from script_tools import (
RC_SETTINGS,
get_args,
get_data,
get_simulation_data,
get_ordered_data,
)
NAME = "VEE"
def main():
sims_path, regen = get_args(
"Various graphs for single N data.",
"folder that contains simulation data at various aspect ratios for some N",
)
data, n, r = get_data(
sims_path / "package.pkl", get_simulation_data, args=(sims_path,), regen=regen
)
domain, alphas = DomainParams(n, 1, 1, r), data["all"]["alpha"]
if regen:
os.remove(OUTPUT_DIR / "OrderedCache" / f"{n}".pkl)
ordered_data = get_data(
OUTPUT_DIR / "OrderedCache" / f"{n}.pkl",
get_ordered_data,
args=(domain, alphas),
regen=regen,
)
min_disorder, max_disorder = [], []
for i, energies in enumerate(data["distinct"]["Energy"]):
disorder_energies = []
for j, energy in enumerate(energies):
if not data["distinct"]["Ordered"][i][j]:
disorder_energies.append(energy)
min_disorder.append(min(disorder_energies))
max_disorder.append(max(disorder_energies))
min_order = []
for i, energies in enumerate(ordered_data["Energy"]):
min_order.append(energies[0])
e_hex = ordered.e_hex(domain)
min_disorder = np.array(min_disorder) / domain.n - e_hex
max_disorder = np.array(max_disorder) / domain.n - e_hex
min_order = np.array(min_order) / domain.n - e_hex
hex_ratios = ordered.hexagon_alpha(domain.n)
plt.rcParams.update(RC_SETTINGS)
fig = plt.figure(figsize=(15, 15))
gs = fig.add_gridspec(1, 1)
ax = fig.add_subplot(gs[0])
ax.plot(alphas, 100 * min_order, color="C1", label="Min Ordered", zorder=10)
ax.plot(alphas, 100 * min_disorder, color="C0", label="Min Disordered")
ax.plot(
alphas,
100 * max_disorder,
color="C0",
linestyle="dotted",
label="Max Disordered",
)
ax.set_xlim(0.3, 1)
# start, end = ax.get_ylim()
# space = np.linspace(0, end, 20)
space = np.arange(0, 6.6, 0.3)
ax.set_ylim(-0.15, 6.6)
ax.set_yticks(space[:-1])
ax.ticklabel_format(axis="y", style="sci")
ax.set_xlabel("Aspect Ratio")
ax.set_ylabel(r"VEE $\left[\times 10^{2}\right]$")
ax.legend(loc=(0.23, 0.5))
# ax.legend()
ax.grid(zorder=0)
props = dict(boxstyle="round", facecolor="white", alpha=0.8, zorder=20)
ax.text(
0.873,
0.97,
f"N={domain.n}",
transform=ax.transAxes,
verticalalignment="top",
bbox=props,
)
out = OUTPUT_DIR / f"{NAME}-N{domain.n}.png"
fig.savefig(out)
print(f"Wrote to {out}.")
if __name__ == "__main__":
os.environ["QT_LOGGING_RULES"] = "*=false"
try:
main()
except KeyboardInterrupt:
print("Program terminated by user.")

95
scripts/vee_diff_pod.py Normal file
View File

@ -0,0 +1,95 @@
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,
get_simulation_data,
get_ordered_data,
)
NAME = "VEEDiff-PoD"
def main():
sims_path, regen = get_args(
"Scatter plot of VEE difference and disordered equilibria.",
"folders that contains various N simulations to plot",
)
packages = []
for fol in sims_path.iterdir():
if fol.is_file():
continue
data, n, r = get_data(
fol / "package.pkl", get_simulation_data, args=(fol,), regen=regen
)
domain, alphas = DomainParams(n, 1, 1, r), data["all"]["alpha"]
ordered_data = get_data(
OUTPUT_DIR / "OrderedCache" / f"{n}.pkl",
get_ordered_data,
args=(domain, alphas),
regen=regen,
)
packages.append([data, ordered_data, domain])
packages.sort(key=lambda x: x[2].n)
plt.rcParams.update(RC_SETTINGS)
fig = plt.figure(figsize=(15, 15))
gs = fig.add_gridspec(1, 1)
ax = fig.add_subplot(gs[0])
for j, package in enumerate(packages):
data, ordered_data, domain = package
min_disorder, max_disorder = [], []
for i, energies in enumerate(data["distinct"]["Energy"]):
disorder_energies = []
for j, energy in enumerate(energies):
if not data["distinct"]["Ordered"][i][j]:
disorder_energies.append(energy)
min_disorder.append(min(disorder_energies))
max_disorder.append(max(disorder_energies))
min_order = []
for i, energies in enumerate(ordered_data["Energy"]):
min_order.append(energies[0])
e_hex = ordered.e_hex(domain)
min_disorder = np.array(min_disorder) / domain.n - e_hex
max_disorder = np.array(max_disorder) / domain.n - e_hex
min_order = np.array(min_order) / domain.n - e_hex
all_disorder_count = []
for disorders in data["all"]["Ordered"]:
all_disorder_count.append(
100 * np.count_nonzero(disorders == False) / len(disorders)
)
ax.scatter(
100 * (min_order - min_disorder), all_disorder_count, label=f"N={domain.n}"
)
ax.set_ylabel("Probability of Disordered Equilibria")
ax.set_xlabel(r"VEE Difference $\left[\times 10^{2}\right]$")
ax.yaxis.set_major_formatter(mtick.PercentFormatter())
ax.set_ylim(48, 102)
ax.set_yticks(np.arange(50, 101, 5))
ax.grid(zorder=0)
ax.legend()
fig.savefig(OUTPUT_DIR / (NAME + ".png"))
print(f"Wrote to {OUTPUT_DIR / (NAME + '.png')}")
if __name__ == "__main__":
main()

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* Generated by Cython 0.29.24 */
/* Generated by Cython 0.29.26 */
/* BEGIN: Cython Metadata
{
@ -34,8 +34,8 @@ END: Cython Metadata */
#elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000)
#error Cython requires Python 2.6+ or Python 3.3+.
#else
#define CYTHON_ABI "0_29_24"
#define CYTHON_HEX_VERSION 0x001D18F0
#define CYTHON_ABI "0_29_26"
#define CYTHON_HEX_VERSION 0x001D1AF0
#define CYTHON_FUTURE_DIVISION 1
#include <stddef.h>
#ifndef offsetof
@ -182,7 +182,7 @@ END: Cython Metadata */
#ifndef CYTHON_USE_UNICODE_INTERNALS
#define CYTHON_USE_UNICODE_INTERNALS 1
#endif
#if PY_VERSION_HEX < 0x030300F0
#if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2
#undef CYTHON_USE_UNICODE_WRITER
#define CYTHON_USE_UNICODE_WRITER 0
#elif !defined(CYTHON_USE_UNICODE_WRITER)
@ -201,7 +201,7 @@ END: Cython Metadata */
#define CYTHON_FAST_THREAD_STATE 1
#endif
#ifndef CYTHON_FAST_PYCALL
#define CYTHON_FAST_PYCALL 1
#define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1)
#endif
#ifndef CYTHON_PEP489_MULTI_PHASE_INIT
#define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000)
@ -220,7 +220,9 @@ END: Cython Metadata */
#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1)
#endif
#if CYTHON_USE_PYLONG_INTERNALS
#include "longintrepr.h"
#if PY_MAJOR_VERSION < 3
#include "longintrepr.h"
#endif
#undef SHIFT
#undef BASE
#undef MASK
@ -337,9 +339,68 @@ END: Cython Metadata */
#define __Pyx_DefaultClassType PyClass_Type
#else
#define __Pyx_BUILTIN_MODULE_NAME "builtins"
#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2
#define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\
PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)
#define __Pyx_DefaultClassType PyType_Type
#if PY_VERSION_HEX >= 0x030B00A1
static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f,
PyObject *code, PyObject *c, PyObject* n, PyObject *v,
PyObject *fv, PyObject *cell, PyObject* fn,
PyObject *name, int fline, PyObject *lnos) {
PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL;
PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL;
const char *fn_cstr=NULL;
const char *name_cstr=NULL;
PyCodeObject* co=NULL;
PyObject *type, *value, *traceback;
PyErr_Fetch(&type, &value, &traceback);
if (!(kwds=PyDict_New())) goto end;
if (!(argcount=PyLong_FromLong(a))) goto end;
if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end;
if (!(posonlyargcount=PyLong_FromLong(0))) goto end;
if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end;
if (!(kwonlyargcount=PyLong_FromLong(k))) goto end;
if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end;
if (!(nlocals=PyLong_FromLong(l))) goto end;
if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end;
if (!(stacksize=PyLong_FromLong(s))) goto end;
if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end;
if (!(flags=PyLong_FromLong(f))) goto end;
if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end;
if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end;
if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end;
if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end;
if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end;
if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end;
if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end;
if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end;
if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end;
if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end;
if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end;
if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too;
if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here
if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too;
Py_XDECREF((PyObject*)co);
co = (PyCodeObject*)call_result;
call_result = NULL;
if (0) {
cleanup_code_too:
Py_XDECREF((PyObject*)co);
co = NULL;
}
end:
Py_XDECREF(kwds);
Py_XDECREF(argcount);
Py_XDECREF(posonlyargcount);
Py_XDECREF(kwonlyargcount);
Py_XDECREF(nlocals);
Py_XDECREF(stacksize);
Py_XDECREF(replace);
Py_XDECREF(call_result);
Py_XDECREF(empty);
if (type) {
PyErr_Restore(type, value, traceback);
}
return co;
}
#else
#define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\
PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)
@ -577,10 +638,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) {
#if PY_VERSION_HEX < 0x030200A4
typedef long Py_hash_t;
#define __Pyx_PyInt_FromHash_t PyInt_FromLong
#define __Pyx_PyInt_AsHash_t PyInt_AsLong
#define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t
#else
#define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t
#define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t
#define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t
#endif
#if PY_MAJOR_VERSION >= 3
#define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func))
@ -750,6 +811,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x);
(likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj))
static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*);
static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t);
static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*);
#if CYTHON_ASSUME_SAFE_MACROS
#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x))
#else
@ -2046,6 +2108,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args,
#ifndef Py_MEMBER_SIZE
#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member)
#endif
#if CYTHON_FAST_PYCALL
static size_t __pyx_pyframe_localsplus_offset = 0;
#include "frameobject.h"
#define __Pxy_PyFrame_Initialize_Offsets()\
@ -2053,6 +2116,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args,
(void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus)))
#define __Pyx_PyFrame_GetLocalsplus(frame)\
(assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset))
#endif // CYTHON_FAST_PYCALL
#endif
/* PyCFunctionFastCall.proto */
@ -22260,6 +22324,9 @@ static PyTypeObject __pyx_type_6squish_6energy_AreaEnergy = {
#if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
0, /*tp_print*/
#endif
#if CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM+0 >= 0x06000000
0, /*tp_pypy_flags*/
#endif
};
static struct __pyx_vtabstruct_6squish_6energy_RadialALEnergy __pyx_vtable_6squish_6energy_RadialALEnergy;
@ -22381,6 +22448,9 @@ static PyTypeObject __pyx_type_6squish_6energy_RadialALEnergy = {
#if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
0, /*tp_print*/
#endif
#if CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM+0 >= 0x06000000
0, /*tp_pypy_flags*/
#endif
};
static struct __pyx_vtabstruct_6squish_6energy_RadialTEnergy __pyx_vtable_6squish_6energy_RadialTEnergy;
@ -22502,6 +22572,9 @@ static PyTypeObject __pyx_type_6squish_6energy_RadialTEnergy = {
#if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
0, /*tp_print*/
#endif
#if CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM+0 >= 0x06000000
0, /*tp_pypy_flags*/
#endif
};
static struct __pyx_vtabstruct_array __pyx_vtable_array;
@ -22691,6 +22764,9 @@ static PyTypeObject __pyx_type___pyx_array = {
#if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
0, /*tp_print*/
#endif
#if CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM+0 >= 0x06000000
0, /*tp_pypy_flags*/
#endif
};
static PyObject *__pyx_tp_new_Enum(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) {
@ -22810,6 +22886,9 @@ static PyTypeObject __pyx_type___pyx_MemviewEnum = {
#if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
0, /*tp_print*/
#endif
#if CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM+0 >= 0x06000000
0, /*tp_pypy_flags*/
#endif
};
static struct __pyx_vtabstruct_memoryview __pyx_vtable_memoryview;
@ -23071,6 +23150,9 @@ static PyTypeObject __pyx_type___pyx_memoryview = {
#if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
0, /*tp_print*/
#endif
#if CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM+0 >= 0x06000000
0, /*tp_pypy_flags*/
#endif
};
static struct __pyx_vtabstruct__memoryviewslice __pyx_vtable__memoryviewslice;
@ -23217,6 +23299,9 @@ static PyTypeObject __pyx_type___pyx_memoryviewslice = {
#if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
0, /*tp_print*/
#endif
#if CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM+0 >= 0x06000000
0, /*tp_pypy_flags*/
#endif
};
static PyMethodDef __pyx_methods[] = {
@ -27336,7 +27421,7 @@ static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int
}
if (!use_cline) {
c_line = 0;
PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False);
(void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False);
}
else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) {
c_line = 0;
@ -27433,30 +27518,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) {
static PyCodeObject* __Pyx_CreateCodeObjectForTraceback(
const char *funcname, int c_line,
int py_line, const char *filename) {
PyCodeObject *py_code = 0;
PyObject *py_srcfile = 0;
PyObject *py_funcname = 0;
PyCodeObject *py_code = NULL;
PyObject *py_funcname = NULL;
#if PY_MAJOR_VERSION < 3
PyObject *py_srcfile = NULL;
py_srcfile = PyString_FromString(filename);
#else
py_srcfile = PyUnicode_FromString(filename);
#endif
if (!py_srcfile) goto bad;
#endif
if (c_line) {
#if PY_MAJOR_VERSION < 3
py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line);
if (!py_funcname) goto bad;
#else
py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line);
if (!py_funcname) goto bad;
funcname = PyUnicode_AsUTF8(py_funcname);
if (!funcname) goto bad;
#endif
}
else {
#if PY_MAJOR_VERSION < 3
py_funcname = PyString_FromString(funcname);
#else
py_funcname = PyUnicode_FromString(funcname);
if (!py_funcname) goto bad;
#endif
}
if (!py_funcname) goto bad;
#if PY_MAJOR_VERSION < 3
py_code = __Pyx_PyCode_New(
0,
0,
@ -27475,11 +27561,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback(
__pyx_empty_bytes /*PyObject *lnotab*/
);
Py_DECREF(py_srcfile);
Py_DECREF(py_funcname);
#else
py_code = PyCode_NewEmpty(filename, funcname, py_line);
#endif
Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline
return py_code;
bad:
Py_XDECREF(py_srcfile);
Py_XDECREF(py_funcname);
#if PY_MAJOR_VERSION < 3
Py_XDECREF(py_srcfile);
#endif
return NULL;
}
static void __Pyx_AddTraceback(const char *funcname, int c_line,
@ -29569,6 +29660,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) {
Py_DECREF(x);
return ival;
}
static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) {
if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) {
return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o);
#if PY_MAJOR_VERSION < 3
} else if (likely(PyInt_CheckExact(o))) {
return PyInt_AS_LONG(o);
#endif
} else {
Py_ssize_t ival;
PyObject *x;
x = PyNumber_Index(o);
if (!x) return -1;
ival = PyInt_AsLong(x);
Py_DECREF(x);
return ival;
}
}
static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) {
return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False);
}

View File

@ -59,11 +59,16 @@ class Simulation:
def normalize(self) -> None:
new_frames = []
first = True
for frame in self.frames:
aspect = frame.w / frame.h
new_domain = DomainParams(
frame.n, sqrt(frame.n * aspect), sqrt(frame.n / aspect), frame.r
)
if first:
self.domain = new_domain
first = False
new_points = frame.site_arr * np.array(
[new_domain.w / frame.w, new_domain.h / frame.h]

View File

@ -1,4 +1,4 @@
/* Generated by Cython 0.29.24 */
/* Generated by Cython 0.29.26 */
/* BEGIN: Cython Metadata
{
@ -34,8 +34,8 @@ END: Cython Metadata */
#elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000)
#error Cython requires Python 2.6+ or Python 3.3+.
#else
#define CYTHON_ABI "0_29_24"
#define CYTHON_HEX_VERSION 0x001D18F0
#define CYTHON_ABI "0_29_26"
#define CYTHON_HEX_VERSION 0x001D1AF0
#define CYTHON_FUTURE_DIVISION 1
#include <stddef.h>
#ifndef offsetof
@ -182,7 +182,7 @@ END: Cython Metadata */
#ifndef CYTHON_USE_UNICODE_INTERNALS
#define CYTHON_USE_UNICODE_INTERNALS 1
#endif
#if PY_VERSION_HEX < 0x030300F0
#if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2
#undef CYTHON_USE_UNICODE_WRITER
#define CYTHON_USE_UNICODE_WRITER 0
#elif !defined(CYTHON_USE_UNICODE_WRITER)
@ -201,7 +201,7 @@ END: Cython Metadata */
#define CYTHON_FAST_THREAD_STATE 1
#endif
#ifndef CYTHON_FAST_PYCALL
#define CYTHON_FAST_PYCALL 1
#define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1)
#endif
#ifndef CYTHON_PEP489_MULTI_PHASE_INIT
#define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000)
@ -220,7 +220,9 @@ END: Cython Metadata */
#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1)
#endif
#if CYTHON_USE_PYLONG_INTERNALS
#include "longintrepr.h"
#if PY_MAJOR_VERSION < 3
#include "longintrepr.h"
#endif
#undef SHIFT
#undef BASE
#undef MASK
@ -337,9 +339,68 @@ END: Cython Metadata */
#define __Pyx_DefaultClassType PyClass_Type
#else
#define __Pyx_BUILTIN_MODULE_NAME "builtins"
#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2
#define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\
PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)
#define __Pyx_DefaultClassType PyType_Type
#if PY_VERSION_HEX >= 0x030B00A1
static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f,
PyObject *code, PyObject *c, PyObject* n, PyObject *v,
PyObject *fv, PyObject *cell, PyObject* fn,
PyObject *name, int fline, PyObject *lnos) {
PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL;
PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL;
const char *fn_cstr=NULL;
const char *name_cstr=NULL;
PyCodeObject* co=NULL;
PyObject *type, *value, *traceback;
PyErr_Fetch(&type, &value, &traceback);
if (!(kwds=PyDict_New())) goto end;
if (!(argcount=PyLong_FromLong(a))) goto end;
if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end;
if (!(posonlyargcount=PyLong_FromLong(0))) goto end;
if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end;
if (!(kwonlyargcount=PyLong_FromLong(k))) goto end;
if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end;
if (!(nlocals=PyLong_FromLong(l))) goto end;
if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end;
if (!(stacksize=PyLong_FromLong(s))) goto end;
if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end;
if (!(flags=PyLong_FromLong(f))) goto end;
if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end;
if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end;
if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end;
if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end;
if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end;
if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end;
if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end;
if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end;
if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end;
if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end;
if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end;
if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too;
if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here
if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too;
Py_XDECREF((PyObject*)co);
co = (PyCodeObject*)call_result;
call_result = NULL;
if (0) {
cleanup_code_too:
Py_XDECREF((PyObject*)co);
co = NULL;
}
end:
Py_XDECREF(kwds);
Py_XDECREF(argcount);
Py_XDECREF(posonlyargcount);
Py_XDECREF(kwonlyargcount);
Py_XDECREF(nlocals);
Py_XDECREF(stacksize);
Py_XDECREF(replace);
Py_XDECREF(call_result);
Py_XDECREF(empty);
if (type) {
PyErr_Restore(type, value, traceback);
}
return co;
}
#else
#define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\
PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)
@ -577,10 +638,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) {
#if PY_VERSION_HEX < 0x030200A4
typedef long Py_hash_t;
#define __Pyx_PyInt_FromHash_t PyInt_FromLong
#define __Pyx_PyInt_AsHash_t PyInt_AsLong
#define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t
#else
#define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t
#define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t
#define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t
#endif
#if PY_MAJOR_VERSION >= 3
#define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func))
@ -750,6 +811,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x);
(likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj))
static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*);
static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t);
static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*);
#if CYTHON_ASSUME_SAFE_MACROS
#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x))
#else
@ -1998,6 +2060,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args,
#ifndef Py_MEMBER_SIZE
#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member)
#endif
#if CYTHON_FAST_PYCALL
static size_t __pyx_pyframe_localsplus_offset = 0;
#include "frameobject.h"
#define __Pxy_PyFrame_Initialize_Offsets()\
@ -2005,6 +2068,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args,
(void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus)))
#define __Pyx_PyFrame_GetLocalsplus(frame)\
(assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset))
#endif // CYTHON_FAST_PYCALL
#endif
/* PyObjectCall.proto */
@ -26678,6 +26742,9 @@ static PyTypeObject __pyx_type_6squish_7voronoi_VoronoiContainer = {
#if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
0, /*tp_print*/
#endif
#if CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM+0 >= 0x06000000
0, /*tp_pypy_flags*/
#endif
};
static struct __pyx_vtabstruct_array __pyx_vtable_array;
@ -26867,6 +26934,9 @@ static PyTypeObject __pyx_type___pyx_array = {
#if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
0, /*tp_print*/
#endif
#if CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM+0 >= 0x06000000
0, /*tp_pypy_flags*/
#endif
};
static PyObject *__pyx_tp_new_Enum(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) {
@ -26986,6 +27056,9 @@ static PyTypeObject __pyx_type___pyx_MemviewEnum = {
#if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
0, /*tp_print*/
#endif
#if CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM+0 >= 0x06000000
0, /*tp_pypy_flags*/
#endif
};
static struct __pyx_vtabstruct_memoryview __pyx_vtable_memoryview;
@ -27247,6 +27320,9 @@ static PyTypeObject __pyx_type___pyx_memoryview = {
#if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
0, /*tp_print*/
#endif
#if CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM+0 >= 0x06000000
0, /*tp_pypy_flags*/
#endif
};
static struct __pyx_vtabstruct__memoryviewslice __pyx_vtable__memoryviewslice;
@ -27393,6 +27469,9 @@ static PyTypeObject __pyx_type___pyx_memoryviewslice = {
#if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
0, /*tp_print*/
#endif
#if CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM+0 >= 0x06000000
0, /*tp_pypy_flags*/
#endif
};
static PyMethodDef __pyx_methods[] = {
@ -31881,7 +31960,7 @@ static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int
}
if (!use_cline) {
c_line = 0;
PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False);
(void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False);
}
else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) {
c_line = 0;
@ -31978,30 +32057,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) {
static PyCodeObject* __Pyx_CreateCodeObjectForTraceback(
const char *funcname, int c_line,
int py_line, const char *filename) {
PyCodeObject *py_code = 0;
PyObject *py_srcfile = 0;
PyObject *py_funcname = 0;
PyCodeObject *py_code = NULL;
PyObject *py_funcname = NULL;
#if PY_MAJOR_VERSION < 3
PyObject *py_srcfile = NULL;
py_srcfile = PyString_FromString(filename);
#else
py_srcfile = PyUnicode_FromString(filename);
#endif
if (!py_srcfile) goto bad;
#endif
if (c_line) {
#if PY_MAJOR_VERSION < 3
py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line);
if (!py_funcname) goto bad;
#else
py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line);
if (!py_funcname) goto bad;
funcname = PyUnicode_AsUTF8(py_funcname);
if (!funcname) goto bad;
#endif
}
else {
#if PY_MAJOR_VERSION < 3
py_funcname = PyString_FromString(funcname);
#else
py_funcname = PyUnicode_FromString(funcname);
if (!py_funcname) goto bad;
#endif
}
if (!py_funcname) goto bad;
#if PY_MAJOR_VERSION < 3
py_code = __Pyx_PyCode_New(
0,
0,
@ -32020,11 +32100,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback(
__pyx_empty_bytes /*PyObject *lnotab*/
);
Py_DECREF(py_srcfile);
Py_DECREF(py_funcname);
#else
py_code = PyCode_NewEmpty(filename, funcname, py_line);
#endif
Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline
return py_code;
bad:
Py_XDECREF(py_srcfile);
Py_XDECREF(py_funcname);
#if PY_MAJOR_VERSION < 3
Py_XDECREF(py_srcfile);
#endif
return NULL;
}
static void __Pyx_AddTraceback(const char *funcname, int c_line,
@ -34343,6 +34428,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) {
Py_DECREF(x);
return ival;
}
static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) {
if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) {
return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o);
#if PY_MAJOR_VERSION < 3
} else if (likely(PyInt_CheckExact(o))) {
return PyInt_AS_LONG(o);
#endif
} else {
Py_ssize_t ival;
PyObject *x;
x = PyNumber_Index(o);
if (!x) return -1;
ival = PyInt_AsLong(x);
Py_DECREF(x);
return ival;
}
}
static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) {
return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False);
}