From b4d6b5dbd8928dca259958dd5b87abe98103eb3b Mon Sep 17 00:00:00 2001 From: Kenneth Jao Date: Mon, 18 Oct 2021 19:57:47 -0400 Subject: [PATCH] Added continuation for stopped simulation --- scripts/check_width_exists.py | 23 -------------- setup.cfg | 2 +- squish/common.py | 3 +- squish/diagram.py | 4 ++- squish/simulation.py | 56 +++++++++++++++++++---------------- squish/squish.py | 52 ++++++++++++++++---------------- 6 files changed, 60 insertions(+), 80 deletions(-) delete mode 100644 scripts/check_width_exists.py diff --git a/scripts/check_width_exists.py b/scripts/check_width_exists.py deleted file mode 100644 index 88acdd7..0000000 --- a/scripts/check_width_exists.py +++ /dev/null @@ -1,23 +0,0 @@ -from pathlib import Path -import numpy as np, pickle, sys - -from squish import Simulation - -def main(): - n = int(sys.argv[1]) - all_widths = set(np.round(np.arange(3, 10.05, 0.05), 2)) - for file in Path(f"squish_output/Radial[T]Search - N{n} - 500").iterdir(): - sim, frames = Simulation.load(file / 'data.squish') - - if sim.domain.n == n: - try: - all_widths.remove(next(frames)["domain"][1]) - except StopIteration: - pass - - remain_widths = sorted(list(all_widths))[::-1] - print("Remaining:", remain_widths) - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index 6ec6064..6710351 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = squish -version = 0.1.3 +version = 0.1.4 author = Kenneth Jao 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. diff --git a/squish/common.py b/squish/common.py index 8617966..28e3def 100644 --- a/squish/common.py +++ b/squish/common.py @@ -6,7 +6,6 @@ from pathlib import Path from ._squish import VoronoiContainer, AreaEnergy, RadialALEnergy, RadialTEnergy OUTPUT_DIR = Path("squish_output") -OUTPUT_DIR.mkdir(exist_ok=True) STR_TO_ENERGY = { "area": AreaEnergy, @@ -17,7 +16,7 @@ STR_TO_ENERGY = { def generate_filepath(sim: SimulationMode, fol: Union[str, Path], prec: int = 2) -> Path: energy = sim.energy.title_str - width, height = round(sim.domain.w, 2), round(sim.domain.h, 2) + width, height = round(sim.domain.w, prec), round(sim.domain.h, prec) base_path = f"{fol}/{energy}{sim.title_str} - " + \ f"N{sim.domain.n} - {width:.{prec}f}x{height:.{prec}f}" diff --git a/squish/diagram.py b/squish/diagram.py index 827e13f..67925fe 100644 --- a/squish/diagram.py +++ b/squish/diagram.py @@ -6,7 +6,7 @@ from matplotlib.ticker import MaxNLocator, FormatStrFormatter from scipy.spatial import Voronoi, voronoi_plot_2d from multiprocessing import Pool, cpu_count -from .common import DomainParams +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]]) @@ -302,6 +302,8 @@ class Diagram: def render_frames(self, frames: List[int], fol: str = 'frames') -> None: + OUTPUT_DIR.mkdir(exist_ok=True) + self.sim.path.mkdir(exist_ok=True) (self.sim.path / fol).mkdir(exist_ok=True) combo_list = [] for i in range(cpu_count()): diff --git a/squish/simulation.py b/squish/simulation.py index caafa6a..c384296 100644 --- a/squish/simulation.py +++ b/squish/simulation.py @@ -5,6 +5,7 @@ import pickle, numpy as np from math import log10 from scipy.linalg import null_space from timeit import default_timer as timer +from pathlib import Path from .common import DomainParams, Energy, generate_filepath, OUTPUT_DIR @@ -46,7 +47,7 @@ class Simulation: return len(self.frames) - def add_frame(self, points: Optional[numpy.ndarray]) -> None: + def add_frame(self, points: Optional[numpy.ndarray] = None) -> None: if points is None: points = np.random.random_sample((self.domain.n, 2)) * self.domain.dim else: @@ -91,6 +92,7 @@ class Simulation: def save(self, info: Dict, overwrite: bool = False) -> None: + OUTPUT_DIR.mkdir(exist_ok=True) self.path.mkdir(exist_ok=True) path = self.path / 'data.squish' @@ -117,8 +119,9 @@ class Simulation: @staticmethod def load(path: str) -> Tuple[Simulation, Generator]: + path = Path(path) def frames() -> Dict: - with open(path, 'rb') as infile: + with open(path / 'data.squish', 'rb') as infile: first = True while True: try: @@ -130,16 +133,26 @@ class Simulation: except EOFError: break - with open(path, 'rb') as infile: + with open(path / 'data.squish', 'rb') as infile: sim_info = pickle.load(infile) domain = DomainParams(*sim_info["domain"]) energy = Energy(sim_info["energy"]) sim = STR_TO_SIM[sim_info["mode"]](domain, energy, *list(sim_info.values())[3:]) + sim.path = path return sim, frames() + @staticmethod + def from_file(path: str) -> Simulation: + sim, frames = Simulation.load(path) + for frame in frames: + sim.frames.append(sim.energy.mode(*frame["domain"], frame["arr"])) + + return sim + + class Flow(Simulation): """Finds an equilibrium from initial sites. @@ -177,12 +190,13 @@ class Flow(Simulation): return info - def run(self, save: bool, log: bool, log_steps: int) -> None: + 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: self.save(self.initial_data, True) - if len(self) == 0: self.add_frame() + if save and len(self) == 0: self.save(self.initial_data, True) + if len(self) == 0: self.add_frame(new_sites) - i, stop = 0, False + i, stop = len(self)-1, False while not stop: # Get to threshold. if save: @@ -262,17 +276,12 @@ class Search(Simulation): return info - def run(self, save: bool, log: bool, log_steps: int) -> None: + def run(self, save: bool, log: bool, log_steps: int, + new_sites: Optional[numpy.ndarray] = None) -> None: if log: print(f'Travel - {self.domain}', flush=True) - if save: self.save(self.initial_data, True) + if save and len(self) == 0: self.save(self.initial_data, True) - if len(self) != 0: - new_sites = self[0].site_arr - self.frames = [] - else: - new_sites = None - - for i in range(self.count): + for i in range(len(self), self.count): # Get to equilibrium. sim = Flow(self.domain, self.energy, self.step_size, self.thres, self.adaptive) sim.add_frame(new_sites) @@ -298,7 +307,6 @@ class Search(Simulation): new_sites = self.frames[i].add_sites(self.kernel_step*vec) - class Shrink(Simulation): """Shrinks width and finds nearest equilibrium. @@ -343,17 +351,12 @@ class Shrink(Simulation): return info - def run(self, save: bool, log: bool, log_steps: int) -> None: + def run(self, save: bool, log: bool, log_steps: int, + new_sites: Optional[numpy.ndarray] = None) -> None: if log: print(f'Shrink - {self.domain}', flush=True) - if save: self.save(self.initial_data, True) + if save and len(self) == 0: self.save(self.initial_data, True) - if len(self) != 0: - new_sites = self[0].site_arr - self.frames = [] - else: - new_sites = None - - width = self.domain.w + width = self.domain.w if len(self.frames) == 0 else self.frames[-1].w i = 0 while width >= self.stop_width: # Get to equilibrium. @@ -371,6 +374,7 @@ class Shrink(Simulation): width -= self.delta i += 1 + STR_TO_SIM = { "flow": Flow, "search": Search, diff --git a/squish/squish.py b/squish/squish.py index 7487891..8cae60d 100644 --- a/squish/squish.py +++ b/squish/squish.py @@ -5,7 +5,7 @@ from shutil import which from pathlib import Path from .common import DomainParams, Energy -from .simulation import Flow, Search, Shrink +from .simulation import Simulation, Flow, Search, Shrink from .diagram import Diagram dia_presets = { @@ -45,13 +45,15 @@ def check_params(container: Dict, needed: List[str], valid: Dict) -> None: def main(): # Loading configuration and settings. - parser = argparse.ArgumentParser("PackSim") + parser = argparse.ArgumentParser("Squish") parser.add_argument('sim_conf', metavar='/path/to/config.json', help="configuration file for a simulation") parser.add_argument('-q', '--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('--width', dest='w', type=float, help="width of domain") @@ -60,17 +62,14 @@ def main(): parser.add_argument('--energy', dest='energy', help="energy type of system") args = parser.parse_args() - config_sim(args) - # if args.input_file is None: - # config_sim(args) - # else: - # loaded_sim(args) + do_sim(args, args.input_file) -def config_sim(args): +def do_sim(args, file): with open(args.sim_conf) as f: params = json.load(f) + check_params(params, ["domain", "simulation"], {}) dmn_params, sim_params = params["domain"], params["simulation"] @@ -105,20 +104,23 @@ def config_sim(args): name = sim_params.get("name") - if mode == "flow": - sim = Flow(domain, energy, step, thres, adaptive, name=name) - elif mode == "search": - check_params(sim_params, ["manifold_step_size", "eq_stop_count"], { - "manifold_step_size": "positive", "eq_stop_count": "positive" - }) - sim = Search(domain, energy, step, thres, adaptive, sim_params["manifold_step_size"], - sim_params["eq_stop_count"], name=name) - elif mode == "shrink": - check_params(sim_params, ["width_change", "width_stop"], { - "width_change": "positive", "width_stop": "positive" - }) - sim = Shrink(domain, energy, step, thres, adaptive, sim_params["width_change"], - sim_params["width_stop"], name=name) + if file is None: + if mode == "flow": + sim = Flow(domain, energy, step, thres, adaptive, name=name) + elif mode == "search": + check_params(sim_params, ["manifold_step_size", "eq_stop_count"], { + "manifold_step_size": "positive", "eq_stop_count": "positive" + }) + sim = Search(domain, energy, step, thres, adaptive, sim_params["manifold_step_size"], + sim_params["eq_stop_count"], name=name) + elif mode == "shrink": + check_params(sim_params, ["width_change", "width_stop"], { + "width_change": "positive", "width_stop": "positive" + }) + sim = Shrink(domain, energy, step, thres, adaptive, sim_params["width_change"], + sim_params["width_stop"], name=name) + else: + sim = Simulation.from_file(file) save_diagram = False if "diagram" in params: @@ -139,8 +141,7 @@ def config_sim(args): if "time" not in dia_params: dia_params["time"] = 30 - sim.add_frame(points) - sim.run(save_sim, not args.quiet, args.log_steps) + sim.run(save_sim, not args.quiet, args.log_steps, points) if save_diagram: diagram = Diagram(sim, dia_params["figures"]) @@ -153,9 +154,6 @@ def config_sim(args): diagram.render_video(dia_params["time"], "use_all") -def loaded_sim(args): - pass - def pre(): os.environ["QT_LOGGING_RULES"] = "*=false" try: