def test_offset_px_mm_strategy(): from dxtbx.model import Panel from dxtbx.model import OffsetParallaxCorrectedPxMmStrategy from scitbx.array_family import flex # for future reference this is the array the same shape # as the image in pixels with offsets in pixels dx = flex.double(flex.grid(10, 10), 1) dy = flex.double(flex.grid(10, 10), 1) strategy = OffsetParallaxCorrectedPxMmStrategy(1, 1, dx, dy) p = Panel() p.set_image_size((10, 10)) p.set_mu(1) p.set_thickness(1) p.set_px_mm_strategy(strategy) d = p.to_dict() pnew = Panel.from_dict(d) assert pnew == p pnew = pickle.loads(pickle.dumps(pnew)) assert pnew == p
def run(self): from dxtbx.model import Panel from dxtbx.model import OffsetParallaxCorrectedPxMmStrategy from scitbx.array_family import flex import cPickle as pickle dx = flex.double(flex.grid(10, 10), 1) dy = flex.double(flex.grid(10, 10), 1) strategy = OffsetParallaxCorrectedPxMmStrategy(1, 1, dx, dy) p = Panel() p.set_image_size((10, 10)) p.set_mu(1) p.set_thickness(1) p.set_px_mm_strategy(strategy) d = p.to_dict() pnew = Panel.from_dict(d) assert pnew == p pnew = pickle.loads(pickle.dumps(pnew)) assert pnew == p print 'OK'
def get_optimized_detector(x, SIM): from dxtbx.model import Detector, Panel new_det = Detector() for pid in range(len(SIM.detector)): panel = SIM.detector[pid] panel_dict = panel.to_dict() group_id = SIM.panel_group_from_id[pid] if group_id in SIM.panel_groups_refined: Oang = x["group%d_RotOrth" % group_id].value Fang = x["group%d_RotFast" % group_id].value Sang = x["group%d_RotSlow" % group_id].value Xdist = x["group%d_ShiftX" % group_id].value Ydist = x["group%d_ShiftY" % group_id].value Zdist = x["group%d_ShiftZ" % group_id].value origin_of_rotation = SIM.panel_reference_from_id[pid] SIM.D.reference_origin = origin_of_rotation SIM.D.update_dxtbx_geoms(SIM.detector, SIM.beam.nanoBragg_constructor_beam, pid, Oang, Fang, Sang, Xdist, Ydist, Zdist, force=False) fdet = SIM.D.fdet_vector sdet = SIM.D.sdet_vector origin = SIM.D.get_origin() else: fdet = panel.get_fast_axis() sdet = panel.get_slow_axis() origin = panel.get_origin() panel_dict["fast_axis"] = fdet panel_dict["slow_axis"] = sdet panel_dict["origin"] = origin new_det.add_panel(Panel.from_dict(panel_dict)) return new_det
def get_multi_panel_eiger(detdist_mm=200, pixsize_mm=0.075, as_single_panel=False): """ :param detdist_mm: sample to detector in mm :param pixsize_mm: pix in mm :param as_single_panel: whether to return as just a large single panel camera :return: dxtbx detector """ # load a file specifying the gap positions # this is a 2D array # usually -1 is a gap, so you can create this array by doing # is_a_gap = np.array(eiger_image)==-1 (pseudo) is_a_gap = h5py.File("eiger_gaps.h5", "r")["is_a_gap"][()] # to view: #import pylab as plt #plt.imshow( is_a_gap) #plt.show() # its not perfect, some small regions are also flagged, we shall filter them though ydim, xdim = is_a_gap.shape center_x = xdim / 2. * pixsize_mm center_y = ydim / 2. * pixsize_mm master_panel_dict = { 'type': 'SENSOR_PAD', 'fast_axis': (1.0, 0.0, 0.0), 'slow_axis': (0.0, -1.0, 0.0), 'origin': (-center_x, center_y, -detdist_mm), 'raw_image_offset': (0, 0), 'image_size': (xdim, ydim), 'pixel_size': (pixsize_mm, pixsize_mm), # NOTE this will depend on your model 'trusted_range': (-1.0, 65535.0), 'thickness': 0.45, 'material': 'Si', 'mu': 3.969545947994824, 'identifier': '', 'mask': [], 'gain': 1.0, 'pedestal': 0.0, 'px_mm_strategy': { 'type': 'SimplePxMmStrategy' } } master_panel = Panel.from_dict(master_panel_dict) master_det = Detector() master_det.add_panel(master_panel) if as_single_panel: return master_det else: return panelize_eiger(master_det, is_a_gap)
def get_optimized_detector(x, ref_params, SIM): new_det = Detector() for pid in range(len(SIM.detector)): panel = SIM.detector[pid] panel_dict = panel.to_dict() group_id = SIM.panel_group_from_id[pid] if group_id in SIM.panel_groups_refined: Oang_p = ref_params["group%d_RotOrth" % group_id] Fang_p = ref_params["group%d_RotFast" % group_id] Sang_p = ref_params["group%d_RotSlow" % group_id] Xdist_p = ref_params["group%d_ShiftX" % group_id] Ydist_p = ref_params["group%d_ShiftY" % group_id] Zdist_p = ref_params["group%d_ShiftZ" % group_id] Oang = Oang_p.get_val(x[Oang_p.xpos]) Fang = Fang_p.get_val(x[Fang_p.xpos]) Sang = Sang_p.get_val(x[Sang_p.xpos]) Xdist = Xdist_p.get_val(x[Xdist_p.xpos]) Ydist = Ydist_p.get_val(x[Ydist_p.xpos]) Zdist = Zdist_p.get_val(x[Zdist_p.xpos]) origin_of_rotation = SIM.panel_reference_from_id[pid] SIM.D.reference_origin = origin_of_rotation SIM.D.update_dxtbx_geoms(SIM.detector, SIM.beam.nanoBragg_constructor_beam, pid, Oang, Fang, Sang, Xdist, Ydist, Zdist, force=False) fdet = SIM.D.fdet_vector sdet = SIM.D.sdet_vector origin = SIM.D.get_origin() else: fdet = panel.get_fast_axis() sdet = panel.get_slow_axis() origin = panel.get_origin() panel_dict["fast_axis"] = fdet panel_dict["slow_axis"] = sdet panel_dict["origin"] = origin new_det.add_panel(Panel.from_dict(panel_dict)) return new_det
def downsample_detector(det, downsamp=1): newD = Detector() for panel in det: fast = panel.get_fast_axis() slow = panel.get_slow_axis() orig = panel.get_origin() panel_dict = panel.to_dict() panel_dict['fast'] = fast panel_dict['slow'] = slow panel_dict['origin'] = orig fast_dim, slow_dim = panel.get_image_size() panel_dict['image_size'] = int(fast_dim / float(downsamp)), int( slow_dim / float(downsamp)) pixsize = panel.get_pixel_size()[0] panel_dict['pixel_size'] = pixsize * downsamp, pixsize * downsamp newpanel = Panel.from_dict(panel_dict) newD.add_panel(newpanel) return newD
def panelize_eiger(eiger_dxtbx_model, is_a_gap): """ :param eiger_dxtbx_model: dxtbx geometry for the eiger (single node model) :param is_a_gap: a 2D numpy array the same shape as the eiger image (4371, 4150) True means the pixel is a gap, False means the pixel is a mask Make this by loading an eiger image and selecting all pixels that are equal to -1 is_a_gap = np.array(eiger_image)==-1 :return: dxtbx multi panel model for eiger 16M """ multiEiger = Detector() # we will make a new detector where wach panel has its own origin, but all share the same fast,slow scan directions detector_origin = np.array(eiger_dxtbx_model[0].get_origin()) F = np.array(eiger_dxtbx_model[0].get_fast_axis()) S = np.array(eiger_dxtbx_model[0].get_slow_axis()) pixsize = eiger_dxtbx_model[0].get_pixel_size()[0] panel_dict = eiger_dxtbx_model[0].to_dict() is_a_panel = np.logical_not(is_a_gap) labs, nlabs = label(is_a_panel) for i in range(nlabs + 1): region = labs == i npixels = np.sum(region) # there might be some other connected regions that are not panels (bad regions for example) if 200000 < npixels < 530000: # panel size is 529420 pixels, I think ypos, xpos = np.where(region) jmin, imin = min(ypos), min( xpos) # location of first pixel in the region jmax, imax = max(ypos), max(xpos) panel_shape = (int(imax - imin), int(jmax - jmin)) panel_origin = detector_origin + F * imin * pixsize + S * jmin * pixsize panel_dict["origin"] = tuple(panel_origin) panel_dict["image_size"] = panel_shape panel = Panel.from_dict(panel_dict) multiEiger.add_panel(panel) return multiEiger
def test_offset_px_mm_strategy(): # for future reference this is the array the same shape # as the image in pixels with offsets in pixels dx = flex.double(flex.grid(10, 10), 1) dy = flex.double(flex.grid(10, 10), 1) strategy = OffsetParallaxCorrectedPxMmStrategy(1, 1, dx, dy) p = Panel() p.set_image_size((10, 10)) p.set_mu(1) p.set_thickness(1) p.set_px_mm_strategy(strategy) d = p.to_dict() # Panel.from_dict sets the strategy to ParallaxCorrectedPxMmStrategy rather than # OffsetParallaxCorrectedPxMmStrategy as the offsets aren't currently serialized pnew = Panel.from_dict(d) assert pnew != p pnew = pickle.loads(pickle.dumps(pnew)) assert pnew != p
from dxtbx.model import Panel for i_shift, delta_shift in enumerate(shifts_mm): # update the detector model if args.panel == "x": shifted = OX + delta_shift, OY, OZ elif args.panel == "y": shifted = OX, OY + delta_shift, OZ else: delta_shift = delta_shift * 10 # larger shift for Z shifted = OX, OY, OZ + delta_shift node_d["origin"] = shifted det[0] = Panel.from_dict(node_d) D.update_dxtbx_geoms(det, B, 0) D.add_diffBragg_spots() img_forward = D.raw_pixels_roi.as_numpy_array() D.raw_pixels_roi *= 0 D.raw_pixels *= 0 delta_shift_meters = delta_shift * 1e-3 fdiff = (img_forward - img) / delta_shift_meters bragg = img > 1e-2 error = (np.abs(fdiff[bragg] - deriv[bragg])).mean() all_errors.append(error) all_shifts.append(delta_shift_meters)
def update_detector(x, ref_params, SIM, save=None): """ Update the internal geometry of the diffBragg instance :param x: refinement parameters as seen by scipy.optimize (e.g. rescaled floats) :param ref_params: diffBragg.refiners.Parameters (dict of RangedParameters) :param SIM: SIM instance (instance of nanoBragg.sim_data.SimData) :param save: optional name to save the detector """ det = SIM.detector if save is not None: new_det = Detector() for pid in range(len(det)): panel = det[pid] panel_dict = panel.to_dict() group_id = SIM.panel_group_from_id[pid] if group_id not in SIM.panel_groups_refined: fdet = panel.get_fast_axis() sdet = panel.get_slow_axis() origin = panel.get_origin() else: Oang_p = ref_params["group%d_RotOrth" % group_id] Fang_p = ref_params["group%d_RotFast" % group_id] Sang_p = ref_params["group%d_RotSlow" % group_id] Xdist_p = ref_params["group%d_ShiftX" % group_id] Ydist_p = ref_params["group%d_ShiftY" % group_id] Zdist_p = ref_params["group%d_ShiftZ" % group_id] Oang = Oang_p.get_val(x[Oang_p.xpos]) Fang = Fang_p.get_val(x[Fang_p.xpos]) Sang = Sang_p.get_val(x[Sang_p.xpos]) Xdist = Xdist_p.get_val(x[Xdist_p.xpos]) Ydist = Ydist_p.get_val(x[Ydist_p.xpos]) Zdist = Zdist_p.get_val(x[Zdist_p.xpos]) origin_of_rotation = SIM.panel_reference_from_id[pid] SIM.D.reference_origin = origin_of_rotation SIM.D.update_dxtbx_geoms(det, SIM.beam.nanoBragg_constructor_beam, pid, Oang, Fang, Sang, Xdist, Ydist, Zdist, force=False) fdet = SIM.D.fdet_vector sdet = SIM.D.sdet_vector origin = SIM.D.get_origin() if save is not None: panel_dict["fast_axis"] = fdet panel_dict["slow_axis"] = sdet panel_dict["origin"] = origin new_det.add_panel(Panel.from_dict(panel_dict)) if save is not None and COMM.rank == 0: t = time.time() El = ExperimentList() E = Experiment() E.detector = new_det El.append(E) El.as_file(save) t = time.time() - t print("Saved detector model to %s (took %.4f sec)" % (save, t), flush=True)
def convert_crystfel_to_dxtbx(geom_filename, output_filename, detdist_override=None): """ :param geom_filename: a crystfel geometry file https://www.desy.de/~twhite/crystfel/manual-crystfel_geometry.html :param output_filename: filename for a dxtbx experiment containing a single detector model (this is a json file) :param detdist_override: alter the detector distance stored in the crystfel geometry to this value (in millimeters) """ geom = load_crystfel_geometry(geom_filename) dxtbx_det = Detector() for panel_name in geom['panels'].keys(): P = geom['panels'][panel_name] FAST = P['fsx'], P['fsy'], P['fsz'] SLOW = P['ssx'], P['ssy'], P['ssz'] # dxtbx uses millimeters pixsize = 1 / P['res'] # meters pixsize_mm = pixsize * 1000 detdist = P['coffset'] + P['clen'] # meters detdist_mm = detdist * 1000 if detdist_override is not None: detdist_mm = detdist_override # dxtbx and crystfel both identify the outer corner of the first pixel in memory as the origin of the panel origin = P['cnx'] * pixsize_mm, P[ 'cny'] * pixsize_mm, -detdist_mm # dxtbx assumes crystal as at point 0,0,0 num_fast_pix = P["max_fs"] - P['min_fs'] + 1 num_slow_pix = P["max_ss"] - P['min_ss'] + 1 panel_description = { 'fast_axis': FAST, 'gain': 1.0, # I dont think nanoBragg cares about this parameter 'identifier': '', 'image_size': (num_fast_pix, num_slow_pix), 'mask': [], 'material': 'Si', 'mu': 0, # NOTE for a thick detector set this to appropriate value 'name': panel_name, 'origin': origin, 'pedestal': 0.0, # I dont think nanoBragg cares about this parameter 'pixel_size': (pixsize_mm, pixsize_mm), 'px_mm_strategy': { 'type': 'SimplePxMmStrategy' }, 'raw_image_offset': (0, 0), # not sure what this is 'slow_axis': SLOW, 'thickness': 0, # note for a thick detector set this to appropriate value 'trusted_range': (-1.0, 1e6), # set as you wish 'type': 'SENSOR_PAD' } dxtbx_node = Panel.from_dict(panel_description) dxtbx_det.add_panel(dxtbx_node) E = Experiment() E.detector = dxtbx_det El = ExperimentList() El.append(E) El.as_file(output_filename) # this can be loaded into nanoBragg