Changed diagram.py so that parallelization doesn't use excess memory, and other small tweaks
This commit is contained in:
parent
475d306e3a
commit
4b472d2200
@ -1,6 +1,6 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
name = squish
|
name = squish
|
||||||
version = 0.1.1
|
version = 0.1.2
|
||||||
author = Kenneth Jao
|
author = Kenneth Jao
|
||||||
author_email = ksjdragon@gmail.com
|
author_email = ksjdragon@gmail.com
|
||||||
description = squish is Python program which perform simulations for the flow of 'soft' or 'compressible' objects under some energy in a periodic domain.
|
description = squish is Python program which perform simulations for the flow of 'soft' or 'compressible' objects under some energy in a periodic domain.
|
||||||
|
|||||||
@ -15,11 +15,12 @@ STR_TO_ENERGY = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def generate_filepath(sim: SimulationMode, fol: Union[str, Path]) -> 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, 2), round(sim.domain.h, 2)
|
width, height = round(sim.domain.w, 2), round(sim.domain.h, 2)
|
||||||
|
|
||||||
base_path = f"{fol}/{energy}{sim.title_str} - N{sim.domain.n} - {width:.2f}x{height:.2f}"
|
base_path = 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)
|
||||||
|
|||||||
@ -26,17 +26,30 @@ class SimData:
|
|||||||
|
|
||||||
|
|
||||||
def __init__(self, sim: Simulation) -> None:
|
def __init__(self, sim: Simulation) -> None:
|
||||||
self.path = sim.path
|
if sim is not None:
|
||||||
self.domains = list([DomainParams(s.n, s.w, s.h, s.r) for s in sim])
|
self.path = sim.path
|
||||||
self.energies = list([s.energy for s in sim])
|
self.domains = list([DomainParams(s.n, s.w, s.h, s.r) for s in sim])
|
||||||
self.voronois = list([s.vor_data for s in sim])
|
self.energies = list([s.energy for s in sim])
|
||||||
self.stats = list([s.stats for s in sim])
|
self.voronois = list([s.vor_data 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:
|
||||||
|
new_data = SimData(None)
|
||||||
|
new_data.path = self.path
|
||||||
|
|
||||||
|
new_data.domains = list([self.domains[i] for i in indices])
|
||||||
|
new_data.energies = list([self.energies[i] for i in indices])
|
||||||
|
new_data.voronois = list([self.voronois[i] for i in indices])
|
||||||
|
new_data.stats = list([self.stats[i] for i in indices])
|
||||||
|
|
||||||
|
return new_data
|
||||||
|
|
||||||
|
|
||||||
def hist(self, stat: str, i: int, bins: int = 10, bounds: Optional[Tuple[float, float]] = None,
|
def hist(self, stat: str, i: int, bins: int = 10, bounds: Optional[Tuple[float, float]] = None,
|
||||||
cumul: bool = False, avg: bool = False) -> Tuple[numpy.ndarray, numpy.ndarray]:
|
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.
|
||||||
@ -95,7 +108,7 @@ class Diagram:
|
|||||||
self.cumulative = cumulative
|
self.cumulative = cumulative
|
||||||
|
|
||||||
|
|
||||||
def generate_frame(self, frame: int, mode: str, fol: str) -> 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!")
|
||||||
|
|
||||||
@ -112,9 +125,11 @@ class Diagram:
|
|||||||
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:
|
||||||
|
name = f"img{frame:05}.png"
|
||||||
|
|
||||||
if mode == "save":
|
if mode == "save":
|
||||||
plt.savefig(self.sim.path / fol / f"img{frame:05}.png")
|
plt.savefig(self.sim.path / fol / name)
|
||||||
plt.close(fig)
|
plt.close(fig)
|
||||||
elif mode == "show":
|
elif mode == "show":
|
||||||
plt.show()
|
plt.show()
|
||||||
@ -290,9 +305,13 @@ class Diagram:
|
|||||||
(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()):
|
||||||
combo_list.append((self, frames[:int((i+1)*len(frames)/cpu_count())],
|
start, end = int(i*len(frames)/cpu_count()), int((i+1)*len(frames)/cpu_count())
|
||||||
fol, len(frames)))
|
new_dia = Diagram(None, self.diagrams, self.cumulative)
|
||||||
|
new_dia.sim = self.sim.slice(frames[start:end])
|
||||||
|
combo_list.append((new_dia, fol, start, len(frames[start:end]), len(frames)))
|
||||||
|
|
||||||
|
# Free up memory, since it's already duplicated to other cores.
|
||||||
|
self.sim = self.sim.slice([])
|
||||||
with Pool(cpu_count()) as pool:
|
with Pool(cpu_count()) as pool:
|
||||||
for _ in pool.imap_unordered(render_frame_range, combo_list):
|
for _ in pool.imap_unordered(render_frame_range, combo_list):
|
||||||
pass
|
pass
|
||||||
@ -300,6 +319,7 @@ class Diagram:
|
|||||||
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"]:
|
||||||
raise ValueError("Not a valid mode for videos!")
|
raise ValueError("Not a valid mode for videos!")
|
||||||
@ -308,12 +328,11 @@ 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), fps*time)).astype(int))
|
frames = list(np.round(np.linspace(0, len(self.sim)-1, fps*time)).astype(int))
|
||||||
print(frames)
|
|
||||||
|
|
||||||
self.render_frames(frames, 'temp')
|
self.render_frames(frames, 'temp')
|
||||||
path = self.sim.path / 'simulation.mp4'
|
path = self.sim.path / 'simulation.mp4'
|
||||||
@ -325,17 +344,17 @@ class Diagram:
|
|||||||
f' "scale=trunc(iw/2)*2:trunc(ih/2)*2" -f mp4 "{path}"')
|
f' "scale=trunc(iw/2)*2:trunc(ih/2)*2" -f mp4 "{path}"')
|
||||||
|
|
||||||
# Remove files.
|
# Remove files.
|
||||||
for i in 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, List[int], str, int]) -> None:
|
def render_frame_range(combo: Tuple[Diagram, str, int, int, int]) -> None:
|
||||||
self, frames, fol, num_frames = combo
|
self, fol, offset, length, num_frames = combo
|
||||||
for frame in frames:
|
for i in range(length):
|
||||||
self.generate_frame(frame, "save", fol)
|
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'Generating frames... |{"#"*hashes}{" "*(20-hashes)}|' + \
|
||||||
|
|||||||
@ -21,12 +21,15 @@ class Simulation:
|
|||||||
|
|
||||||
__slots__ = ['domain', 'energy', 'path', 'frames']
|
__slots__ = ['domain', 'energy', 'path', 'frames']
|
||||||
|
|
||||||
def __init__(self, domain: DomainParams, energy: Energy, name: Optional[str] = None) -> None:
|
def __init__(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 = []
|
||||||
|
|
||||||
if name is None:
|
if name is None:
|
||||||
self.path = generate_filepath(self, OUTPUT_DIR)
|
self.path = generate_filepath(self, OUTPUT_DIR)
|
||||||
|
elif isinstance(name, int):
|
||||||
|
self.path = generate_filepath(self, OUTPUT_DIR, name)
|
||||||
else:
|
else:
|
||||||
self.path = OUTPUT_DIR / name
|
self.path = OUTPUT_DIR / name
|
||||||
|
|
||||||
@ -86,16 +89,16 @@ class Simulation:
|
|||||||
return distinct_count
|
return distinct_count
|
||||||
|
|
||||||
|
|
||||||
def save(self, info: Dict) -> None:
|
def save(self, info: Dict, overwrite: bool = False) -> None:
|
||||||
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, '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)
|
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))
|
||||||
|
|
||||||
@ -175,7 +178,7 @@ class Flow(Simulation):
|
|||||||
|
|
||||||
def run(self, save: bool, log: bool, log_steps: int) -> None:
|
def run(self, save: bool, log: bool, log_steps: int) -> None:
|
||||||
if log: print(f"Find - {self.domain}", flush=True)
|
if log: print(f"Find - {self.domain}", flush=True)
|
||||||
if save: self.save(self.initial_data)
|
if save: self.save(self.initial_data, True)
|
||||||
if len(self) == 0: self.add_frame()
|
if len(self) == 0: self.add_frame()
|
||||||
|
|
||||||
i, grad_norm = 0, float('inf')
|
i, grad_norm = 0, float('inf')
|
||||||
@ -212,7 +215,7 @@ class Flow(Simulation):
|
|||||||
self[i].add_sites(change/shrink_factor))
|
self[i].add_sites(change/shrink_factor))
|
||||||
self.step_size /= shrink_factor
|
self.step_size /= shrink_factor
|
||||||
|
|
||||||
self.step_size = max(10e-4, self.step_size)
|
self.step_size = max(10e-6, self.step_size)
|
||||||
|
|
||||||
self.frames.append(new_frame)
|
self.frames.append(new_frame)
|
||||||
|
|
||||||
@ -269,7 +272,7 @@ class Search(Simulation):
|
|||||||
|
|
||||||
def run(self, save: bool, log: bool, log_steps: int) -> None:
|
def run(self, save: bool, log: bool, log_steps: int) -> None:
|
||||||
if log: print(f'Travel - {self.domain}', flush=True)
|
if log: print(f'Travel - {self.domain}', flush=True)
|
||||||
if save: self.save(self.initial_data)
|
if save: self.save(self.initial_data, True)
|
||||||
|
|
||||||
if len(self) != 0:
|
if len(self) != 0:
|
||||||
new_sites = self[0].site_arr
|
new_sites = self[0].site_arr
|
||||||
@ -350,7 +353,7 @@ class Shrink(Simulation):
|
|||||||
|
|
||||||
def run(self, save: bool, log: bool, log_steps: int) -> None:
|
def run(self, save: bool, log: bool, log_steps: int) -> None:
|
||||||
if log: print(f'Shrink - {self.domain}', flush=True)
|
if log: print(f'Shrink - {self.domain}', flush=True)
|
||||||
if save: self.save(self.initial_data)
|
if save: self.save(self.initial_data, True)
|
||||||
|
|
||||||
if len(self) != 0:
|
if len(self) != 0:
|
||||||
new_sites = self[0].site_arr
|
new_sites = self[0].site_arr
|
||||||
@ -381,5 +384,3 @@ STR_TO_SIM = {
|
|||||||
"search": Search,
|
"search": Search,
|
||||||
"shrink": Shrink
|
"shrink": Shrink
|
||||||
}
|
}
|
||||||
|
|
||||||
simulation = Simulation
|
|
||||||
Loading…
x
Reference in New Issue
Block a user