def tst_beam_plane_intersection(): from dxtbx.model import Panel from scitbx import matrix # The input parameters (from a GXPARM.XDS file) fast_axis = (0.000000, -0.939693, -0.342020) slow_axis = (1.000000, 0.000000, 0.000000) normal = (0.000000, -0.342020, 0.939693) pixel_size = (0.172000, 0.172000) pixel_origin = (244.836136, 320.338531) image_size = (487, 619) distance = 122.124901 wavelength = 0.689400 # Calculate the vector to the detector (0, 0) pixel origin = ((matrix.col(fast_axis).normalize() * pixel_size[0]) * (0 - pixel_origin[0]) + (matrix.col(slow_axis).normalize() * pixel_size[1]) * (0 - pixel_origin[1]) + (distance * matrix.col(normal).normalize())) # Create a detector object panel = Panel("", "", fast_axis, slow_axis, origin, pixel_size, image_size, (0, 0), 0.0, "") # Create the intersection object intersection = lambda x: panel.get_ray_intersection(x) # Perform a load of tests tst_intersection_at_origin(intersection, wavelength, origin) tst_intersection_at_corners(intersection, panel, wavelength) tst_intersection_away_from_panel(intersection, panel, wavelength)
def tst_panel(): '''Test pickling the panel object.''' obj1 = Panel() obj1.set_local_frame((1, 0, 0), (0, 1, 0), (0, 0, 1)) obj2 = pickle_then_unpickle(obj1) assert(obj1 == obj2) print "OK"
def tst_panel(): '''Test pickling the panel object.''' obj1 = Panel() obj1.set_local_frame((1, 0, 0), (0, 1, 0), (0, 0, 1)) obj2 = pickle_then_unpickle(obj1) assert (obj1 == obj2) print "OK"
def tst_forward_and_reverse_transform(): from dxtbx.model import Panel from scitbx import matrix # The input parameters (from a GXPARM.XDS file) fast_axis = (0.000000, -0.939693, -0.342020) slow_axis = (1.000000, 0.000000, 0.000000) normal = (0.000000, -0.342020, 0.939693) pixel_size = (0.172000, 0.172000) pixel_origin = (244.836136, 320.338531) image_size = (487, 619) distance = 122.124901 wavelength = 0.689400 # Calculate the vector to the detector (0, 0) pixel origin = ((matrix.col(fast_axis).normalize() * pixel_size[0]) * (0 - pixel_origin[0]) + (matrix.col(slow_axis).normalize() * pixel_size[1]) * (0 - pixel_origin[1]) + (distance * matrix.col(normal).normalize())) # Create a detector object panel = Panel("", "", fast_axis, slow_axis, origin, pixel_size, image_size, (0, 0), 0.0, "") # Create the intersection object and transform object intersection = lambda x: panel.get_ray_intersection(x) transform = lambda x: panel.get_lab_coord(x) # Do a test tst_fwd_rev_random(intersection, transform, panel)
def test_detector(): '''Test pickling the detector object.''' p = Panel() p.set_local_frame((1, 0, 0), (0, 1, 0), (0, 0, 1)) obj1 = Detector(p) obj2 = pickle_then_unpickle(obj1) assert obj1 == obj2
def test_panel_mask(): panel = Panel() panel.set_image_size((100, 100)) panel.add_mask(40, 0, 60, 100) panel.add_mask(0, 40, 100, 60) panel.set_trusted_range((-1, 10)) data = flex.double(flex.grid(100, 100)) data[10, 10] = -1 data[20, 20] = 10 data[30, 30] = 100 data[40, 40] = -10 m1 = panel.get_untrusted_rectangle_mask() m2 = panel.get_trusted_range_mask(data) count = 0 for j in range(100): for i in range(40, 60): assert m1[j, i] is False count += 1 for i in range(100): for j in range(40, 60): if i >= 40 and i < 60: continue assert m1[j, i] is False count += 1 assert m1.count(False) == count, "%d, %d" % (m1.count(False), count) assert m2.count(False) == 4 assert m2[10, 10] is False assert m2[20, 20] is False assert m2[30, 30] is False assert m2[40, 40] is False
def tst_detector(): '''Test pickling the detector object.''' p = Panel() p.set_local_frame((1, 0, 0), (0, 1, 0), (0, 0, 1)) obj1 = Detector(p) obj2 = pickle_then_unpickle(obj1) assert(obj1 == obj2) print "OK"
def test_hierarchical_detector(): '''Test pickling the detector object.''' p = Panel() p.set_local_frame((1, 0, 0), (0, 1, 0), (0, 0, 1)) obj1 = Detector() root = obj1.hierarchy() root.add_panel(p) root.add_group() obj2 = pickle_then_unpickle(obj1) assert obj2.hierarchy()[0] == obj2[0] assert obj2.hierarchy()[0] in obj2 assert obj2.hierarchy()[1].is_group() assert obj1 == obj2
def tst_hierarchical_detector(): '''Test pickling the detector object.''' p = Panel() p.set_local_frame((1, 0, 0), (0, 1, 0), (0, 0, 1)) obj1 = Detector() root = obj1.hierarchy() root.add_panel(p) root.add_group() obj2 = pickle_then_unpickle(obj1) assert(obj2.hierarchy()[0] == obj2[0]) assert(obj2.hierarchy()[0] in obj2) assert(obj2.hierarchy()[1].is_group()) assert(obj1 == obj2) 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 tst_set_models(imageset): # Create some other models beam = Beam((1, 0, 0), 0.5) detector = Detector( Panel( "UNKNOWN", "Panel", (1, 0, 0), (0, 1, 0), (0, 0, 1), (0.1, 0.1), (1000, 1000), (0, 1), )) # Override sequence models imageset.set_beam(beam) imageset.set_detector(detector) # Ensure this doens't interfere with reading for i in imageset: pass # Get the models back and check they're ok beam2 = imageset.get_beam() detector2 = imageset.get_detector() assert beam2 == beam assert detector2 == detector # Get the models from an index back and check they're not the same beam2 = imageset.get_beam(0) detector2 = imageset.get_detector(0) assert beam2 != beam assert detector2 != detector
def test_parallax_correction(): # Attenuation length table = attenuation_coefficient.get_table("Si") mu = table.mu_at_angstrom(1) / 10.0 t0 = 0.320 # Create the detector detector = Detector( Panel( "", # Type "", # Name (10, 0, 0), # Fast axis (0, 10, 0), # Slow axis (0, 0, 200), # Origin (0.172, 0.172), # Pixel size (512, 512), # Image size (0, 1000), # Trusted range 0.0, # Thickness "", # Material ParallaxCorrectedPxMmStrategy(mu, t0), ) ) for i in range(10000): mm = (random.uniform(-1000, 1000), random.uniform(-1000, 1000)) px = detector[0].millimeter_to_pixel(mm) mm2 = detector[0].pixel_to_millimeter(px) assert abs(matrix.col(mm) - matrix.col(mm2)) < 1e-3
def create_multipanel_detector(offset, ncols=3, nrows=2): reference_detector = create_detector(offset) reference_panel = reference_detector[0] panel_npix = reference_panel.get_image_size() panel_npix = int(panel_npix[0] / ncols), int(panel_npix[1] / nrows) multi_panel_detector = Detector() for i in range(ncols): for j in range(nrows): origin_pix = i * panel_npix[0], j * panel_npix[1] origin = reference_panel.get_pixel_lab_coord(origin_pix) new_panel = Panel( reference_panel.get_type(), reference_panel.get_name() + str(j + i * nrows), reference_panel.get_fast_axis(), reference_panel.get_slow_axis(), origin, reference_panel.get_pixel_size(), panel_npix, reference_panel.get_trusted_range(), reference_panel.get_thickness(), reference_panel.get_material(), identifier=reference_panel.get_identifier(), ) multi_panel_detector.add_panel(new_panel) return multi_panel_detector
def make_panel_in_array(array_elt, reference_panel): """Helper function to make a panel in a coplanar array with each panel size 1/3 that of a reference panel""" px_size = tuple((e / 3.0) for e in reference_panel.get_pixel_size()) ref_panel_size = reference_panel.get_image_size_mm() x_shift = array_elt[0] * ref_panel_size[0] / 3.0 y_shift = array_elt[1] * ref_panel_size[1] / 3.0 origin = ( matrix.col(reference_panel.get_origin()) + x_shift * matrix.col(reference_panel.get_fast_axis()) + y_shift * matrix.col(reference_panel.get_slow_axis()) ) return Panel( type="PAD", name="Panel", fast_axis=reference_panel.get_fast_axis(), slow_axis=reference_panel.get_slow_axis(), origin=origin, pixel_size=px_size, image_size=reference_panel.get_image_size(), trusted_range=(0, 1.0e6), thickness=0.0, material="", )
def test_plane_to_lab_transform(): from dxtbx.model import Panel # The input parameters (from a GXPARM.XDS file) fast_axis = (0.000000, -0.939693, -0.342020) slow_axis = (1.000000, 0.000000, 0.000000) normal = (0.000000, -0.342020, 0.939693) pixel_size = (0.172000, 0.172000) pixel_origin = (244.836136, 320.338531) image_size = (487, 619) distance = 122.124901 # Calculate the vector to the detector (0, 0) pixel origin = ((matrix.col(fast_axis).normalize() * pixel_size[0]) * (0 - pixel_origin[0]) + (matrix.col(slow_axis).normalize() * pixel_size[1]) * (0 - pixel_origin[1]) + (distance * matrix.col(normal).normalize())) # Create a detector object panel = Panel("", "", fast_axis, slow_axis, origin, pixel_size, image_size, (0, 0), 0.0, "") # Create the intersection object transform = panel.get_lab_coord # Perform a load of tests tst_transform_at_origin(transform, panel) tst_transform_at_corners(transform, panel)
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 create_detector(offset=0): # Create the detector detector = Detector( Panel( "", # Type "Panel", # Name (10, 0, 0), # Fast axis (0, 10, 0), # Slow axis (0 + offset, 0 + offset, 200 - offset), # Origin (0.172, 0.172), # Pixel size (512, 512), # Image size (0, 1000), # Trusted range 0.1, # Thickness "Si", # Material identifier="123")) # Identifier return detector
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 random_panel(lim=(0, 50)): """For testing, return a square panel with a randomised position and orientation""" # start with a randomised origin vector o = matrix.col( ( random.uniform(-200, 200), random.uniform(-200, 200), random.uniform(-200, 200), ) ) # two orthogonal unit vectors randomly oriented in the normal plane # of the origin vector u1 = o.ortho().normalize() u2 = o.cross(u1).normalize() # theta = random.uniform(0, 2. * pi) u1 = u1.rotate_around_origin(o, pi / 12) u2 = u2.rotate_around_origin(o, pi / 12) # offset the plane normal from the origin vector by random rotations # of up to 45 degrees for each direction u1 = u1.rotate_around_origin(u2, random.uniform(-pi / 2.0, pi / 2.0)) u2 = u2.rotate_around_origin(u1, random.uniform(-pi / 2.0, pi / 2.0)) return Panel( "PAD", "Panel", u1, u2, o, (lim[1] / 200, lim[1] / 200), (200, 200), (0, 2e20), 0.0, "", )
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 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
def test_detector(): from dxtbx.model import ParallaxCorrectedPxMmStrategy def create_detector(offset=0): # Create the detector detector = Detector( Panel( "", # Type "Panel", # Name (10, 0, 0), # Fast axis (0, 10, 0), # Slow axis (0 + offset, 0 + offset, 200 - offset), # Origin (0.172, 0.172), # Pixel size (512, 512), # Image size (0, 1000), # Trusted range 0.1, # Thickness "Si", # Material identifier="123")) # Identifier return detector detector = create_detector() # Perform some tests tst_get_identifier(detector) tst_get_gain(detector) tst_set_mosflm_beam_centre(detector) tst_get_pixel_lab_coord(detector) tst_get_image_size_mm(detector) tst_is_value_in_trusted_range(detector) tst_is_coord_valid(detector) tst_pixel_to_millimeter_to_pixel(detector) tst_get_names(detector) tst_get_thickness(detector) tst_get_material(detector) tst_resolution(detector) tst_panel_mask() # Attenuation length from cctbx.eltbx import attenuation_coefficient table = attenuation_coefficient.get_table("Si") mu = table.mu_at_angstrom(1) / 10.0 t0 = 0.320 # Create another detector with different origin detector_moved = create_detector(offset=100) tst_detectors_are_different(detector, detector_moved) detector_moved_copy = create_detector(offset=100) tst_detectors_are_same(detector_moved, detector_moved_copy) # Create the detector detector = Detector( Panel( "", # Type "", # Name (10, 0, 0), # Fast axis (0, 10, 0), # Slow axis (0, 0, 200), # Origin (0.172, 0.172), # Pixel size (512, 512), # Image size (0, 1000), # Trusted range 0.0, # Thickness "", # Material ParallaxCorrectedPxMmStrategy(mu, t0))) tst_parallax_correction(detector)
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 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)
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 test_panel(): """Test pickling the panel object.""" obj1 = Panel() obj1.set_local_frame((1, 0, 0), (0, 1, 0), (0, 0, 1)) obj2 = pickle_then_unpickle(obj1) assert obj1 == obj2
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() pnew = Panel.from_dict(d) assert pnew == p pnew = pickle.loads(pickle.dumps(pnew)) assert pnew == p
def _setup_detector(self, detector, beam): nx_detector = detector.handle nx_module = detector.modules[0].handle # Get the detector name and type if "type" in nx_detector: detector_type = str(nx_detector["type"][()]) else: detector_type = "unknown" detector_name = str(nx_detector.name) # Get the trusted range of pixel values if "saturation_value" in nx_detector: trusted_range = (-1, float(nx_detector["saturation_value"][()])) else: trusted_range = (-1, 99999999) # Get the detector thickness thickness = nx_detector["sensor_thickness"] thickness_value = float(thickness[()]) thickness_units = thickness.attrs["units"] thickness_value = float(convert_units(thickness_value, thickness_units, "mm")) # Get the detector material material = nx_detector["sensor_material"][()] if hasattr(material, "shape"): material = "".join(m.decode() for m in material) detector_material = clean_string(str(material)) material = { "Si": "Si", np.string_("Si"): "Si", np.string_("Silicon"): "Si", np.string_("Sillicon"): "Si", np.string_("CdTe"): "CdTe", np.string_("GaAs"): "GaAs", }.get(detector_material) if not material: raise RuntimeError("Unknown material: %s" % detector_material) try: x_pixel = nx_detector["x_pixel_size"][()] * 1000.0 y_pixel = nx_detector["y_pixel_size"][()] * 1000.0 legacy_beam_x = float(x_pixel * nx_detector["beam_center_x"][()]) legacy_beam_y = float(y_pixel * nx_detector["beam_center_y"][()]) legacy_distance = float(1000 * nx_detector["detector_distance"][()]) except KeyError: legacy_beam_x = 0 legacy_beam_y = 0 # Get the fast pixel size and vector fast_pixel_direction = nx_module["fast_pixel_direction"] fast_pixel_direction_value = float(fast_pixel_direction[()]) fast_pixel_direction_units = fast_pixel_direction.attrs["units"] fast_pixel_direction_vector = fast_pixel_direction.attrs["vector"] fast_pixel_direction_value = convert_units( fast_pixel_direction_value, fast_pixel_direction_units, "mm" ) fast_axis = matrix.col(fast_pixel_direction_vector).normalize() # Get the slow pixel size and vector slow_pixel_direction = nx_module["slow_pixel_direction"] slow_pixel_direction_value = float(slow_pixel_direction[()]) slow_pixel_direction_units = slow_pixel_direction.attrs["units"] slow_pixel_direction_vector = slow_pixel_direction.attrs["vector"] slow_pixel_direction_value = convert_units( slow_pixel_direction_value, slow_pixel_direction_units, "mm" ) slow_axis = matrix.col(slow_pixel_direction_vector).normalize() origin = matrix.col((0.0, 0.0, -legacy_distance)) if origin.elems[0] == 0.0 and origin.elems[1] == 0: origin = -(origin + legacy_beam_x * fast_axis + legacy_beam_y * slow_axis) # Change of basis to convert from NeXus to IUCr/ImageCIF convention cob = matrix.sqr((-1, 0, 0, 0, 1, 0, 0, 0, -1)) origin = cob * matrix.col(origin) fast_axis = cob * fast_axis slow_axis = cob * slow_axis # Ensure that fast and slow axis are orthogonal normal = fast_axis.cross(slow_axis) slow_axis = -fast_axis.cross(normal) # Compute the attenuation coefficient. # This will fail for undefined composite materials # mu_at_angstrom returns cm^-1, but need mu in mm^-1 table = attenuation_coefficient.get_table(material) wavelength = beam.get_wavelength() mu = table.mu_at_angstrom(wavelength) / 10.0 # Construct the detector model pixel_size = (fast_pixel_direction_value, slow_pixel_direction_value) # image size stored slow to fast but dxtbx needs fast to slow image_size = tuple(int(x) for x in reversed(nx_module["data_size"][-2:])) image_size = (1030, 1064) self.model = Detector() self.model.add_panel( Panel( detector_type, detector_name, tuple(fast_axis), tuple(slow_axis), tuple(origin), pixel_size, image_size, trusted_range, thickness_value, material, mu, ) ) # Set the parallax correction for panel in self.model: panel.set_px_mm_strategy(ParallaxCorrectedPxMmStrategy(mu, thickness_value)) panel.set_type("SENSOR_PAD") self._detector_model = self.model
def __init__(self, obj, beam): from dxtbx.model import Detector, Panel from cctbx.eltbx import attenuation_coefficient from dxtbx.model import ParallaxCorrectedPxMmStrategy from scitbx import matrix # Get the handles nx_file = obj.handle.file nx_detector = obj.handle nx_module = obj.modules[0].handle # Get the detector name and type detector_type = str(nx_detector['type'][()]) detector_name = str(nx_detector.name) # Get the trusted range of pixel values trusted_range = (-1, float(nx_detector['saturation_value'][()])) # Get the detector thickness thickness = nx_detector['sensor_thickness'] thickness_value = float(thickness[()]) thickness_units = thickness.attrs['units'] thickness_value = float( convert_units(thickness_value, thickness_units, "mm")) # Get the detector material material = str(nx_detector['sensor_material'][()]) # Get the fast pixel size and vector fast_pixel_direction = nx_module['fast_pixel_direction'] fast_pixel_direction_value = float(fast_pixel_direction[()]) fast_pixel_direction_units = fast_pixel_direction.attrs['units'] fast_pixel_direction_vector = fast_pixel_direction.attrs['vector'] fast_pixel_direction_value = convert_units(fast_pixel_direction_value, fast_pixel_direction_units, "mm") fast_axis = matrix.col(fast_pixel_direction_vector).normalize() # Get the slow pixel size and vector slow_pixel_direction = nx_module['slow_pixel_direction'] slow_pixel_direction_value = float(slow_pixel_direction[()]) slow_pixel_direction_units = slow_pixel_direction.attrs['units'] slow_pixel_direction_vector = slow_pixel_direction.attrs['vector'] slow_pixel_direction_value = convert_units(slow_pixel_direction_value, slow_pixel_direction_units, "mm") slow_axis = matrix.col(slow_pixel_direction_vector).normalize() # Get the origin vector module_offset = nx_module['module_offset'] origin = construct_vector(nx_file, module_offset.name) # Ensure that fast and slow axis are orthogonal normal = fast_axis.cross(slow_axis) slow_axis = -fast_axis.cross(normal) # Compute the attenuation coefficient. # This will fail for undefined composite materials # mu_at_angstrom returns cm^-1, but need mu in mm^-1 if material == 'Si': pass elif material == 'Silicon': material = 'Si' elif material == 'Sillicon': material = 'Si' elif material == 'CdTe': pass elif material == 'GaAs': pass else: raise RuntimeError('Unknown material: %s' % material) table = attenuation_coefficient.get_table(material) wavelength = beam.get_wavelength() mu = table.mu_at_angstrom(wavelength) / 10.0 # Construct the detector model pixel_size = (fast_pixel_direction_value, slow_pixel_direction_value) image_size = tuple(map(int, nx_module['data_size'])) self.model = Detector() self.model.add_panel( Panel(detector_type, detector_name, tuple(fast_axis), tuple(slow_axis), tuple(origin), pixel_size, image_size, trusted_range, thickness_value, material, mu)) # Set the parallax correction for panel in self.model: panel.set_px_mm_strategy( ParallaxCorrectedPxMmStrategy(mu, thickness_value)) panel.set_type('SENSOR_PAD')
dl = (-0.001825172553060027, -0.9999981947571188, -37.76001244640159, 0.9999973206373582, -0.0018259228624977202, 19.59161224494454, -0.0014238901839527113, -0.0005258214562373528, -150.0059) dl1 = dl[0], dl[3], dl[6] dl2 = dl[1], dl[4], dl[7] dl0 = dl[2], dl[5], dl[8] dp1 = dp[0], dp[3], dp[6] dp2 = dp[1], dp[4], dp[7] dp0 = dp[2], dp[5], dp[8] d1 = (-0.00182517255306, 0.999997320637, -0.00142389018396) d2 = (0.999998194757, 0.0018259228625, 0.000525821456245) d0 = (-48.3367467929, -1.3827137802, -149.981643976) p = Panel() p.set_parent_frame(dp1, dp2, dp0) p.set_local_frame(dl1, dl2, dl0) p.set_frame(d1, d2, d0) #print repr([10000000000*pp for pp in p.get_parent_d_matrix()]) #for pp in p.get_parent_d_matrix(): # print '{0:.16f}'.format(pp) # #p.set_local_frame(dl1, dl2, dl0) #d_matrix1 = p.get_d_matrix() #p = Panel()
-150.0059, ) dl1 = dl[0], dl[3], dl[6] dl2 = dl[1], dl[4], dl[7] dl0 = dl[2], dl[5], dl[8] dp1 = dp[0], dp[3], dp[6] dp2 = dp[1], dp[4], dp[7] dp0 = dp[2], dp[5], dp[8] d1 = (-0.00182517255306, 0.999997320637, -0.00142389018396) d2 = (0.999998194757, 0.0018259228625, 0.000525821456245) d0 = (-48.3367467929, -1.3827137802, -149.981643976) p = Panel() p.set_parent_frame(dp1, dp2, dp0) p.set_local_frame(dl1, dl2, dl0) p.set_frame(d1, d2, d0) # print repr([10000000000*pp for pp in p.get_parent_d_matrix()]) # for pp in p.get_parent_d_matrix(): # print '{0:.16f}'.format(pp) # # p.set_local_frame(dl1, dl2, dl0) # d_matrix1 = p.get_d_matrix() # p = Panel() # p.set_frame(dl1, dl2, dl0)