Skip to content

Commit 4de22d6

Browse files
authored
Merge pull request #81 from kif/ID27_Neggia
Id27 neggia
2 parents cc943aa + 68e9559 commit 4de22d6

File tree

1 file changed

+125
-15
lines changed

1 file changed

+125
-15
lines changed

Diff for: plugins/id27.py

+125-15
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@
1717
import pyFAI
1818
from dahu.plugin import Plugin
1919
from dahu.factory import register
20+
2021
lock = Semaphore()
2122
logger = logging.getLogger("id27")
2223

2324
RAW = "RAW_DATA"
2425
PROCESSED = "PROCESSED_DATA"
2526
WORKDIR = "/scratch/shared"
2627
PREFIX = os.path.dirname(sys.executable) #where there scripts are
28+
NEGGIA_PLUGIN = os.path.join(os.environ["HOME"], "lib", "dectris-neggia.so")
29+
XDS_EXE = "xds_par"
2730

2831
try:
2932
from cryio import crysalis
@@ -313,10 +316,21 @@ def fabio_conversion(file_path,
313316
folder="xdi",
314317
fabioimage="tifimage",
315318
extension="tif",
316-
export_icat=False):
317-
"Convert a set of eiger files to cbf or tiff"
319+
export_icat=False,
320+
detector="eiger"):
321+
"""Convert a set of eiger files to cbf or tiff
322+
323+
:param file_path: First par of the input filename, typically /
324+
:param scan_number: last part of the path, typically "scan0001".
325+
The actual filename is actually guessed since there can be several of them, all will be processed
326+
:param folder: name of the output folder for writing (in PROCESSED_DATA, not in RAW_DATA folder)
327+
:param fabioimage: type of file to write, name of the Fabio class name.
328+
:param export_icat: set to True to export to icat the result.
329+
:param detector: name of the detector, used to determine the input filename
330+
:return: the logs of the conversion.
331+
"""
318332
results = []
319-
filename = os.path.join(file_path, scan_number, 'eiger_????.h5')
333+
filename = os.path.join(file_path, scan_number, f'{detector}_????.h5')
320334
files = {f:fabio.open(f).nframes for f in sorted(glob.glob(filename))} #since python 3.7 dict are ordered !
321335
all_single = max(files.values())==1
322336
file_path = file_path.rstrip("/")
@@ -452,8 +466,9 @@ class XdiConversion(Plugin):
452466
This is the plugin to convert an HDF5 to a stack of TIFF files
453467
454468
Typical JSON file:
455-
{"file_path": "/data/id27/inhouse/some/file.h5",
456-
"scan_number": "0001"
469+
{"file_path": "/data/id27/inhouse/some/path", #excluding the scan-number and the filename
470+
"scan_number": "scan0001"
471+
"detector": "eiger" #optionnal
457472
}
458473
459474
"""
@@ -465,12 +480,14 @@ def process(self):
465480

466481
file_path = self.input["file_path"]
467482
scan_number = self.input["scan_number"]
483+
detector = self.input.get("detector", "eiger")
468484
results = fabio_conversion(file_path,
469485
scan_number,
470486
folder="xdi",
471487
fabioimage="tifimage",
472488
extension="tif",
473-
export_icat=False)
489+
export_icat=False,
490+
detector=detector)
474491
self.output["output"] = results
475492

476493

@@ -553,8 +570,8 @@ class XdsConversion(Plugin):
553570
This is the plugin to convert an HDF5 to a stack of CBF files for XDS
554571
555572
Typical JSON file:
556-
{"file_path": "/data/id27/inhouse/some/file.h5",
557-
"scan_number": "0001"
573+
{"file_path": "/data/id27/inhouse/some/path", #excluding the scan-number and the filename
574+
"scan_number": "scan0001"
558575
}
559576
560577
"""
@@ -638,7 +655,7 @@ def process(self):
638655
ai["error_model"] = "poisson"
639656
ai["application"] = "pyfai-integrate"
640657
ai["version"] = 3
641-
ai["method"] = ["bbox", "csr", "opencl"]
658+
ai["method"] = ["full", "csr", "opencl"]
642659
ai["opencl_device"] = "gpu"
643660
ai["nbpt_rad"] = self.input.get("npt", 1)
644661
ai["nbpt_azim"] = 1
@@ -648,8 +665,8 @@ def process(self):
648665
param["experiment_title"] = os.path.join(os.path.basename(file_path), scan_number)
649666
param["fast_motor_name"] = "fast"
650667
param["slow_motor_name"] = "slow"
651-
param["fast_motor_points"] = fast_scan
652-
param["slow_motor_points"] = slow_scan
668+
param["nbpt_fast"] = fast_scan
669+
param["nbpt_slow"] = slow_scan
653670
param["offset"] = 0
654671
param["output_file"] = dest
655672
param["input_data"] = [(i, None, None) for i in files]
@@ -672,13 +689,16 @@ def process(self):
672689
try:
673690
send_icat(file_path, dest_dir, metadata=metadata)
674691
except Exception as err:
692+
self.log_error(f"Error in send_icat {type(err)}: {err}", do_raise=False)
675693
import traceback
676-
print(f"Error {type(err)}: {err}")
677-
traceback.print_exc(err, file=sys.stdout)
694+
traceback.print_exc(file=sys.stdout)
678695

679696

680697
def send_icat(raw_dir, processed_dir, beamline="id27", proposal="", dataset="", metadata=None):
681698
"Function that sends to icat the processed data"
699+
if IcatClient is None:
700+
logger.warning("pyicat_plus is not installed, skipping")
701+
return
682702
icat_client = IcatClient(metadata_urls=["bcu-mq-01.esrf.fr:61613", "bcu-mq-02.esrf.fr:61613"])
683703
metadata = metadata or {"definition": "dummy processing", "Sample_name": "unknown sample"}
684704
l = raw_dir.split("/")
@@ -700,6 +720,96 @@ def send_icat(raw_dir, processed_dir, beamline="id27", proposal="", dataset="",
700720
icat_client.store_processed_data(**kwargs)
701721
return kwargs
702722

723+
@register
724+
class XdsProcessing(Plugin):
725+
"""
726+
This is the plugin to convert an HDF5-lima file into a Neggia-compatible and processes it using XDS.
727+
728+
Typical JSON file:
729+
{"plugin_name": "id27.xdsprocessing",
730+
"file_path": "/data/id27/inhouse/some/path", #excluding the scan-number and the filename
731+
"scan_number": "scan0001",
732+
"ponifile": "/tmp/geometry.poni",
733+
"detector": "eiger" #optionnal
734+
"xds_extra": ["",
735+
"!UNIT_CELL_CONSTANTS= 10.317 10.317 7.3378 90 90 120 ! put correct values if known",
736+
...]
737+
MINIMUM_NUMBER_OF_PIXELS_IN_A_SPOT=4 ! default of 6 is sometimes too high
738+
MAXIMUM_NUMBER_OF_STRONG_PIXELS=18000 ! total number of strong pixels
739+
used for indexation
740+
BACKGROUND_PIXEL=2.0 ! used by COLSPOT and INTEGRATE
741+
SIGNAL_PIXEL=3.0 ! needs to be lager than BACKGROUND_PIXEL, specifies
742+
standard deviation, used in COLSPOT and INTEGRATE
743+
744+
!EXCLUDE_RESOLUTION_RANGE= 3.93 3.87 !ice-ring at 3.897 Angstrom
745+
!INCLUDE_RESOLUTION_RANGE=40 1.75  ! after CORRECT, insert high resol
746+
limit; re-run CORRECT
747+
748+
}
703749
704-
705-
750+
"""
751+
752+
def process(self):
753+
Plugin.process(self)
754+
if not self.input:
755+
logger.error("input is empty")
756+
757+
script_name = "hdf2neggia"
758+
file_path = self.input["file_path"]
759+
scan_number = self.input["scan_number"]
760+
ponifile = self.input["ponifile"]
761+
detector = self.input.get("detector", "eiger")
762+
xds_extra = self.input.get("xds_extra")
763+
if xds_extra is None:
764+
xds_extra = ["",
765+
"!UNIT_CELL_CONSTANTS= 10.317 10.317 7.3378 90 90 120 ! put correct values if known",
766+
"MINIMUM_NUMBER_OF_PIXELS_IN_A_SPOT=4 ! default of 6 is sometimes too high",
767+
"MAXIMUM_NUMBER_OF_STRONG_PIXELS=18000 ! total number of strong pixels used for indexation",
768+
"BACKGROUND_PIXEL=2.0 ! used by COLSPOT and INTEGRATE",
769+
"SIGNAL_PIXEL=3.0 ! needs to be lager than BACKGROUND_PIXEL, specifies standard deviation, used in COLSPOT and INTEGRATE",
770+
"!EXCLUDE_RESOLUTION_RANGE= 3.93 3.87 !ice-ring at 3.897 Angstrom",
771+
"!INCLUDE_RESOLUTION_RANGE=40 1.75  ! after CORRECT, insert high resol limit; re-run CORRECT",
772+
""]
773+
774+
filename = os.path.join(file_path, scan_number, f'{detector}_????.h5')
775+
files = sorted(glob.glob(filename))
776+
file_path = file_path.rstrip("/")
777+
778+
splitted = file_path.split("/")
779+
if RAW in splitted:
780+
raw_pos = splitted.index(RAW)
781+
splitted[raw_pos] = PROCESSED
782+
splitted.append(scan_number)
783+
splitted.insert(0, "/")
784+
dest_dir = os.path.join(*splitted)
785+
# sample_name = splitted[raw_pos + 1]
786+
else:
787+
dest_dir = os.path.join(file_path.replace(RAW,PROCESSED), scan_number)
788+
# sample_name = "unknown sample"
789+
dest_dir = os.path.join(dest_dir, "xsd")
790+
if len(files) == 0:
791+
raise RuntimeError(f"No such file {filename}")
792+
793+
if not os.path.exists(dest_dir):
794+
os.makedirs(dest_dir, exist_ok=True)
795+
796+
script_name = os.path.join(PREFIX, script_name)
797+
parameters = [script_name,
798+
"--geometry", ponifile,
799+
"--output", dest_dir,
800+
"--neggia", NEGGIA_PLUGIN,
801+
"--CdTe"] + files
802+
self.log_warning(f'start script with parameters: `{" ".join(parameters)}`')
803+
res = subprocess.run(parameters, capture_output=True, check=False)
804+
self.output["convert"] = unpack_processed(res)
805+
if res.returncode == 0:
806+
# Implement the tuning of the XDS.INP file here...
807+
xdsinp = os.path.join(dest_dir, "XDS.INP")
808+
with open(xdsinp, "a") as xdsfile:
809+
xdsfile.write(os.linesep)
810+
for line in xds_extra:
811+
xdsfile.write(line+os.linesep)
812+
813+
res = subprocess.run(XDS_EXE, cwd=dest_dir, capture_output=True, check=False)
814+
self.output["xds"] = unpack_processed(res)
815+

0 commit comments

Comments
 (0)