Reformatted using spaces and python-black.
This commit is contained in:
parent
b4d6b5dbd8
commit
e7e7cefb56
@ -1,92 +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(.07, .12, .97, .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 = []
|
|
||||||
store_data = {}
|
|
||||||
|
|
||||||
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[zero_ind-1])
|
|
||||||
|
|
||||||
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(.07, .12, .97, .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.legend()
|
|
||||||
ax.set_xlabel("Width")
|
|
||||||
ax.set_ylabel("Smallest positive 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.")
|
|
||||||
113
scripts/coercivity.py
Normal file
113
scripts/coercivity.py
Normal 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.")
|
||||||
@ -9,27 +9,40 @@ from squish.common import OUTPUT_DIR
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser("Graphs convergence graphs for a collection of simulations.")
|
parser = argparse.ArgumentParser(
|
||||||
parser.add_argument('sims_path', metavar='path/to/data',
|
"Graphs convergence graphs for a collection of simulations."
|
||||||
help="folder that contains simulation files at various step sizes.")
|
)
|
||||||
parser.add_argument('-q', '--quiet', dest='quiet', action='store_true', default=False,
|
parser.add_argument(
|
||||||
help="suppress all normal output")
|
"sims_path",
|
||||||
|
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()
|
args = parser.parse_args()
|
||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
for file in Path(args.sims_path).iterdir():
|
for file in Path(args.sims_path).iterdir():
|
||||||
sim, frames = Simulation.load(file / "data.squish")
|
sim, frames = Simulation.load(file)
|
||||||
|
|
||||||
step = sim.step_size
|
step = sim.step_size
|
||||||
data[step] = {"times": [], "values": [], "diffs": []}
|
data[step] = {"times": [], "values": [], "diffs": []}
|
||||||
for i, frame_info in enumerate(frames):
|
for i, frame_info in enumerate(frames):
|
||||||
data[step]["times"].append(step*i)
|
data[step]["times"].append(step * i)
|
||||||
data[step]["values"].append(np.linalg.norm(frame_info["arr"]))
|
data[step]["values"].append(np.linalg.norm(frame_info["arr"]))
|
||||||
data[step]["diffs"].append(np.linalg.norm(all_info[-1]["arr"] - frame_info["arr"]))
|
data[step]["diffs"].append(
|
||||||
|
np.linalg.norm(all_info[-1]["arr"] - frame_info["arr"])
|
||||||
|
)
|
||||||
|
|
||||||
fig, ax = plt.subplots(1, 2, figsize=(16, 8))
|
fig, ax = plt.subplots(1, 2, figsize=(16, 8))
|
||||||
plt.subplots_adjust(.07, .12, .97, .9)
|
plt.subplots_adjust(0.07, 0.12, 0.97, 0.9)
|
||||||
|
|
||||||
for step, d in data.items():
|
for step, d in data.items():
|
||||||
ax[0].plot(d["times"], d["values"], label=step)
|
ax[0].plot(d["times"], d["values"], label=step)
|
||||||
@ -50,7 +63,7 @@ def main():
|
|||||||
print(f"Wrote to {OUTPUT_DIR / 'Equilibrium Convergence.png'}")
|
print(f"Wrote to {OUTPUT_DIR / 'Equilibrium Convergence.png'}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
os.environ["QT_LOGGING_RULES"] = "*=false"
|
os.environ["QT_LOGGING_RULES"] = "*=false"
|
||||||
try:
|
try:
|
||||||
main()
|
main()
|
||||||
|
|||||||
@ -10,77 +10,97 @@ from squish.common import OUTPUT_DIR
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser("Graphs average defects at N.")
|
parser = argparse.ArgumentParser("Graphs average defects at N.")
|
||||||
parser.add_argument('sims_path', metavar='path/to/data',
|
parser.add_argument(
|
||||||
help="folder that contains simulation files at various Ns.")
|
"sims_path",
|
||||||
parser.add_argument('-q', '--quiet', dest='quiet', action='store_true', default=False,
|
metavar="path/to/data",
|
||||||
help="suppress all normal output")
|
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()
|
args = parser.parse_args()
|
||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
|
files = list(Path(args.sims_path).iterdir())
|
||||||
for file in Path(args.sims_path).iterdir():
|
for i, file in enumerate(files):
|
||||||
sim, frames = Simulation.load(file / "data.squish")
|
sim, frames = Simulation.load(file)
|
||||||
avg_defects = 0
|
avg_defects = 0
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
for frame in frames:
|
for frame in frames:
|
||||||
if np.var(frame["stats"]["avg_radius"]) > 1e-8:
|
if np.var(frame["stats"]["avg_radius"]) > 1e-8:
|
||||||
avg_defects += np.count_nonzero(frame["stats"]["site_edge_count"] != 6)
|
avg_defects += np.count_nonzero(frame["stats"]["site_edge_count"] != 6)
|
||||||
|
|
||||||
count += 1
|
count += 1
|
||||||
|
|
||||||
|
avg_defects /= 1 if count == 0 else count
|
||||||
avg_defects /= (1 if count == 0 else count)
|
|
||||||
data[sim.domain.n] = avg_defects
|
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())
|
data = sorted(data.items())
|
||||||
ns, defects = np.array([x[0] for x in data]), np.array([x[1] for x in data])
|
ns, defects = np.array([x[0] for x in data]), np.array([x[1] for x in data])
|
||||||
|
|
||||||
corrected = []
|
corrected = []
|
||||||
for i, x in enumerate(defects):
|
for i, x in enumerate(defects):
|
||||||
if x == 0:
|
if x == 0:
|
||||||
corrected.append(defects[i+1])
|
corrected.append(defects[i + 1])
|
||||||
else:
|
else:
|
||||||
corrected.append(x)
|
corrected.append(x)
|
||||||
|
|
||||||
fig, ax = plt.subplots(1, 2, figsize=(16, 8))
|
fig, ax = plt.subplots(1, 2, figsize=(16, 8))
|
||||||
plt.subplots_adjust(.07, .12, .97, .9)
|
plt.subplots_adjust(0.07, 0.12, 0.97, 0.9)
|
||||||
|
|
||||||
fig.suptitle("Defects at N")
|
fig.suptitle("Defects vs. Number of Sites (N)")
|
||||||
|
|
||||||
m0, b0 = np.polyfit(ns, defects, 1)
|
m0, b0 = np.polyfit(ns, defects, 1)
|
||||||
|
|
||||||
ax[0].plot(ns, defects)
|
ax[0].plot(ns, defects)
|
||||||
ax[0].plot(ns, m0*ns+b0, label=f"Slope: {m0:.5f}")
|
ax[0].plot(ns, m0 * ns + b0, label=f"Slope: {m0:.5f}")
|
||||||
ax[0].grid(zorder=0)
|
ax[0].grid(zorder=0)
|
||||||
ax[0].legend()
|
ax[0].legend()
|
||||||
ax[0].set_xlabel("N")
|
ax[0].set_xlabel("N")
|
||||||
ax[0].set_ylabel("Average Defects")
|
ax[0].set_ylabel("Average Defects")
|
||||||
|
|
||||||
x, y = np.log10(ns), np.log10(corrected)
|
x, y = np.log(ns), np.log(corrected)
|
||||||
m, b = np.polyfit(x, y, 1)
|
m, b = np.polyfit(x, y, 1)
|
||||||
|
|
||||||
x2, y2 = x[14:], np.log10(defects[14:])
|
x2, y2 = x[40:], np.log(defects[40:])
|
||||||
m2, b2 = np.polyfit(x2, y2, 1)
|
m2, b2 = np.polyfit(x2, y2, 1)
|
||||||
|
|
||||||
ax[1].plot(x, y, linestyle='dotted', color='C0')
|
ax[1].plot(x, y, linestyle="dotted", color="C0")
|
||||||
ax[1].plot(x, np.log10(defects))
|
ax[1].plot(x, np.log(defects))
|
||||||
|
|
||||||
ax[1].plot(x, m*x+b, label=f"All N: {m:.5f}")
|
# ax[1].plot(x, m*x+b, label=f"All N: {m:.5f}")
|
||||||
ax[1].plot(x2, m2*x2+b2, label=f"N $\\geq$ 25: {m2:.5f}")
|
ax[1].plot(x2, m2 * x2 + b2, label=f"N $\\geq$ 40: {m2:.5f}")
|
||||||
ax[1].grid(zorder=0)
|
ax[1].grid(zorder=0)
|
||||||
ax[1].legend()
|
ax[1].legend()
|
||||||
ax[1].set_xlabel("log10 N")
|
ax[1].set_xticks(np.arange(3.75, 6.25, 0.25))
|
||||||
ax[1].set_ylabel("log10 Average Defects")
|
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")
|
fig.savefig(OUTPUT_DIR / "DefectsN.png")
|
||||||
print(f"Wrote to {OUTPUT_DIR / 'DefectsN.png'}")
|
print(f"Wrote to {OUTPUT_DIR / 'DefectsN.png'}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
os.environ["QT_log10GING_RULES"] = "*=false"
|
os.environ["QT_log10GING_RULES"] = "*=false"
|
||||||
try:
|
try:
|
||||||
main()
|
main()
|
||||||
|
|||||||
@ -10,28 +10,32 @@ from squish.common import OUTPUT_DIR
|
|||||||
|
|
||||||
|
|
||||||
def eq_file_process(file: Path) -> Tuple[float, List[float], List[float]]:
|
def eq_file_process(file: Path) -> Tuple[float, List[float], List[float]]:
|
||||||
sim, frames = Simulation.load(file / 'data.squish')
|
sim, frames = Simulation.load(file)
|
||||||
|
|
||||||
alls = []
|
alls = []
|
||||||
for frame_info in frames:
|
for frame_info in frames:
|
||||||
alls.append([
|
alls.append(
|
||||||
|
[
|
||||||
frame_info["energy"],
|
frame_info["energy"],
|
||||||
np.var(frame_info["stats"]["avg_radius"]) <= 1e-8,
|
np.var(frame_info["stats"]["avg_radius"]) <= 1e-8,
|
||||||
np.count_nonzero(frame_info["stats"]["site_edge_count"] != 6)
|
np.count_nonzero(frame_info["stats"]["site_edge_count"] != 6),
|
||||||
])
|
]
|
||||||
|
)
|
||||||
|
|
||||||
sim, frames = Simulation.load(file / 'data.squish')
|
sim, frames = Simulation.load(file)
|
||||||
sim.frames = list(frames)
|
sim.frames = list(frames)
|
||||||
counts = sim.get_distinct()
|
counts = sim.get_distinct()
|
||||||
|
|
||||||
distincts = []
|
distincts = []
|
||||||
for j, frame_info in enumerate(sim.frames):
|
for j, frame_info in enumerate(sim.frames):
|
||||||
distincts.append([
|
distincts.append(
|
||||||
|
[
|
||||||
frame_info["energy"],
|
frame_info["energy"],
|
||||||
np.var(frame_info["stats"]["avg_radius"]) <= 1e-8,
|
np.var(frame_info["stats"]["avg_radius"]) <= 1e-8,
|
||||||
np.count_nonzero(frame_info["stats"]["site_edge_count"] != 6),
|
np.count_nonzero(frame_info["stats"]["site_edge_count"] != 6),
|
||||||
counts[j]
|
counts[j],
|
||||||
])
|
]
|
||||||
|
)
|
||||||
|
|
||||||
return sim.domain.w, alls, distincts
|
return sim.domain.w, alls, distincts
|
||||||
|
|
||||||
@ -39,16 +43,20 @@ def eq_file_process(file: Path) -> Tuple[float, List[float], List[float]]:
|
|||||||
def get_equilibria_data(filepath: Path) -> Tuple[Dict, numpy.ndarray, DomainParams]:
|
def get_equilibria_data(filepath: Path) -> Tuple[Dict, numpy.ndarray, DomainParams]:
|
||||||
data = {"all": {}, "distinct": {}}
|
data = {"all": {}, "distinct": {}}
|
||||||
files = list(Path(filepath).iterdir())
|
files = list(Path(filepath).iterdir())
|
||||||
sim, frames = Simulation.load(files[0] / 'data.squish')
|
sim, frames = Simulation.load(files[0])
|
||||||
|
|
||||||
with Pool(cpu_count()) as pool:
|
with Pool(cpu_count()) as pool:
|
||||||
for i, res in enumerate(pool.imap_unordered(eq_file_process, files)):
|
for i, res in enumerate(pool.imap_unordered(eq_file_process, files)):
|
||||||
data["all"][res[0]] = res[1]
|
data["all"][res[0]] = res[1]
|
||||||
data["distinct"][res[0]] = res[2]
|
data["distinct"][res[0]] = res[2]
|
||||||
|
|
||||||
hashes = int(21*i/len(files))
|
hashes = int(21 * i / len(files))
|
||||||
print(f'Loading simulations for N={sim.domain.n}... |{"#"*hashes}{" "*(20-hashes)}|' + \
|
print(
|
||||||
f' {i+1}/{len(files)} simulations loaded.', flush=True, end='\r')
|
f'Loading simulations for N={sim.domain.n}... |{"#"*hashes}{" "*(20-hashes)}|'
|
||||||
|
+ f" {i+1}/{len(files)} simulations loaded.",
|
||||||
|
flush=True,
|
||||||
|
end="\r",
|
||||||
|
)
|
||||||
print(flush=True)
|
print(flush=True)
|
||||||
|
|
||||||
widths = np.asarray(sorted(data["all"]))
|
widths = np.asarray(sorted(data["all"]))
|
||||||
@ -59,10 +67,19 @@ def get_equilibria_data(filepath: Path) -> Tuple[Dict, numpy.ndarray, DomainPara
|
|||||||
def main():
|
def main():
|
||||||
# Loading arguments.
|
# Loading arguments.
|
||||||
parser = argparse.ArgumentParser("Outputs width search data into diagrams")
|
parser = argparse.ArgumentParser("Outputs width search data into diagrams")
|
||||||
parser.add_argument('sims_path', metavar='path/to/data',
|
parser.add_argument(
|
||||||
help="folder that contains simulation files of all searches for all N.")
|
"sims_path",
|
||||||
parser.add_argument('-q', '--quiet', dest='quiet', action='store_true', default=False,
|
metavar="path/to/data",
|
||||||
help="suppress all normal output")
|
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()
|
args = parser.parse_args()
|
||||||
|
|
||||||
@ -78,7 +95,9 @@ def main():
|
|||||||
disorder_count = []
|
disorder_count = []
|
||||||
for width in widths:
|
for width in widths:
|
||||||
equal_shape = list([c[1] for c in sim_data["all"][width]])
|
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_count.append(
|
||||||
|
100 * equal_shape.count(False) / len(sim_data["all"][width])
|
||||||
|
)
|
||||||
|
|
||||||
disorder_dict[domain.n] = disorder_count
|
disorder_dict[domain.n] = disorder_count
|
||||||
|
|
||||||
@ -88,20 +107,26 @@ def main():
|
|||||||
# with open("testing.pkl", "wb") as f:
|
# with open("testing.pkl", "wb") as f:
|
||||||
# pickle.dump(disorder_dict, f, pickle.HIGHEST_PROTOCOL)
|
# pickle.dump(disorder_dict, f, pickle.HIGHEST_PROTOCOL)
|
||||||
|
|
||||||
disorder_arr = np.zeros((max_n-min_n+1, len(widths)))
|
disorder_arr = np.zeros((max_n - min_n + 1, len(widths)))
|
||||||
for key, value in disorder_dict.items():
|
for key, value in disorder_dict.items():
|
||||||
disorder_arr[key-min_n] = np.asarray(value)
|
disorder_arr[key - min_n] = np.asarray(value)
|
||||||
|
|
||||||
fig, ax = plt.subplots(figsize=(12, 8))
|
fig, ax = plt.subplots(figsize=(12, 8))
|
||||||
|
|
||||||
extent = [min(widths), max(widths), min_n, max_n+1]
|
extent = [min(widths), max(widths), min_n, max_n + 1]
|
||||||
ax.imshow(disorder_arr, cmap='plasma', interpolation='nearest', aspect='auto', extent=extent)
|
ax.imshow(
|
||||||
|
disorder_arr,
|
||||||
|
cmap="plasma",
|
||||||
|
interpolation="nearest",
|
||||||
|
aspect="auto",
|
||||||
|
extent=extent,
|
||||||
|
)
|
||||||
|
|
||||||
ax.invert_xaxis()
|
ax.invert_xaxis()
|
||||||
ax.set_xticks([round(w,2) for w in widths[::-2]])
|
ax.set_xticks([round(w, 2) for w in widths[::-2]])
|
||||||
ax.set_xticklabels(ax.get_xticks(), rotation = 90)
|
ax.set_xticklabels(ax.get_xticks(), rotation=90)
|
||||||
ax.set_yticks(list(range(min_n, max_n+1)))
|
ax.set_yticks(list(range(min_n, max_n + 1)))
|
||||||
plt.subplots_adjust(.07, .12, .97, .9)
|
plt.subplots_adjust(0.07, 0.12, 0.97, 0.9)
|
||||||
|
|
||||||
ax.title.set_text(filepath)
|
ax.title.set_text(filepath)
|
||||||
ax.set_xlabel("Width")
|
ax.set_xlabel("Width")
|
||||||
@ -111,7 +136,7 @@ def main():
|
|||||||
print(f"Wrote to {OUTPUT_DIR / filepath}.")
|
print(f"Wrote to {OUTPUT_DIR / filepath}.")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
os.environ["QT_LOGGING_RULES"] = "*=false"
|
os.environ["QT_LOGGING_RULES"] = "*=false"
|
||||||
try:
|
try:
|
||||||
main()
|
main()
|
||||||
|
|||||||
@ -9,13 +9,27 @@ from squish.common import OUTPUT_DIR
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser("Graphs perturbation graphs for a collection of simulations.")
|
parser = argparse.ArgumentParser(
|
||||||
parser.add_argument('sims_path', metavar='path/to/data',
|
"Graphs perturbation graphs for a collection of simulations."
|
||||||
help="folder that contains simulations of perturbations from an equilibrium.")
|
)
|
||||||
parser.add_argument('end_path', metavar='path/to/equilbrium',
|
parser.add_argument(
|
||||||
help="NumPy binary (.npy) file that contains the equilibrium to compare to.")
|
"sims_path",
|
||||||
parser.add_argument('-q', '--quiet', dest='quiet', action='store_true', default=False,
|
metavar="path/to/data",
|
||||||
help="suppress all normal output")
|
help="folder that contains simulations 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.",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-q",
|
||||||
|
"--quiet",
|
||||||
|
dest="quiet",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
help="suppress all normal output",
|
||||||
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
@ -23,10 +37,10 @@ def main():
|
|||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
for file in Path(args.sims_path).iterdir():
|
for file in Path(args.sims_path).iterdir():
|
||||||
k = float(file.name.split('k')[-1])
|
k = float(file.name.split("k")[-1])
|
||||||
delta = 10**k
|
delta = 10 ** k
|
||||||
|
|
||||||
sim, frames = Simulation.load(file / 'data.squish')
|
sim, frames = Simulation.load(file)
|
||||||
data[delta] = {"norm": [], "time": [], "k": k}
|
data[delta] = {"norm": [], "time": [], "k": k}
|
||||||
|
|
||||||
for i, frame in enumerate(frames):
|
for i, frame in enumerate(frames):
|
||||||
@ -36,24 +50,27 @@ def main():
|
|||||||
data[delta]["time"].append(sim.step_size * i)
|
data[delta]["time"].append(sim.step_size * i)
|
||||||
|
|
||||||
fig, ax = plt.subplots(figsize=(12, 8))
|
fig, ax = plt.subplots(figsize=(12, 8))
|
||||||
plt.subplots_adjust(.07, .12, .97, .9)
|
plt.subplots_adjust(0.07, 0.12, 0.97, 0.9)
|
||||||
|
|
||||||
for delta in sorted(data):
|
for delta in sorted(data):
|
||||||
ax.plot(np.log10(np.array(data[delta]["time"])+1), np.log10(data[delta]["norm"]),
|
ax.plot(
|
||||||
label=f"k = {data[delta]['k']}")
|
np.log10(np.array(data[delta]["time"]) + 1),
|
||||||
|
np.log10(data[delta]["norm"]),
|
||||||
|
label=f"k = {data[delta]['k']}",
|
||||||
|
)
|
||||||
|
|
||||||
fig.suptitle("Equilibrium Perturbations")
|
fig.suptitle("Equilibrium Perturbations")
|
||||||
ax.grid(zorder=0)
|
ax.grid(zorder=0)
|
||||||
#ax.set_xlim([0, 5])
|
# ax.set_xlim([0, 5])
|
||||||
ax.legend()
|
ax.legend()
|
||||||
ax.set_xlabel("Log Time")
|
ax.set_xlabel("$\\log_{10}$ Time")
|
||||||
ax.set_ylabel("Log L2 Norm of Difference")
|
ax.set_ylabel("$\\log_{10}$ L2 Norm of Difference")
|
||||||
|
|
||||||
fig.savefig(OUTPUT_DIR / "Equilibrium Perturbations.png")
|
fig.savefig(OUTPUT_DIR / "Equilibrium Perturbations.png")
|
||||||
print(f"Wrote to {OUTPUT_DIR / 'Equilibrium Perturbations.png'}")
|
print(f"Wrote to {OUTPUT_DIR / 'Equilibrium Perturbations.png'}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
os.environ["QT_LOGGING_RULES"] = "*=false"
|
os.environ["QT_LOGGING_RULES"] = "*=false"
|
||||||
try:
|
try:
|
||||||
main()
|
main()
|
||||||
|
|||||||
@ -15,15 +15,22 @@ def order_process(domain: DomainParams) -> Tuple[float, float, float]:
|
|||||||
energies = []
|
energies = []
|
||||||
configs = order.configurations(domain)
|
configs = order.configurations(domain)
|
||||||
for config in configs:
|
for config in configs:
|
||||||
energies.append(2*domain.w*domain.h + \
|
energies.append(
|
||||||
2*math.pi*domain.n*(domain.r**2 - 2*domain.r*order.avg_radius(domain, config)))
|
2 * domain.w * domain.h
|
||||||
|
+ 2
|
||||||
|
* math.pi
|
||||||
|
* domain.n
|
||||||
|
* (domain.r ** 2 - 2 * domain.r * order.avg_radius(domain, config))
|
||||||
|
)
|
||||||
|
|
||||||
return domain.w, min(energies), max(energies)
|
return domain.w, min(energies), max(energies)
|
||||||
|
|
||||||
|
|
||||||
def get_ordered_energies(orig_domain: DomainParams, widths: np.ndarray) -> Dict:
|
def get_ordered_energies(orig_domain: DomainParams, widths: np.ndarray) -> Dict:
|
||||||
data = {}
|
data = {}
|
||||||
domains = [DomainParams(orig_domain.n, w, orig_domain.h, orig_domain.r) for w in widths]
|
domains = [
|
||||||
|
DomainParams(orig_domain.n, w, orig_domain.h, orig_domain.r) for w in widths
|
||||||
|
]
|
||||||
|
|
||||||
with Pool(cpu_count()) as pool:
|
with Pool(cpu_count()) as pool:
|
||||||
mins, maxes = {}, {}
|
mins, maxes = {}, {}
|
||||||
@ -31,9 +38,13 @@ def get_ordered_energies(orig_domain: DomainParams, widths: np.ndarray) -> Dict:
|
|||||||
mins[res[0]] = res[1]
|
mins[res[0]] = res[1]
|
||||||
maxes[res[0]] = res[2]
|
maxes[res[0]] = res[2]
|
||||||
|
|
||||||
hashes = int(21*i/len(widths))
|
hashes = int(21 * i / len(widths))
|
||||||
print(f'Generating at width {res[0]:.02f}... |{"#"*hashes}{" "*(20-hashes)}|' + \
|
print(
|
||||||
f' {i+1}/{len(widths)} completed.', flush=True, end='\r')
|
f'Generating at width {res[0]:.02f}... |{"#"*hashes}{" "*(20-hashes)}|'
|
||||||
|
+ f" {i+1}/{len(widths)} completed.",
|
||||||
|
flush=True,
|
||||||
|
end="\r",
|
||||||
|
)
|
||||||
|
|
||||||
print(flush=True)
|
print(flush=True)
|
||||||
|
|
||||||
@ -44,28 +55,32 @@ def get_ordered_energies(orig_domain: DomainParams, widths: np.ndarray) -> Dict:
|
|||||||
|
|
||||||
|
|
||||||
def eq_file_process(file: Path) -> Tuple[float, List[float], List[float]]:
|
def eq_file_process(file: Path) -> Tuple[float, List[float], List[float]]:
|
||||||
sim, frames = Simulation.load(file / 'data.squish')
|
sim, frames = Simulation.load(file)
|
||||||
|
|
||||||
alls = []
|
alls = []
|
||||||
for frame_info in frames:
|
for frame_info in frames:
|
||||||
alls.append([
|
alls.append(
|
||||||
|
[
|
||||||
frame_info["energy"],
|
frame_info["energy"],
|
||||||
np.var(frame_info["stats"]["avg_radius"]) <= 1e-8,
|
np.var(frame_info["stats"]["avg_radius"]) <= 1e-8,
|
||||||
np.count_nonzero(frame_info["stats"]["site_edge_count"] != 6)
|
np.count_nonzero(frame_info["stats"]["site_edge_count"] != 6),
|
||||||
])
|
]
|
||||||
|
)
|
||||||
|
|
||||||
sim, frames = Simulation.load(file / 'data.squish')
|
sim, frames = Simulation.load(file)
|
||||||
sim.frames = list(frames)
|
sim.frames = list(frames)
|
||||||
counts = sim.get_distinct()
|
counts = sim.get_distinct()
|
||||||
|
|
||||||
distincts = []
|
distincts = []
|
||||||
for j, frame_info in enumerate(sim.frames):
|
for j, frame_info in enumerate(sim.frames):
|
||||||
distincts.append([
|
distincts.append(
|
||||||
|
[
|
||||||
frame_info["energy"],
|
frame_info["energy"],
|
||||||
np.var(frame_info["stats"]["avg_radius"]) <= 1e-8,
|
np.var(frame_info["stats"]["avg_radius"]) <= 1e-8,
|
||||||
np.count_nonzero(frame_info["stats"]["site_edge_count"] != 6),
|
np.count_nonzero(frame_info["stats"]["site_edge_count"] != 6),
|
||||||
counts[j]
|
counts[j],
|
||||||
])
|
]
|
||||||
|
)
|
||||||
|
|
||||||
return sim.domain.w, alls, distincts
|
return sim.domain.w, alls, distincts
|
||||||
|
|
||||||
@ -79,12 +94,16 @@ def get_equilibria_data(filepath: Path) -> Tuple[Dict, numpy.ndarray, DomainPara
|
|||||||
data["all"][res[0]] = res[1]
|
data["all"][res[0]] = res[1]
|
||||||
data["distinct"][res[0]] = res[2]
|
data["distinct"][res[0]] = res[2]
|
||||||
|
|
||||||
hashes = int(21*i/len(files))
|
hashes = int(21 * i / len(files))
|
||||||
print(f'Loading simulations... |{"#"*hashes}{" "*(20-hashes)}|' + \
|
print(
|
||||||
f' {i+1}/{len(files)} simulations loaded.', flush=True, end='\r')
|
f'Loading simulations... |{"#"*hashes}{" "*(20-hashes)}|'
|
||||||
|
+ f" {i+1}/{len(files)} simulations loaded.",
|
||||||
|
flush=True,
|
||||||
|
end="\r",
|
||||||
|
)
|
||||||
print(flush=True)
|
print(flush=True)
|
||||||
|
|
||||||
sim, frames = Simulation.load(files[0] / 'data.squish')
|
sim, frames = Simulation.load(files[0])
|
||||||
widths = np.asarray(sorted(data["all"]))
|
widths = np.asarray(sorted(data["all"]))
|
||||||
domain = DomainParams(sim.domain.n, widths[-1], sim.domain.h, sim.domain.r)
|
domain = DomainParams(sim.domain.n, widths[-1], sim.domain.h, sim.domain.r)
|
||||||
return data, widths, domain
|
return data, widths, domain
|
||||||
@ -93,18 +112,27 @@ def get_equilibria_data(filepath: Path) -> Tuple[Dict, numpy.ndarray, DomainPara
|
|||||||
def axis_settings(ax, widths):
|
def axis_settings(ax, widths):
|
||||||
ax.invert_xaxis()
|
ax.invert_xaxis()
|
||||||
ax.grid(zorder=0)
|
ax.grid(zorder=0)
|
||||||
ax.set_xticks([round(w,2) for w in widths[::-2]])
|
ax.set_xticks([round(w, 2) for w in widths[::-2]])
|
||||||
ax.set_xticklabels(ax.get_xticks(), rotation = 90)
|
ax.set_xticklabels(ax.get_xticks(), rotation=90)
|
||||||
plt.subplots_adjust(.07, .12, .97, .9)
|
plt.subplots_adjust(0.07, 0.12, 0.97, 0.9)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
# Loading arguments.
|
# Loading arguments.
|
||||||
parser = argparse.ArgumentParser("Outputs width search data into diagrams")
|
parser = argparse.ArgumentParser("Outputs width search data into diagrams")
|
||||||
parser.add_argument('sims_path', metavar='path/to/data',
|
parser.add_argument(
|
||||||
help="folder that contains simulation files, or cached data file.")
|
"sims_path",
|
||||||
parser.add_argument('-q', '--quiet', dest='quiet', action='store_true', default=False,
|
metavar="path/to/data",
|
||||||
help="suppress all normal output")
|
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()
|
args = parser.parse_args()
|
||||||
|
|
||||||
@ -121,19 +149,25 @@ def main():
|
|||||||
all_disorder_count = []
|
all_disorder_count = []
|
||||||
for width in widths:
|
for width in widths:
|
||||||
equal_shape = list([c[1] for c in data["all"][width]])
|
equal_shape = list([c[1] for c in data["all"][width]])
|
||||||
all_disorder_count.append(100*equal_shape.count(False)/len(data["all"][width]))
|
all_disorder_count.append(
|
||||||
|
100 * equal_shape.count(False) / len(data["all"][width])
|
||||||
|
)
|
||||||
|
|
||||||
ax.plot(widths, all_disorder_count)
|
ax.plot(widths, all_disorder_count)
|
||||||
axis_settings(ax, widths)
|
axis_settings(ax, widths)
|
||||||
|
|
||||||
|
with open("N83-prob.txt", "w") as f:
|
||||||
|
f.write(", ".join([str(x) for x in widths]) + "\n")
|
||||||
|
f.write(", ".join([str(x) for x in all_disorder_count]))
|
||||||
|
|
||||||
ax.yaxis.set_major_formatter(mtick.PercentFormatter())
|
ax.yaxis.set_major_formatter(mtick.PercentFormatter())
|
||||||
ax.title.set_text(f"Probability of Disorder - N{domain.n}")
|
ax.title.set_text(f"Probability of Disorder - N{domain.n}")
|
||||||
ax.set_xlabel("Width")
|
ax.set_xlabel("Width")
|
||||||
ax.set_ylabel("Disordered Equilibria")
|
ax.set_ylabel("Disordered Equilibria")
|
||||||
boa_y_min = round(min(all_disorder_count)/20)*20 - 5
|
boa_y_min = round(min(all_disorder_count) / 20) * 20 - 5
|
||||||
ax.set_yticks(np.arange(boa_y_min, 100.01, 2.5))
|
ax.set_yticks(np.arange(boa_y_min, 100.01, 2.5))
|
||||||
fig.savefig(fig_folder / "Probability of Disorder.png")
|
fig.savefig(fig_folder / "Probability of Disorder.png")
|
||||||
|
|
||||||
|
|
||||||
# Density of States diagram.
|
# Density of States diagram.
|
||||||
fig, ax = plt.subplots(figsize=(16, 8))
|
fig, ax = plt.subplots(figsize=(16, 8))
|
||||||
distinct_ordered, distinct_unordered = [], []
|
distinct_ordered, distinct_unordered = [], []
|
||||||
@ -143,21 +177,20 @@ def main():
|
|||||||
distinct_unordered.append(equal_shape.count(False))
|
distinct_unordered.append(equal_shape.count(False))
|
||||||
|
|
||||||
ax2 = ax.twinx()
|
ax2 = ax.twinx()
|
||||||
ax.plot(widths, distinct_unordered, label="Unordered Equilibria", color='C0')
|
ax.plot(widths, distinct_unordered, label="Unordered Equilibria", color="C0")
|
||||||
ax2.plot(widths, distinct_ordered, label="Ordered Equilibria", color='C1')
|
ax2.plot(widths, distinct_ordered, label="Ordered Equilibria", color="C1")
|
||||||
axis_settings(ax, widths)
|
axis_settings(ax, widths)
|
||||||
ax.title.set_text(f"Density of States - N{domain.n}")
|
ax.title.set_text(f"Density of States - N{domain.n}")
|
||||||
ax.set_xlabel("Width")
|
ax.set_xlabel("Width")
|
||||||
ax.set_ylabel("Number of States (Disordered)", color='C0')
|
ax.set_ylabel("Number of States (Disordered)", color="C0")
|
||||||
ax2.set_ylabel("Number of States (Ordered)", color='C1')
|
ax2.set_ylabel("Number of States (Ordered)", color="C1")
|
||||||
|
|
||||||
dos_y_max_unorder = 1.05*max(distinct_unordered)
|
dos_y_max_unorder = 1.05 * max(distinct_unordered)
|
||||||
dos_y_max_order = 1.05*max(distinct_ordered)
|
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.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))
|
# 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))
|
ax2.set_yticks(np.arange(0, dos_y_max_order))
|
||||||
|
|
||||||
|
|
||||||
fig.savefig(fig_folder / "Density Of States.png")
|
fig.savefig(fig_folder / "Density Of States.png")
|
||||||
|
|
||||||
# Defect density diagram
|
# Defect density diagram
|
||||||
@ -165,17 +198,19 @@ def main():
|
|||||||
|
|
||||||
defects = []
|
defects = []
|
||||||
for width in widths:
|
for width in widths:
|
||||||
defects.append(sum([c[2] for c in data["all"][width] if not c[1]])/len(data["all"][width]))
|
defects.append(
|
||||||
|
sum([c[2] for c in data["all"][width] if not c[1]])
|
||||||
|
/ len(data["all"][width])
|
||||||
|
)
|
||||||
|
|
||||||
ax.plot(widths, defects)
|
ax.plot(widths, defects)
|
||||||
axis_settings(ax, widths)
|
axis_settings(ax, widths)
|
||||||
ax.title.set_text(f"Average Defects - N{domain.n}")
|
ax.title.set_text(f"Average Defects - N{domain.n}")
|
||||||
ax.set_xlabel("Width")
|
ax.set_xlabel("Width")
|
||||||
ax.set_ylabel("Defects")
|
ax.set_ylabel("Defects")
|
||||||
ax.set_yticks(np.arange(0, 1+max(defects), 0.5))
|
ax.set_yticks(np.arange(0, 1 + max(defects), 0.5))
|
||||||
fig.savefig(fig_folder / "Defects.png")
|
fig.savefig(fig_folder / "Defects.png")
|
||||||
|
|
||||||
|
|
||||||
# Bifurcation diagram
|
# Bifurcation diagram
|
||||||
fig, ax = plt.subplots(figsize=(16, 8))
|
fig, ax = plt.subplots(figsize=(16, 8))
|
||||||
|
|
||||||
@ -200,19 +235,23 @@ def main():
|
|||||||
max_unorder = np.asarray([max(width) for width in unordered_energies])
|
max_unorder = np.asarray([max(width) for width in unordered_energies])
|
||||||
|
|
||||||
offset = np.array(order_data["min"])
|
offset = np.array(order_data["min"])
|
||||||
#offset = np.array(min_order)
|
# offset = np.array(min_order)
|
||||||
|
|
||||||
min_unorder_off = min_unorder - offset
|
min_unorder_off = min_unorder - offset
|
||||||
max_unorder_off = max_unorder - offset
|
max_unorder_off = max_unorder - offset
|
||||||
ax.plot(widths, min_order - offset, color='C1')
|
ax.plot(widths, min_order - offset, color="C1")
|
||||||
#ax.plot(widths, max_order - offset, color='C1', linestyle='dotted')
|
# ax.plot(widths, max_order - offset, color='C1', linestyle='dotted')
|
||||||
ax.plot(widths, min_unorder_off, color='C0')
|
ax.plot(widths, min_unorder_off, color="C0")
|
||||||
ax.plot(widths, max_unorder_off, color='C0', linestyle='dotted')
|
ax.plot(widths, max_unorder_off, color="C0", linestyle="dotted")
|
||||||
axis_settings(ax, widths)
|
axis_settings(ax, widths)
|
||||||
|
|
||||||
|
with open("N83-od.txt", "w") as f:
|
||||||
|
f.write(", ".join([str(x) for x in widths]) + "\n")
|
||||||
|
f.write(", ".join([str(x) for x in min_unorder_off]) + "\n")
|
||||||
|
f.write(", ".join([str(x) for x in max_unorder_off]))
|
||||||
|
|
||||||
for i in null_unorder:
|
for i in null_unorder:
|
||||||
ax.scatter(widths[i], 0,
|
ax.scatter(widths[i], 0, marker="X", color="blue", s=50, zorder=4)
|
||||||
marker='X', color="blue", s=50, zorder=4)
|
|
||||||
# ax.scatter(widths[i], max_unorder[i] - offset[i],
|
# ax.scatter(widths[i], max_unorder[i] - offset[i],
|
||||||
# marker='X', edgecolors="blue", facecolors='none', s=100, zorder=4)
|
# marker='X', edgecolors="blue", facecolors='none', s=100, zorder=4)
|
||||||
|
|
||||||
@ -220,13 +259,16 @@ def main():
|
|||||||
ax.set_xlabel("Width")
|
ax.set_xlabel("Width")
|
||||||
ax.set_ylabel("Reduced Energy")
|
ax.set_ylabel("Reduced Energy")
|
||||||
bif_y_max = np.max(np.abs(np.concatenate((min_unorder_off, max_unorder_off))))
|
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))))
|
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)))
|
ax.set_yticks(np.concatenate((-bif_top[1:][::-1], bif_top)))
|
||||||
fig.savefig(fig_folder / "Bifurcation.png")
|
fig.savefig(fig_folder / "Bifurcation.png")
|
||||||
|
|
||||||
print(f"Wrote to {fig_folder}.")
|
print(f"Wrote to {fig_folder}.")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
if __name__ == "__main__":
|
||||||
os.environ["QT_LOGGING_RULES"] = "*=false"
|
os.environ["QT_LOGGING_RULES"] = "*=false"
|
||||||
try:
|
try:
|
||||||
main()
|
main()
|
||||||
|
|||||||
@ -10,16 +10,20 @@ OUTPUT_DIR = Path("squish_output")
|
|||||||
STR_TO_ENERGY = {
|
STR_TO_ENERGY = {
|
||||||
"area": AreaEnergy,
|
"area": AreaEnergy,
|
||||||
"radial-al": RadialALEnergy,
|
"radial-al": RadialALEnergy,
|
||||||
"radial-t" : RadialTEnergy
|
"radial-t": RadialTEnergy,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def generate_filepath(sim: SimulationMode, fol: Union[str, Path], prec: int = 2) -> Path:
|
def generate_filepath(
|
||||||
|
sim: SimulationMode, fol: Union[str, Path], prec: int = 2
|
||||||
|
) -> Path:
|
||||||
energy = sim.energy.title_str
|
energy = sim.energy.title_str
|
||||||
width, height = round(sim.domain.w, prec), round(sim.domain.h, prec)
|
width, height = round(sim.domain.w, prec), round(sim.domain.h, prec)
|
||||||
|
|
||||||
base_path = f"{fol}/{energy}{sim.title_str} - " + \
|
base_path = (
|
||||||
f"N{sim.domain.n} - {width:.{prec}f}x{height:.{prec}f}"
|
f"{fol}/{energy}{sim.title_str} - "
|
||||||
|
+ f"N{sim.domain.n} - {width:.{prec}f}x{height:.{prec}f}"
|
||||||
|
)
|
||||||
|
|
||||||
i = 1
|
i = 1
|
||||||
real_path = Path(base_path)
|
real_path = Path(base_path)
|
||||||
@ -42,8 +46,7 @@ class DomainParams:
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ['n', 'w', 'h', 'r', 'dim']
|
__slots__ = ["n", "w", "h", "r", "dim"]
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, n: int, w: float, h: float, r: float) -> None:
|
def __init__(self, n: int, w: float, h: float, r: float) -> None:
|
||||||
if n < 2:
|
if n < 2:
|
||||||
@ -58,7 +61,6 @@ class DomainParams:
|
|||||||
self.n, self.w, self.h, self.r = int(n), float(w), float(h), float(r)
|
self.n, self.w, self.h, self.r = int(n), float(w), float(h), float(r)
|
||||||
self.dim = np.array([self.w, self.h])
|
self.dim = np.array([self.w, self.h])
|
||||||
|
|
||||||
|
|
||||||
def __iter__(self) -> Iterator:
|
def __iter__(self) -> Iterator:
|
||||||
return iter((self.n, self.w, self.h, self.r))
|
return iter((self.n, self.w, self.h, self.r))
|
||||||
|
|
||||||
@ -74,26 +76,23 @@ class Energy:
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ['mode']
|
__slots__ = ["mode"]
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, mode: Union[str, VoronoiContainer]) -> None:
|
def __init__(self, mode: Union[str, VoronoiContainer]) -> None:
|
||||||
if isinstance(mode, str):
|
if isinstance(mode, str):
|
||||||
try:
|
try:
|
||||||
self.mode = STR_TO_ENERGY[mode.lower()]
|
self.mode = STR_TO_ENERGY[mode.lower()]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise ValueError(f"\'{mode}\' is not a valid energy!")
|
raise ValueError(f"'{mode}' is not a valid energy!")
|
||||||
else:
|
else:
|
||||||
if mode is not VoronoiContainer and issubclass(mode, VoronoiContainer):
|
if mode is not VoronoiContainer and issubclass(mode, VoronoiContainer):
|
||||||
raise ValueError("Provided class is not a valid energy!")
|
raise ValueError("Provided class is not a valid energy!")
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def attr_str(self) -> str:
|
def attr_str(self) -> str:
|
||||||
return self.mode.attr_str
|
return self.mode.attr_str
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def title_str(self) -> str:
|
def title_str(self) -> str:
|
||||||
return self.mode.title_str
|
return self.mode.title_str
|
||||||
@ -8,7 +8,10 @@ from multiprocessing import Pool, cpu_count
|
|||||||
|
|
||||||
from .common import DomainParams, OUTPUT_DIR
|
from .common import DomainParams, OUTPUT_DIR
|
||||||
|
|
||||||
SYMM = np.array([[0,0], [1,0], [1,1], [0,1], [-1,1], [-1,0], [-1,-1], [0,-1], [1,-1]])
|
SYMM = np.array(
|
||||||
|
[[0, 0], [1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1], [0, -1], [1, -1]]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class SimData:
|
class SimData:
|
||||||
"""Stores diagram information for a simulation.
|
"""Stores diagram information for a simulation.
|
||||||
@ -22,8 +25,7 @@ class SimData:
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ['path', 'domains', 'energies', 'voronois', 'stats']
|
__slots__ = ["path", "domains", "energies", "voronois", "stats"]
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, sim: Simulation) -> None:
|
def __init__(self, sim: Simulation) -> None:
|
||||||
if sim is not None:
|
if sim is not None:
|
||||||
@ -33,11 +35,9 @@ class SimData:
|
|||||||
self.voronois = list([s.vor_data for s in sim])
|
self.voronois = list([s.vor_data for s in sim])
|
||||||
self.stats = list([s.stats for s in sim])
|
self.stats = list([s.stats for s in sim])
|
||||||
|
|
||||||
|
|
||||||
def __len__(self) -> int:
|
def __len__(self) -> int:
|
||||||
return len(self.domains)
|
return len(self.domains)
|
||||||
|
|
||||||
|
|
||||||
def slice(self, indices: List[int]) -> SimData:
|
def slice(self, indices: List[int]) -> SimData:
|
||||||
new_data = SimData(None)
|
new_data = SimData(None)
|
||||||
new_data.path = self.path
|
new_data.path = self.path
|
||||||
@ -49,17 +49,24 @@ class SimData:
|
|||||||
|
|
||||||
return new_data
|
return new_data
|
||||||
|
|
||||||
|
def hist(
|
||||||
def hist(self, stat: str, i: int, bins: int = 10, bounds: Optional[Tuple[float, float]] = None,
|
self,
|
||||||
cumul: bool = False, avg: bool = False) -> Tuple[numpy.ndarray, numpy.ndarray]:
|
stat: str,
|
||||||
|
i: int,
|
||||||
|
bins: int = 10,
|
||||||
|
bounds: Optional[Tuple[float, float]] = None,
|
||||||
|
cumul: bool = False,
|
||||||
|
avg: bool = False,
|
||||||
|
) -> Tuple[numpy.ndarray, numpy.ndarray]:
|
||||||
"""Generates a histogram from the selected data.
|
"""Generates a histogram from the selected data.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
stat (str): name of data to obtain
|
stat (str): name of data to obtain
|
||||||
i (int): which frame to select from
|
i (int): which frame to select from
|
||||||
bins (int): number of bins for the histogram.
|
bins (int): number of bins for the histogram.
|
||||||
bounds (Optional[Tuple[float, float]]): upper and lower bounds of the histogram.
|
bounds (Optional[Tuple[float, float]]): upper and lower bounds of the
|
||||||
this will automatically take the minimum and maximum value of not set.
|
histogram. This will automatically take the minimum and maximum value
|
||||||
|
if not set.
|
||||||
cumul (bool): aggregates all data up to frame i if True.
|
cumul (bool): aggregates all data up to frame i if True.
|
||||||
avg (bool): will average the data based on number of frames if True.
|
avg (bool): will average the data based on number of frames if True.
|
||||||
|
|
||||||
@ -67,24 +74,27 @@ class SimData:
|
|||||||
Tuple[numpy.ndarray, numpy.ndarray]: the histogram and its bins.
|
Tuple[numpy.ndarray, numpy.ndarray]: the histogram and its bins.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if cumul:
|
if cumul:
|
||||||
values = np.concatenate([f[stat] for f in self.stats[:(i+1)]])
|
values = np.concatenate([f[stat] for f in self.stats[: (i + 1)]])
|
||||||
else:
|
else:
|
||||||
values = self.stats[i][stat]
|
values = self.stats[i][stat]
|
||||||
|
|
||||||
if np.var(values) <= 1e-8:
|
if np.var(values) <= 1e-8:
|
||||||
hist = np.zeros((bins,))
|
hist = np.zeros((bins,))
|
||||||
val = np.average(values)
|
val = np.average(values)
|
||||||
hist[(bins+1) // 2 - 1] = len(values)
|
hist[(bins + 1) // 2 - 1] = len(values)
|
||||||
bin_list = np.linspace(0, val, bins//2+1, endpoint=True)
|
bin_list = np.linspace(0, val, bins // 2 + 1, endpoint=True)
|
||||||
bin_list = np.concatenate((bin_list, (bin_list+val)[1:]))
|
bin_list = np.concatenate((bin_list, (bin_list + val)[1:]))
|
||||||
return hist, bin_list[not (bins%2):]
|
return hist, bin_list[not (bins % 2) :]
|
||||||
|
|
||||||
hist, bin_edges = np.histogram(values, bins=bins, range=bounds)
|
hist, bin_edges = np.histogram(values, bins=bins, range=bounds)
|
||||||
bin_list = np.array([(bin_edges[i] + bin_edges[i+1])/2 for i in range(len(bin_edges)-1)])
|
bin_list = np.array(
|
||||||
|
[(bin_edges[i] + bin_edges[i + 1]) / 2 for i in range(len(bin_edges) - 1)]
|
||||||
|
)
|
||||||
|
|
||||||
if avg and cumul:
|
if avg and cumul:
|
||||||
return hist / (i+1), bin_list
|
return hist / (i + 1), bin_list
|
||||||
|
|
||||||
return hist, bin_list
|
return hist, bin_list
|
||||||
|
|
||||||
@ -99,30 +109,30 @@ class Diagram:
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ['sim', 'diagrams', 'cumulative']
|
__slots__ = ["sim", "diagrams", "cumulative"]
|
||||||
|
|
||||||
|
def __init__(
|
||||||
def __init__(self, sim: Simulation, diagrams: np.ndarray, cumulative: bool = False) -> None:
|
self, sim: Simulation, diagrams: np.ndarray, cumulative: bool = False
|
||||||
|
) -> None:
|
||||||
self.sim = SimData(sim)
|
self.sim = SimData(sim)
|
||||||
self.diagrams = np.atleast_2d(diagrams)
|
self.diagrams = np.atleast_2d(diagrams)
|
||||||
self.cumulative = cumulative
|
self.cumulative = cumulative
|
||||||
|
|
||||||
|
|
||||||
def generate_frame(self, frame: int, mode: str, fol: str, name: str = None) -> None:
|
def generate_frame(self, frame: int, mode: str, fol: str, name: str = None) -> None:
|
||||||
if mode not in ["save", "open"]:
|
if mode not in ["save", "open"]:
|
||||||
raise ValueError("Not a valid mode for diagrams!")
|
raise ValueError("Not a valid mode for diagrams!")
|
||||||
|
|
||||||
shape = self.diagrams.shape
|
shape = self.diagrams.shape
|
||||||
fig, axes = plt.subplots(*shape, figsize=(shape[1]*8, shape[0]*8))
|
fig, axes = plt.subplots(*shape, figsize=(shape[1] * 8, shape[0] * 8))
|
||||||
if self.diagrams.shape == (1,1):
|
if self.diagrams.shape == (1, 1):
|
||||||
getattr(self, str(self.diagrams[0][0]) + '_plot')(frame, axes)
|
getattr(self, str(self.diagrams[0][0]) + "_plot")(frame, axes)
|
||||||
else:
|
else:
|
||||||
axes = np.atleast_2d(axes)
|
axes = np.atleast_2d(axes)
|
||||||
it = np.nditer(self.diagrams, flags=["multi_index"])
|
it = np.nditer(self.diagrams, flags=["multi_index"])
|
||||||
for diagram in it:
|
for diagram in it:
|
||||||
if diagram == "":
|
if diagram == "":
|
||||||
continue
|
continue
|
||||||
getattr(self, str(diagram) + '_plot')(frame, axes[it.multi_index])
|
getattr(self, str(diagram) + "_plot")(frame, axes[it.multi_index])
|
||||||
|
|
||||||
plt.tight_layout()
|
plt.tight_layout()
|
||||||
if name is None:
|
if name is None:
|
||||||
@ -134,33 +144,36 @@ class Diagram:
|
|||||||
elif mode == "show":
|
elif mode == "show":
|
||||||
plt.show()
|
plt.show()
|
||||||
|
|
||||||
|
|
||||||
def voronoi_plot(self, i: int, ax: AxesSubplot) -> None:
|
def voronoi_plot(self, i: int, ax: AxesSubplot) -> None:
|
||||||
domain = self.sim.domains[i]
|
domain = self.sim.domains[i]
|
||||||
n, w, h = domain.n, domain.w, domain.h
|
n, w, h = domain.n, domain.w, domain.h
|
||||||
scale = 1.5
|
scale = 1.5
|
||||||
area = n <= 60
|
area = n <= 60
|
||||||
|
|
||||||
voronoi_plot_2d(self.sim.voronois[i], ax, show_vertices=False, point_size = 7-n/100)
|
voronoi_plot_2d(
|
||||||
ax.plot([-w, 2*w], [0, 0], 'r')
|
self.sim.voronois[i], ax, show_vertices=False, point_size=7 - n / 100
|
||||||
ax.plot([-w, 2*w], [h, h], 'r')
|
)
|
||||||
ax.plot([0,0], [-h, 2*h], 'r')
|
ax.plot([-w, 2 * w], [0, 0], "r")
|
||||||
ax.plot([w, w], [-h, 2*h], 'r')
|
ax.plot([-w, 2 * w], [h, h], "r")
|
||||||
ax.axis('equal')
|
ax.plot([0, 0], [-h, 2 * h], "r")
|
||||||
ax.set_xlim([(1-scale)*w/2, (1+scale)*w/2])
|
ax.plot([w, w], [-h, 2 * h], "r")
|
||||||
ax.set_ylim([(1-scale)*h/2, (1+scale)*h/2])
|
ax.axis("equal")
|
||||||
|
ax.set_xlim([(1 - scale) * w / 2, (1 + scale) * w / 2])
|
||||||
|
ax.set_ylim([(1 - scale) * h / 2, (1 + scale) * h / 2])
|
||||||
ax.title.set_text("Voronoi Visualization")
|
ax.title.set_text("Voronoi Visualization")
|
||||||
|
|
||||||
props = dict(boxstyle='round', facecolor='wheat', alpha=0.8)
|
props = dict(boxstyle="round", facecolor="wheat", alpha=0.8)
|
||||||
|
|
||||||
defects = {5: {"x": [], "y": []}, 7: {"x": [], "y": []}}
|
defects = {5: {"x": [], "y": []}, 7: {"x": [], "y": []}}
|
||||||
|
|
||||||
for j in range(n):
|
for j in range(n):
|
||||||
for s in SYMM:
|
for s in SYMM:
|
||||||
vec = (self.sim.voronois[i].points[j] + s*self.sim.domains[i].dim)
|
vec = self.sim.voronois[i].points[j] + s * self.sim.domains[i].dim
|
||||||
|
|
||||||
if area:
|
if area:
|
||||||
txt = ax.text(*vec, str(round(self.sim.stats[i]["site_areas"][j], 3)))
|
txt = ax.text(
|
||||||
|
*vec, str(round(self.sim.stats[i]["site_areas"][j], 3))
|
||||||
|
)
|
||||||
txt.set_clip_on(True)
|
txt.set_clip_on(True)
|
||||||
|
|
||||||
if self.sim.stats[i]["site_edge_count"][j] == 5:
|
if self.sim.stats[i]["site_edge_count"][j] == 5:
|
||||||
@ -173,31 +186,35 @@ class Diagram:
|
|||||||
ax.scatter(defects[5]["x"], defects[5]["y"], marker="p", color="red")
|
ax.scatter(defects[5]["x"], defects[5]["y"], marker="p", color="red")
|
||||||
ax.scatter(defects[7]["x"], defects[7]["y"], marker="*", color="red")
|
ax.scatter(defects[7]["x"], defects[7]["y"], marker="*", color="red")
|
||||||
|
|
||||||
|
ax.text(
|
||||||
ax.text(0.05, 0.95, f'Energy: {self.sim.energies[i]}', transform=ax.transAxes, fontsize=14,
|
0.05,
|
||||||
verticalalignment='top', bbox=props)
|
0.95,
|
||||||
|
f"Energy: {self.sim.energies[i]}",
|
||||||
|
transform=ax.transAxes,
|
||||||
|
fontsize=14,
|
||||||
|
verticalalignment="top",
|
||||||
|
bbox=props,
|
||||||
|
)
|
||||||
|
|
||||||
def energy_plot(self, i: int, ax: AxesSubplot) -> None:
|
def energy_plot(self, i: int, ax: AxesSubplot) -> None:
|
||||||
ax.set_xlim([0, len(self.sim)])
|
ax.set_xlim([0, len(self.sim)])
|
||||||
|
|
||||||
energies = self.sim.energies[:(i+1)]
|
energies = self.sim.energies[: (i + 1)]
|
||||||
ax.plot(list(range(i+1)), energies)
|
ax.plot(list(range(i + 1)), energies)
|
||||||
ax.title.set_text('Energy vs. Time')
|
ax.title.set_text("Energy vs. Time")
|
||||||
# max_value = round(self.sim[0].energy)
|
# max_value = round(self.sim[0].energy)
|
||||||
# min_value = round(self.sim[-1].energy)
|
# min_value = round(self.sim[-1].energy)
|
||||||
#diff = max_value-min_value
|
# diff = max_value-min_value
|
||||||
#ax.set_yticks(np.arange(int(min_value-diff/5), int(max_value+diff/5), diff/25))
|
# ax.set_yticks(np.arange(int(min_value-diff/5), int(max_value+diff/5), diff/25))
|
||||||
ax.set_xlabel("Iterations")
|
ax.set_xlabel("Iterations")
|
||||||
ax.set_ylabel("Energy")
|
ax.set_ylabel("Energy")
|
||||||
ax.grid()
|
ax.grid()
|
||||||
|
|
||||||
|
|
||||||
def site_areas_plot(self, i: int, ax: AxesSubplot) -> None:
|
def site_areas_plot(self, i: int, ax: AxesSubplot) -> None:
|
||||||
y, x = self.sim.hist("site_areas", i, cumul=self.cumulative, avg=True)
|
y, x = self.sim.hist("site_areas", i, cumul=self.cumulative, avg=True)
|
||||||
|
|
||||||
ax.bar(x, y, width=0.8*(x[1]-x[0]))
|
ax.bar(x, y, width=0.8 * (x[1] - x[0]))
|
||||||
ax.title.set_text('Site Areas')
|
ax.title.set_text("Site Areas")
|
||||||
ax.set_xlabel("Area")
|
ax.set_xlabel("Area")
|
||||||
ax.set_ylabel("Average Occurances")
|
ax.set_ylabel("Average Occurances")
|
||||||
ax.set_xticks(x)
|
ax.set_xticks(x)
|
||||||
@ -207,24 +224,26 @@ class Diagram:
|
|||||||
# if color != 'C0':
|
# if color != 'C0':
|
||||||
# xtick.set_color(color)
|
# xtick.set_color(color)
|
||||||
|
|
||||||
|
|
||||||
def site_edge_count_plot(self, i: int, ax: AxesSubplot) -> None:
|
def site_edge_count_plot(self, i: int, ax: AxesSubplot) -> None:
|
||||||
y, x = self.sim.hist("site_edge_count", i, bounds=(1, 11), cumul=self.cumulative, avg=True)
|
y, x = self.sim.hist(
|
||||||
|
"site_edge_count", i, bounds=(1, 11), cumul=self.cumulative, avg=True
|
||||||
|
)
|
||||||
|
|
||||||
ax.bar(x, y, width=0.8*(x[1]-x[0]))
|
ax.bar(x, y, width=0.8 * (x[1] - x[0]))
|
||||||
ax.title.set_text('Edges per Site')
|
ax.title.set_text("Edges per Site")
|
||||||
ax.set_xlabel("Number of Edges")
|
ax.set_xlabel("Number of Edges")
|
||||||
ax.set_ylabel("Average Occurances")
|
ax.set_ylabel("Average Occurances")
|
||||||
ax.set_xticks(x)
|
ax.set_xticks(x)
|
||||||
ax.set_xticklabels([int(z) for z in x])
|
ax.set_xticklabels([int(z) for z in x])
|
||||||
ax.yaxis.set_major_locator(MaxNLocator(integer=True))
|
ax.yaxis.set_major_locator(MaxNLocator(integer=True))
|
||||||
|
|
||||||
|
|
||||||
def site_isos_plot(self, i: int, ax: AxesSubplot) -> None:
|
def site_isos_plot(self, i: int, ax: AxesSubplot) -> None:
|
||||||
y, x = self.sim.hist("site_isos", i, bounds=(0,1), cumul=self.cumulative, avg=True)
|
y, x = self.sim.hist(
|
||||||
|
"site_isos", i, bounds=(0, 1), cumul=self.cumulative, avg=True
|
||||||
|
)
|
||||||
|
|
||||||
ax.bar(x, y, width=0.8*(x[1]-x[0]))
|
ax.bar(x, y, width=0.8 * (x[1] - x[0]))
|
||||||
ax.title.set_text('Isoparametric Values')
|
ax.title.set_text("Isoparametric Values")
|
||||||
ax.set_xlabel("Isoparametric Value")
|
ax.set_xlabel("Isoparametric Value")
|
||||||
ax.set_ylabel("Average Occurances")
|
ax.set_ylabel("Average Occurances")
|
||||||
ax.set_xticks(x)
|
ax.set_xticks(x)
|
||||||
@ -234,83 +253,84 @@ class Diagram:
|
|||||||
# if color != 'C0':
|
# if color != 'C0':
|
||||||
# xtick.set_color(color)
|
# xtick.set_color(color)
|
||||||
|
|
||||||
|
|
||||||
def site_energies_plot(self, i: int, ax: AxesSubplot) -> None:
|
def site_energies_plot(self, i: int, ax: AxesSubplot) -> None:
|
||||||
y, x = self.sim.hist("site_energies", i, cumul=self.cumulative, avg=True)
|
y, x = self.sim.hist("site_energies", i, cumul=self.cumulative, avg=True)
|
||||||
|
|
||||||
ax.bar(x, y, width=0.8*(x[1]-x[0]))
|
ax.bar(x, y, width=0.8 * (x[1] - x[0]))
|
||||||
ax.title.set_text('Site Energies')
|
ax.title.set_text("Site Energies")
|
||||||
ax.set_xlabel("Energy")
|
ax.set_xlabel("Energy")
|
||||||
ax.set_ylabel("Average Occurances")
|
ax.set_ylabel("Average Occurances")
|
||||||
ax.set_xticks(x)
|
ax.set_xticks(x)
|
||||||
ax.ticklabel_format(useOffset=False)
|
ax.ticklabel_format(useOffset=False)
|
||||||
ax.yaxis.set_major_locator(MaxNLocator(integer=True))
|
ax.yaxis.set_major_locator(MaxNLocator(integer=True))
|
||||||
|
|
||||||
|
|
||||||
def avg_radius_plot(self, i: int, ax: AxesSubplot) -> None:
|
def avg_radius_plot(self, i: int, ax: AxesSubplot) -> None:
|
||||||
y, x = self.sim.hist("avg_radius", i, cumul=self.cumulative, avg=True)
|
y, x = self.sim.hist("avg_radius", i, cumul=self.cumulative, avg=True)
|
||||||
|
|
||||||
ax.bar(x, y, width=0.8*(x[1]-x[0]))
|
ax.bar(x, y, width=0.8 * (x[1] - x[0]))
|
||||||
ax.title.set_text('Site Average Radii')
|
ax.title.set_text("Site Average Radii")
|
||||||
ax.set_xlabel("Average Radius")
|
ax.set_xlabel("Average Radius")
|
||||||
ax.set_ylabel("Average Occurances")
|
ax.set_ylabel("Average Occurances")
|
||||||
ax.set_xticks(x)
|
ax.set_xticks(x)
|
||||||
ax.ticklabel_format(useOffset=False)
|
ax.ticklabel_format(useOffset=False)
|
||||||
ax.yaxis.set_major_locator(MaxNLocator(integer=True))
|
ax.yaxis.set_major_locator(MaxNLocator(integer=True))
|
||||||
|
|
||||||
|
|
||||||
def isoparam_avg_plot(self, i: int, ax: AxesSubplot) -> None:
|
def isoparam_avg_plot(self, i: int, ax: AxesSubplot) -> None:
|
||||||
y, x = self.sim.hist("isoparam_avg", i, cumul=self.cumulative, avg=True)
|
y, x = self.sim.hist("isoparam_avg", i, cumul=self.cumulative, avg=True)
|
||||||
|
|
||||||
ax.bar(x,y, width=0.8*(x[1]-x[0]))
|
ax.bar(x, y, width=0.8 * (x[1] - x[0]))
|
||||||
ax.title.set_text('Site Isoperimetric Averages')
|
ax.title.set_text("Site Isoperimetric Averages")
|
||||||
ax.set_xlabel("Isoperimetric Average")
|
ax.set_xlabel("Isoperimetric Average")
|
||||||
ax.set_ylabel("Average Occurances")
|
ax.set_ylabel("Average Occurances")
|
||||||
ax.set_xticks(x)
|
ax.set_xticks(x)
|
||||||
ax.ticklabel_format(useOffset=False)
|
ax.ticklabel_format(useOffset=False)
|
||||||
ax.yaxis.set_major_locator(MaxNLocator(integer=True))
|
ax.yaxis.set_major_locator(MaxNLocator(integer=True))
|
||||||
|
|
||||||
|
|
||||||
def edge_lengths_plot(self, i: int, ax: AxesSubplot) -> None:
|
def edge_lengths_plot(self, i: int, ax: AxesSubplot) -> None:
|
||||||
y, x = self.sim.hist("edge_lengths", i, 30, cumul=self.cumulative, avg=True)
|
y, x = self.sim.hist("edge_lengths", i, 30, cumul=self.cumulative, avg=True)
|
||||||
|
|
||||||
ax.bar(x, y, width=0.8*(x[1]-x[0]))
|
ax.bar(x, y, width=0.8 * (x[1] - x[0]))
|
||||||
ax.title.set_text('Edge Lengths')
|
ax.title.set_text("Edge Lengths")
|
||||||
ax.set_xlabel("Length")
|
ax.set_xlabel("Length")
|
||||||
ax.set_ylabel("Average Occurances")
|
ax.set_ylabel("Average Occurances")
|
||||||
ax.set_xticks(x)
|
ax.set_xticks(x)
|
||||||
ax.set_xticklabels(ax.get_xticks(), rotation = 90)
|
ax.set_xticklabels(ax.get_xticks(), rotation=90)
|
||||||
ax.xaxis.set_major_formatter(FormatStrFormatter('%.3f'))
|
ax.xaxis.set_major_formatter(FormatStrFormatter("%.3f"))
|
||||||
#ax.ticklabel_format(useOffset=False)
|
# ax.ticklabel_format(useOffset=False)
|
||||||
ax.yaxis.set_major_locator(MaxNLocator(integer=True))
|
ax.yaxis.set_major_locator(MaxNLocator(integer=True))
|
||||||
# for xtick, color in zip(ax.get_xticklabels(), lengths_bar[2]):
|
# for xtick, color in zip(ax.get_xticklabels(), lengths_bar[2]):
|
||||||
# if color != 'C0':
|
# if color != 'C0':
|
||||||
# xtick.set_color(color)
|
# xtick.set_color(color)
|
||||||
|
|
||||||
|
|
||||||
def eigs_plot(self, i: int, ax: AxesSubplot) -> None:
|
def eigs_plot(self, i: int, ax: AxesSubplot) -> None:
|
||||||
try:
|
try:
|
||||||
eigs = self.sim.stats[i]["eigs"]
|
eigs = self.sim.stats[i]["eigs"]
|
||||||
ax.plot(list(range(len(eigs))), eigs, marker='o', linestyle='dashed', color='C0')
|
ax.plot(
|
||||||
ax.plot([0,len(eigs)], [0, 0], color="red")
|
list(range(len(eigs))), eigs, marker="o", linestyle="dashed", color="C0"
|
||||||
|
)
|
||||||
|
ax.plot([0, len(eigs)], [0, 0], color="red")
|
||||||
except KeyError:
|
except KeyError:
|
||||||
ax.text(0.5, 0.5, "Not Computed")
|
ax.text(0.5, 0.5, "Not Computed")
|
||||||
|
|
||||||
ax.title.set_text('Hessian Eigenvalues')
|
ax.title.set_text("Hessian Eigenvalues")
|
||||||
ax.set_xlabel("")
|
ax.set_xlabel("")
|
||||||
ax.set_ylabel("Value")
|
ax.set_ylabel("Value")
|
||||||
|
|
||||||
|
def render_frames(self, frames: List[int], fol: str = "frames") -> None:
|
||||||
def render_frames(self, frames: List[int], fol: str = 'frames') -> None:
|
|
||||||
OUTPUT_DIR.mkdir(exist_ok=True)
|
OUTPUT_DIR.mkdir(exist_ok=True)
|
||||||
self.sim.path.mkdir(exist_ok=True)
|
self.sim.path.mkdir(exist_ok=True)
|
||||||
(self.sim.path / fol).mkdir(exist_ok=True)
|
(self.sim.path / fol).mkdir(exist_ok=True)
|
||||||
combo_list = []
|
combo_list = []
|
||||||
for i in range(cpu_count()):
|
for i in range(cpu_count()):
|
||||||
start, end = int(i*len(frames)/cpu_count()), int((i+1)*len(frames)/cpu_count())
|
start, end = (
|
||||||
|
int(i * len(frames) / cpu_count()),
|
||||||
|
int((i + 1) * len(frames) / cpu_count()),
|
||||||
|
)
|
||||||
new_dia = Diagram(None, self.diagrams, self.cumulative)
|
new_dia = Diagram(None, self.diagrams, self.cumulative)
|
||||||
new_dia.sim = self.sim.slice(frames[start:end])
|
new_dia.sim = self.sim.slice(frames[start:end])
|
||||||
combo_list.append((new_dia, fol, start, len(frames[start:end]), len(frames)))
|
combo_list.append(
|
||||||
|
(new_dia, fol, start, len(frames[start:end]), len(frames))
|
||||||
|
)
|
||||||
|
|
||||||
# Free up memory, since it's already duplicated to other cores.
|
# Free up memory, since it's already duplicated to other cores.
|
||||||
self.sim = self.sim.slice([])
|
self.sim = self.sim.slice([])
|
||||||
@ -319,8 +339,7 @@ class Diagram:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
print(flush=True)
|
print(flush=True)
|
||||||
print(f'Wrote to \"{self.sim.path / fol}\".', flush=True)
|
print(f'Wrote to "{self.sim.path / fol}".', flush=True)
|
||||||
|
|
||||||
|
|
||||||
def render_video(self, time: int, mode: str) -> None:
|
def render_video(self, time: int, mode: str) -> None:
|
||||||
if mode not in ["use_all", "sample"]:
|
if mode not in ["use_all", "sample"]:
|
||||||
@ -330,27 +349,31 @@ class Diagram:
|
|||||||
frames = list(range(len(self.sim)))
|
frames = list(range(len(self.sim)))
|
||||||
elif mode == "sample":
|
elif mode == "sample":
|
||||||
fps = 30
|
fps = 30
|
||||||
if len(self.sim) < fps*time:
|
if len(self.sim) < fps * time:
|
||||||
frames = list(range(len(self.sim)))
|
frames = list(range(len(self.sim)))
|
||||||
fps = len(self.sim)/time
|
fps = len(self.sim) / time
|
||||||
else:
|
else:
|
||||||
frames = list(np.round(np.linspace(0, len(self.sim)-1, fps*time)).astype(int))
|
frames = list(
|
||||||
|
np.round(np.linspace(0, len(self.sim) - 1, fps * time)).astype(int)
|
||||||
|
)
|
||||||
|
|
||||||
self.render_frames(frames, 'temp')
|
self.render_frames(frames, "temp")
|
||||||
path = self.sim.path / 'simulation.mp4'
|
path = self.sim.path / "simulation.mp4"
|
||||||
|
|
||||||
print("Assembling MP4...", flush=True)
|
print("Assembling MP4...", flush=True)
|
||||||
os.system(f'ffmpeg -hide_banner -loglevel error -r {fps} -i' + \
|
os.system(
|
||||||
f' \"{self.sim.path}/temp/img%05d.png\"' + \
|
f"ffmpeg -hide_banner -loglevel error -r {fps} -i"
|
||||||
f' -c:v libx264 -crf 18 -preset slow -pix_fmt yuv420p -vf' + \
|
+ f' "{self.sim.path}/temp/img%05d.png"'
|
||||||
f' "scale=trunc(iw/2)*2:trunc(ih/2)*2" -f mp4 "{path}"')
|
+ f" -c:v libx264 -crf 18 -preset slow -pix_fmt yuv420p -vf"
|
||||||
|
+ f' "scale=trunc(iw/2)*2:trunc(ih/2)*2" -f mp4 "{path}"'
|
||||||
|
)
|
||||||
|
|
||||||
# Remove files.
|
# Remove files.
|
||||||
for i in range(len(frames)):
|
for i in range(len(frames)):
|
||||||
os.remove(self.sim.path / f"temp/img{i:05}.png")
|
os.remove(self.sim.path / f"temp/img{i:05}.png")
|
||||||
|
|
||||||
os.rmdir(self.sim.path / 'temp')
|
os.rmdir(self.sim.path / "temp")
|
||||||
print(f'Wrote to \"{path}\".', flush=True)
|
print(f'Wrote to "{path}".', flush=True)
|
||||||
|
|
||||||
|
|
||||||
def render_frame_range(combo: Tuple[Diagram, str, int, int, int]) -> None:
|
def render_frame_range(combo: Tuple[Diagram, str, int, int, int]) -> None:
|
||||||
@ -358,6 +381,10 @@ def render_frame_range(combo: Tuple[Diagram, str, int, int, int]) -> None:
|
|||||||
for i in range(length):
|
for i in range(length):
|
||||||
self.generate_frame(i, "save", fol, f"img{i+offset:05}.png")
|
self.generate_frame(i, "save", fol, f"img{i+offset:05}.png")
|
||||||
i = len(list((self.sim.path / fol).iterdir()))
|
i = len(list((self.sim.path / fol).iterdir()))
|
||||||
hashes = int(21*i/num_frames)
|
hashes = int(21 * i / num_frames)
|
||||||
print(f'Generating frames... |{"#"*hashes}{" "*(20-hashes)}|' + \
|
print(
|
||||||
f' {i}/{num_frames} frames rendered.', flush=True, end='\r')
|
f'Generating frames... |{"#"*hashes}{" "*(20-hashes)}|'
|
||||||
|
+ f" {i}/{num_frames} frames rendered.",
|
||||||
|
flush=True,
|
||||||
|
end="\r",
|
||||||
|
)
|
||||||
|
|||||||
@ -6,11 +6,12 @@ from math import gcd, sqrt, log, tan, atan, pi
|
|||||||
|
|
||||||
Config = Tuple[int, int]
|
Config = Tuple[int, int]
|
||||||
|
|
||||||
|
|
||||||
def configurations(domain: DomainParams) -> List[Config]:
|
def configurations(domain: DomainParams) -> List[Config]:
|
||||||
n, w, h = domain.n, domain.w, domain.h
|
n, w, h = domain.n, domain.w, domain.h
|
||||||
valid = []
|
valid = []
|
||||||
mults = np.arange(n)
|
mults = np.arange(n)
|
||||||
configs = np.dstack((np.repeat(mults,n).T, np.tile(mults, n).T))[0][1:]
|
configs = np.dstack((np.repeat(mults, n).T, np.tile(mults, n).T))[0][1:]
|
||||||
for i in range(len(configs)):
|
for i in range(len(configs)):
|
||||||
eq_x = n if configs[i][0] == 0 else configs[i][0]
|
eq_x = n if configs[i][0] == 0 else configs[i][0]
|
||||||
eq_y = n if configs[i][1] == 0 else configs[i][1]
|
eq_y = n if configs[i][1] == 0 else configs[i][1]
|
||||||
@ -18,8 +19,13 @@ def configurations(domain: DomainParams) -> List[Config]:
|
|||||||
if gcd(eq_x, eq_y) != 1:
|
if gcd(eq_x, eq_y) != 1:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
vecs = configs[i]*np.dstack((w*mults, h*mults)).swapaxes(0,1)/n % domain.dim
|
vecs = (
|
||||||
vmod2 = np.squeeze(np.matmul(vecs, vecs.transpose(0,2,1)))
|
configs[i]
|
||||||
|
* np.dstack((w * mults, h * mults)).swapaxes(0, 1)
|
||||||
|
/ n
|
||||||
|
% domain.dim
|
||||||
|
)
|
||||||
|
vmod2 = np.squeeze(np.matmul(vecs, vecs.transpose(0, 2, 1)))
|
||||||
vmodv = np.squeeze(vecs).dot(vecs[1].T).T.flatten()
|
vmodv = np.squeeze(vecs).dot(vecs[1].T).T.flatten()
|
||||||
|
|
||||||
if np.all(vmod2 >= vmodv):
|
if np.all(vmod2 >= vmodv):
|
||||||
@ -28,20 +34,26 @@ def configurations(domain: DomainParams) -> List[Config]:
|
|||||||
return valid
|
return valid
|
||||||
|
|
||||||
|
|
||||||
def get_config_generators(domain: DomainParams, config: Config) -> Tuple[Config, Config]:
|
def get_config_generators(
|
||||||
|
domain: DomainParams, config: Config
|
||||||
|
) -> Tuple[Config, Config]:
|
||||||
n, w, h = domain.n, domain.w, domain.h
|
n, w, h = domain.n, domain.w, domain.h
|
||||||
q1 = sites(domain, config)
|
q1 = sites(domain, config)
|
||||||
v = q1[1]
|
v = q1[1]
|
||||||
# Sites to check can ignore 0*v and v itself.
|
# Sites to check can ignore 0*v and v itself.
|
||||||
all_sites = np.concatenate((q1, q1-[w,0], q1-[w,h], q1-[0,h]))[2:]
|
all_sites = np.concatenate((q1, q1 - [w, 0], q1 - [w, h], q1 - [0, h]))[2:]
|
||||||
|
|
||||||
# Checking 0 < ax + by < v*v to make the sites are within the region.
|
# Checking 0 < ax + by < v*v to make the sites are within the region.
|
||||||
tol = 1e-3
|
tol = 1e-3
|
||||||
vdot = np.matmul(all_sites, v)
|
vdot = np.matmul(all_sites, v)
|
||||||
in_box = all_sites[np.where((-tol <= vdot) & (vdot <= (v.dot(v)+tol)))[0]]
|
in_box = all_sites[np.where((-tol <= vdot) & (vdot <= (v.dot(v) + tol)))[0]]
|
||||||
in_box = np.expand_dims(in_box, 0).swapaxes(0,1) # Used for the next step, getting site*site
|
in_box = np.expand_dims(in_box, 0).swapaxes(
|
||||||
|
0, 1
|
||||||
|
) # Used for the next step, getting site*site
|
||||||
|
|
||||||
w = in_box[np.argmin(np.squeeze(np.matmul(in_box, in_box.transpose(0,2,1))))].flatten()
|
w = in_box[
|
||||||
|
np.argmin(np.squeeze(np.matmul(in_box, in_box.transpose(0, 2, 1))))
|
||||||
|
].flatten()
|
||||||
|
|
||||||
return tuple(v), tuple(w)
|
return tuple(v), tuple(w)
|
||||||
|
|
||||||
@ -49,7 +61,7 @@ def get_config_generators(domain: DomainParams, config: Config) -> Tuple[Config,
|
|||||||
def sites(domain: DomainParams, config: Config) -> numpy.ndarray:
|
def sites(domain: DomainParams, config: Config) -> numpy.ndarray:
|
||||||
n, w, h = domain.n, domain.w, domain.h
|
n, w, h = domain.n, domain.w, domain.h
|
||||||
config, mults = np.array(config), np.arange(domain.n)
|
config, mults = np.array(config), np.arange(domain.n)
|
||||||
return (config*np.dstack((w*mults, h*mults))[0]/n) % domain.dim
|
return (config * np.dstack((w * mults, h * mults))[0] / n) % domain.dim
|
||||||
|
|
||||||
|
|
||||||
def area(domain: DomainParams, config: Config) -> float:
|
def area(domain: DomainParams, config: Config) -> float:
|
||||||
@ -57,7 +69,11 @@ def area(domain: DomainParams, config: Config) -> float:
|
|||||||
v, w = np.array(v), np.array(w)
|
v, w = np.array(v), np.array(w)
|
||||||
c = circumcenter(v, w)
|
c = circumcenter(v, w)
|
||||||
|
|
||||||
return mag(v)*mag(v/2 - c) + mag(w)*mag(w/2-c) + mag(v-w)*mag((v+w)/2-c)
|
return (
|
||||||
|
mag(v) * mag(v / 2 - c)
|
||||||
|
+ mag(w) * mag(w / 2 - c)
|
||||||
|
+ mag(v - w) * mag((v + w) / 2 - c)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def avg_radius(domain: DomainParams, config: Config) -> float:
|
def avg_radius(domain: DomainParams, config: Config) -> float:
|
||||||
@ -65,20 +81,23 @@ def avg_radius(domain: DomainParams, config: Config) -> float:
|
|||||||
v, w = np.array(v), np.array(w)
|
v, w = np.array(v), np.array(w)
|
||||||
c = circumcenter(v, w)
|
c = circumcenter(v, w)
|
||||||
|
|
||||||
return 2*(avg_rp(mag(v), 2*mag(v/2 - c)) + avg_rp(mag(w), 2*mag(w/2-c)) + \
|
return 2 * (
|
||||||
avg_rp(mag(v-w),2*mag((v+w)/2-c)))
|
avg_rp(mag(v), 2 * mag(v / 2 - c))
|
||||||
|
+ avg_rp(mag(w), 2 * mag(w / 2 - c))
|
||||||
|
+ avg_rp(mag(v - w), 2 * mag((v + w) / 2 - c))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def avg_rp(d: float, l: float) -> float:
|
def avg_rp(d: float, l: float) -> float:
|
||||||
return (d/(4*pi))*log(tan(.5*(atan(l/d)+pi/2))**2)
|
return (d / (4 * pi)) * log(tan(0.5 * (atan(l / d) + pi / 2)) ** 2)
|
||||||
|
|
||||||
|
|
||||||
def circumcenter(v: numpy.ndarray, w: numpy.ndarray) -> Config:
|
def circumcenter(v: numpy.ndarray, w: numpy.ndarray) -> Config:
|
||||||
det = 1/(2*rot(v).dot(w))
|
det = 1 / (2 * rot(v).dot(w))
|
||||||
v2, w2 = v.dot(v), w.dot(w)
|
v2, w2 = v.dot(v), w.dot(w)
|
||||||
c = np.empty((2,))
|
c = np.empty((2,))
|
||||||
c[0], c[1] = w[1]*v2 - v[1]*w2,-w[0]*v2 + v[0]*w2
|
c[0], c[1] = w[1] * v2 - v[1] * w2, -w[0] * v2 + v[0] * w2
|
||||||
return det*c
|
return det * c
|
||||||
|
|
||||||
|
|
||||||
def rot(v: numpy.ndarray) -> numpy.ndarray:
|
def rot(v: numpy.ndarray) -> numpy.ndarray:
|
||||||
|
|||||||
@ -21,10 +21,11 @@ class Simulation:
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ['domain', 'energy', 'path', 'frames']
|
__slots__ = ["domain", "energy", "path", "frames"]
|
||||||
|
|
||||||
def __init__(self, domain: DomainParams, energy: Energy, \
|
def __init__(
|
||||||
name: Optional[str, int] = None) -> None:
|
self, domain: DomainParams, energy: Energy, name: Optional[str, int] = None
|
||||||
|
) -> None:
|
||||||
self.domain, self.energy = domain, energy
|
self.domain, self.energy = domain, energy
|
||||||
self.frames = []
|
self.frames = []
|
||||||
|
|
||||||
@ -35,18 +36,15 @@ class Simulation:
|
|||||||
else:
|
else:
|
||||||
self.path = OUTPUT_DIR / name
|
self.path = OUTPUT_DIR / name
|
||||||
|
|
||||||
|
|
||||||
def __iter__(self) -> Iterator:
|
def __iter__(self) -> Iterator:
|
||||||
return iter(self.frames)
|
return iter(self.frames)
|
||||||
|
|
||||||
def __getitem__(self, key: int) -> Energy:
|
def __getitem__(self, key: int) -> Energy:
|
||||||
return self.frames[key]
|
return self.frames[key]
|
||||||
|
|
||||||
|
|
||||||
def __len__(self) -> int:
|
def __len__(self) -> int:
|
||||||
return len(self.frames)
|
return len(self.frames)
|
||||||
|
|
||||||
|
|
||||||
def add_frame(self, points: Optional[numpy.ndarray] = None) -> None:
|
def add_frame(self, points: Optional[numpy.ndarray] = None) -> None:
|
||||||
if points is None:
|
if points is None:
|
||||||
points = np.random.random_sample((self.domain.n, 2)) * self.domain.dim
|
points = np.random.random_sample((self.domain.n, 2)) * self.domain.dim
|
||||||
@ -59,7 +57,6 @@ class Simulation:
|
|||||||
|
|
||||||
self.frames.append(self.energy.mode(*self.domain, points % self.domain.dim))
|
self.frames.append(self.energy.mode(*self.domain, points % self.domain.dim))
|
||||||
|
|
||||||
|
|
||||||
def get_distinct(self) -> List[int]:
|
def get_distinct(self) -> List[int]:
|
||||||
"""Gets the distinct configurations based on the average radii of the sites.
|
"""Gets the distinct configurations based on the average radii of the sites.
|
||||||
and returns the number of configurations for each distinct configuration.
|
and returns the number of configurations for each distinct configuration.
|
||||||
@ -67,7 +64,6 @@ class Simulation:
|
|||||||
|
|
||||||
distinct_avg_radii, distinct_count, new_frames = [], [], []
|
distinct_avg_radii, distinct_count, new_frames = [], [], []
|
||||||
|
|
||||||
|
|
||||||
for frame in self.frames:
|
for frame in self.frames:
|
||||||
try:
|
try:
|
||||||
stats = frame.stats
|
stats = frame.stats
|
||||||
@ -90,38 +86,35 @@ class Simulation:
|
|||||||
self.frames = new_frames
|
self.frames = new_frames
|
||||||
return distinct_count
|
return distinct_count
|
||||||
|
|
||||||
|
|
||||||
def save(self, info: Dict, overwrite: bool = False) -> None:
|
def save(self, info: Dict, overwrite: bool = False) -> None:
|
||||||
OUTPUT_DIR.mkdir(exist_ok=True)
|
OUTPUT_DIR.mkdir(exist_ok=True)
|
||||||
self.path.mkdir(exist_ok=True)
|
self.path.mkdir(exist_ok=True)
|
||||||
path = self.path / 'data.squish'
|
path = self.path / "data.squish"
|
||||||
|
|
||||||
with open(path, 'wb' if overwrite else 'ab') as out:
|
with open(path, "wb" if overwrite else "ab") as out:
|
||||||
pickle.dump(info, out, pickle.HIGHEST_PROTOCOL)
|
pickle.dump(info, out, pickle.HIGHEST_PROTOCOL)
|
||||||
|
|
||||||
|
|
||||||
def save_all(self) -> None:
|
def save_all(self) -> None:
|
||||||
self.save(self.initial_data, True)
|
self.save(self.initial_data, True)
|
||||||
for i in range(len(self.frames)):
|
for i in range(len(self.frames)):
|
||||||
self.save(self.frame_data(i))
|
self.save(self.frame_data(i))
|
||||||
|
|
||||||
|
|
||||||
def frame_data(self, index: int) -> None:
|
def frame_data(self, index: int) -> None:
|
||||||
f = self[index]
|
f = self[index]
|
||||||
info = {
|
info = {
|
||||||
"arr": f.site_arr,
|
"arr": f.site_arr,
|
||||||
"domain": (f.n, f.w, f.h, f.r),
|
"domain": (f.n, f.w, f.h, f.r),
|
||||||
"energy": f.energy,
|
"energy": f.energy,
|
||||||
"stats": f.stats
|
"stats": f.stats,
|
||||||
}
|
}
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load(path: str) -> Tuple[Simulation, Generator]:
|
def load(path: str) -> Tuple[Simulation, Generator]:
|
||||||
path = Path(path)
|
path = Path(path)
|
||||||
|
|
||||||
def frames() -> Dict:
|
def frames() -> Dict:
|
||||||
with open(path / 'data.squish', 'rb') as infile:
|
with open(path / "data.squish", "rb") as infile:
|
||||||
first = True
|
first = True
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
@ -133,17 +126,18 @@ class Simulation:
|
|||||||
except EOFError:
|
except EOFError:
|
||||||
break
|
break
|
||||||
|
|
||||||
with open(path / 'data.squish', 'rb') as infile:
|
with open(path / "data.squish", "rb") as infile:
|
||||||
sim_info = pickle.load(infile)
|
sim_info = pickle.load(infile)
|
||||||
|
|
||||||
domain = DomainParams(*sim_info["domain"])
|
domain = DomainParams(*sim_info["domain"])
|
||||||
energy = Energy(sim_info["energy"])
|
energy = Energy(sim_info["energy"])
|
||||||
sim = STR_TO_SIM[sim_info["mode"]](domain, energy, *list(sim_info.values())[3:])
|
sim = STR_TO_SIM[sim_info["mode"]](
|
||||||
|
domain, energy, *list(sim_info.values())[3:]
|
||||||
|
)
|
||||||
sim.path = path
|
sim.path = path
|
||||||
|
|
||||||
return sim, frames()
|
return sim, frames()
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_file(path: str) -> Simulation:
|
def from_file(path: str) -> Simulation:
|
||||||
sim, frames = Simulation.load(path)
|
sim, frames = Simulation.load(path)
|
||||||
@ -167,16 +161,22 @@ class Flow(Simulation):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ['step_size', 'thres', 'adaptive']
|
__slots__ = ["step_size", "thres", "adaptive"]
|
||||||
attr_str = "flow"
|
attr_str = "flow"
|
||||||
title_str = "Flow"
|
title_str = "Flow"
|
||||||
|
|
||||||
def __init__(self, domain: DomainParams, energy: Energy, step_size: float, thres: float,
|
def __init__(
|
||||||
adaptive: bool, name: Optional[str] = None) -> None:
|
self,
|
||||||
|
domain: DomainParams,
|
||||||
|
energy: Energy,
|
||||||
|
step_size: float,
|
||||||
|
thres: float,
|
||||||
|
adaptive: bool,
|
||||||
|
name: Optional[str] = None,
|
||||||
|
) -> None:
|
||||||
super().__init__(domain, energy, name=name)
|
super().__init__(domain, energy, name=name)
|
||||||
self.step_size, self.thres, self.adaptive = step_size, thres, adaptive
|
self.step_size, self.thres, self.adaptive = step_size, thres, adaptive
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def initial_data(self) -> Dict:
|
def initial_data(self) -> Dict:
|
||||||
info = {
|
info = {
|
||||||
@ -185,18 +185,25 @@ class Flow(Simulation):
|
|||||||
"energy": self.energy.attr_str,
|
"energy": self.energy.attr_str,
|
||||||
"step_size": self.step_size,
|
"step_size": self.step_size,
|
||||||
"thres": self.thres,
|
"thres": self.thres,
|
||||||
"adaptive": self.adaptive
|
"adaptive": self.adaptive,
|
||||||
}
|
}
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
def run(
|
||||||
|
self,
|
||||||
|
save: bool,
|
||||||
|
log: bool,
|
||||||
|
log_steps: int,
|
||||||
|
new_sites: Optional[numpy.ndarray] = None,
|
||||||
|
) -> None:
|
||||||
|
if log:
|
||||||
|
print(f"Find - {self.domain}", flush=True)
|
||||||
|
if save and len(self) == 0:
|
||||||
|
self.save(self.initial_data, True)
|
||||||
|
if len(self) == 0:
|
||||||
|
self.add_frame(new_sites)
|
||||||
|
|
||||||
def run(self, save: bool, log: bool, log_steps: int,
|
i, stop = len(self) - 1, False
|
||||||
new_sites: Optional[numpy.ndarray] = None) -> None:
|
|
||||||
if log: print(f"Find - {self.domain}", flush=True)
|
|
||||||
if save and len(self) == 0: self.save(self.initial_data, True)
|
|
||||||
if len(self) == 0: self.add_frame(new_sites)
|
|
||||||
|
|
||||||
i, stop = len(self)-1, False
|
|
||||||
|
|
||||||
while not stop: # Get to threshold.
|
while not stop: # Get to threshold.
|
||||||
if save:
|
if save:
|
||||||
@ -214,10 +221,10 @@ class Flow(Simulation):
|
|||||||
end = timer()
|
end = timer()
|
||||||
|
|
||||||
if self.adaptive:
|
if self.adaptive:
|
||||||
error = change - grad*self.step_size
|
error = change - grad * self.step_size
|
||||||
tol = 10**min(-3, -2+log10(grad_norm))
|
tol = 10 ** min(-3, -2 + log10(grad_norm))
|
||||||
|
|
||||||
self.step_size *= (tol/np.linalg.norm(error))**.5
|
self.step_size *= (tol / np.linalg.norm(error)) ** 0.5
|
||||||
|
|
||||||
if not save:
|
if not save:
|
||||||
del self.frames[0]
|
del self.frames[0]
|
||||||
@ -227,10 +234,12 @@ class Flow(Simulation):
|
|||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
if (log and i % log_steps == 0) or stop:
|
if (log and i % log_steps == 0) or stop:
|
||||||
print(f'Iteration: {i:05} | Energy: {frame.energy: .5f}' + \
|
print(
|
||||||
f' | Gradient: {grad_norm:.8f} | Step: {self.step_size: .5f} | ' + \
|
f"Iteration: {i:05} | Energy: {frame.energy: .5f}"
|
||||||
f'Time: {end-start: .3f} |', flush=True)
|
+ f" | Gradient: {grad_norm:.8f} | Step: {self.step_size: .5f} | "
|
||||||
|
+ f"Time: {end-start: .3f} |",
|
||||||
|
flush=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Search(Simulation):
|
class Search(Simulation):
|
||||||
@ -249,18 +258,25 @@ class Search(Simulation):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ['step_size', 'thres', 'adaptive', 'kernel_step', 'count']
|
__slots__ = ["step_size", "thres", "adaptive", "kernel_step", "count"]
|
||||||
attr_str = "search"
|
attr_str = "search"
|
||||||
title_str = "Search"
|
title_str = "Search"
|
||||||
|
|
||||||
def __init__(self, domain: DomainParams, energy: Energy, step_size: float, thres: float,
|
def __init__(
|
||||||
adaptive: bool, kernel_step: float, count: int,
|
self,
|
||||||
name: Optional[str] = None) -> None:
|
domain: DomainParams,
|
||||||
|
energy: Energy,
|
||||||
|
step_size: float,
|
||||||
|
thres: float,
|
||||||
|
adaptive: bool,
|
||||||
|
kernel_step: float,
|
||||||
|
count: int,
|
||||||
|
name: Optional[str] = None,
|
||||||
|
) -> None:
|
||||||
super().__init__(domain, energy, name=name)
|
super().__init__(domain, energy, name=name)
|
||||||
self.step_size, self.thres, self.adaptive = step_size, thres, adaptive
|
self.step_size, self.thres, self.adaptive = step_size, thres, adaptive
|
||||||
self.kernel_step, self.count = kernel_step, count
|
self.kernel_step, self.count = kernel_step, count
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def initial_data(self) -> Dict:
|
def initial_data(self) -> Dict:
|
||||||
info = {
|
info = {
|
||||||
@ -271,40 +287,54 @@ class Search(Simulation):
|
|||||||
"thres": self.thres,
|
"thres": self.thres,
|
||||||
"adaptive": self.adaptive,
|
"adaptive": self.adaptive,
|
||||||
"kernel_step": self.kernel_step,
|
"kernel_step": self.kernel_step,
|
||||||
"count": self.count
|
"count": self.count,
|
||||||
}
|
}
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
def run(
|
||||||
def run(self, save: bool, log: bool, log_steps: int,
|
self,
|
||||||
new_sites: Optional[numpy.ndarray] = None) -> None:
|
save: bool,
|
||||||
if log: print(f'Travel - {self.domain}', flush=True)
|
log: bool,
|
||||||
if save and len(self) == 0: self.save(self.initial_data, True)
|
log_steps: int,
|
||||||
|
new_sites: Optional[numpy.ndarray] = None,
|
||||||
|
) -> None:
|
||||||
|
if log:
|
||||||
|
print(f"Travel - {self.domain}", flush=True)
|
||||||
|
if save and len(self) == 0:
|
||||||
|
self.save(self.initial_data, True)
|
||||||
|
|
||||||
for i in range(len(self), self.count):
|
for i in range(len(self), self.count):
|
||||||
# Get to equilibrium.
|
# Get to equilibrium.
|
||||||
sim = Flow(self.domain, self.energy, self.step_size, self.thres, self.adaptive)
|
sim = Flow(
|
||||||
|
self.domain, self.energy, self.step_size, self.thres, self.adaptive
|
||||||
|
)
|
||||||
sim.add_frame(new_sites)
|
sim.add_frame(new_sites)
|
||||||
sim.run(False, log, log_steps)
|
sim.run(False, log, log_steps)
|
||||||
|
|
||||||
self.frames.append(sim[-1])
|
self.frames.append(sim[-1])
|
||||||
if save: self.save(self.frame_data(i))
|
if save:
|
||||||
if log: print(f'Equilibrium: {i:04}\n', flush=True)
|
self.save(self.frame_data(i))
|
||||||
|
if log:
|
||||||
|
print(f"Equilibrium: {i:04}\n", flush=True)
|
||||||
|
|
||||||
# Get Hessian,and check nullity. If > 2, perturb.
|
# Get Hessian,and check nullity. If > 2, perturb.
|
||||||
hess = self.frames[i].hessian(10e-5)
|
hess = self.frames[i].hessian(10e-5)
|
||||||
eigs = np.sort(np.linalg.eig(hess)[0])
|
eigs = np.sort(np.linalg.eig(hess)[0])
|
||||||
self.frames[i].stats["eigs"] = eigs
|
self.frames[i].stats["eigs"] = eigs
|
||||||
|
|
||||||
zero_eigs = np.count_nonzero(np.isclose(eigs, np.zeros((len(eigs),)), atol=1e-4))
|
zero_eigs = np.count_nonzero(
|
||||||
|
np.isclose(eigs, np.zeros((len(eigs),)), atol=1e-4)
|
||||||
|
)
|
||||||
|
|
||||||
if zero_eigs == 2:
|
if zero_eigs == 2:
|
||||||
new_sites = None
|
new_sites = None
|
||||||
else:
|
else:
|
||||||
print("Warning: Nullity > 2. Expected if AreaEnergy.", flush=True)
|
print("Warning: Nullity > 2. Expected if AreaEnergy.", flush=True)
|
||||||
ns = null_space(hess, 10e-4).T
|
ns = null_space(hess, 10e-4).T
|
||||||
vec = ns[random.randint(0, len(ns)-1)].reshape((self.domain.n, 2)) # Random vector.
|
vec = ns[random.randint(0, len(ns) - 1)].reshape(
|
||||||
new_sites = self.frames[i].add_sites(self.kernel_step*vec)
|
(self.domain.n, 2)
|
||||||
|
) # Random vector.
|
||||||
|
new_sites = self.frames[i].add_sites(self.kernel_step * vec)
|
||||||
|
|
||||||
|
|
||||||
class Shrink(Simulation):
|
class Shrink(Simulation):
|
||||||
@ -312,7 +342,7 @@ class Shrink(Simulation):
|
|||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
domain (DomainParams): domain parameters for this simulation.
|
domain (DomainParams): domain parameters for this simulation.
|
||||||
energy (Energy): energy being used for caluclations.
|
energy (Energy): energy being used for calcu1lations.
|
||||||
path (Path): path to the location of where to store simulation files.
|
path (Path): path to the location of where to store simulation files.
|
||||||
frames (List[VoronoiContainer]): stores frames of the simulation.
|
frames (List[VoronoiContainer]): stores frames of the simulation.
|
||||||
step_size (float): size fo step by for each iteration.
|
step_size (float): size fo step by for each iteration.
|
||||||
@ -323,18 +353,27 @@ class Shrink(Simulation):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ['step_size', 'thres', 'adaptive', 'delta', 'stop_width']
|
__slots__ = ["step_size", "thres", "adaptive", "delta", "stop_width"]
|
||||||
attr_str = "shrink"
|
attr_str = "shrink"
|
||||||
title_str = "Shrink"
|
title_str = "Shrink"
|
||||||
|
|
||||||
|
def __init__(
|
||||||
def __init__(self, domain: DomainParams, energy: Energy, step_size: float, thres: float,
|
self,
|
||||||
adaptive: bool, delta: float, stop_width: float,
|
domain: DomainParams,
|
||||||
name: Optional[str] = None) -> None:
|
energy: Energy,
|
||||||
|
step_size: float,
|
||||||
|
thres: float,
|
||||||
|
adaptive: bool,
|
||||||
|
delta: float,
|
||||||
|
stop_width: float,
|
||||||
|
name: Optional[str] = None,
|
||||||
|
) -> None:
|
||||||
super().__init__(domain, energy, name=name)
|
super().__init__(domain, energy, name=name)
|
||||||
self.step_size, self.thres, self.adaptive = step_size, thres, adaptive
|
self.step_size, self.thres, self.adaptive = step_size, thres, adaptive
|
||||||
self.delta, self.stop_width = self.domain.w*delta/100, self.domain.w*stop_width
|
self.delta, self.stop_width = (
|
||||||
|
self.domain.w * delta / 100,
|
||||||
|
self.domain.w * stop_width,
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def initial_data(self) -> Dict:
|
def initial_data(self) -> Dict:
|
||||||
@ -346,37 +385,45 @@ class Shrink(Simulation):
|
|||||||
"thres": self.thres,
|
"thres": self.thres,
|
||||||
"adaptive": self.adaptive,
|
"adaptive": self.adaptive,
|
||||||
"delta": self.delta,
|
"delta": self.delta,
|
||||||
"stop_width": self.stop_width
|
"stop_width": self.stop_width,
|
||||||
}
|
}
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
def run(
|
||||||
def run(self, save: bool, log: bool, log_steps: int,
|
self,
|
||||||
new_sites: Optional[numpy.ndarray] = None) -> None:
|
save: bool,
|
||||||
if log: print(f'Shrink - {self.domain}', flush=True)
|
log: bool,
|
||||||
if save and len(self) == 0: self.save(self.initial_data, True)
|
log_steps: int,
|
||||||
|
new_sites: Optional[numpy.ndarray] = None,
|
||||||
|
) -> None:
|
||||||
|
if log:
|
||||||
|
print(f"Shrink - {self.domain}", flush=True)
|
||||||
|
if save and len(self) == 0:
|
||||||
|
self.save(self.initial_data, True)
|
||||||
|
|
||||||
width = self.domain.w if len(self.frames) == 0 else self.frames[-1].w
|
width = self.domain.w if len(self.frames) == 0 else self.frames[-1].w
|
||||||
i = 0
|
i = 0
|
||||||
while width >= self.stop_width:
|
while width >= self.stop_width:
|
||||||
# Get to equilibrium.
|
# Get to equilibrium.
|
||||||
new_domain = DomainParams(self.domain.n, width, self.domain.h, self.domain.r)
|
new_domain = DomainParams(
|
||||||
sim = Flow(new_domain, self.energy, self.step_size, self.thres, self.adaptive)
|
self.domain.n, width, self.domain.h, self.domain.r
|
||||||
|
)
|
||||||
|
sim = Flow(
|
||||||
|
new_domain, self.energy, self.step_size, self.thres, self.adaptive
|
||||||
|
)
|
||||||
sim.add_frame(new_sites)
|
sim.add_frame(new_sites)
|
||||||
sim.run(False, log, log_steps)
|
sim.run(False, log, log_steps)
|
||||||
new_sites = sim[-1].site_arr
|
new_sites = sim[-1].site_arr
|
||||||
|
|
||||||
self.frames.append(sim[-1])
|
self.frames.append(sim[-1])
|
||||||
if save: self.save(self.frame_data(i))
|
if save:
|
||||||
|
self.save(self.frame_data(i))
|
||||||
|
|
||||||
if log: print(f'Width: {width:.4f}\n')
|
if log:
|
||||||
|
print(f"Width: {width:.4f}\n")
|
||||||
|
|
||||||
width -= self.delta
|
width -= self.delta
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
|
|
||||||
STR_TO_SIM = {
|
STR_TO_SIM = {"flow": Flow, "search": Search, "shrink": Shrink}
|
||||||
"flow": Flow,
|
|
||||||
"search": Search,
|
|
||||||
"shrink": Shrink
|
|
||||||
}
|
|
||||||
|
|||||||
170
squish/squish.py
170
squish/squish.py
@ -13,11 +13,12 @@ dia_presets = {
|
|||||||
"energy": [["voronoi", "energy"]],
|
"energy": [["voronoi", "energy"]],
|
||||||
"stats": [
|
"stats": [
|
||||||
["voronoi", "eigs", "site_edge_count"],
|
["voronoi", "eigs", "site_edge_count"],
|
||||||
["site_isos", "site_energies", "edge_lengths"]
|
["site_isos", "site_energies", "edge_lengths"],
|
||||||
],
|
],
|
||||||
"eigs": [["voronoi", "eigs"]]
|
"eigs": [["voronoi", "eigs"]],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def check_params(container: Dict, needed: List[str], valid: Dict) -> None:
|
def check_params(container: Dict, needed: List[str], valid: Dict) -> None:
|
||||||
"""Checks container for the necessary items, and raises
|
"""Checks container for the necessary items, and raises
|
||||||
an error if the parameter is not found.
|
an error if the parameter is not found.
|
||||||
@ -25,41 +26,65 @@ def check_params(container: Dict, needed: List[str], valid: Dict) -> None:
|
|||||||
Args:
|
Args:
|
||||||
container (Dict): contains the submitted parameters.
|
container (Dict): contains the submitted parameters.
|
||||||
needed (List[str]): contains the needed paramters.
|
needed (List[str]): contains the needed paramters.
|
||||||
valid: (Dict): if there are specific valid parameters, it will also check for these.
|
valid: (Dict): if there are specific valid parameters, it will also check these.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for need in needed:
|
for need in needed:
|
||||||
if need not in container:
|
if need not in container:
|
||||||
raise ValueError(f"Parameter \'{need}\' is required.")
|
raise ValueError(f"Parameter '{need}' is required.")
|
||||||
|
|
||||||
if need in valid:
|
if need in valid:
|
||||||
if type(valid[need]) is list:
|
if type(valid[need]) is list:
|
||||||
if container[need] not in valid[need]:
|
if container[need] not in valid[need]:
|
||||||
raise ValueError(f"Parameter \'{need}\' must be one of these values: " + \
|
raise ValueError(
|
||||||
f"{str(valid[need])[1:-1]}.")
|
f"Parameter '{need}' must be one of these values: "
|
||||||
|
+ f"{str(valid[need])[1:-1]}."
|
||||||
|
)
|
||||||
elif valid[need] == "positive":
|
elif valid[need] == "positive":
|
||||||
if container[need] < 0:
|
if container[need] < 0:
|
||||||
raise ValueError(f"Parameter \'{need}\' must be positive.")
|
raise ValueError(f"Parameter '{need}' must be positive.")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
# Loading configuration and settings.
|
# Loading configuration and settings.
|
||||||
parser = argparse.ArgumentParser("Squish")
|
parser = argparse.ArgumentParser("Squish")
|
||||||
parser.add_argument('sim_conf', metavar='/path/to/config.json',
|
parser.add_argument(
|
||||||
help="configuration file for a simulation")
|
"sim_conf",
|
||||||
parser.add_argument('-q', '--quiet', dest='quiet', action='store_true', default=False,
|
metavar="/path/to/config.json",
|
||||||
help="suppress all normal output")
|
help="configuration file for a simulation",
|
||||||
parser.add_argument('-l', '--log', dest='log_steps', default=50, type=int,
|
)
|
||||||
help="number of iterations before logging")
|
parser.add_argument(
|
||||||
parser.add_argument('-i', dest='input_file', metavar='/path/to/sim',
|
"-q",
|
||||||
help="folder that contains outputted simulation files.", default=None)
|
"--quiet",
|
||||||
|
dest="quiet",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
help="suppress all normal output",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-l",
|
||||||
|
"--log",
|
||||||
|
dest="log_steps",
|
||||||
|
default=50,
|
||||||
|
type=int,
|
||||||
|
help="number of iterations before logging",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-i",
|
||||||
|
dest="input_file",
|
||||||
|
metavar="/path/to/sim",
|
||||||
|
help="folder that contains outputted simulation files.",
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
parser.add_argument('--n_objects', dest='n', type=int, help="objects in domain")
|
parser.add_argument("--n_objects", dest="n", type=int, help="objects in domain")
|
||||||
parser.add_argument('--width', dest='w', type=float, help="width of domain")
|
parser.add_argument("--width", dest="w", type=float, help="width of domain")
|
||||||
parser.add_argument('--height', dest='h', type=float, help="height of domain")
|
parser.add_argument("--height", dest="h", type=float, help="height of domain")
|
||||||
parser.add_argument('--natural_radius', dest='r', type=float, help="natural radius of object")
|
parser.add_argument(
|
||||||
parser.add_argument('--energy', dest='energy', help="energy type of system")
|
"--natural_radius", dest="r", type=float, help="natural radius of object"
|
||||||
|
)
|
||||||
|
parser.add_argument("--energy", dest="energy", help="energy type of system")
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
do_sim(args, args.input_file)
|
do_sim(args, args.input_file)
|
||||||
@ -69,38 +94,63 @@ def do_sim(args, file):
|
|||||||
with open(args.sim_conf) as f:
|
with open(args.sim_conf) as f:
|
||||||
params = json.load(f)
|
params = json.load(f)
|
||||||
|
|
||||||
|
|
||||||
check_params(params, ["domain", "simulation"], {})
|
check_params(params, ["domain", "simulation"], {})
|
||||||
dmn_params, sim_params = params["domain"], params["simulation"]
|
dmn_params, sim_params = params["domain"], params["simulation"]
|
||||||
|
|
||||||
overrides = {args.n: "n_objects", args.w: "width", args.h: "height", args.r: "natural_radius",
|
overrides = {
|
||||||
args.energy: "energy"}
|
args.n: "n_objects",
|
||||||
|
args.w: "width",
|
||||||
|
args.h: "height",
|
||||||
|
args.r: "natural_radius",
|
||||||
|
args.energy: "energy",
|
||||||
|
}
|
||||||
for arg, arg_name in overrides.items():
|
for arg, arg_name in overrides.items():
|
||||||
if arg is not None:
|
if arg is not None:
|
||||||
dmn_params[arg_name] = arg
|
dmn_params[arg_name] = arg
|
||||||
|
|
||||||
check_params(dmn_params, ["n_objects", "width", "height", "natural_radius", "energy"], {
|
check_params(
|
||||||
"n_objects": "positive", "width": "positive", "height": "positive",
|
dmn_params,
|
||||||
"natural_radius": "positive", "energy": ["area", "radial-al", "radial-t"]
|
["n_objects", "width", "height", "natural_radius", "energy"],
|
||||||
})
|
{
|
||||||
domain = DomainParams(dmn_params["n_objects"], dmn_params["width"], \
|
"n_objects": "positive",
|
||||||
dmn_params["height"], dmn_params["natural_radius"])
|
"width": "positive",
|
||||||
|
"height": "positive",
|
||||||
|
"natural_radius": "positive",
|
||||||
|
"energy": ["area", "radial-al", "radial-t"],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
domain = DomainParams(
|
||||||
|
dmn_params["n_objects"],
|
||||||
|
dmn_params["width"],
|
||||||
|
dmn_params["height"],
|
||||||
|
dmn_params["natural_radius"],
|
||||||
|
)
|
||||||
energy = Energy(dmn_params["energy"])
|
energy = Energy(dmn_params["energy"])
|
||||||
|
|
||||||
points = None
|
points = None
|
||||||
if "points" in dmn_params:
|
if "points" in dmn_params:
|
||||||
if type(dmn_params["points"]) is str:
|
if type(dmn_params["points"]) is str:
|
||||||
with open(Path(dmn_params["points"]), 'rb') as f:
|
with open(Path(dmn_params["points"]), "rb") as f:
|
||||||
points = np.load(f)
|
points = np.load(f)
|
||||||
else:
|
else:
|
||||||
points = np.asarray(dmn_params["points"])
|
points = np.asarray(dmn_params["points"])
|
||||||
|
|
||||||
check_params(sim_params, ["mode", "step_size", "threshold", "save_sim", "adaptive"], {
|
check_params(
|
||||||
"mode": ["flow", "search", "shrink"], "step_size": "positive", "threshold": "positive",
|
sim_params,
|
||||||
})
|
["mode", "step_size", "threshold", "save_sim", "adaptive"],
|
||||||
mode, step, thres, adaptive, save_sim = sim_params["mode"], sim_params["step_size"], \
|
{
|
||||||
sim_params["threshold"], sim_params["adaptive"], \
|
"mode": ["flow", "search", "shrink"],
|
||||||
sim_params["save_sim"]
|
"step_size": "positive",
|
||||||
|
"threshold": "positive",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
mode, step, thres, adaptive, save_sim = (
|
||||||
|
sim_params["mode"],
|
||||||
|
sim_params["step_size"],
|
||||||
|
sim_params["threshold"],
|
||||||
|
sim_params["adaptive"],
|
||||||
|
sim_params["save_sim"],
|
||||||
|
)
|
||||||
|
|
||||||
name = sim_params.get("name")
|
name = sim_params.get("name")
|
||||||
|
|
||||||
@ -108,17 +158,37 @@ def do_sim(args, file):
|
|||||||
if mode == "flow":
|
if mode == "flow":
|
||||||
sim = Flow(domain, energy, step, thres, adaptive, name=name)
|
sim = Flow(domain, energy, step, thres, adaptive, name=name)
|
||||||
elif mode == "search":
|
elif mode == "search":
|
||||||
check_params(sim_params, ["manifold_step_size", "eq_stop_count"], {
|
check_params(
|
||||||
"manifold_step_size": "positive", "eq_stop_count": "positive"
|
sim_params,
|
||||||
})
|
["manifold_step_size", "eq_stop_count"],
|
||||||
sim = Search(domain, energy, step, thres, adaptive, sim_params["manifold_step_size"],
|
{"manifold_step_size": "positive", "eq_stop_count": "positive"},
|
||||||
sim_params["eq_stop_count"], name=name)
|
)
|
||||||
|
sim = Search(
|
||||||
|
domain,
|
||||||
|
energy,
|
||||||
|
step,
|
||||||
|
thres,
|
||||||
|
adaptive,
|
||||||
|
sim_params["manifold_step_size"],
|
||||||
|
sim_params["eq_stop_count"],
|
||||||
|
name=name,
|
||||||
|
)
|
||||||
elif mode == "shrink":
|
elif mode == "shrink":
|
||||||
check_params(sim_params, ["width_change", "width_stop"], {
|
check_params(
|
||||||
"width_change": "positive", "width_stop": "positive"
|
sim_params,
|
||||||
})
|
["width_change", "width_stop"],
|
||||||
sim = Shrink(domain, energy, step, thres, adaptive, sim_params["width_change"],
|
{"width_change": "positive", "width_stop": "positive"},
|
||||||
sim_params["width_stop"], name=name)
|
)
|
||||||
|
sim = Shrink(
|
||||||
|
domain,
|
||||||
|
energy,
|
||||||
|
step,
|
||||||
|
thres,
|
||||||
|
adaptive,
|
||||||
|
sim_params["width_change"],
|
||||||
|
sim_params["width_stop"],
|
||||||
|
name=name,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
sim = Simulation.from_file(file)
|
sim = Simulation.from_file(file)
|
||||||
|
|
||||||
@ -126,12 +196,12 @@ def do_sim(args, file):
|
|||||||
if "diagram" in params:
|
if "diagram" in params:
|
||||||
save_diagram = True
|
save_diagram = True
|
||||||
dia_params = params["diagram"]
|
dia_params = params["diagram"]
|
||||||
check_params(dia_params, ["filetype", "figures"], {
|
check_params(dia_params, ["filetype", "figures"], {"filetype": ["img", "mp4"]})
|
||||||
"filetype": ["img", "mp4"]
|
|
||||||
})
|
|
||||||
if dia_params["filetype"] == "mp4":
|
if dia_params["filetype"] == "mp4":
|
||||||
if which("ffmpeg") is None:
|
if which("ffmpeg") is None:
|
||||||
raise ValueError("The program 'ffmpeg' needs to be installed on your system.")
|
raise ValueError(
|
||||||
|
"The program 'ffmpeg' needs to be installed on your system."
|
||||||
|
)
|
||||||
|
|
||||||
if type(dia_params["figures"]) is str:
|
if type(dia_params["figures"]) is str:
|
||||||
dia_params["figures"] = np.asarray(dia_presets[dia_params["figures"]])
|
dia_params["figures"] = np.asarray(dia_presets[dia_params["figures"]])
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user