def clear_data(points, config='test', force=False): """Remove data for a given value of point Parameters ---------- Point : float the parameter of the simulation whose data you want to remove """ from os import scandir from shutil import rmtree from lib.utils import (find_all_availables, find_running, authorization_request, config_dir, point_str, point_dir) points_run, _ = find_running() points_run = [x[0] for x in points_run if x[1] == config] points_req_run = [x for x in points if x in points_run] points_clearable = [x for x in points if x not in points_run] if len(points_req_run) > 0: print("Simulations for following λ are running: ", points_req_run, '\n so they are not clearable') if len(points_req_run) > 0 and len(points_clearable) > 0: print() if len(points_clearable) == 0: print("No λ found in the requested range.") for Point in points_clearable: try: if not config == 'test' and not force: what_to_do = "to remove simulation folder" authorized = authorization_request(what_to_do, Point) else: authorized = 'yes' if authorized == 'yes': rmtree(config_dir(config) + "/" + point_dir(Point)) if force: print("(λ = ", Point[0], ", β = ", Point[1], ") ", sep='', end='') print("Simulation folder removed.") elif authorized == 'quit': print(f'Nothing done for last point {Point}.') return except FileNotFoundError: all_points = find_all_availables() raise ValueError("A folder with the given point doesn't exist"+ "\n\t\t\t all_points: " + str(all_points)) if all([not 'Beta' in str(x) for x in scandir(config_dir(config))]): return True else: return False
def rm_conf(config, force): from os import rmdir, remove, scandir from os.path import isfile from re import fullmatch import json from lib.utils import points_recast, config_dir, project_folder points_old, _ = points_recast([], [], '', True, config, 'tools') cleared = clear_data(points_old, config, force) if not cleared: print('Config not empty.') return path = config_dir(config) for x in scandir(path): if fullmatch('.*.cdt', x.name): remove(x) if isfile(path + '/pstop.pickle'): remove(path + '/pstop.pickle') rmdir(path) print(f"Removed config '{config}' at path:\n {path}") with open(project_folder() + '/output/configs.json', 'r') as config_file: configs = json.load(config_file) del configs[config] with open(project_folder() + '/output/configs.json', 'w') as config_file: json.dump(configs, config_file, indent=4)
def volumes_plot(configs=None, path=None): from os.path import isfile import matplotlib.pyplot as plt from lib.utils import point_dir, config_dir mvs = mean_volumes(configs, print_flag=False) curves = {} for c, sims in mvs.items(): for Point, mv in sims.items(): if isfile( config_dir(c) + '/' + point_dir(Point) + '/max_volume_reached'): continue curve = c + ' β=' + str(Point[1]) coords = (Point[0], mv) try: curves[curve] += [coords] except KeyError: curves[curve] = [coords] for lab, points in curves.items(): points = sorted(points, key=lambda x: x[0]) plt.plot(*zip(*points), marker='o', label=lab) plt.xlabel('λ') plt.ylabel('Volume') plt.legend() plt.show()
def set_fit_props(name, points, config, remove): from os import chdir, popen from os.path import basename, dirname import json from lib.utils import (fit_dir, config_dir, point_dir, dir_point, authorization_request) if remove: if points: print('Warning: points specification not compatible with --remove ' 'option.') return elif config != 'test': print('Warning: config specification not compatible with --remove ' 'option.') return chdir(fit_dir(name)) try: with open('sims.json', 'r') as file: sims = json.load(file) except FileNotFoundError: sims = [] # SIMS UPDATE if not remove: c_dir = config_dir(config) for Point in points: p_dir = c_dir + '/' + point_dir(Point) if p_dir not in sims: sims += [p_dir] with open('sims.json', 'w') as file: json.dump(sims, file, indent=4) # SIMS REMOTION else: new_sims = sims.copy() for sim in sims: Point = dir_point(basename(sim)) config = basename(dirname(sim)) what = f"to remove sim from fit '{name}'" extra = f"\033[38;5;80m config: '{config}'\033[0m" auth = authorization_request(Point=Point, what_to_do=what, extra_message=extra) if auth == 'quit': print('Nothing done for last sim.') return elif auth == 'yes': new_sims.remove(sim) with open('sims.json', 'w') as file: json.dump(new_sims, file, indent=4) print('Sim removed') else: print('Nothing removed.')
def sim_obs(points, config, plot, fit, exclude_torelons, exclude_bootstrap, fit_name, force): from os.path import basename, dirname, realpath import json from pprint import pprint from lib.utils import config_dir, dir_point, fit_dir if fit_name: f_dir = fit_dir(fit_name) try: with open(f_dir + '/sims.json', 'r') as file: sims = json.load(file) except FileNotFoundError: print('No simulation already assigned to this fit.') points = [] points_configs = {} for s in sims: if s[-1] == '/': s = s[:-1] Point = dir_point(basename(s)) points += [Point] points_configs = {**points_configs, Point: realpath(dirname(s))} c_dir = None else: points_configs = None c_dir = config_dir(config) col = 216 # color print(f'Number of selected points: \033[38;5;{col}m{len(points)}\033[0m') print(f'\033[38;5;{col}m', end='') pprint(points) print('\033[0m') if not force: i = 0 for Point in points: args = (Point, points_configs, c_dir, i, force, plot, fit, exclude_torelons, exclude_bootstrap) ret = sim_obs_compute(args) if ret == 'return': return elif ret == 'continue': continue i += 1 else: import multiprocessing as mp i = 0 args = [] for Point in points: args += [(Point, points_configs, c_dir, i, force, plot, fit, exclude_torelons, exclude_bootstrap)] i += 1 with mp.Pool(mp.cpu_count() - 1) as pool: pool.map(sim_obs_compute, args)
def sim_info(Point, config): from os import chdir from lib.utils import point_dir, config_dir chdir(config_dir(config) + '/' + point_dir(Point)) import json with open('state.json', 'r') as state_file: state = json.load(state_file) print(json.dumps(state, indent=4)[1:-1])
def launch_run(points, arg_strs, config, queue, arch, file): from os import chdir, listdir from lib.utils import config_dir chdir(config_dir(config)) if is_local(): # slurm_launch(points, arg_strs, queue, arch, file) local_launch(points, arg_strs) elif is_lsf(): lsf_launch(points, arg_strs) elif is_slurm(): slurm_launch(points, arg_strs, queue, arch, file) else: raise NameError('Platform not recognized ' '(known platforms in platform.py)')
def reset_conf(name): from os.path import isdir from os import chdir, mkdir from shutil import rmtree from lib.utils import authorization_request, config_dir config = config_dir(name) # if delete: # action = 'delete' # else: action = 'reset' what_to_do = 'to ' + action + ' the configuration \'' + name + '\'' authorized = authorization_request(what_to_do) if authorized == 'yes': rmtree(config) mkdir(config) print(f'Configuration {name} has been reset.') else: print('Nothing done.')
def launch(points_old, points_new, config, linear_history, end_time, end_steps, force, time_lengths, adj, max_volume, move22, move24, move_gauge, fake_run, debug, queue, arch, file): """Output analysis for CDT_2D simulation. attempts_str = str(attempts) Parameters ---------- points_old : type Description of parameter `points_old`. points_new : type Description of parameter `points_new`. config : type Description of parameter `config`. linear_history : type Description of parameter `linear_history`. time : type Description of parameter `time`. steps : type Description of parameter `steps`. force : type Description of parameter `force`. time_lengths : type Description of parameter `time_lengths`. fake_run : type Description of parameter `fake_run`. debug : type Description of parameter `debug`. Raises ------ Exception descrizione dell'eccezione lanciata """ from os import mkdir, chdir, getcwd, scandir from os.path import isfile, isdir from shutil import copyfile from re import split, sub from platform import node import json from lib.utils import (find_running, point_dir, point_str, moves_weights, authorization_request, end_parser, launch_script_name, make_script_name, config_dir, project_folder) from lib.platforms import launch_run # set moves' weights move22, move24, move_gauge = moves_weights(move22, move24, move_gauge) points_run, _ = find_running() points_run = [x[0] for x in points_run if x[1] == config] points_old_auth = [] # old ones which will get the authorization to rerun points_req_run = [] # those requested which are already running for Point in points_old: if Point not in points_run: if not config == 'test' and not force: what_to_do = "to rerun simulation" authorized = authorization_request(what_to_do, Point) else: authorized = 'yes' if authorized == 'yes': points_old_auth += [Point] elif authorized == 'quit': print('No simulation launched.') return else: points_req_run += [Point] points = points_old_auth + points_new if len(points_new) > 0: print("New simulations will be launched for following (λ, β): ", points_new) if len(points_old_auth) > 0: print("Old simulations will be rerunned for following (λ, β): ", points_old_auth) if len(points_req_run) > 0: print("Simulations for following (λ, β) were already running: ", points_req_run) if len(points) > 0: print() arg_strs = {} for Point in points: chdir(config_dir(config)) dir_name = point_dir(Point) launch_script_n = launch_script_name(Point) make_script_n = make_script_name(Point) if Point in points_old: if not isdir(dir_name + "/history/adjacencies"): mkdir(dir_name + "/history/adjacencies") with open(dir_name + "/state.json", "r+") as state_file: state = json.load(state_file) if state['is_thermalized']: print('((λ, β) = ' + str(Point) + ') Ha già finito!') # @todo da migliorare continue if state['last_run_succesful']: run_num = state['run_done'] + 1 else: print('((λ, β) = ' + str(Point) + ') Problem in the last run') continue if state['is_thermalized'] and linear_history == '0': linear_history = '1M' # I'm putting the default because this case is present only for # backward compatibility, and before the timelength was stuck to 80 try: time_length = state['timelength'] except KeyError: time_length = time_lengths[Point] checkpoints = [ x.name for x in scandir(dir_name + "/checkpoint") if (split('_|\.|run', x.name)[1] == str(run_num - 1) and x.name[-4:] != '.tmp') ] # nell'ordinamento devo sostituire i '.' con le '~', o in generale # un carattere che venga dopo '_', altrimenti 'run1.1_...' viene # prima di 'run1_...' checkpoints.sort(key=lambda s: s.replace('.', '~')) last_check = checkpoints[-1] else: mkdir(dir_name) mkdir(dir_name + "/checkpoint") mkdir(dir_name + "/history") mkdir(dir_name + "/history/adjacencies") mkdir(dir_name + "/bin") make_template = project_folder() + '/lib/scripts/make_script.py' launch_template = project_folder( ) + '/lib/scripts/launch_script.py' copyfile(make_template, dir_name + '/' + make_script_n) copyfile(launch_template, dir_name + '/' + launch_script_n) if fake_run: print('Created simulation directory for: (Lambda= ' + str(Point[0]) + ', Beta= ' + str(Point[1]) + ')') run_num = 1 last_check = None time_length = time_lengths[Point] # devo farlo qui perché prima non sono sicuro che dir_name esista # ('mkdir(dir_name)') chdir(dir_name) if isfile('max_volume_reached'): print(f'Point {Point} won\'t be relaunched because it reached ' 'maximum volume available in the previous run.') continue if int(run_num) > 1: from lib.tools import recovery_history recovery_history() if linear_history != '0' and not state['linear-history']: state['linear-history-cut'] = state['iter_done'] if state['linear-history']: if linear_history == '0': print('\033[38;5;69mWarning:\033[0m') print(f"Point {Point} has been already run with " f"linear_history {state['linear-history']}, so this " f"value will be used.") elif linear_history != state['linear-history']: print('\033[38;5;69mWarning:\033[0m') print(f"Point {Point} has been already run with " f"linear_history {state['linear-history']}, so this " f"will be used instead of: {linear_history}.") linear_history = state['linear-history'] # ensure state_file existence or update it if int(run_num) == 1: state = { 'Lambda': Point[0], 'Beta': Point[1], 'run_done': 0, 'is_thermalized': False, 'last_checkpoint': None, 'iter_done': 0, 'timelength': time_length } with open('state.json', 'w') as state_file: json.dump(state, state_file, indent=4) # END CONDITION MANIPULATION # ricongiungo le due variabili perché è ancora facile # distinguerle dall'ultimo carattere if end_steps != '0': end_condition = end_steps else: end_condition = end_time # needed for thermalization loop end_partial, end_condition, end_type = end_parser(end_condition) if linear_history != '0': # i.e. `if linear_history:` if end_type == 'time': end_partial = str(end_condition) + 's' else: end_partial = end_condition # set debug_flag for c++ (in c++ style) debug_flag = str(debug).lower() # set adj_flag for c++ (in c++ style) adj_flag = str(adj).lower() # max_volume max_volume = int(max_volume[0] if type(max_volume) == list else max_volume) # is necessary to recompile each run because on the grid the launch node # could be different from run_node exe_name = "CDT_2D-" + point_str(Point) #+ "_run" + str(run_num) arguments = [ project_folder(), run_num, Point[0], Point[1], time_length, end_condition, debug_flag, last_check, linear_history, adj_flag, move22, move24, max_volume, end_partial, end_type, exe_name ] arg_str = '' for x in arguments: arg_str += ' ' + str(x) arg_strs[Point] = arg_str if fake_run: print() print(*(["bin/" + exe_name] + arguments[:8])) if not fake_run: from lib.platforms import launch_run points = list(arg_strs.keys()) launch_run(points, arg_strs, config, queue, arch, file)
def plot(points_old, config, gauge=False): from matplotlib.pyplot import figure, show import numpy as np from lib.utils import find_running, point_dir, config_dir points_run, _ = find_running() points_run = [x[0] for x in points_run if x[1] == config] color_cycle = [ 'xkcd:carmine', 'xkcd:teal', 'xkcd:peach', 'xkcd:mustard', 'xkcd:cerulean' ] n_col = len(color_cycle) canvases = [] props = [] i = -1 for Point in points_old: i += 1 Lambda = Point[0] Beta = Point[1] if not gauge: vol_file = (config_dir(config) + '/' + point_dir(Point) + '/history/volumes.txt') indices, volumes = np.loadtxt(vol_file, unpack=True) file = vol_file else: vol_file = (config_dir(config) + '/' + point_dir(Point) + '/history/volumes.txt') v_indices, volumes = np.loadtxt(vol_file, unpack=True) gauge_file = (config_dir(config) + '/' + point_dir(Point) + '/history/gauge.txt') g_indices, gauge_action, topological_charge, \ av_contr = np.loadtxt(gauge_file, unpack=True) v_indices = tuple([np.searchsorted(v_indices, g_indices)]) indices = g_indices volumes = 6 * (gauge_action / volumes[v_indices]) / Beta file = gauge_file fig = figure() ax = fig.add_subplot(111) props += [{'fig': fig, 'ax': ax, 'skip': len(volumes), 'file': file}] canvases += [fig.canvas] fig.set_size_inches(7, 5) ax.plot(indices, volumes, color=color_cycle[i % n_col]) if Point in points_run: run_t = ', running' else: run_t = '' title = 'λ = ' + str(Point[0]) + ', β = ' + str(Point[1]) + run_t if gauge: title = 'average plaquette\n' + title ax.set_title(title) def on_key(event): i = canvases.index(event.canvas) p = props[i] if event.key == 'f5': try: ind_aux, vol_aux = np.loadtxt(p['file'], unpack=True, skiprows=p['skip']) except ValueError: ind_aux = [] vol_aux = [] try: if len(vol_aux) > 10: props[i]['skip'] += len(vol_aux) p['ax'].plot(ind_aux, vol_aux, color=color_cycle[i % n_col]) p['fig'].canvas.draw() except TypeError: pass if not gauge: fig.canvas.mpl_connect('key_press_event', on_key) show()
def show(points_old, config, disk_usage=''): """Output analysis for CDT_2D simulation. attempts_str = str(attempts) Descrizione... Parameters ---------- p1 : tipo descrizione del primo parametro p1 Returns ------- tipo descrizione del tipo di ritorno """ from textwrap import wrap from numpy import histogram, median from lib.utils import eng_not, config_dir if len(points_old) == 0: print("There are no folders currently.") else: print('┌' + '─' * (len(config) + 9) + '┐') print('│ ' + config.upper() + ' CONFIG │') print('╰' + '─' * (len(config) + 9) + '┘\n') num = str(len(points_old)) print(" " + num + " λ values in the range requested:") for x in wrap(str(points_old), width=65, initial_indent=' ' * 3, subsequent_indent=' ' * 4): print(x) lambdas_old = [p[0] for p in points_old] if disk_usage == '': hist_lambda = histogram(lambdas_old, 20) highest = max(hist_lambda[0]) print() for h in range(0, highest): for x in hist_lambda[0]: if (x >= highest - h): print(' X ', end='') else: print(' ', end='') print("") l_min = eng_not(min(lambdas_old)) l_med = eng_not(median(lambdas_old)) l_max = eng_not(max(lambdas_old)) print(l_min, ' ' * 23, l_med, ' ' * 23, l_max) elif disk_usage == 'disk': from os import popen, chdir from lib.utils import color_mem, color_lambda chdir(config_dir(config)) x = popen('du -hd 1').read().split('\n') x[:-1].sort(key=lambda x: x.split()[0]) y = popen('du -hd 2 */checkpoint').read().split('\n') y[:-1].sort(key=lambda x: x.split()[0]) z = popen('du -hd 2 */bin').read().split('\n') z[:-1].sort(key=lambda x: x.split()[0]) a = popen('du -hd 2 */history').read().split('\n') a[:-1].sort(key=lambda x: x.split()[0]) dim = [] for i in range(len(x) - 2): w = x[i].split('\t./Lambda') v = y[i].split() u = z[i].split() t = a[i].split() s = ', '.join(w[1].split('_Beta')) dim += [[s, w[0], v[0], u[0], t[0]]] print('\n', ' ' * 3, '┌', '─' * 56, '╮', sep='') print(' ' * 3, '│ POINT (λ, β) │ SIZE │ CHECK │ BIN. │ ', 'HISTORY │', sep='') print(' ' * 3, '╰', '─' * 16, '┼', '─' * 8, '┼', '─' * 9, '┼', '─' * 8, '┼', '─' * 11, '┘', sep='') for l in dim: b = color_mem(l[1].ljust(4), size=True) c = color_mem(l[2].ljust(4)) d = color_mem(l[3].ljust(4)) e = color_mem(l[4].ljust(4)) point = l[0].split(', ') x = ' ' + r_f(point[0], 7) + ', ' + point[1][:7] a = color_lambda(x.rjust(18), [b, c, d, e]) print(a, ' │ ', b, ' │ ', c, ' │ ', d, ' │ ', e) print() print('The overall disk used is: ', x[-2].split()[0]) elif disk_usage == 'num': from os import popen, chdir from lib.utils import color_mem, color_num, color_lambda chdir(config_dir(config)) x = popen('du -hd 1').read().split('\n') dim = [] for i in range(len(x) - 2): w = x[i].split('\t./Lambda') v = str( int( popen('ls -1q Lambda' + w[1] + '/checkpoint/ | wc -l').read())) u = str( int( popen('ls -1q Lambda' + w[1] + '/bin/ | wc -l').read())) s = ', '.join(w[1].split('_Beta')) dim += [[s, w[0], v, u]] dim.sort(key=lambda x: x[0]) print('\n', ' ' * 3, '┌', '─' * 44, '╮', sep='') print(' ' * 3, '│ POINT (λ, β) │ SIZE │ CHECK │ BIN. │', sep='') print(' ' * 3, '╰', '─' * 16, '┼', '─' * 8, '┼', '─' * 9, '┼', '─' * 8, '┘', sep='') for l in dim: b = color_mem(l[1].ljust(4), size=True) c = color_num(l[2].rjust(4)) d = color_num(l[3].rjust(4)) point = l[0].split(', ') x = ' ' + r_f(point[0], 7) + ', ' + point[1][:7] a = color_lambda(x.rjust(18), [b, c, d]) print(a, ' │ ', b, ' │ ', c, ' │ ', d) print()
def stop(points_old, config, is_all, pids, force): # @todo: distinguere fra processi 'data' e 'test' # si fa con un argomento config che viene da args.is_data from os import environ, system, popen import pickle from lib.utils import find_running, point_dir, config_dir points_run, sim_info = find_running() points_run = [x[0] for x in points_run if x[1] == config] # if config or not is_all: # if not config: # config = 'test' # points_run = [x[0] for x in points_run if x[1] == config] # else: # points_run = [x[0] for x in points_run] running_pids = [ps_i[2] for ps_i in sim_info] if pids: for pid in pids: if pid in running_pids or force: ps_out = popen('ps -fu ' + environ['USER']).read().split('\n') for line in ps_out[1:-1]: infos = line.split() ps_pid = int(infos[1]) ps_ppid = int(infos[2]) if ps_pid == pid or ps_ppid == pid: if ps_ppid != 1: system('kill ' + str(ps_ppid)) system('kill ' + str(ps_pid)) else: print(f'Invalid PID: {pid}, ' + 'there is no running simulation with that one.') return try: with open(config_dir(config) + '/pstop.pickle', 'rb') as stop_file: points_stopped = pickle.load(stop_file) except FileNotFoundError: points_stopped = [] l_aux = [] for Point in points_stopped: if Point in points_run: l_aux += [Point] points_stopped = l_aux points_stopping = [] points_notstop = [] for Point in points_old: if Point in points_run and Point not in points_stopped: points_stopped += [Point] points_stopping += [Point] from os import system from time import time from datetime import datetime sf = '%d-%m-%Y %H:%M:%S' system('echo ' + datetime.fromtimestamp(time()).strftime(sf) + ' > ' + config_dir(config) + '/' + point_dir(Point) + '/stop') # forse '.stop' anzichè 'stop' else: points_notstop += [Point] with open(config_dir(config) + '/pstop.pickle', 'wb') as stop_file: pickle.dump(points_stopped, stop_file) if len(points_stopping) > 0: print("Simulations for following (λ, β) just stopped: ", points_stopping) if len(points_notstop) > 0 and not is_all: print("Simulations for following (λ, β) were not running: ", points_notstop)
def show_state(configs, full_show=False): # @todo: add support for the other platforms # @todo: for clusters: add 'pending' state import pickle import json from os import environ, popen from platform import node from datetime import datetime from time import time from lib.utils import find_running, point_dir, config_dir from lib.platforms import get_ps_out if not type(configs) == list: configs = [configs] # if node() == 'Paperopoli' or node() == 'fis-delia.unipi.it': ps_out = get_ps_out() # else: # ps_out = [] # print("This platform is still not supported") # return empty = len(['' for line in ps_out if ' bin/CDT_2D-Lambda' in line]) == 0 if len(ps_out) > 1 and not empty: print(' LAMBDA-λ BETA-β TIME STATUS CONFIG', end='') if full_show == '0': print() elif full_show == '1': print(' RUN_ID PID PPID') elif full_show == '2': print(' LIN_HIST START DISK US.') points_run_all, sim_all = find_running() configs += ['-'] d = {} for config in configs: points_run_list = [] sim_list = [] for i in range(len(sim_all)): try: if points_run_all[i][1] == config: points_run_list += [points_run_all[i]] sim_list += [sim_all[i]] except IndexError: # It's possible that find_running can't retrieve the config # for some simulations, these will be manged after pass d[config] = points_run_list, sim_list # for i in range(len(sim_all)): # if len(points_run_all[i]) == 1: # points_run_list += [points_run_all[i] + ['-']] # sim_list += [sim_all[i]] # d['-'] = points_run_list, sim_list else: print("There are no running simulations currently.") return for config in configs: try: if config == '-': raise FileNotFoundError with open(config_dir(config) + '/pstop.pickle', 'rb') as stop_file: points_stopped = pickle.load(stop_file) except FileNotFoundError: points_stopped = [] if len(ps_out) > 1 and not empty: points_run_list, sim_list = d[config] for i in range(0, len(sim_list)): points_run = points_run_list[i] sim = sim_list[i] Point = points_run[0] l_conf = points_run[1] if Point in points_stopped: state = 'killed' else: state = 'running' print(r_f(str(Point[0]), 9), r_f(str(Point[1]), 9), sim[0].rjust(11), ' ', state.ljust(10), l_conf.ljust(11), end='') if full_show == '0': print() elif full_show == '1': print(sim[1].rjust(4), ' ', sim[2].ljust(8), sim[3].ljust(8)) elif full_show == '2': if config != '-': Point_dir = config_dir(config) + '/' + \ point_dir(Point) + '/' with open(Point_dir + 'state.json', 'r') as state_file: state = json.load(state_file) lin_hist = state['linear-history'] start = state['start_time'] disk_us = popen('du -hs ' + Point_dir).read().split()[0] else: lin_hist = '-' start = '-' disk_us = '-' print( str(lin_hist).ljust(9), start[-8:].ljust(10), disk_us.rjust(8)) points_run = [x[0] for x in points_run_list if x[1] == config] l_aux = [] for Point in points_stopped: if Point in points_run: l_aux += [Point] points_stopped = l_aux else: points_stopped = [] if config != '-': with open(config_dir(config) + '/pstop.pickle', 'wb') as stop_file: pickle.dump(points_stopped, stop_file) if len(ps_out) > 1 and not empty: clock = datetime.fromtimestamp(time()).strftime('%H:%M:%S') print('\n [CLOCK: ' + clock + ']')