Source code for mesoSPIM.src.utils.utility_functions
'''
Contains a variety of mesoSPIM utility functions
'''
import os
import psutil
import ctypes
import logging
logger = logging.getLogger(__name__)
# Windows API binding
GetCurrentProcessorNumber = ctypes.windll.kernel32.GetCurrentProcessorNumber
[docs]
def convert_seconds_to_string(delta_t):
'''
Converts an input value in seconds into a string in the format hh:mm:ss
Interestingly, a variant using np.divmod is around 4-5x slower in initial tests.
'''
if delta_t <= 0:
return '--:--:--'
else:
hours, remainder = divmod(delta_t, 3600)
minutes, seconds = divmod(remainder, 60)
return f"{int(hours):02}:{int(minutes):02}:{int(seconds):02}"
[docs]
def write_line(file, key='', value=''):
''' Little helper method to write a single line with a key and value for metadata
Adds a line break at the end.
'''
if key != '':
file.write('['+str(key)+'] '+str(value) + '\n')
else:
file.write('\n')
[docs]
def gb_size_of_array_shape(shape):
'''Given a tuple of array shape, return the size in GB of a uint16 array.
Args:
shape (tuple[int]): Array dimensions, e.g. ``(100, 2048, 2048)``.
Returns:
float: Size in gibibytes (GiB).
'''
for idx,ii in enumerate(shape):
if idx == 0:
total = ii
else:
total *= ii
total = total * 16 / 8
return total / 1024**3
[docs]
def replace_with_underscores(string):
'''Replace spaces, slashes and percent signs with underscores or ASCII equivalents.
Used for sanitising file and folder names produced from user inputs.
Args:
string (str): Raw string, e.g. a filter name like ``"488 nm / 50%"``.
Returns:
str: Sanitised string safe for use in file paths.
'''
s = string.replace(' ', '_').replace('/', '_').replace('%', 'pct')
return s
[docs]
def log_cpu_core(logger, msg=""):
'''Log (at DEBUG level) which logical CPU core the calling thread is currently running on.
Useful for verifying thread affinity in the Core / Camera / Writer thread model——each
Qt thread should remain pinned to a consistent CPU core.
Args:
logger (logging.Logger): Logger instance used for the debug message.
msg (str): Optional prefix string included in the log message.
'''
pid = os.getpid()
proc = psutil.Process(pid)
#core = proc.cpu_num() # returns the current logical CPU number. Linux only.
core = GetCurrentProcessorNumber() # Windows only.
logger.debug(f"{msg} running on logical CPU core: {core}")
[docs]
def timed(func):
'''Decorator to time functions and log the elapsed time'''
import time
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
elapsed_ms = (time.perf_counter() - start) * 1000
logger.info(f"{func.__name__} took {elapsed_ms:.1f} ms")
return result
return wrapper