def run(self, inData): outData = {} # First get the list of subWedges if "subWedge" in inData: list_sub_wedge = inData["subWedge"] directory_prefix = "" else: first_image = inData["imagePath"][0] last_image = inData["imagePath"][-1] prefix = UtilsImage.getPrefix(first_image) first_image_number = UtilsImage.getImageNumber((first_image)) last_image_number = UtilsImage.getImageNumber((last_image)) directory_prefix = "{0}_{1}_{2}".format( prefix, first_image_number, last_image_number ) list_sub_wedge = self.getListSubWedge(inData) indata_xds_integration = { "subWedge": list_sub_wedge } xds_integration = XDSIndexAndIntegration( inData=indata_xds_integration, workingDirectorySuffix=directory_prefix, ) xds_integration.execute() outData = xds_integration.outData return outData
def createBatchList(self, inData): listOfBatches = [] listOfImagesInBatch = [] if len(self.listImage) == 0: self.directory = pathlib.Path(inData["directory"]) self.template = inData["template"] startNo = inData["startNo"] endNo = inData["endNo"] for index in range(startNo, endNo + 1): listOfImagesInBatch.append(index) if len(listOfImagesInBatch) == self.batchSize or index == 9999: listOfBatches.append(listOfImagesInBatch) listOfImagesInBatch = [] else: firstImage = pathlib.Path(self.listImage[0]) self.directory = firstImage.parent self.template = UtilsImage.getTemplate(firstImage) for image in self.listImage: imageNo = UtilsImage.getImageNumber(image) listOfImagesInBatch.append(imageNo) if len(listOfImagesInBatch) == self.batchSize: listOfBatches.append(listOfImagesInBatch) listOfImagesInBatch = [] if len(listOfImagesInBatch) > 0: listOfBatches.append(listOfImagesInBatch) return listOfBatches
def test_splitPrefixRunNumber(self): path = pathlib.Path( "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0001.cbf" ) pre_prefix, run_number = UtilsImage.splitPrefixRunNumber(path) self.assertEqual(pre_prefix, "PsPL7C-252") self.assertEqual(run_number, 1) path = pathlib.Path( "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/Ps_PL_7C-2_52_1_0001.cbf" ) pre_prefix, run_number = UtilsImage.splitPrefixRunNumber(path) self.assertEqual(pre_prefix, "Ps_PL_7C-2_52") self.assertEqual(run_number, 1)
def test_getH5FilePath_ref(self): refH5Master1 = "ref-UPF2-UPF2__4_1_1_master.h5" refH5Data1 = "ref-UPF2-UPF2__4_1_1_data_000001.h5" file1 = "ref-UPF2-UPF2__4_1_0001.h5" h5MasterFilePath, h5DataFilePath, h5FileNumber = UtilsImage.getH5FilePath( file1, hasOverlap=True) self.assertEqual(refH5Master1, str(h5MasterFilePath)) self.assertEqual(refH5Data1, str(h5DataFilePath)) refH5Master2 = "ref-UPF2-UPF2__4_1_2_master.h5" refH5Data2 = "ref-UPF2-UPF2__4_1_2_data_000001.h5" file2 = "ref-UPF2-UPF2__4_1_0002.h5" h5MasterFilePath, h5DataFilePath, h5FileNumber = UtilsImage.getH5FilePath( file2, hasOverlap=True) self.assertEqual(refH5Master2, str(h5MasterFilePath)) self.assertEqual(refH5Data2, str(h5DataFilePath))
def test_readEiger4mHeader(self): referenceDataPath = self.dataPath / 'ReadImageHeader_Eiger4M.json' inData = UtilsTest.loadAndSubstitueTestData(referenceDataPath) h5MasterFilePath, h5DataFilePath, h5FileNumber = UtilsImage.getH5FilePath( inData['imagePath'][0]) dictHeader = ReadImageHeader.readHdf5Header(h5MasterFilePath) self.assertEqual(dictHeader['description'], 'Dectris Eiger 4M')
def test_readEiger16mHeader(self): referenceDataPath = self.dataPath / "ReadImageHeader_Eiger16M.json" inData = UtilsTest.loadAndSubstitueTestData(referenceDataPath) h5MasterFilePath, h5DataFilePath, h5FileNumber = UtilsImage.getH5FilePath( inData["imagePath"][0] ) dictHeader = ReadImageHeader.readHdf5Header(h5MasterFilePath) self.assertEqual(dictHeader["description"], "Dectris EIGER2 CdTe 16M")
def getH5FilePath(cls, filePath, batchSize=1, isFastMesh=False): imageNumber = UtilsImage.getImageNumber(filePath) prefix = UtilsImage.getPrefix(filePath) if isFastMesh: h5ImageNumber = int((imageNumber - 1) / 100) + 1 h5FileNumber = 1 else: h5ImageNumber = 1 h5FileNumber = int((imageNumber - 1) / batchSize) * batchSize + 1 h5MasterFileName = "{prefix}_{h5FileNumber}_master.h5".format( prefix=prefix, h5FileNumber=h5FileNumber) h5MasterFilePath = filePath.parent / h5MasterFileName h5DataFileName = \ "{prefix}_{h5FileNumber}_data_{h5ImageNumber:06d}.h5".format( prefix=prefix, h5FileNumber=h5FileNumber, h5ImageNumber=h5ImageNumber) h5DataFilePath = filePath.parent / h5DataFileName return h5MasterFilePath, h5DataFilePath, h5FileNumber
def findDataCollectionFromFileLocationAndFileName(imagePath, client=None): logger = UtilsLogging.getLogger() dataCollectionWS3VO = None noTrials = 10 fileLocation = os.path.dirname(imagePath) fileName = os.path.basename(imagePath) if fileName.endswith(".h5"): prefix = UtilsImage.getPrefix(fileName) imageNumber = UtilsImage.getImageNumber(fileName) fileName = "{0}_{1:04d}.h5".format(prefix, imageNumber) try: if client is None: client = getCollectionWebService() if client is None: logger.error( "No web service client available, cannot contact findDataCollectionFromFileLocationAndFileName web service." ) elif fileLocation is None: logger.error( "No fileLocation given, cannot contact findDataCollectionFromFileLocationAndFileName web service." ) elif fileName is None: logger.error( "No fileName given, cannot contact findDataCollectionFromFileLocationAndFileName web service." ) else: dataCollectionWS3VO = client.service.findDataCollectionFromFileLocationAndFileName( fileLocation, fileName) except Exception as e: logger.error( "ISPyB error for findDataCollectionFromFileLocationAndFileName: {0}, {1} trials left" .format(e, noTrials)) raise e if dataCollectionWS3VO is None: time.sleep(1) if noTrials == 0: raise RuntimeError( "ISPyB error for findDataCollectionFromFileLocationAndFileName - no data collections found for path {0}" .format(imagePath)) else: logger.warning( "Cannot find {0} in ISPyB - retrying, {1} trials left".format( imagePath, noTrials)) return dataCollectionWS3VO
def readImageHeaders(listImagePath): # Read the header(s) inDataReadImageHeader = {"imagePath": listImagePath} readImageHeader = ReadImageHeader( inData=inDataReadImageHeader, workingDirectorySuffix=UtilsImage.getPrefix(listImagePath[0]), ) readImageHeader.execute() listSubWedge = readImageHeader.outData["subWedge"] return listSubWedge
def run(self, inData): outData = {} hdf5File = pathlib.Path(inData['hdf5File']) # Read the header inDataReadImageHeader = { "imagePath": [inData['hdf5File']], "isFastMesh": False } readImageHeader = ReadImageHeader(inData=inDataReadImageHeader) readImageHeader.execute() if readImageHeader.isSuccess(): firstSubWedge = readImageHeader.outData["subWedge"][0] experimentalCondition = firstSubWedge["experimentalCondition"] detector = experimentalCondition["detector"] beam = experimentalCondition["beam"] goniostat = experimentalCondition["goniostat"] beamX = detector["beamPositionX"] / 2.0 / detector["pixelSizeX"] beamY = detector["beamPositionY"] / 2.0 / detector["pixelSizeY"] directory = hdf5File.parent prefix = UtilsImage.getPrefix(hdf5File) hdf5ImageNumber = 1 if 'master' in str(hdf5File): masterFile = hdf5File else: if UtilsConfig.isEMBL(): fileName = '{0}_master.h5'.format(prefix) else: fileName = '{0}_{1}_master.h5'.format( prefix, hdf5ImageNumber) masterFile = directory / fileName image = fabio.open(str(masterFile)) image.data = image.data.reshape(2181, 2, 2074, 2).sum(3).sum(1) cbfImage = image.convert("cbf") pilatus_headers = fabio.cbfimage.PilatusHeader( "Silicon sensor, thickness 0.000750 m") pilatus_headers["Start_angle"] = goniostat["rotationAxisStart"] pilatus_headers["Angle_increment"] = goniostat["oscillationWidth"] pilatus_headers["Detector"] = "Eiger2 16M binned to 4M" pilatus_headers["Pixel_size"] = (detector["pixelSizeY"] * 2, detector["pixelSizeX"] * 2) pilatus_headers["Exposure_time"] = beam["exposureTime"] pilatus_headers["Wavelength"] = beam["wavelength"] pilatus_headers[ "Detector_distance"] = detector["distance"] / 1000.0 pilatus_headers["Beam_xy"] = (beamY, beamX) pilatus_headers["Count_cutoff"] = 1009869 cbfImage.pilatus_headers = pilatus_headers directory = inData.get("forcedOutputDirectory", str(self.getWorkingDirectory())) cbfImagePath = os.path.join( directory, os.path.basename(inData['hdf5File']).replace(".h5", ".cbf")) cbfImage.save(cbfImagePath) outData["outputCBFFile"] = cbfImagePath return outData
def test_generateCommands_withImageRange(self): referenceDataPath = self.dataPath / 'H5ToCBF_withImageRange.json' inData = UtilsTest.loadAndSubstitueTestData(referenceDataPath, loadTestImages=False) hdf5File = pathlib.Path(inData['hdf5File']) directory = hdf5File.parent prefix = UtilsImage.getPrefix(hdf5File) commandLine, template = H5ToCBFTask.generateCommandsWithImageRange( inData, directory, prefix, hdf5File) self.assertTrue(commandLine is not None) self.assertTrue(template is not None)
def loadTestImage(imageFileName): """ This method tries to download images from http://www.edna-site.org/data/tests/images """ imageDirPath = getTestImageDirPath() if not imageDirPath.exists(): imageDirPath.mkdir(mode=0o777, parents=True) # Check if h5 data if imageFileName.endswith(".h5"): imagePath = imageDirPath / imageFileName hasOverlap = imagePath.name.startswith("ref-") h5MasterFilePath, h5DataFilePath, h5FileNumber = UtilsImage.getH5FilePath(imagePath, hasOverlap=hasOverlap) listImagePath = [h5MasterFilePath, h5DataFilePath] else: listImagePath = [imageDirPath / imageFileName] for imagePath in listImagePath: if not imagePath.exists(): logger.info( "Trying to download image %s" % str(imagePath) + ", timeout set to %d s" % MAX_DOWNLOAD_TIME ) if "http_proxy" in os.environ: dictProxies = {'http': os.environ["http_proxy"]} proxy_handler = ProxyHandler(dictProxies) opener = build_opener(proxy_handler).open else: opener = urlopen timer = threading.Timer(MAX_DOWNLOAD_TIME + 1, __timeoutDuringDownload) timer.start() data = opener("%s/%s" % (URL_EDNA_SITE, imagePath.name), data=None, timeout=MAX_DOWNLOAD_TIME ).read() timer.cancel() try: open(str(imagePath), "wb").write(data) except IOError: raise IOError( "Unable to write downloaded data to disk at %s" % imagePath ) if os.path.exists(str(imagePath)): logger.info("Image %s successfully downloaded." % imagePath) else: raise RuntimeError( "Could not automatically download test image %r!\n" + "If you are behind a firewall, " + "please set the environment variable http_proxy.\n" + "Otherwise please try to download the images manually from\n" + "http://www.edna-site.org/data/tests/images" % imageFileName)
def run(self, inData): outData = {} hdf5File = pathlib.Path(inData['hdf5File']) directory = hdf5File.parent prefix = UtilsImage.getPrefix(hdf5File) if 'imageNumber' in inData: commandLine, cbfFile = self.generateCommandsWithImageNumber( inData, directory, prefix, hdf5File) outData['outputCBFFile'] = str(cbfFile) elif 'startImageNumber' in inData and 'endImageNumber' in inData: commandLine, template = self.generateCommandsWithImageRange( inData, directory, prefix, hdf5File) outData['outputCBFFileTemplate'] = template self.setLogFileName('h5ToCBF.log') self.runCommandLine('eiger2cbf ' + commandLine, ignoreErrors=True) return outData
def runControlDozor(listSubWedge): listControlDozor = [] listOutDataControlDozor = [] for subWedge in listSubWedge: listSubWedgeImage = subWedge["image"] for image in listSubWedgeImage: # listImage.append(image['path']) inDataControlDozor = {"image": [image["path"]]} controlDozor = ControlDozor( inData=inDataControlDozor, workingDirectorySuffix=UtilsImage.getPrefixNumber( image["path"]), ) listControlDozor.append(controlDozor) controlDozor.start() for controlDozor in listControlDozor: controlDozor.join() if controlDozor.isSuccess(): listOutDataControlDozor.append(controlDozor.outData) return listOutDataControlDozor
def run(self, inData): outData = {} # First get the list of subWedges if "subWedge" in inData: listSubWedge = inData["subWedge"] else: listSubWedge = self.getListSubWedge(inData) # Get list of spots from Dozor listOutDataControlDozor = self.runControlDozor(listSubWedge) listDozorSpotFile = [] for outDataControlDozor in listOutDataControlDozor: if "dozorSpotFile" in outDataControlDozor["imageQualityIndicators"][0]: dozorSpotFile = outDataControlDozor["imageQualityIndicators"][0]["dozorSpotFile"] listDozorSpotFile.append(dozorSpotFile) imageDict = listSubWedge[0] listXdsIndexingTask = [] listResult = [] listSpaceGroup = [] # Run XDS indexing xdsIndexinInData = { "subWedge": listSubWedge, "dozorSpotFile": listDozorSpotFile } xdsIndexingTask = XDSIndexing( inData=xdsIndexinInData, workingDirectorySuffix=UtilsImage.getPrefix(imageDict["image"][0]["path"]) ) xdsIndexingTask.execute() xparmXdsPath = None if xdsIndexingTask.isSuccess(): xdsIndexingOutData = xdsIndexingTask.outData xparmXdsPath = xdsIndexingOutData["xparmXdsPath"] resultIndexing = ControlIndexing.getResultIndexingFromXds(xdsIndexingOutData) outData = { "resultIndexing": resultIndexing, "resultDozor": listOutDataControlDozor, "xparmXdsPath": xparmXdsPath } return outData
def createThumbnail( image, format="jpg", height=512, width=512, outputPath=None, minLevel=0, maxLevel=99.95, dilatation=4, workingDirectory=None, outputFileName=None, doResolutionRings=False, pixelSizeX=None, pixelSizeY=None, beamPositionX=None, beamPositionY=None, distance=None, wavelength=None, ): imageFileName = os.path.basename(image) imagePath = image imageNameWithoutSuffix, imageSuffix = os.path.splitext(imageFileName) if imageSuffix == ".h5": imageNumber = UtilsImage.getImageNumber(image) h5MasterFilePath, h5DataFilePath, h5FileNumber = UtilsImage.getH5FilePath( image, isFastMesh=True) noTrials = 5 fabioImage = None while noTrials > 0: try: fabioImage = fabio.openimage.openimage(h5MasterFilePath) noTrials = 0 except Exception as e: logger.debug("Error when trying to open {0}: {1}".format( h5MasterFilePath, e)) logger.debug( "Sleeping 5s and trying again, {0} trials left".format( noTrials)) noTrials -= 1 time.sleep(5) if fabioImage is None: raise RuntimeError( "Cannot open file {0} with fabio".format(h5MasterFilePath)) logger.debug("No frames: {0}".format(fabioImage.nframes)) if imageNumber < fabioImage.nframes: numpyImage = fabioImage.getframe(imageNumber).data else: numpyImage = fabioImage.data if numpyImage.dtype == numpy.dtype("uint32"): numpyImage = numpy.where(numpyImage > 65536 * 65536 - 2, 0, numpyImage) else: numpyImage = numpy.where(numpyImage > 256 * 256 - 2, 0, numpyImage) else: fabioImage = fabio.openimage.openimage(image) numpyImage = fabioImage.data # Default format suffix = "jpg" pilFormat = "JPEG" if format is not None: if format.lower() == "png": suffix = "png" pilFormat = "PNG" # The following code has been adapted from EDPluginExecThumbnail written by J.Kieffer dtype = numpyImage.dtype sortedArray = numpyImage.flatten() sortedArray.sort() numpyImage = numpy.maximum(numpyImage, int(minLevel) * numpy.ones_like(numpyImage)) maxLevel = sortedArray[int( round(float(maxLevel) * sortedArray.size / 100.0))] if maxLevel < 25: maxLevel = 25 numpyImage = numpy.minimum(numpyImage, maxLevel * numpy.ones_like(numpyImage)) numpyImage = scipy.ndimage.morphology.grey_dilation( numpyImage, (dilatation, dilatation)) mumpyImageFloat = (numpyImage.astype(numpy.float32)) / float(maxLevel) numpyImageInt = (mumpyImageFloat * 255.0).astype(numpy.uint8) # Check if we should do resolution rings listResolution = [] if doResolutionRings: delta = (height + width) / 2000 if delta < 1.0: delta = 1.0 centreX = beamPositionX / pixelSizeX centreY = beamPositionY / pixelSizeY sizeY, sizeX = numpyImageInt.shape averageSize = (sizeX + sizeY) / 2.0 yy, xx = numpy.mgrid[:sizeY, :sizeX] circle = (xx - centreX)**2 + (yy - centreY)**2 for resolution in [1.0, 1.1, 1.2, 1.5, 2.0, 3.0, 4.0]: import math theta = math.asin(wavelength / (2 * resolution)) radius = math.tan(2 * theta) * distance / pixelSizeX listResolution.append((resolution, radius / averageSize)) numpyImageInt = numpy.where( numpy.logical_and(circle < (radius + delta)**2, circle > (radius - delta)**2), 254, numpyImageInt) pilOutputImage = ImageOps.invert(Image.fromarray(numpyImageInt, 'L')) if height is not None and width is not None: pilOutputImage = pilOutputImage.resize((width, height), Image.ANTIALIAS) width, height = pilOutputImage.size for resolution, distance in listResolution: centreX = width / 2 centreY = height / 2 textfont = ImageFont.truetype( "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", int(height / 30), encoding="unic") resolutionText = "{0} Å".format(resolution) imageEditable = ImageDraw.Draw(pilOutputImage) newDistance = distance * (height + width) / 2.0 / math.sqrt(2) imageEditable.text((centreX + newDistance - width / 20, centreY + newDistance - height / 20), resolutionText, 0, font=textfont) if width * height > ImageFile.MAXBLOCK: ImageFile.MAXBLOCK = width * height if outputPath is None: if outputFileName is None: outputPath = os.path.join( workingDirectory, os.path.splitext(imageFileName)[0] + "." + suffix) else: outputPath = os.path.join(workingDirectory, outputFileName) pilOutputImage.save(outputPath, pilFormat, quality=85, optimize=True) logger.info("Output thumbnail path: %s" % outputPath) return outputPath
def tes_mergeCbfInDirectory(self): for number in range(8, 9): cbfDirectory = "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX{0}".format( number) UtilsImage.mergeCbfInDirectory(cbfDirectory)
def createHdf5HeaderData(cls, imagePath, skipNumberOfImages=False, hasOverlap=False, isFastMesh=True): h5MasterFilePath, h5DataFilePath, h5FileNumber = UtilsImage.getH5FilePath( pathlib.Path(imagePath), isFastMesh=isFastMesh, hasOverlap=hasOverlap) # Waiting for file timedOut, finalSize = UtilsPath.waitForFile(h5MasterFilePath, expectedSize=2000000, timeOut=DEFAULT_TIME_OUT) if timedOut: errorMessage = "Timeout when waiting for image %s" % imagePath logger.error(errorMessage) raise BaseException(errorMessage) logger.info("Final size for {0}: {1}".format(h5MasterFilePath, finalSize)) noTrialsLeft = 5 dictHeader = None while noTrialsLeft > 0: try: dictHeader = cls.readHdf5Header(h5MasterFilePath) noTrialsLeft = 0 except Exception as e: logger.warning( "Cannot read header from {0}, no trials left: {1}".format( h5MasterFilePath, noTrialsLeft)) time.sleep(5) noTrialsLeft -= 1 if dictHeader is None: raise RuntimeError( "Cannot read header from {0}!".format(h5MasterFilePath)) description = dictHeader["description"] if "Eiger 4M" in description: detectorName = "EIGER 4M" detectorType = "eiger4m" numberPixelX = 2070 numberPixelY = 2167 elif "eiger" in description.lower() and "16M" in description: detectorName = "EIGER 16M" detectorType = "eiger16m" numberPixelX = 4148 numberPixelY = 4362 else: raise RuntimeError( "{0} cannot read image header from images with detector type {1}" .format(cls.__class__.__name__, description)) # Image number image_number = UtilsImage.getImageNumber(imagePath) # Find out size of data set prefix = str(h5MasterFilePath).split("master")[0] listDataImage = [] noImages = 0 if not skipNumberOfImages: for data in dictHeader["data"]: dataFilePath = prefix + data + ".h5" timedOut, finalSize = UtilsPath.waitForFile( dataFilePath, expectedSize=100000, timeOut=DEFAULT_TIME_OUT) if timedOut: raise RuntimeError( "Timeout waiting for file {0}".format(dataFilePath)) # listDataImage.append({ # 'path': dataFilePath # }) f = h5py.File(dataFilePath, "r") dataShape = f["entry"]["data"]["data"].shape noImages += dataShape[0] f.close() experimentalCondition = {} # Pixel size and beam position detector = { "numberPixelX": int(numberPixelX), "numberPixelY": int(numberPixelY), "pixelSizeX": round(dictHeader["x_pixel_size"] * 1000, 3), "pixelSizeY": round(dictHeader["y_pixel_size"] * 1000, 3), "beamPositionX": round( float(dictHeader["beam_center_x"] * dictHeader["x_pixel_size"] * 1000), 3, ), "beamPositionY": round( float(dictHeader["beam_center_y"] * dictHeader["y_pixel_size"] * 1000), 3, ), "distance": round(float(dictHeader["detector_distance"]) * 1000, 3), "serialNumber": dictHeader["detector_number"], "name": detectorName, "type": detectorType, } experimentalCondition["detector"] = detector # Beam object beam = { "wavelength": round(float(dictHeader["wavelength"]), 6), "exposureTime": round(float(dictHeader["count_time"]), 6), } experimentalCondition["beam"] = beam # Goniostat object goniostat = {} rotationAxisStart = round(float(dictHeader["omega_start"]), 4) oscillationWidth = round(float(dictHeader["omega_range_average"]), 4) # Offset for the image number rotationAxisStart += (image_number - 1) * oscillationWidth goniostat["rotationAxisStart"] = rotationAxisStart goniostat["rotationAxisEnd"] = rotationAxisStart + oscillationWidth goniostat["oscillationWidth"] = oscillationWidth experimentalCondition["goniostat"] = goniostat # Create the image object image_dict = { "path": imagePath, "date": dictHeader["data_collection_date"], "number": 1, } # imageNumber = UtilsImage.getImageNumber(imagePath) # image['number'] = imageNumber subWedge = { "experimentalCondition": experimentalCondition, "image": [image_dict], } return subWedge
def createHdf5HeaderData(cls, imagePath, skipNumberOfImages=False, hasOverlap=False, isFastMesh=False): h5MasterFilePath, h5DataFilePath, h5FileNumber = UtilsImage.getH5FilePath( pathlib.Path(imagePath), isFastMesh=isFastMesh, hasOverlap=hasOverlap) # Waiting for file timedOut, finalSize = UtilsPath.waitForFile(h5MasterFilePath, expectedSize=100000, timeOut=DEFAULT_TIME_OUT) if timedOut: errorMessage = "Timeout when waiting for image %s" % imagePath logger.error(errorMessage) raise BaseException(errorMessage) dictHeader = cls.readHdf5Header(h5MasterFilePath) description = dictHeader['description'] if 'Eiger 4M' in description: detectorName = 'EIGER 4M' detectorType = 'eiger4m' numberPixelX = 2070 numberPixelY = 2167 else: raise RuntimeError( '{0} cannot read image header from images with detector type {1}' .format(cls.__class__.__name__, description)) # Find out size of data set prefix = str(h5MasterFilePath).split('master')[0] listDataImage = [] noImages = 0 if not skipNumberOfImages: for data in dictHeader['data']: dataFilePath = prefix + data + '.h5' timedOut, finalSize = UtilsPath.waitForFile( dataFilePath, expectedSize=1000000, timeOut=DEFAULT_TIME_OUT) if timedOut: raise RuntimeError( 'Timeout waiting for file {0}'.format(dataFilePath)) # listDataImage.append({ # 'path': dataFilePath # }) f = h5py.File(dataFilePath, 'r') dataShape = f['entry']['data']['data'].shape noImages += dataShape[0] f.close() experimentalCondition = {} # Pixel size and beam position detector = { 'numberPixelX': int(numberPixelX), 'numberPixelY': int(numberPixelY), 'pixelSizeX': round(dictHeader['x_pixel_size'] * 1000, 3), 'pixelSizeY': round(dictHeader['y_pixel_size'] * 1000, 3), 'beamPositionX': round( float(dictHeader['beam_center_x'] * dictHeader['x_pixel_size'] * 1000), 3), 'beamPositionY': round( float(dictHeader['beam_center_y'] * dictHeader['y_pixel_size'] * 1000), 3), 'distance': round(float(dictHeader['detector_distance']) * 1000, 3), 'serialNumber': dictHeader['detector_number'], 'name': detectorName, 'type': detectorType } experimentalCondition['detector'] = detector # Beam object beam = { 'wavelength': round(float(dictHeader['wavelength']), 6), 'exposureTime': round(float(dictHeader['count_time']), 6) } experimentalCondition['beam'] = beam # Goniostat object goniostat = {} rotationAxisStart = round(float(dictHeader['omega_start']), 4) oscillationWidth = round(float(dictHeader['omega_increment']), 4) goniostat['rotationAxisStart'] = rotationAxisStart goniostat[ 'rotationAxisEnd'] = rotationAxisStart + oscillationWidth * noImages goniostat['oscillationWidth'] = oscillationWidth experimentalCondition['goniostat'] = goniostat # Create the image object masterImage = { 'path': imagePath, 'date': dictHeader['data_collection_date'], 'number': 1 } # imageNumber = UtilsImage.getImageNumber(imagePath) # image['number'] = imageNumber subWedge = { 'experimentalCondition': experimentalCondition, 'image': [masterImage] + listDataImage } return subWedge
def test_getTemplateQuestionMark(self): template = UtilsImage.getTemplate(self.imageFileName, symbol="?") templateReference = "ref-testscale_1_????.img" self.assertEqual(templateReference, template)
def test_getTemplateHash2(self): template = UtilsImage.getTemplate(self.imageFileName2) templateReference = "ref-testscale_1_#####.img" self.assertEqual(templateReference, template)
def test_getImageNumber(self): imageNumber = UtilsImage.getImageNumber(self.imageFileName) self.assertEqual(imageNumber, 1)
def createCBFHeaderData(cls, imagePath): # Waiting for file timedOut, finalSize = UtilsPath.waitForFile(imagePath, expectedSize=100000, timeOut=DEFAULT_TIME_OUT) if timedOut: errorMessage = "Timeout when waiting for image %s" % imagePath logger.error(errorMessage) raise BaseException(errorMessage) dictHeader = cls.readCBFHeader(imagePath) detector = dictHeader["Detector:"] if ("PILATUS 3M" in detector or "PILATUS3 2M" in detector or "PILATUS 2M" in detector or "PILATUS2 3M" in detector): detectorName = "PILATUS2 3M" detectorType = "pilatus2m" numberPixelX = 1475 numberPixelY = 1679 elif "PILATUS 6M" in detector or "PILATUS3 6M" in detector: detectorName = "PILATUS2 6M" detectorType = "pilatus6m" numberPixelX = 2463 numberPixelY = 2527 elif "eiger" in detector.lower() and "4m" in detector.lower(): detectorName = "EIGER 4M" detectorType = "eiger4m" numberPixelX = 2070 numberPixelY = 2167 elif "eiger2" in detector.lower() and "16m" in detector.lower(): detectorName = "EIGER2 16M" detectorType = "eiger16m" numberPixelX = 4148 numberPixelY = 4362 else: raise RuntimeError( "{0} cannot read image header from images with dector type {1}" .format(cls.__class__.__name__, detector)) experimentalCondition = {} detector = {"numberPixelX": numberPixelX, "numberPixelY": numberPixelY} # Pixel size listPixelSizeXY = dictHeader["Pixel_size"].split(" ") detector["pixelSizeX"] = float(listPixelSizeXY[0]) * 1000 detector["pixelSizeY"] = float(listPixelSizeXY[3]) * 1000 # Beam position listBeamPosition = (dictHeader["Beam_xy"].replace("(", " ").replace( ")", " ").replace(",", " ").split()) detector["beamPositionX"] = float( listBeamPosition[0]) * detector["pixelSizeX"] detector["beamPositionY"] = float( listBeamPosition[1]) * detector["pixelSizeY"] distance = float(dictHeader["Detector_distance"].split(" ")[0]) * 1000 detector["distance"] = distance detector["serialNumber"] = dictHeader["Detector:"] detector["name"] = detectorName detector["type"] = detectorType experimentalCondition["detector"] = detector # Beam object beam = { "wavelength": float(dictHeader["Wavelength"].split(" ")[0]), "exposureTime": float(dictHeader["Exposure_time"].split(" ")[0]), } experimentalCondition["beam"] = beam # Goniostat object goniostat = {} rotationAxisStart = float(dictHeader["Start_angle"].split(" ")[0]) oscillationWidth = float(dictHeader["Angle_increment"].split(" ")[0]) goniostat["rotationAxisStart"] = rotationAxisStart goniostat["rotationAxisEnd"] = rotationAxisStart + oscillationWidth goniostat["oscillationWidth"] = oscillationWidth experimentalCondition["goniostat"] = goniostat # Create the image object image = {"path": imagePath} if "DateTime" in dictHeader: image["date"] = dictHeader["DateTime"] imageNumber = UtilsImage.getImageNumber(imagePath) image["number"] = imageNumber subWedge = { "experimentalCondition": experimentalCondition, "image": [image] } return subWedge
def test_getPrefix(self): prefix = UtilsImage.getPrefix(self.imageFileName) self.assertEqual(prefix, "ref-testscale_1")
def tes_mergeCbf(self): listPath = [ "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0001.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0002.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0003.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0004.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0005.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0006.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0007.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0008.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0009.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0010.cbf", ] outputPath = ( "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_3_0001.cbf" ) UtilsImage.mergeCbf(listPath, outputPath) listPath = [ "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0450.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0451.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0452.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0453.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0454.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0455.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0456.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0457.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0458.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0459.cbf", ] outputPath = ( "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_3_0002.cbf" ) UtilsImage.mergeCbf(listPath, outputPath) listPath = [ "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0900.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0901.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0902.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0903.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0904.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0905.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0906.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0907.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0908.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_0909.cbf", ] outputPath = ( "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_3_0003.cbf" ) UtilsImage.mergeCbf(listPath, outputPath) listPath = [ "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_1350.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_1351.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_1352.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_1353.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_1354.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_1355.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_1356.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_1357.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_1358.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_1359.cbf", ] outputPath = ( "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_3_0004.cbf" ) UtilsImage.mergeCbf(listPath, outputPath) listPath = [ "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_1800.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_1801.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_1802.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_1803.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_1804.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_1805.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_1806.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_1807.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_1808.cbf", "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_1_1809.cbf", ] outputPath = ( "/data/scisoft/pxsoft/data/EDNA2_INDEXING/id23eh1/EX1/PsPL7C-252_3_0005.cbf" ) UtilsImage.mergeCbf(listPath, outputPath)
def run(self, inData): # Format suffix format = inData.get("format", "jpeg") if format == "jpeg": thumbSuffix = ".jpeg" elif format == "jpg": thumbSuffix = ".jpg" else: raise RuntimeError("Unsupported format: {0}".format(format)) # Loop through all images listJPEGTask = [] listThumbTask = [] forcedOutputDirectory = inData.get("forcedOutputDirectory", None) for imagePath in inData["image"]: # Check image file extension imageFileName, suffix = os.path.splitext( os.path.basename(imagePath)) if not suffix in [".img", ".marccd", ".mccd", ".cbf", ".h5"]: raise RuntimeError( "Unknown image file name extension for pyarch thumbnail generator: %s" % imagePath) # Wait for image file if suffix == ".h5": h5MasterFilePath, h5DataFilePath, h5FileNumber = UtilsImage.getH5FilePath( imagePath, isFastMesh=True) waitFilePath = h5DataFilePath else: waitFilePath = imagePath expectedSize = self.getExpectedSize(imagePath) hasTimedOut, finalSize = UtilsPath.waitForFile( waitFilePath, expectedSize=expectedSize, timeOut=600) if hasTimedOut: raise RuntimeError( "Waiting for file {0} timed out!".format(imagePath)) outputFileName = imageFileName + thumbSuffix if forcedOutputDirectory is not None: outputPath = os.path.join(forcedOutputDirectory, outputFileName) else: outputPath = None # Create JPEG with resolution rings inDataReadHeader = { "imagePath": [imagePath], "skipNumberOfImages": True, "isFastMesh": True } readHeader = ReadImageHeader( inData=inDataReadHeader, workingDirectorySuffix=imageFileName, ) readHeader.execute() experimentalCondition = readHeader.outData["subWedge"][0][ "experimentalCondition"] detector = experimentalCondition["detector"] beam = experimentalCondition["beam"] inDataCreateJPEG = { "image": imagePath, "height": 1024, "width": 1024, "outputFileName": outputFileName, "outputPath": outputPath, "doResolutionRings": True, "pixelSizeX": detector["pixelSizeX"], "pixelSizeY": detector["pixelSizeY"], "beamPositionX": detector["beamPositionX"], "beamPositionY": detector["beamPositionY"], "distance": detector["distance"], "wavelength": beam["wavelength"], } createJPEG = CreateThumbnail(inData=inDataCreateJPEG, workingDirectorySuffix=imageFileName + "_JPEG") createJPEG.start() listJPEGTask.append(createJPEG) # Create thumbnail outputFileName = imageFileName + ".thumb" + thumbSuffix if forcedOutputDirectory is not None: outputPath = os.path.join(forcedOutputDirectory, outputFileName) else: outputPath = None inDataCreateThumb = { "image": imagePath, "height": 256, "width": 256, "outputFileName": outputFileName, "outputPath": outputPath, "doResolutionRings": True, "pixelSizeX": detector["pixelSizeX"], "pixelSizeY": detector["pixelSizeY"], "beamPositionX": detector["beamPositionX"], "beamPositionY": detector["beamPositionY"], "distance": detector["distance"], "wavelength": beam["wavelength"], } createThumb = CreateThumbnail( inData=inDataCreateThumb, workingDirectorySuffix=imageFileName + "_thumbnail") createThumb.start() listThumbTask.append(createThumb) outData = {"pathToJPEGImage": [], "pathToThumbImage": []} for task in listJPEGTask: task.join() if forcedOutputDirectory: outData["pathToJPEGImage"].append(task.outData["thumbNail"]) else: pyarchPath = self.copyThumbnailToPyarch(task) outData["pathToJPEGImage"].append(pyarchPath) for task in listThumbTask: task.join() if forcedOutputDirectory: outData["pathToThumbImage"].append(task.outData["thumbNail"]) else: pyarchPath = self.copyThumbnailToPyarch(task) outData["pathToThumbImage"].append(pyarchPath) return outData
def createCBFHeaderData(cls, imagePath): # Waiting for file timedOut, finalSize = UtilsPath.waitForFile(imagePath, expectedSize=100000, timeOut=DEFAULT_TIME_OUT) if timedOut: errorMessage = "Timeout when waiting for image %s" % imagePath logger.error(errorMessage) raise BaseException(errorMessage) dictHeader = cls.readCBFHeader(imagePath) detector = dictHeader['Detector:'] if 'PILATUS 3M' in detector or 'PILATUS3 2M' in detector or \ 'PILATUS 2M' in detector or 'PILATUS2 3M' in detector: detectorName = 'PILATUS2 3M' detectorType = 'pilatus2m' numberPixelX = 1475 numberPixelY = 1679 elif 'PILATUS 6M' in detector or 'PILATUS3 6M' in detector: detectorName = 'PILATUS2 6M' detectorType = 'pilatus6m' numberPixelX = 2463 numberPixelY = 2527 else: raise RuntimeError( '{0} cannot read image header from images with dector type {1}' .format(cls.__class__.__name__, detector)) experimentalCondition = {} detector = {'numberPixelX': numberPixelX, 'numberPixelY': numberPixelY} # Pixel size listPixelSizeXY = dictHeader['Pixel_size'].split(' ') detector['pixelSizeX'] = float(listPixelSizeXY[0]) * 1000 detector['pixelSizeY'] = float(listPixelSizeXY[3]) * 1000 # Beam position listBeamPosition = dictHeader['Beam_xy'].replace('(', ' ').replace( ')', ' ').replace(',', ' ').split() detector['beamPositionX'] = float(listBeamPosition[0]) * \ detector['pixelSizeX'] detector['beamPositionY'] = float(listBeamPosition[1]) * \ detector['pixelSizeY'] distance = float(dictHeader['Detector_distance'].split(' ')[0]) * 1000 detector['distance'] = distance detector['serialNumber'] = dictHeader['Detector:'] detector['name'] = detectorName detector['type'] = detectorType experimentalCondition['detector'] = detector # Beam object beam = { 'wavelength': float(dictHeader['Wavelength'].split(' ')[0]), 'exposureTime': float(dictHeader['Exposure_time'].split(' ')[0]) } experimentalCondition['beam'] = beam # Goniostat object goniostat = {} rotationAxisStart = float(dictHeader['Start_angle'].split(' ')[0]) oscillationWidth = float(dictHeader['Angle_increment'].split(' ')[0]) goniostat['rotationAxisStart'] = rotationAxisStart goniostat['rotationAxisEnd'] = rotationAxisStart + oscillationWidth goniostat['oscillationWidth'] = oscillationWidth experimentalCondition['goniostat'] = goniostat # Create the image object image = {'path': imagePath} if 'DateTime' in dictHeader: image['date'] = dictHeader['DateTime'] imageNumber = UtilsImage.getImageNumber(imagePath) image['number'] = imageNumber subWedge = { 'experimentalCondition': experimentalCondition, 'image': [image] } return subWedge
def generateMOSFLMInData(cls, inData): if "imagePath" in inData: inDataReadImageHeader = {"imagePath": inData["imagePath"]} readImageHeader = ReadImageHeader(inData=inDataReadImageHeader) readImageHeader.execute() listSubWedges = readImageHeader.outData["subWedge"] elif "subWedge" in inData: listSubWedges = inData["subWedge"] else: # Here we assume that we have inData in MOSFLM format... return inData firstSubWedge = listSubWedges[0] experimentalCondition = firstSubWedge["experimentalCondition"] detector = experimentalCondition["detector"] beam = experimentalCondition["beam"] goniostat = experimentalCondition["goniostat"] detectorType = detector["type"] if detectorType.startswith("pilatus"): mosflmDetector = "PILATUS" elif detectorType.startswith("eiger"): mosflmDetector = "EIGER" else: raise RuntimeError("Unknown detecor type for MOSFLM: " + detectorType) listImage = firstSubWedge["image"] firstImage = listImage[0] firstPath = firstImage["path"] mosflmInData = { # The MOSFLM beam position convention is opposite to the XDS / CBF/ Dozor convention "beam": { "x": detector["beamPositionY"], "y": detector["beamPositionX"] }, "detector": { "numberPixelX": detector["numberPixelX"], "numberPixelY": detector["numberPixelY"], "pixelSizeX": detector["pixelSizeX"], "pixelSizeY": detector["pixelSizeY"], "type": mosflmDetector }, "directory": os.path.dirname(firstPath), "distance": detector["distance"], "template": UtilsImage.getTemplate(firstPath), "wavelength": beam["wavelength"] } listMosflmImage = [] for subWedge in listSubWedges: goniostat = subWedge["experimentalCondition"]["goniostat"] rotationAxisStart = goniostat['rotationAxisStart'] oscillationWidth = goniostat['oscillationWidth'] imageIndex = 0 for image in subWedge["image"]: number = UtilsImage.getImageNumber(image["path"]) rotationAxisStart = rotationAxisStart + oscillationWidth * imageIndex rotationAxisEnd = rotationAxisStart + oscillationWidth mosflmImage = { "number": number, "rotationAxisStart": rotationAxisStart, "rotationAxisEnd": rotationAxisEnd } listMosflmImage.append(mosflmImage) mosflmInData["image"] = listMosflmImage return mosflmInData
def test_getPrefixH5(self): prefix = UtilsImage.getPrefix(self.imageFileNameH5) self.assertEqual(prefix, "mesh-local-user_0_1")
def generateImageLinks(in_data, working_directory=None): first_sub_wedge = in_data["subWedge"][0] first_image_path = first_sub_wedge["image"][0]["path"] prefix = UtilsImage.getPrefix(first_image_path) suffix = UtilsImage.getSuffix(first_image_path) if suffix == "h5": lowest_xds_image_number = 1 highest_xds_image_number = 1 h5MasterFilePath, h5DataFilePath, h5FileNumber = UtilsImage.getH5FilePath( first_image_path, hasOverlap=True, isFastMesh=False) h5MasterFile = os.path.basename((str(h5MasterFilePath))) h5DataFile = os.path.basename((str(h5DataFilePath))) list_image_link = [ [str(h5MasterFilePath), h5MasterFile], [str(h5DataFilePath), h5DataFile], ] if working_directory is not None: os.symlink(str(h5MasterFilePath), h5MasterFile) os.symlink(str(h5DataFilePath), h5DataFile) template = h5MasterFile.replace("master", "??????") lowest_xds_image_number = None highest_xds_image_number = None for subwedge in in_data["subWedge"]: image_list = subwedge["image"] for image_dict in image_list: image_path = image_dict["path"] image_number = UtilsImage.getImageNumber(image_path) if lowest_xds_image_number is None or lowest_xds_image_number > image_number: lowest_xds_image_number = image_number if highest_xds_image_number is None or highest_xds_image_number < image_number: highest_xds_image_number = image_number else: template = "%s_xdslink_?????.%s" % (prefix, suffix) xds_lowest_image_number_global = 1 # First we have to find the smallest goniostat rotation axis start: oscillation_start_min = 0 # Loop through the list of sub wedges list_of_list = [] lowest_xds_image_number = None highest_xds_image_number = None list_spot_range = [] for sub_wedge in in_data["subWedge"]: list_image_link = [] image_list = sub_wedge["image"] goniostat = sub_wedge["experimentalCondition"]["goniostat"] oscillation_start = goniostat["rotationAxisStart"] oscillation_range = goniostat["oscillationWidth"] # First find the lowest and highest image numbers lowest_image_number = None for image in image_list: image_number = image["number"] if lowest_image_number is None or image_number < lowest_image_number: lowest_image_number = image_number # Loop through the list of images spot_range_min = None spot_range_max = None for image in image_list: image_number = image["number"] image_oscillation_start = ( oscillation_start + (image_number - lowest_image_number) * oscillation_range) # if xdsLowestImageNumberGlobal is None: # xdsLowestImageNumberGlobal = 1 + int((imageOscillationStart - oscillationStartMin) / oscillationRange) xds_image_number = xds_lowest_image_number_global + int( (image_oscillation_start - oscillation_start_min) / oscillation_range + 0.5) print( xds_image_number, image_oscillation_start, oscillation_start_min, oscillation_range, ) source_path = image["path"] target = "%s_xdslink_%05d.%s" % (prefix, xds_image_number, suffix) print([source_path, target]) list_image_link.append([source_path, target]) if working_directory is not None and not os.path.exists( target): os.symlink(source_path, target) if (lowest_xds_image_number is None or lowest_xds_image_number > xds_image_number): lowest_xds_image_number = xds_image_number if (highest_xds_image_number is None or highest_xds_image_number < xds_image_number): highest_xds_image_number = xds_image_number if spot_range_min is None or spot_range_min > xds_image_number: spot_range_min = xds_image_number if spot_range_max is None or spot_range_max < xds_image_number: spot_range_max = xds_image_number list_spot_range.append([spot_range_min, spot_range_max]) list_of_list.append(list_image_link) previous_exclude_data_range_max = 1 list_exclude_data_range = [] for spot_range_min, spot_range_max in list_spot_range: if spot_range_min > previous_exclude_data_range_max + 1: list_exclude_data_range.append( [previous_exclude_data_range_max, spot_range_min - 1]) previous_exclude_data_range_max = spot_range_max + 1 dictImageLinks = { "imageLink": list_of_list, "spotRange": list_spot_range, "dataRange": [lowest_xds_image_number, highest_xds_image_number], "excludeDataRange": list_exclude_data_range, "template": template, } return dictImageLinks