Public Access
173 lines
6.7 KiB
Python
Executable File
173 lines
6.7 KiB
Python
Executable File
#! /usr/bin/env python3
|
|
|
|
import time
|
|
import sys
|
|
import os
|
|
import os.path
|
|
import argparse
|
|
import logging
|
|
import tables
|
|
import damaris.data.DataPool as DataPool
|
|
import damaris.gui.ResultReader as ResultReader
|
|
import damaris.gui.ExperimentWriter as ExperimentWriter
|
|
import damaris.gui.BackendDriver as BackendDriver
|
|
import damaris.gui.ResultHandling as ResultHandling
|
|
import damaris.gui.ExperimentHandling as ExperimentHandling
|
|
|
|
logger = logging.getLogger("damaris.cli")
|
|
|
|
def progressbar(event):
|
|
if event.subject=="__recentexperiment" or event.subject=="__recentresult":
|
|
r=event.origin.get("__recentresult",-1)+1
|
|
e=event.origin.get("__recentexperiment",-1)+1
|
|
if e!=0:
|
|
ratio=100.0*r/e
|
|
else:
|
|
ratio=100.0
|
|
sys.stderr.write("\r%d/%d (%.0f%%)"%(r,e,ratio))
|
|
sys.stderr.flush()
|
|
|
|
|
|
class ScriptInterface:
|
|
|
|
def __init__(self, exp_script=None, res_script=None, backend_executable=None, spool_dir="spool", log_callback=None):
|
|
self.exp_script=exp_script
|
|
self.res_script=res_script
|
|
self.backend_executable=backend_executable
|
|
self.spool_dir=os.path.abspath(spool_dir)
|
|
self.exp_handling=self.res_handling=None
|
|
self._log_callback = log_callback
|
|
|
|
self.exp_writer=self.res_reader=self.back_driver=None
|
|
if self.backend_executable is not None:
|
|
self.back_driver=BackendDriver.BackendDriver(self.backend_executable, spool_dir)
|
|
if self.exp_script: self.exp_writer=self.back_driver.get_exp_writer()
|
|
if self.res_script: self.res_reader=self.back_driver.get_res_reader()
|
|
else:
|
|
self.back_driver=None
|
|
if self.exp_script: self.exp_writer=ExperimentWriter.ExperimentWriter(spool_dir)
|
|
if self.res_script: self.res_reader=ResultReader.ResultReader(spool_dir)
|
|
|
|
self.data=DataPool()
|
|
|
|
|
|
def runScripts(self):
|
|
# get script engines
|
|
if self.exp_script and self.exp_writer:
|
|
self.exp_handling=ExperimentHandling.ExperimentHandling(self.exp_script, self.exp_writer, self.data, self._log_callback)
|
|
if self.res_script and self.res_reader:
|
|
self.res_handling=ResultHandling.ResultHandling(self.res_script, self.res_reader, self.data, self._log_callback)
|
|
|
|
# start them
|
|
if self.exp_handling: self.exp_handling.start()
|
|
if self.back_driver is not None: self.back_driver.start()
|
|
if self.res_handling: self.res_handling.start()
|
|
|
|
def waitForScriptsEnding(self):
|
|
# time of last dump
|
|
dump_interval=600
|
|
next_dump_time=time.time()+dump_interval
|
|
# keyboard interrupts are handled in extra cleanup loop
|
|
try:
|
|
while [_f for _f in [self.exp_handling,self.res_handling,self.back_driver] if _f]:
|
|
time.sleep(0.1)
|
|
if time.time()>next_dump_time:
|
|
self.dump_data("pool/data_pool.h5")
|
|
next_dump_time+=dump_interval
|
|
|
|
if self.exp_handling is not None:
|
|
if not self.exp_handling.is_alive():
|
|
self.exp_handling.join()
|
|
if self.exp_handling.raised_exception:
|
|
logger.error(": experiment script failed at line %d (function %s): %s",
|
|
self.exp_handling.location[0],
|
|
self.exp_handling.location[1],
|
|
self.exp_handling.raised_exception)
|
|
else:
|
|
logger.info(": experiment script finished")
|
|
self.exp_handling = None
|
|
|
|
if self.res_handling is not None:
|
|
if not self.res_handling.is_alive():
|
|
self.res_handling.join()
|
|
if self.res_handling.raised_exception:
|
|
logger.error(": result script failed at line %d (function %s): %s",
|
|
self.res_handling.location[0],
|
|
self.res_handling.location[1],
|
|
self.res_handling.raised_exception)
|
|
else:
|
|
logger.info(": result script finished")
|
|
self.res_handling = None
|
|
|
|
if self.back_driver is not None:
|
|
if not self.back_driver.is_alive():
|
|
logger.info(": backend finished")
|
|
self.back_driver=None
|
|
|
|
except KeyboardInterrupt:
|
|
still_running=[_f for _f in [self.exp_handling,self.res_handling,self.back_driver] if _f]
|
|
for r in still_running:
|
|
r.quit_flag.set()
|
|
|
|
for r in still_running:
|
|
r.join()
|
|
|
|
def dump_data(self, filename):
|
|
try:
|
|
# write data from pool
|
|
dump_file=tables.open_file(filename,mode="w",title="DAMARIS experiment data")
|
|
self.data.write_hdf5(dump_file, complib='zlib', complevel=6)
|
|
# write scripts
|
|
scriptgroup=dump_file.create_group("/","scripts","Used Scripts")
|
|
dump_file.create_array(scriptgroup,"experiment_script", self.exp_script)
|
|
dump_file.create_array(scriptgroup,"result_script", self.res_script)
|
|
dump_file.create_array(scriptgroup,"backend_executable", self.backend_executable)
|
|
dump_file.create_array(scriptgroup,"spool_directory", self.spool_dir)
|
|
dump_file.flush()
|
|
dump_file.close()
|
|
dump_file=None
|
|
# todo
|
|
except Exception as e:
|
|
logger.error("Dump failed: %s", e)
|
|
|
|
|
|
|
|
if __name__=="__main__":
|
|
parser = argparse.ArgumentParser(
|
|
description="Run DAMARIS experiment and result scripts."
|
|
)
|
|
parser.add_argument("experiment_script", help="Path to the experiment script file")
|
|
parser.add_argument("result_script", help="Path to the result script file")
|
|
parser.add_argument(
|
|
"spool_dir", nargs="?", default=None,
|
|
help="Spool directory (defaults to current working directory)"
|
|
)
|
|
parser.add_argument(
|
|
"--backend", default="/usr/lib/damaris/backends/Mobilecore",
|
|
help="Path to the backend executable"
|
|
)
|
|
parser.add_argument(
|
|
"--output", default="data_pool.h5",
|
|
help="Output HDF5 file path (default: data_pool.h5)"
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
spool_dir = args.spool_dir if args.spool_dir else os.getcwd()
|
|
|
|
with open(args.experiment_script) as f:
|
|
expscript = f.read()
|
|
with open(args.result_script) as f:
|
|
resscript = f.read()
|
|
|
|
si = ScriptInterface(expscript, resscript, args.backend, spool_dir)
|
|
|
|
si.data.register_listener(progressbar)
|
|
|
|
si.runScripts()
|
|
|
|
si.waitForScriptsEnding()
|
|
|
|
si.dump_data(args.output)
|
|
|
|
si = None
|