示例#1
0
def candidate_orientation_matrices(basis_vectors, max_combinations=None):

    # select unique combinations of input vectors to test
    # the order of combinations is such that combinations comprising vectors
    # nearer the beginning of the input list will appear before combinations
    # comprising vectors towards the end of the list
    n = len(basis_vectors)
    # hardcoded limit on number of vectors, fixes issue #72
    # https://github.com/dials/dials/issues/72
    n = min(n, 100)
    basis_vectors = basis_vectors[:n]
    combinations = flex.vec3_int(flex.nested_loop((n, n, n)))
    combinations = combinations.select(
        flex.sort_permutation(combinations.as_vec3_double().norms()))

    # select only those combinations where j > i and k > j
    i, j, k = combinations.as_vec3_double().parts()
    sel = flex.bool(len(combinations), True)
    sel &= j > i
    sel &= k > j
    combinations = combinations.select(sel)

    if max_combinations is not None and max_combinations < len(combinations):
        combinations = combinations[:max_combinations]

    half_pi = 0.5 * math.pi
    min_angle = 20 / 180 * math.pi  # 20 degrees, arbitrary cutoff
    for i, j, k in combinations:
        a = basis_vectors[i]
        b = basis_vectors[j]
        angle = a.angle(b)
        if angle < min_angle or (math.pi - angle) < min_angle:
            continue
        a_cross_b = a.cross(b)
        gamma = a.angle(b)
        if gamma < half_pi:
            # all angles obtuse if possible please
            b = -b
            a_cross_b = -a_cross_b
        c = basis_vectors[k]
        if abs(half_pi - a_cross_b.angle(c)) < min_angle:
            continue
        alpha = b.angle(c, deg=True)
        if alpha < half_pi:
            c = -c
        if a_cross_b.dot(c) < 0:
            # we want right-handed basis set, therefore invert all vectors
            a = -a
            b = -b
            c = -c
        model = Crystal(a, b, c, space_group_symbol="P 1")
        uc = model.get_unit_cell()
        cb_op_to_niggli = uc.change_of_basis_op_to_niggli_cell()
        model = model.change_basis(cb_op_to_niggli)

        uc = model.get_unit_cell()
        params = uc.parameters()
        if uc.volume() > (params[0] * params[1] * params[2] / 100):
            # unit cell volume cutoff from labelit 2004 paper
            yield model
示例#2
0
    def apply_symmetry(self, crystal_model):
        if not (self.target_symmetry_primitive
                and self.target_symmetry_primitive.space_group()):
            return crystal, sgtbx.change_of_basis_op()

        target_space_group = self.target_symmetry_primitive.space_group()

        A = crystal_model.get_A()

        max_delta = self._max_delta
        items = iotbx_converter(crystal_model.get_unit_cell(),
                                max_delta=max_delta)
        target_sg_ref = target_space_group.info().reference_setting().group()
        best_angular_difference = 1e8
        best_subgroup = None
        for item in items:
            if bravais_lattice(group=target_sg_ref) != bravais_lattice(
                    group=item["ref_subsym"].space_group()):
                continue
            if item["max_angular_difference"] < best_angular_difference:
                best_angular_difference = item["max_angular_difference"]
                best_subgroup = item

        if best_subgroup is None:
            return None, None

        cb_op_inp_best = best_subgroup["cb_op_inp_best"]
        orient = crystal_orientation(A, True)
        orient_best = orient.change_basis(
            scitbx.matrix.sqr(
                cb_op_inp_best.c().as_double_array()[0:9]).transpose())
        constrain_orient = orient_best.constrain(best_subgroup["system"])

        best_subsym = best_subgroup["best_subsym"]
        cb_op_best_ref = best_subsym.change_of_basis_op_to_reference_setting()
        target_sg_best = target_sg_ref.change_basis(cb_op_best_ref.inverse())
        ref_subsym = best_subsym.change_basis(cb_op_best_ref)
        cb_op_ref_primitive = ref_subsym.change_of_basis_op_to_primitive_setting(
        )
        cb_op_best_primitive = cb_op_ref_primitive * cb_op_best_ref
        cb_op_inp_primitive = cb_op_ref_primitive * cb_op_best_ref * cb_op_inp_best

        direct_matrix = constrain_orient.direct_matrix()

        a = scitbx.matrix.col(direct_matrix[:3])
        b = scitbx.matrix.col(direct_matrix[3:6])
        c = scitbx.matrix.col(direct_matrix[6:9])
        model = Crystal(a, b, c, space_group=target_sg_best)
        assert target_sg_best.is_compatible_unit_cell(model.get_unit_cell())

        model = model.change_basis(cb_op_best_primitive)
        return model, cb_op_inp_primitive
示例#3
0
def filter_doubled_cell(solutions):
    accepted_solutions = []
    for i1, s1 in enumerate(solutions):
        doubled_cell = False
        for (m1, m2, m3) in (
            (2, 1, 1),
            (1, 2, 1),
            (1, 1, 2),
            (2, 2, 1),
            (2, 1, 2),
            (1, 2, 2),
            (2, 2, 2),
        ):
            if doubled_cell:
                break
            a, b, c = (matrix.col(v)
                       for v in s1.crystal.get_real_space_vectors())
            new_cryst = Crystal(
                real_space_a=1 / m1 * a,
                real_space_b=1 / m2 * b,
                real_space_c=1 / m3 * c,
                space_group=s1.crystal.get_space_group(),
            )
            new_unit_cell = new_cryst.get_unit_cell()
            for s2 in solutions:
                if s2 is s1:
                    continue
                if new_unit_cell.is_similar_to(s2.crystal.get_unit_cell(),
                                               relative_length_tolerance=0.05):
                    R, axis, angle, cb = difference_rotation_matrix_axis_angle(
                        new_cryst, s2.crystal)
                    if (angle < 1) and (s1.n_indexed < (1.1 * s2.n_indexed)):
                        doubled_cell = True
                        break

        if not doubled_cell:
            accepted_solutions.append(s1)

    return accepted_solutions
def test_crystal_model():
    real_space_a = matrix.col((10, 0, 0))
    real_space_b = matrix.col((0, 11, 0))
    real_space_c = matrix.col((0, 0, 12))
    model = Crystal(
        real_space_a=(10, 0, 0),
        real_space_b=(0, 11, 0),
        real_space_c=(0, 0, 12),
        space_group_symbol="P 1",
    )
    # This doesn't work as python class uctbx.unit_cell(uctbx_ext.unit_cell)
    # so C++ and python classes are different types
    # assert isinstance(model.get_unit_cell(), uctbx.unit_cell)
    assert model.get_unit_cell().parameters() == (10.0, 11.0, 12.0, 90.0, 90.0,
                                                  90.0)
    assert approx_equal(model.get_A(),
                        (1 / 10, 0, 0, 0, 1 / 11, 0, 0, 0, 1 / 12))
    assert approx_equal(
        matrix.sqr(model.get_A()).inverse(), (10, 0, 0, 0, 11, 0, 0, 0, 12))
    assert approx_equal(model.get_B(), model.get_A())
    assert approx_equal(model.get_U(), (1, 0, 0, 0, 1, 0, 0, 0, 1))
    assert approx_equal(model.get_real_space_vectors(),
                        (real_space_a, real_space_b, real_space_c))
    assert (model.get_crystal_symmetry().unit_cell().parameters() ==
            model.get_unit_cell().parameters())
    assert model.get_crystal_symmetry().space_group() == model.get_space_group(
    )

    model2 = Crystal(
        real_space_a=(10, 0, 0),
        real_space_b=(0, 11, 0),
        real_space_c=(0, 0, 12),
        space_group_symbol="P 1",
    )
    assert model == model2

    model2a = Crystal(model.get_A(), model.get_space_group())
    assert model == model2a

    model2b = Crystal(
        matrix.sqr(model.get_A()).inverse().elems,
        model.get_space_group().type().lookup_symbol(),
        reciprocal=False,
    )
    assert model == model2b

    # rotate 45 degrees about x-axis
    R1 = matrix.sqr((
        1,
        0,
        0,
        0,
        math.cos(math.pi / 4),
        -math.sin(math.pi / 4),
        0,
        math.sin(math.pi / 4),
        math.cos(math.pi / 4),
    ))
    # rotate 30 degrees about y-axis
    R2 = matrix.sqr((
        math.cos(math.pi / 6),
        0,
        math.sin(math.pi / 6),
        0,
        1,
        0,
        -math.sin(math.pi / 6),
        0,
        math.cos(math.pi / 6),
    ))
    # rotate 60 degrees about z-axis
    R3 = matrix.sqr((
        math.cos(math.pi / 3),
        -math.sin(math.pi / 3),
        0,
        math.sin(math.pi / 3),
        math.cos(math.pi / 3),
        0,
        0,
        0,
        1,
    ))
    R = R1 * R2 * R3
    model.set_U(R)
    # B is unchanged
    assert approx_equal(model.get_B(),
                        (1 / 10, 0, 0, 0, 1 / 11, 0, 0, 0, 1 / 12))
    assert approx_equal(model.get_U(), R)
    assert approx_equal(model.get_A(),
                        matrix.sqr(model.get_U()) * matrix.sqr(model.get_B()))
    a_, b_, c_ = model.get_real_space_vectors()
    assert approx_equal(a_, R * real_space_a)
    assert approx_equal(b_, R * real_space_b)
    assert approx_equal(c_, R * real_space_c)
    assert (str(model).replace("-0.0000", " 0.0000") == """\
Crystal:
    Unit cell: (10.000, 11.000, 12.000, 90.000, 90.000, 90.000)
    Space group: P 1
    U matrix:  {{ 0.4330, -0.7500,  0.5000},
                { 0.7891,  0.0474, -0.6124},
                { 0.4356,  0.6597,  0.6124}}
    B matrix:  {{ 0.1000,  0.0000,  0.0000},
                { 0.0000,  0.0909,  0.0000},
                { 0.0000,  0.0000,  0.0833}}
    A = UB:    {{ 0.0433, -0.0682,  0.0417},
                { 0.0789,  0.0043, -0.0510},
                { 0.0436,  0.0600,  0.0510}}
""")
    model.set_B((1 / 12, 0, 0, 0, 1 / 12, 0, 0, 0, 1 / 12))
    assert approx_equal(model.get_unit_cell().parameters(),
                        (12, 12, 12, 90, 90, 90))

    U = matrix.sqr((0.3455, -0.2589, -0.9020, 0.8914, 0.3909, 0.2293, 0.2933,
                    -0.8833, 0.3658))
    B = matrix.sqr((1 / 13, 0, 0, 0, 1 / 13, 0, 0, 0, 1 / 13))
    model.set_A(U * B)
    assert approx_equal(model.get_A(), U * B)
    assert approx_equal(model.get_U(), U, 1e-4)
    assert approx_equal(model.get_B(), B, 1e-5)

    model3 = Crystal(
        real_space_a=(10, 0, 0),
        real_space_b=(0, 11, 0),
        real_space_c=(0, 0, 12),
        space_group=sgtbx.space_group_info("P 222").group(),
    )
    assert model3.get_space_group().type().hall_symbol() == " P 2 2"
    assert model != model3
    #
    sgi_ref = sgtbx.space_group_info(number=230)
    model_ref = Crystal(
        real_space_a=(44, 0, 0),
        real_space_b=(0, 44, 0),
        real_space_c=(0, 0, 44),
        space_group=sgi_ref.group(),
    )
    assert approx_equal(model_ref.get_U(), (1, 0, 0, 0, 1, 0, 0, 0, 1))
    assert approx_equal(model_ref.get_B(),
                        (1 / 44, 0, 0, 0, 1 / 44, 0, 0, 0, 1 / 44))
    assert approx_equal(model_ref.get_A(), model_ref.get_B())
    assert approx_equal(model_ref.get_unit_cell().parameters(),
                        (44, 44, 44, 90, 90, 90))
    a_ref, b_ref, c_ref = map(matrix.col, model_ref.get_real_space_vectors())
    cb_op_to_primitive = sgi_ref.change_of_basis_op_to_primitive_setting()
    model_primitive = model_ref.change_basis(cb_op_to_primitive)
    cb_op_to_reference = (model_primitive.get_space_group().info().
                          change_of_basis_op_to_reference_setting())
    a_prim, b_prim, c_prim = map(matrix.col,
                                 model_primitive.get_real_space_vectors())
    assert (cb_op_to_primitive.as_abc() ==
            "-1/2*a+1/2*b+1/2*c,1/2*a-1/2*b+1/2*c,1/2*a+1/2*b-1/2*c")
    assert approx_equal(a_prim, -1 / 2 * a_ref + 1 / 2 * b_ref + 1 / 2 * c_ref)
    assert approx_equal(b_prim, 1 / 2 * a_ref - 1 / 2 * b_ref + 1 / 2 * c_ref)
    assert approx_equal(c_prim, 1 / 2 * a_ref + 1 / 2 * b_ref - 1 / 2 * c_ref)
    assert cb_op_to_reference.as_abc() == "b+c,a+c,a+b"
    assert approx_equal(a_ref, b_prim + c_prim)
    assert approx_equal(b_ref, a_prim + c_prim)
    assert approx_equal(c_ref, a_prim + b_prim)
    assert approx_equal(
        model_primitive.get_U(),
        [
            -0.5773502691896258,
            0.40824829046386285,
            0.7071067811865476,
            0.5773502691896257,
            -0.4082482904638631,
            0.7071067811865476,
            0.5773502691896257,
            0.8164965809277259,
            0.0,
        ],
    )
    assert approx_equal(
        model_primitive.get_B(),
        [
            0.0262431940540739,
            0.0,
            0.0,
            0.00927837023781507,
            0.02783511071344521,
            0.0,
            0.01607060866333063,
            0.01607060866333063,
            0.03214121732666125,
        ],
    )
    assert approx_equal(
        model_primitive.get_A(),
        (0, 1 / 44, 1 / 44, 1 / 44, 0, 1 / 44, 1 / 44, 1 / 44, 0),
    )
    assert approx_equal(
        model_primitive.get_unit_cell().parameters(),
        [
            38.1051177665153,
            38.1051177665153,
            38.1051177665153,
            109.47122063449069,
            109.47122063449069,
            109.47122063449069,
        ],
    )
    assert model_ref != model_primitive
    model_ref_recycled = model_primitive.change_basis(cb_op_to_reference)
    assert approx_equal(model_ref.get_U(), model_ref_recycled.get_U())
    assert approx_equal(model_ref.get_B(), model_ref_recycled.get_B())
    assert approx_equal(model_ref.get_A(), model_ref_recycled.get_A())
    assert approx_equal(
        model_ref.get_unit_cell().parameters(),
        model_ref_recycled.get_unit_cell().parameters(),
    )
    assert model_ref == model_ref_recycled

    uc = uctbx.unit_cell(
        (58.2567, 58.1264, 39.7093, 46.9077, 46.8612, 62.1055))
    sg = sgtbx.space_group_info(symbol="P1").group()
    cs = crystal.symmetry(unit_cell=uc, space_group=sg)
    cb_op_to_minimum = cs.change_of_basis_op_to_minimum_cell()
    # the reciprocal matrix
    B = matrix.sqr(uc.fractionalization_matrix()).transpose()
    U = random_rotation()
    direct_matrix = (U * B).inverse()
    model = Crystal(direct_matrix[:3],
                    direct_matrix[3:6],
                    direct_matrix[6:9],
                    space_group=sg)
    assert uc.is_similar_to(model.get_unit_cell())
    uc_minimum = uc.change_basis(cb_op_to_minimum)
    model_minimum = model.change_basis(cb_op_to_minimum)
    assert uc_minimum.is_similar_to(model_minimum.get_unit_cell())
    assert model_minimum != model
    model_minimum.update(model)
    assert model_minimum == model  # lgtm

    A_static = matrix.sqr(model.get_A())
    A_as_scan_points = [A_static]
    num_scan_points = 11
    for i in range(num_scan_points - 1):
        A_as_scan_points.append(
            A_as_scan_points[-1] *
            matrix.sqr(euler_angles.xyz_matrix(0.1, 0.2, 0.3)))
    model.set_A_at_scan_points(A_as_scan_points)
    model_minimum = model.change_basis(cb_op_to_minimum)
    assert model.num_scan_points == model_minimum.num_scan_points == num_scan_points
    M = matrix.sqr(cb_op_to_minimum.c_inv().r().transpose().as_double())
    M_inv = M.inverse()
    for i in range(num_scan_points):
        A_orig = matrix.sqr(model.get_A_at_scan_point(i))
        A_min = matrix.sqr(model_minimum.get_A_at_scan_point(i))
        assert approx_equal(A_min, A_orig * M_inv)
    assert model.get_unit_cell().parameters() == pytest.approx(
        (58.2567, 58.1264, 39.7093, 46.9077, 46.8612, 62.1055))
    uc = uctbx.unit_cell((10, 11, 12, 91, 92, 93))
    model.set_unit_cell(uc)
    assert model.get_unit_cell().parameters() == pytest.approx(uc.parameters())
def test_check_old_vs_new():
    from dxtbx.tests.model.crystal_model_old import crystal_model_old

    model_1 = Crystal(
        real_space_a=(10, 0, 0),
        real_space_b=(0, 11, 0),
        real_space_c=(0, 0, 12),
        space_group_symbol="P 1",
    )

    model_2 = crystal_model_old(
        real_space_a=(10, 0, 0),
        real_space_b=(0, 11, 0),
        real_space_c=(0, 0, 12),
        space_group_symbol="P 1",
    )

    cov_B = matrix.sqr([1] * (9 * 9))

    model_1.set_B_covariance(cov_B)
    model_2.set_B_covariance(cov_B)

    A_list = [model_1.get_A() for i in range(20)]

    model_1.set_A_at_scan_points(A_list)
    model_2.set_A_at_scan_points(A_list)

    A1 = model_1.get_A()
    A2 = model_2.get_A()
    U1 = model_1.get_U()
    U2 = model_2.get_U()
    B1 = model_1.get_B()
    B2 = model_2.get_B()
    UC1 = model_1.get_unit_cell()
    UC2 = model_2.get_unit_cell()
    RSV1 = model_1.get_real_space_vectors()
    RSV2 = model_2.get_real_space_vectors()
    SG1 = model_1.get_space_group()
    SG2 = model_2.get_space_group()

    assert model_1.num_scan_points == model_2.num_scan_points

    A_list_1 = [
        model_1.get_A_at_scan_point(i)
        for i in range(model_1.get_num_scan_points())
    ]
    A_list_2 = [
        model_2.get_A_at_scan_point(i)
        for i in range(model_1.get_num_scan_points())
    ]
    B_list_1 = [
        model_1.get_B_at_scan_point(i)
        for i in range(model_1.get_num_scan_points())
    ]
    B_list_2 = [
        model_2.get_B_at_scan_point(i)
        for i in range(model_1.get_num_scan_points())
    ]
    U_list_1 = [
        model_1.get_U_at_scan_point(i)
        for i in range(model_1.get_num_scan_points())
    ]
    U_list_2 = [
        model_2.get_U_at_scan_point(i)
        for i in range(model_1.get_num_scan_points())
    ]

    assert approx_equal(A1, A2)
    assert approx_equal(B1, B2)
    assert approx_equal(U1, U2)
    assert approx_equal(UC1.parameters(), UC2.parameters())
    assert approx_equal(RSV1[0], RSV2[0])
    assert approx_equal(RSV1[1], RSV2[1])
    assert approx_equal(RSV1[2], RSV2[2])
    assert str(SG1.info()) == str(SG2.info())

    for i in range(model_1.get_num_scan_points()):
        assert approx_equal(A_list_1[i], A_list_2[i])
        assert approx_equal(B_list_1[i], B_list_2[i])
        assert approx_equal(U_list_1[i], U_list_2[i])

    cell_sd_1 = model_1.get_cell_parameter_sd()
    cell_sd_2 = model_2.get_cell_parameter_sd()
    cell_volume_sd_1 = model_1.get_cell_volume_sd()
    cell_volume_sd_2 = model_2.get_cell_volume_sd()
    covB1 = model_1.get_B_covariance()
    covB2 = model_1.get_B_covariance()

    assert approx_equal(covB1, covB2)
    assert approx_equal(cell_volume_sd_1, cell_volume_sd_2)
    assert approx_equal(cell_sd_1, cell_sd_2)
示例#6
0
def test_refinement(dials_regression):
    """Test a refinement run"""

    # Get a beam and detector from a experiments. This one has a CS-PAD, but that
    # is irrelevant
    data_dir = os.path.join(dials_regression, "refinement_test_data",
                            "hierarchy_test")
    experiments_path = os.path.join(data_dir, "datablock.json")
    assert os.path.exists(experiments_path)

    # load models
    from dxtbx.model.experiment_list import ExperimentListFactory

    experiments = ExperimentListFactory.from_serialized_format(
        experiments_path, check_format=False)
    im_set = experiments.imagesets()[0]
    detector = deepcopy(im_set.get_detector())
    beam = im_set.get_beam()

    # Invent a crystal, goniometer and scan for this test
    from dxtbx.model import Crystal

    crystal = Crystal((40.0, 0.0, 0.0), (0.0, 40.0, 0.0), (0.0, 0.0, 40.0),
                      space_group_symbol="P1")
    orig_xl = deepcopy(crystal)

    from dxtbx.model import GoniometerFactory

    goniometer = GoniometerFactory.known_axis((1.0, 0.0, 0.0))

    # Build a mock scan for a 180 degree sequence
    from dxtbx.model import ScanFactory

    sf = ScanFactory()
    scan = sf.make_scan(
        image_range=(1, 1800),
        exposure_times=0.1,
        oscillation=(0, 0.1),
        epochs=list(range(1800)),
        deg=True,
    )
    sequence_range = scan.get_oscillation_range(deg=False)
    im_width = scan.get_oscillation(deg=False)[1]
    assert sequence_range == (0.0, pi)
    assert approx_equal(im_width, 0.1 * pi / 180.0)

    # Build an experiment list
    experiments = ExperimentList()
    experiments.append(
        Experiment(
            beam=beam,
            detector=detector,
            goniometer=goniometer,
            scan=scan,
            crystal=crystal,
            imageset=None,
        ))

    # simulate some reflections
    refs, _ = generate_reflections(experiments)

    # change unit cell a bit (=0.1 Angstrom length upsets, 0.1 degree of
    # alpha and beta angles)
    from dials.algorithms.refinement.parameterisation.crystal_parameters import (
        CrystalUnitCellParameterisation, )

    xluc_param = CrystalUnitCellParameterisation(crystal)
    cell_params = crystal.get_unit_cell().parameters()
    cell_params = [
        a + b for a, b in zip(cell_params, [0.1, -0.1, 0.1, 0.1, -0.1, 0.0])
    ]
    from cctbx.uctbx import unit_cell
    from rstbx.symmetry.constraints.parameter_reduction import symmetrize_reduce_enlarge
    from scitbx import matrix

    new_uc = unit_cell(cell_params)
    newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose()
    S = symmetrize_reduce_enlarge(crystal.get_space_group())
    S.set_orientation(orientation=newB)
    X = tuple([e * 1.0e5 for e in S.forward_independent_parameters()])
    xluc_param.set_param_vals(X)

    # reparameterise the crystal at the perturbed geometry
    xluc_param = CrystalUnitCellParameterisation(crystal)

    # Dummy parameterisations for other models
    beam_param = None
    xlo_param = None
    det_param = None

    # parameterisation of the prediction equation
    from dials.algorithms.refinement.parameterisation.parameter_report import (
        ParameterReporter, )

    pred_param = TwoThetaPredictionParameterisation(experiments, det_param,
                                                    beam_param, xlo_param,
                                                    [xluc_param])
    param_reporter = ParameterReporter(det_param, beam_param, xlo_param,
                                       [xluc_param])

    # reflection manager
    refman = TwoThetaReflectionManager(refs, experiments, nref_per_degree=20)

    # reflection predictor
    ref_predictor = TwoThetaExperimentsPredictor(experiments)

    # target function
    target = TwoThetaTarget(experiments, ref_predictor, refman, pred_param)

    # minimisation engine
    from dials.algorithms.refinement.engine import (
        LevenbergMarquardtIterations as Refinery, )

    refinery = Refinery(
        target=target,
        prediction_parameterisation=pred_param,
        log=None,
        max_iterations=20,
    )

    # Refiner
    from dials.algorithms.refinement.refiner import Refiner

    refiner = Refiner(
        experiments=experiments,
        pred_param=pred_param,
        param_reporter=param_reporter,
        refman=refman,
        target=target,
        refinery=refinery,
    )
    refiner.run()

    # compare crystal with original crystal
    refined_xl = refiner.get_experiments()[0].crystal

    # print refined_xl
    assert refined_xl.is_similar_to(orig_xl,
                                    uc_rel_length_tolerance=0.001,
                                    uc_abs_angle_tolerance=0.01)
示例#7
0
def write_par_file(file_name, experiment):
    from dxtbx.model import Crystal
    from iotbx.mtz.extract_from_symmetry_lib import ccp4_symbol
    from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame
    from scitbx import matrix

    imageset = experiment.imageset
    detector = imageset.get_detector()
    goniometer = imageset.get_goniometer()
    beam = imageset.get_beam()
    scan = imageset.get_scan()

    R_to_mosflm = align_reference_frame(beam.get_s0(), (1.0, 0.0, 0.0),
                                        goniometer.get_rotation_axis(),
                                        (0.0, 0.0, 1.0))

    cryst = experiment.crystal
    cryst = cryst.change_basis(cryst.get_space_group().info().
                               change_of_basis_op_to_reference_setting())
    A = matrix.sqr(cryst.get_A())
    A_inv = A.inverse()

    real_space_a = R_to_mosflm * A_inv.elems[:3]
    real_space_b = R_to_mosflm * A_inv.elems[3:6]
    real_space_c = R_to_mosflm * A_inv.elems[6:9]

    cryst_mosflm = Crystal(real_space_a,
                           real_space_b,
                           real_space_c,
                           space_group=cryst.get_space_group())
    U_mosflm = matrix.sqr(cryst_mosflm.get_U())
    B_mosflm = matrix.sqr(cryst_mosflm.get_B())
    UB_mosflm = U_mosflm * B_mosflm
    uc_params = cryst_mosflm.get_unit_cell().parameters()
    assert U_mosflm.is_r3_rotation_matrix(), U_mosflm

    beam_centre = tuple(reversed(detector[0].get_beam_centre(beam.get_s0())))
    distance = detector[0].get_directed_distance()
    polarization = R_to_mosflm * matrix.col(beam.get_polarization_normal())
    rotation = matrix.col(goniometer.get_rotation_axis())
    if rotation.angle(matrix.col(
            detector[0].get_fast_axis())) < rotation.angle(
                matrix.col(detector[0].get_slow_axis())):
        direction = "FAST"
    else:
        direction = "SLOW"
    rotation = R_to_mosflm * rotation

    # Calculate average spot diameter for SEPARATION parameter
    # http://xds.mpimf-heidelberg.mpg.de/html_doc/xds_parameters.html
    # BEAM_DIVERGENCE=
    # This value is approximately arctan(spot diameter/DETECTOR_DISTANCE)
    profile = experiment.profile
    spot_diameter = math.tan(profile.delta_b() * math.pi / 180) * distance
    spot_diameter_px = spot_diameter * detector[0].get_pixel_size()[0]

    # determine parameters for RASTER keyword
    # http://www.mrc-lmb.cam.ac.uk/harry/cgi-bin/keyword2.cgi?RASTER

    # NXS, NYS (odd integers) define the overall dimensions of the rectangular array of pixels for each spot
    # NXS and NYS are set to twice the spot size plus 5 pixels
    nxs = 2 * int(math.ceil(spot_diameter_px)) + 5
    nys = nxs

    # NRX, NRY are the number of columns or rows of points in the background rim
    # NRX and NRY are set to half the spot size plus 2 pixels
    nrx = int(math.ceil(0.5 * spot_diameter_px)) + 2
    nry = nrx

    # NC the corner background cut-off which corresponds to a half-square of side NC points
    # NC is set to the mean of the spot size in X and Y plus 4
    nc = int(math.ceil(spot_diameter_px)) + 4

    def space_group_symbol(space_group):
        symbol = ccp4_symbol(space_group.info(),
                             lib_name="syminfo.lib",
                             require_at_least_one_lib=False)
        if symbol != "P 1":
            symbol = symbol.replace(" 1", "")
        symbol = symbol.replace(" ", "")
        return symbol

    logger.info("Saving BEST parameter file to %s", file_name)
    with open(file_name, "w") as f:
        print("# parameter file for BEST", file=f)
        print("TITLE          From DIALS", file=f)
        print("DETECTOR       PILA", file=f)
        print("SITE           Not set", file=f)
        print(
            "DIAMETER       %6.2f" % (max(detector[0].get_image_size()) *
                                      detector[0].get_pixel_size()[0]),
            file=f,
        )
        print(f"PIXEL          {round(detector[0].get_pixel_size()[0], 10)}",
              file=f)
        print("ROTAXIS        %4.2f %4.2f %4.2f" % rotation.elems,
              direction,
              file=f)
        print("POLAXIS        %4.2f %4.2f %4.2f" % polarization.elems, file=f)
        print("GAIN               1.00", file=f)  # correct for Pilatus images
        # http://strucbio.biologie.uni-konstanz.de/xdswiki/index.php/FAQ#You_said_that_the_XDS_deals_with_high_mosaicity._How_high_mosaicity_is_still_manageable.3F
        # http://journals.iucr.org/d/issues/2012/01/00/wd5161/index.html
        # Transform from XDS definition of sigma_m to FWHM (MOSFLM mosaicity definition)
        print(f"CMOSAIC            {experiment.profile.sigma_m() * 2.355:.2f}",
              file=f)
        print(f"PHISTART           {scan.get_oscillation_range()[0]:.2f}",
              file=f)
        print(f"PHIWIDTH           {scan.get_oscillation()[1]:.2f}", file=f)
        print(f"DISTANCE        {distance:7.2f}", file=f)
        print(f"WAVELENGTH      {beam.get_wavelength():.5f}", file=f)
        print(f"POLARISATION    {beam.get_polarization_fraction():7.5f}",
              file=f)
        print(f"SYMMETRY       {space_group_symbol(cryst.get_space_group())}",
              file=f)
        print("UB             %9.6f %9.6f %9.6f" % UB_mosflm[:3], file=f)
        print("               %9.6f %9.6f %9.6f" % UB_mosflm[3:6], file=f)
        print("               %9.6f %9.6f %9.6f" % UB_mosflm[6:], file=f)
        print("CELL           %8.2f %8.2f %8.2f %6.2f %6.2f %6.2f" % uc_params,
              file=f)
        print("RASTER           %i %i %i %i %i" % (nxs, nys, nc, nrx, nry),
              file=f)
        print(f"SEPARATION      {spot_diameter:.3f}  {spot_diameter:.3f}",
              file=f)
        print("BEAM           %8.3f %8.3f" % beam_centre, file=f)
        print("# end of parameter file for BEST", file=f)
示例#8
0
    def load(self):

        # some parameters

        # NOTE: for reference, inside each h5 file there is
        #   [u'Amatrices', u'Hi', u'bboxes', u'h5_path']

        # get the total number of shots using worker 0
        if rank == 0:
            print("I am root. I am calculating total number of shots")
            h5s = [h5py_File(f, "r") for f in self.fnames]
            Nshots_per_file = [h["h5_path"].shape[0] for h in h5s]
            Nshots_tot = sum(Nshots_per_file)
            print("I am root. Total number of shots is %d" % Nshots_tot)

            print("I am root. I will divide shots amongst workers.")
            shot_tuples = []
            for i_f, fname in enumerate(self.fnames):
                fidx_shotidx = [(i_f, i_shot)
                                for i_shot in range(Nshots_per_file[i_f])]
                shot_tuples += fidx_shotidx

            from numpy import array_split
            print("I am root. Number of uniques = %d" % len(set(shot_tuples)))
            shots_for_rank = array_split(shot_tuples, size)

            # close the open h5s..
            for h in h5s:
                h.close()

        else:
            Nshots_tot = None
            shots_for_rank = None
            h5s = None

        #Nshots_tot = comm.bcast( Nshots_tot, root=0)
        if has_mpi:
            shots_for_rank = comm.bcast(shots_for_rank, root=0)
        #h5s = comm.bcast( h5s, root=0)  # pull in the open hdf5 files

        my_shots = shots_for_rank[rank]
        if self.Nload is not None:
            my_shots = my_shots[:self.Nload]

        # open the unique filenames for this rank
        # TODO: check max allowed pointers to open hdf5 file
        my_unique_fids = set([fidx for fidx, _ in my_shots])
        my_open_files = {
            fidx: h5py_File(self.fnames[fidx], "r")
            for fidx in my_unique_fids
        }
        Ntot = 0
        self.all_bbox_pixels = []
        for img_num, (fname_idx, shot_idx) in enumerate(my_shots):
            if img_num == args.Nmax:
                #print("Already processed maximum number images!")
                continue
            h = my_open_files[fname_idx]

            # load the dxtbx image data directly:
            npz_path = h["h5_path"][shot_idx]
            # NOTE take me out!
            if args.testmode:
                import os
                npz_path = os.path.basename(npz_path)
            img_handle = numpy_load(npz_path)
            img = img_handle["img"]

            if len(img.shape) == 2:  # if single panel>>
                img = np.array([img])

            #D = det_from_dict(img_handle["det"][()])
            B = beam_from_dict(img_handle["beam"][()])

            # get the indexed crystal Amatrix
            Amat = h["Amatrices"][shot_idx]
            amat_elems = list(sqr(Amat).inverse().elems)
            # real space basis vectors:
            a_real = amat_elems[:3]
            b_real = amat_elems[3:6]
            c_real = amat_elems[6:]

            # dxtbx indexed crystal model
            C = Crystal(a_real, b_real, c_real, "P43212")

            # change basis here ? Or maybe just average a/b
            a, b, c, _, _, _ = C.get_unit_cell().parameters()
            a_init = .5 * (a + b)
            c_init = c

            # shoe boxes where we expect spots
            bbox_dset = h["bboxes"]["shot%d" % shot_idx]
            n_bboxes_total = bbox_dset.shape[0]
            # is the shoe box within the resolution ring and does it have significant SNR (see filter_bboxes.py)
            is_a_keeper = h["bboxes"]["keepers%d" % shot_idx][()]

            # tilt plane to the background pixels in the shoe boxes
            tilt_abc_dset = h["tilt_abc"]["shot%d" % shot_idx]
            try:
                panel_ids_dset = h["panel_ids"]["shot%d" % shot_idx]
                has_panels = True
            except KeyError:
                has_panels = False

            # apply the filters:
            bboxes = [
                bbox_dset[i_bb] for i_bb in range(n_bboxes_total)
                if is_a_keeper[i_bb]
            ]
            tilt_abc = [
                tilt_abc_dset[i_bb] for i_bb in range(n_bboxes_total)
                if is_a_keeper[i_bb]
            ]
            if has_panels:
                panel_ids = [
                    panel_ids_dset[i_bb] for i_bb in range(n_bboxes_total)
                    if is_a_keeper[i_bb]
                ]
            else:
                panel_ids = [0] * len(tilt_abc)

            # how many pixels do we have
            tot_pix = [(j2 - j1) * (i2 - i1) for i1, i2, j1, j2 in bboxes]
            Ntot += sum(tot_pix)

            # actually load the pixels...
            #data_boxes = [ img[j1:j2, i1:i2] for i1,i2,j1,j2 in bboxes]

            # Here we will try a per-shot refinement of the unit cell and Umatrix, as well as ncells abc
            # and spot scale etc..

            # load some ground truth data from the simulation dumps (e.g. spectrum)
            h5_fname = h["h5_path"][shot_idx].replace(".npz", "")
            # NOTE remove me
            if args.testmode:
                h5_fname = os.path.basename(h5_fname)
            data = h5py_File(h5_fname, "r")

            tru = sqr(data["crystalA"][()]).inverse().elems
            a_tru = tru[:3]
            b_tru = tru[3:6]
            c_tru = tru[6:]
            C_tru = Crystal(a_tru, b_tru, c_tru, "P43212")
            try:
                angular_offset_init = compare_with_ground_truth(
                    a_tru, b_tru, c_tru, [C], symbol="P43212")[0]
            except Exception as err:
                print(
                    "Rank %d: Boo cant use the comparison w GT function: %s" %
                    (rank, err))

            fluxes = data["spectrum"][()]
            es = data["exposure_s"][()]
            fluxes *= es  # multiply by the exposure time
            spectrum = zip(wavelens, fluxes)
            # dont simulate when there are no photons!
            spectrum = [(wave, flux) for wave, flux in spectrum
                        if flux > self.flux_min]

            # make a unit cell manager that the refiner will use to track the B-matrix
            aa, _, cc, _, _, _ = C_tru.get_unit_cell().parameters()
            ucell_man = TetragonalManager(a=a_init, c=c_init)
            if args.startwithtruth:
                ucell_man = TetragonalManager(a=aa, c=cc)

            # create the sim_data instance that the refiner will use to run diffBragg
            # create a nanoBragg crystal
            nbcryst = nanoBragg_crystal()
            nbcryst.dxtbx_crystal = C
            if args.startwithtruth:
                nbcryst.dxtbx_crystal = C_tru

            nbcryst.thick_mm = 0.1
            nbcryst.Ncells_abc = 30, 30, 30
            nbcryst.miller_array = Fhkl_guess.as_amplitude_array()
            nbcryst.n_mos_domains = 1
            nbcryst.mos_spread_deg = 0.0

            # create a nanoBragg beam
            nbbeam = nanoBragg_beam()
            nbbeam.size_mm = 0.001
            nbbeam.unit_s0 = B.get_unit_s0()
            nbbeam.spectrum = spectrum

            # sim data instance
            SIM = SimData()
            SIM.detector = CSPAD
            #SIM.detector = D
            SIM.crystal = nbcryst
            SIM.beam = nbbeam
            SIM.panel_id = 0  # default

            spot_scale = 12
            if args.sad:
                spot_scale = 1
            SIM.instantiate_diffBragg(default_F=0, oversample=0)
            SIM.D.spot_scale = spot_scale

            img_in_photons = img / self.gain

            print("Rank %d, Starting refinement!" % rank)
            try:
                RUC = RefineAllMultiPanel(
                    spot_rois=bboxes,
                    abc_init=tilt_abc,
                    img=img_in_photons,  # NOTE this is now a multi panel image
                    SimData_instance=SIM,
                    plot_images=args.plot,
                    plot_residuals=args.residual,
                    ucell_manager=ucell_man)

                RUC.panel_ids = panel_ids
                RUC.multi_panel = True
                RUC.split_evaluation = args.split
                RUC.trad_conv = True
                RUC.refine_detdist = False
                RUC.refine_background_planes = False
                RUC.refine_Umatrix = True
                RUC.refine_Bmatrix = True
                RUC.refine_ncells = True
                RUC.use_curvatures = False  # args.curvatures
                RUC.calc_curvatures = True  #args.curvatures
                RUC.refine_crystal_scale = True
                RUC.refine_gain_fac = False
                RUC.plot_stride = args.stride
                RUC.poisson_only = False
                RUC.trad_conv_eps = 5e-3  # NOTE this is for single panel model
                RUC.max_calls = 300
                RUC.verbose = False
                RUC.use_rot_priors = True
                RUC.use_ucell_priors = True
                if args.verbose:
                    if rank == 0:  # only show refinement stats for rank 0
                        RUC.verbose = True
                RUC.run()
                if RUC.hit_break_to_use_curvatures:
                    RUC.use_curvatures = True
                    RUC.run(setup=False)
            except AssertionError as err:
                print(
                    "Rank %d, filename %s Hit assertion error during refinement: %s"
                    % (rank, data.filename, err))
                continue

            angle, ax = RUC.get_correction_misset(as_axis_angle_deg=True)
            if args.startwithtruth:
                C = Crystal(a_tru, b_tru, c_tru, "P43212")
            C.rotate_around_origin(ax, angle)
            C.set_B(RUC.get_refined_Bmatrix())
            a_ref, _, c_ref, _, _, _ = C.get_unit_cell().parameters()
            # compute missorientation with ground truth model
            try:
                angular_offset = compare_with_ground_truth(a_tru,
                                                           b_tru,
                                                           c_tru, [C],
                                                           symbol="P43212")[0]
                print(
                    "Rank %d, filename=%s, ang=%f, init_ang=%f, a=%f, init_a=%f, c=%f, init_c=%f"
                    % (rank, data.filename, angular_offset,
                       angular_offset_init, a_ref, a_init, c_ref, c_init))
            except Exception as err:
                print("Rank %d, filename=%s, error %s" %
                      (rank, data.filename, err))

            # free the memory from diffBragg instance
            RUC.S.D.free_all()
            del img  # not sure if needed here..
            del img_in_photons

            if args.testmode:
                exit()

            # peak at the memory usage of this rank
            mem = getrusage(RUSAGE_SELF).ru_maxrss  # peak mem usage in KB
            mem = mem / 1e6  # convert to GB

            if rank == 0:
                print "RANK 0: %.2g total pixels in %d/%d bboxes (file %d / %d); MemUsg=%2.2g GB" \
                      % (Ntot, len(bboxes), n_bboxes_total,  img_num+1, len(my_shots), mem)

            # TODO: accumulate all pixels
            #self.all_bbox_pixels += data_boxes

        for h in my_open_files.values():
            h.close()

        print("Rank %d; all subimages loaded!" % rank)
def test2():
    """Test on simulated data"""

    # Get models for reflection prediction
    import dials.test.algorithms.refinement.setup_geometry as setup_geometry

    from libtbx.phil import parse

    overrides = """geometry.parameters.crystal.a.length.value = 77
  geometry.parameters.crystal.b.length.value = 77
  geometry.parameters.crystal.c.length.value = 37"""

    master_phil = parse(
        """
      include scope dials.test.algorithms.refinement.geometry_phil
      """,
        process_includes=True,
    )

    from dxtbx.model import Crystal

    models = setup_geometry.Extract(master_phil)
    crystal = Crystal(
        real_space_a=(2.62783398111729, -63.387215823567125,
                      -45.751375737456975),
        real_space_b=(15.246640559660356, -44.48254330406616,
                      62.50501032727026),
        real_space_c=(-76.67246874451074, -11.01804131886244,
                      10.861322446352226),
        space_group_symbol="I 2 3",
    )
    detector = models.detector
    goniometer = models.goniometer
    beam = models.beam

    # Build a mock scan for a 180 degree sweep
    from dxtbx.model import ScanFactory

    sf = ScanFactory()
    scan = sf.make_scan(
        image_range=(1, 1800),
        exposure_times=0.1,
        oscillation=(0, 0.1),
        epochs=range(1800),
        deg=True,
    )

    # Build an experiment list
    from dxtbx.model.experiment_list import ExperimentList, Experiment

    experiments = ExperimentList()
    experiments.append(
        Experiment(
            beam=beam,
            detector=detector,
            goniometer=goniometer,
            scan=scan,
            crystal=crystal,
            imageset=None,
        ))

    # Generate all indices in a 1.5 Angstrom sphere
    from dials.algorithms.spot_prediction import IndexGenerator
    from cctbx.sgtbx import space_group, space_group_symbols

    resolution = 1.5
    index_generator = IndexGenerator(
        crystal.get_unit_cell(),
        space_group(space_group_symbols(1).hall()).type(),
        resolution,
    )
    indices = index_generator.to_array()

    # Predict rays within the sweep range
    from dials.algorithms.refinement.prediction import ScansRayPredictor

    sweep_range = scan.get_oscillation_range(deg=False)
    ray_predictor = ScansRayPredictor(experiments, sweep_range)
    obs_refs = ray_predictor(indices)

    # Take only those rays that intersect the detector
    from dials.algorithms.spot_prediction import ray_intersection

    intersects = ray_intersection(detector, obs_refs)
    obs_refs = obs_refs.select(intersects)

    # Make a reflection predictor and re-predict for all these reflections. The
    # result is the same, but we gain also the flags and xyzcal.px columns
    from dials.algorithms.refinement.prediction import ExperimentsPredictor

    ref_predictor = ExperimentsPredictor(experiments)
    obs_refs["id"] = flex.int(len(obs_refs), 0)
    obs_refs = ref_predictor(obs_refs)

    # Copy 'observed' centroids from the predicted ones, applying sinusoidal
    # offsets
    obs_x, obs_y, obs_z = obs_refs["xyzcal.mm"].parts()

    # obs_z is in range (0, pi). Calculate offsets for phi at twice that
    # frequency
    im_width = scan.get_oscillation(deg=False)[1]
    z_off = flex.sin(2 * obs_z) * im_width
    obs_z += z_off

    # Calculate offsets for x
    pixel_size = detector[0].get_pixel_size()
    x_off = flex.sin(20 * obs_z) * pixel_size[0]

    # Calculate offsets for y with a phase-shifted sine wave
    from math import pi

    y_off = flex.sin(4 * obs_z + pi / 6) * pixel_size[1]

    # Incorporate the offsets into the 'observed' centroids
    obs_z += z_off
    obs_x += x_off
    obs_y += y_off
    obs_refs["xyzobs.mm.value"] = flex.vec3_double(obs_x, obs_y, obs_z)

    # Now do centroid analysis of the residuals
    results = CentroidAnalyser(obs_refs, debug=True)()

    # FIXME this test shows that the suggested interval width heuristic is not
    # yet robust. This simulation function seems a useful direction to proceed
    # in though
    raise RuntimeError("test2 failed")

    print("OK")
    return
示例#10
0
文件: symmetry.py 项目: dwpaley/dials
    def apply_symmetry(self, crystal_model):
        """Apply symmetry constraints to a crystal model.

        Returns the crystal model (with symmetry constraints applied) in the same
        setting as provided as input. The cb_op returned by the method is
        that necessary to transform that model to the user-provided
        target symmetry.

        Args:
            crystal_model (dxtbx.model.Crystal): The input crystal model to which to
              apply symmetry constraints.

        Returns: (dxtbx.model.Crystal, cctbx.sgtbx.change_of_basis_op):
        The crystal model with symmetry constraints applied, and the change_of_basis_op
        that transforms the returned model to the user-specified target symmetry.
        """
        if not (
            self.target_symmetry_primitive
            and self.target_symmetry_primitive.space_group()
        ):
            return crystal, sgtbx.change_of_basis_op()

        target_space_group = self.target_symmetry_primitive.space_group()

        A = crystal_model.get_A()

        max_delta = self._max_delta
        items = iotbx_converter(crystal_model.get_unit_cell(), max_delta=max_delta)
        target_sg_ref = target_space_group.info().reference_setting().group()
        best_angular_difference = 1e8

        best_subgroup = None
        for item in items:
            if bravais_lattice(group=target_sg_ref) != item["bravais"]:
                continue
            if item["max_angular_difference"] < best_angular_difference:
                best_angular_difference = item["max_angular_difference"]
                best_subgroup = item

        if best_subgroup is None:
            return None, None

        cb_op_inp_best = best_subgroup["cb_op_inp_best"]
        best_subsym = best_subgroup["best_subsym"]
        ref_subsym = best_subgroup["ref_subsym"]
        cb_op_ref_best = ref_subsym.change_of_basis_op_to_best_cell()
        cb_op_best_ref = cb_op_ref_best.inverse()
        cb_op_inp_ref = cb_op_best_ref * cb_op_inp_best
        cb_op_ref_inp = cb_op_inp_ref.inverse()

        orient = crystal_orientation(A, True)
        orient_ref = orient.change_basis(
            scitbx.matrix.sqr((cb_op_inp_ref).c().as_double_array()[0:9]).transpose()
        )
        constrain_orient = orient_ref.constrain(best_subgroup["system"])
        direct_matrix = constrain_orient.direct_matrix()

        a = scitbx.matrix.col(direct_matrix[:3])
        b = scitbx.matrix.col(direct_matrix[3:6])
        c = scitbx.matrix.col(direct_matrix[6:9])
        model = Crystal(a, b, c, space_group=target_sg_ref)
        assert target_sg_ref.is_compatible_unit_cell(model.get_unit_cell())

        model = model.change_basis(cb_op_ref_inp)

        if self.cb_op_inp_best is not None:
            # Then the unit cell has been provided: this is the cb_op to map to the
            # user-provided input unit cell
            return model, self.cb_op_inp_best.inverse() * cb_op_inp_best
        if not self.cb_op_ref_inp.is_identity_op():
            if self.target_symmetry_inp.space_group() == best_subsym.space_group():
                # Handle where e.g. the user has requested I2 instead of the reference C2
                return model, cb_op_inp_best
            # The user has specified a setting that is not the reference setting
            return model, self.cb_op_ref_inp * cb_op_inp_ref
        # Default to reference setting
        # This change of basis op will ensure that we get the best beta angle without
        # changing the centring (e.g. from C2 to I2)
        cb_op_ref_best = ref_subsym.change_of_basis_op_to_best_cell(
            best_monoclinic_beta=False
        )
        return model, cb_op_ref_best * cb_op_inp_ref
示例#11
0
def test():
    import random
    import textwrap

    from cctbx.uctbx import unit_cell
    from libtbx.test_utils import approx_equal

    def random_direction_close_to(vector):
        return vector.rotate_around_origin(
            matrix.col((random.random(), random.random(),
                        random.random())).normalize(),
            random.gauss(0, 1.0),
            deg=True,
        )

    # make a random P1 crystal and parameterise it
    a = random.uniform(10, 50) * random_direction_close_to(
        matrix.col((1, 0, 0)))
    b = random.uniform(10, 50) * random_direction_close_to(
        matrix.col((0, 1, 0)))
    c = random.uniform(10, 50) * random_direction_close_to(
        matrix.col((0, 0, 1)))
    xl = Crystal(a, b, c, space_group_symbol="P 1")

    xl_op = CrystalOrientationParameterisation(xl)
    xl_ucp = CrystalUnitCellParameterisation(xl)

    null_mat = matrix.sqr((0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0))

    # compare analytical and finite difference derivatives
    an_ds_dp = xl_op.get_ds_dp()
    fd_ds_dp = get_fd_gradients(xl_op, [1.0e-6 * pi / 180] * 3)
    for e, f in zip(an_ds_dp, fd_ds_dp):
        assert approx_equal((e - f), null_mat, eps=1.0e-6)

    an_ds_dp = xl_ucp.get_ds_dp()
    fd_ds_dp = get_fd_gradients(xl_ucp, [1.0e-7] * xl_ucp.num_free())
    for e, f in zip(an_ds_dp, fd_ds_dp):
        assert approx_equal((e - f), null_mat, eps=1.0e-6)

    # random initial orientations with a random parameter shift at each
    attempts = 100
    for i in range(attempts):

        # make a random P1 crystal and parameterise it
        a = random.uniform(10, 50) * random_direction_close_to(
            matrix.col((1, 0, 0)))
        b = random.uniform(10, 50) * random_direction_close_to(
            matrix.col((0, 1, 0)))
        c = random.uniform(10, 50) * random_direction_close_to(
            matrix.col((0, 0, 1)))
        xl = Crystal(a, b, c, space_group_symbol="P 1")
        xl_op = CrystalOrientationParameterisation(xl)
        xl_uc = CrystalUnitCellParameterisation(xl)

        # apply a random parameter shift to the orientation
        p_vals = xl_op.get_param_vals()
        p_vals = random_param_shift(
            p_vals, [1000 * pi / 9, 1000 * pi / 9, 1000 * pi / 9])
        xl_op.set_param_vals(p_vals)

        # compare analytical and finite difference derivatives
        xl_op_an_ds_dp = xl_op.get_ds_dp()
        xl_op_fd_ds_dp = get_fd_gradients(xl_op, [1.0e-5 * pi / 180] * 3)

        # apply a random parameter shift to the unit cell. We have to
        # do this in a way that is respectful to metrical constraints,
        # so don't modify the parameters directly; modify the cell
        # constants and extract the new parameters
        cell_params = xl.get_unit_cell().parameters()
        cell_params = random_param_shift(cell_params, [1.0] * 6)
        new_uc = unit_cell(cell_params)
        newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose()
        S = symmetrize_reduce_enlarge(xl.get_space_group())
        S.set_orientation(orientation=newB)
        X = S.forward_independent_parameters()
        xl_uc.set_param_vals(X)

        xl_uc_an_ds_dp = xl_ucp.get_ds_dp()

        # now doing finite differences about each parameter in turn
        xl_uc_fd_ds_dp = get_fd_gradients(xl_ucp, [1.0e-7] * xl_ucp.num_free())

        for j in range(3):
            assert approx_equal((xl_op_fd_ds_dp[j] - xl_op_an_ds_dp[j]),
                                null_mat,
                                eps=1.0e-6), textwrap.dedent("""\
        Failure in try {i}
        failure for parameter number {j}
        of the orientation parameterisation
        with fd_ds_dp =
        {fd}
        and an_ds_dp =
        {an}
        so that difference fd_ds_dp - an_ds_dp =
        {diff}
        """).format(
                                    i=i,
                                    j=j,
                                    fd=xl_op_fd_ds_dp[j],
                                    an=xl_op_an_ds_dp[j],
                                    diff=xl_op_fd_ds_dp[j] - xl_op_an_ds_dp[j],
                                )

        for j in range(xl_ucp.num_free()):
            assert approx_equal((xl_uc_fd_ds_dp[j] - xl_uc_an_ds_dp[j]),
                                null_mat,
                                eps=1.0e-6), textwrap.dedent("""\
        Failure in try {i}
        failure for parameter number {j}
        of the unit cell parameterisation
        with fd_ds_dp =
        {fd}
        and an_ds_dp =
        {an}
        so that difference fd_ds_dp - an_ds_dp =
        {diff}
        """).format(
                                    i=i,
                                    j=j,
                                    fd=xl_uc_fd_ds_dp[j],
                                    an=xl_uc_an_ds_dp[j],
                                    diff=xl_uc_fd_ds_dp[j] - xl_uc_an_ds_dp[j],
                                )
        # apply a random parameter shift to the orientation
        p_vals = xl_op.get_param_vals()
        p_vals = random_param_shift(
            p_vals, [1000 * pi / 9, 1000 * pi / 9, 1000 * pi / 9])
        xl_op.set_param_vals(p_vals)

        # compare analytical and finite difference derivatives
        xl_op_an_ds_dp = xl_op.get_ds_dp()
        xl_op_fd_ds_dp = get_fd_gradients(xl_op, [1.e-5 * pi / 180] * 3)

        # apply a random parameter shift to the unit cell. We have to
        # do this in a way that is respectful to metrical constraints,
        # so don't modify the parameters directly; modify the cell
        # constants and extract the new parameters
        cell_params = xl.get_unit_cell().parameters()
        cell_params = random_param_shift(cell_params, [1.] * 6)
        new_uc = unit_cell(cell_params)
        newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose()
        S = symmetrize_reduce_enlarge(xl.get_space_group())
        S.set_orientation(orientation=newB)
        X = S.forward_independent_parameters()
        xl_uc.set_param_vals(X)

        xl_uc_an_ds_dp = xl_ucp.get_ds_dp()

        # now doing finite differences about each parameter in turn
        xl_uc_fd_ds_dp = get_fd_gradients(xl_ucp, [1.e-7] * xl_ucp.num_free())

        for j in range(3):
            try:
示例#13
0
    def load(self):
        # some parameters
        # NOTE: for reference, inside each h5 file there is
        #   [u'Amatrices', u'Hi', u'bboxes', u'h5_path']
        # get the total number of shots using worker 0
        if rank == 0:
            self.time_load_start = time.time()
            print("I am root. I am calculating total number of shots")
            h5s = [h5py_File(f, "r") for f in self.fnames]
            Nshots_per_file = [h["h5_path"].shape[0] for h in h5s]
            Nshots_tot = sum(Nshots_per_file)
            print("I am root. Total number of shots is %d" % Nshots_tot)

            print("I am root. I will divide shots amongst workers.")
            shot_tuples = []
            roi_per = []
            for i_f, fname in enumerate(self.fnames):
                fidx_shotidx = [(i_f, i_shot) for i_shot in range(Nshots_per_file[i_f])]
                shot_tuples += fidx_shotidx

                # store the number of usable roi per shot in order to divide shots amongst ranks equally
                roi_per += [sum(h5s[i_f]["bboxes"]["%s%d" % (args.keeperstag, i_shot)][()])
                            for i_shot in range(Nshots_per_file[i_f])]

            from numpy import array_split
            from numpy.random import permutation
            print ("I am root. Number of uniques = %d" % len(set(shot_tuples)))

            # divide the array into chunks of roughly equal sum (total number of ROI)
            if args.partition and args.restartfile is None and args.xinitfile is None:
                diff = np.inf
                roi_per = np.array(roi_per)
                tstart = time.time()
                best_order = range(len(roi_per))
                print("Partitioning for better load balancing across ranks.. ")
                while 1:
                    order = permutation(len(roi_per))
                    res = [sum(a) for a in np.array_split(roi_per[order], size)]
                    new_diff = max(res) - min(res)
                    t_elapsed = time.time() - tstart
                    t_remain = args.partitiontime - t_elapsed
                    if new_diff < diff:
                        diff = new_diff
                        best_order = order.copy()
                        print("Best diff=%d, Parition time remaining: %.3f seconds" % (diff, t_remain))
                    if t_elapsed > args.partitiontime:
                        break
                shot_tuples = [shot_tuples[i] for i in best_order]

            elif args.partition and args.restartfile is not None:
                print ("Warning: skipping partitioning time to use shot mapping as laid out in restart file dir")
            else:
                print ("Proceeding without partitioning")

            # optional to divide into a sub group
            shot_tuples = array_split(shot_tuples, args.ngroups)[args.groupId]
            shots_for_rank = array_split(shot_tuples, size)
            import os  # FIXME, I thought I was imported already!
            if args.outdir is not None:  # save for a fast restart (shot order is important!)
                np.save(os.path.join(args.outdir, "shots_for_rank"), shots_for_rank)
            if args.restartfile is not None:
                # the directory containing the restart file should have a shots for rank file
                dirname = os.path.dirname(args.restartfile)
                print ("Loading shot mapping from dir %s" % dirname)
                shots_for_rank = np.load(os.path.join(dirname, "shots_for_rank.npy"))
                # propagate the shots for rank file...
                if args.outdir is not None:
                    np.save(os.path.join(args.outdir, "shots_for_rank"), shots_for_rank)
            if args.xinitfile is not None:
                # the directory containing the restart file should have a shots for rank file
                dirname = os.path.dirname(args.xinitfile)
                print ("Loading shot mapping from dir %s" % dirname)
                shots_for_rank = np.load(os.path.join(dirname, "shots_for_rank.npy"))
                # propagate the shots for rank file...
                if args.outdir is not None:
                    np.save(os.path.join(args.outdir, "shots_for_rank"), shots_for_rank)

            # close the open h5s..
            for h in h5s:
                h.close()

        else:
            Nshots_tot = None
            shots_for_rank = None
            h5s = None

        # Nshots_tot = comm.bcast( Nshots_tot, root=0)
        if has_mpi:
            shots_for_rank = comm.bcast(shots_for_rank, root=0)
        # h5s = comm.bcast( h5s, root=0)  # pull in the open hdf5 files

        my_shots = shots_for_rank[rank]
        if self.Nload is not None:
            start = 0
            if args.loadstart is not None:
                start = args.loadstart
            my_shots = my_shots[start: start + self.Nload]
        print("Rank %d: I will load %d shots, first shot: %s, last shot: %s"
              % (comm.rank, len(my_shots), my_shots[0], my_shots[-1]))

        # open the unique filenames for this rank
        # TODO: check max allowed pointers to open hdf5 file
        import h5py
        my_unique_fids = set([fidx for fidx, _ in my_shots])
        self.my_open_files = {fidx: h5py_File(self.fnames[fidx], "r") for fidx in my_unique_fids}
        # for fidx in my_unique_fids:
        #    fpath = self.fnames[fidx]
        #    if args.imgdirname is not None:
        #        fpath = fpath.split("/kaladin/")[1]
        #        fpath = os.path.join(args.imgdirname, fpath)
        #    self.my_open_files[fidx] = h5py.File(fpath, "r")
        Ntot = 0

        for img_num, (fname_idx, shot_idx) in enumerate(my_shots):
            h = self.my_open_files[fname_idx]

            # load the dxtbx image data directly:
            npz_path = h["h5_path"][shot_idx]

            if args.imgdirname is not None:
                import os
                npz_path = npz_path.split("/kaladin/")[1]
                npz_path = os.path.join(args.imgdirname, npz_path)

            if args.noiseless:
                noiseless_path = npz_path.replace(".npz", ".noiseless.npz")
                img_handle = numpy_load(noiseless_path)
            else:
                img_handle = numpy_load(npz_path)

            img = img_handle["img"]

            if len(img.shape) == 2:  # if single panel
                img = array([img])

            B = beam_from_dict(img_handle["beam"][()])

            log_init_crystal_scale = 0  # default
            if args.usepreoptscale:
                log_init_crystal_scale = h["crystal_scale_%s" % args.preopttag][shot_idx]
            # get the indexed crystal Amatrix
            Amat = h["Amatrices"][shot_idx]
            if args.usepreoptAmat:
                Amat = h["Amatrices_%s" % args.preopttag][shot_idx]
            amat_elems = list(sqr(Amat).inverse().elems)
            # real space basis vectors:
            a_real = amat_elems[:3]
            b_real = amat_elems[3:6]
            c_real = amat_elems[6:]

            # dxtbx indexed crystal model
            C = Crystal(a_real, b_real, c_real, "P43212")

            # change basis here ? Or maybe just average a/b
            a, b, c, _, _, _ = C.get_unit_cell().parameters()
            a_init = .5 * (a + b)
            c_init = c

            # shoe boxes where we expect spots
            bbox_dset = h["bboxes"]["shot%d" % shot_idx]
            n_bboxes_total = bbox_dset.shape[0]
            # is the shoe box within the resolution ring and does it have significant SNR (see filter_bboxes.py)
            is_a_keeper = h["bboxes"]["%s%d" % (args.keeperstag, shot_idx)][()]
            # tilt plane to the background pixels in the shoe boxes
            tilt_abc_dset = h["tilt_abc"]["shot%d" % shot_idx]
            # miller indices (not yet reduced by symm equivs)
            Hi_dset = h["Hi"]["shot%d" % shot_idx]
            try:
                panel_ids_dset = h["panel_ids"]["shot%d" % shot_idx]
                has_panels = True
            except KeyError:
                has_panels = False

            # apply the filters:
            bboxes = [bbox_dset[i_bb] for i_bb in range(n_bboxes_total) if is_a_keeper[i_bb]]
            tilt_abc = [tilt_abc_dset[i_bb] for i_bb in range(n_bboxes_total) if is_a_keeper[i_bb]]
            Hi = [tuple(Hi_dset[i_bb]) for i_bb in range(n_bboxes_total) if is_a_keeper[i_bb]]
            proc_file_idx = [i_bb for i_bb in range(n_bboxes_total) if is_a_keeper[i_bb]]

            if has_panels:
                panel_ids = [panel_ids_dset[i_bb] for i_bb in range(n_bboxes_total) if is_a_keeper[i_bb]]
            else:
                panel_ids = [0] * len(tilt_abc)

            # how many pixels do we have
            tot_pix = [(j2 - j1) * (i2 - i1) for i1, i2, j1, j2 in bboxes]
            Ntot += sum(tot_pix)

            # load some ground truth data from the simulation dumps (e.g. spectrum)
            # h5_fname = h["h5_path"][shot_idx].replace(".npz", "")
            h5_fname = npz_path.replace(".npz", "")
            if args.character is not None:
                h5_fname = h5_fname.replace("rock", args.character)
            if args.testmode2:
                h5_fname = npz_path.split(".npz")[0]
            data = h5py_File(h5_fname, "r")

            xtal_scale_truth = data["spot_scale"][()]
            tru = sqr(data["crystalA"][()]).inverse().elems
            a_tru = tru[:3]
            b_tru = tru[3:6]
            c_tru = tru[6:]
            C_tru = Crystal(a_tru, b_tru, c_tru, "P43212")

            fluxes = data["spectrum"][()]
            es = data["exposure_s"][()]

            # comm.Barrier()
            # exit()
            fluxes *= es  # multiply by the exposure time
            # TODO: wavelens should come from the imageset file itself
            if "wavelengths" in data.keys():
                wavelens = data["wavelengths"][()]
            else:
                raise KeyError("Wavelengths missing from hdf5 data")
                #from cxid9114.parameters import WAVELEN_HIGH
                #wavelens = [WAVELEN_HIGH]

            spectrum = zip(wavelens, fluxes)
            # dont simulate when there are no photons!
            spectrum = [(wave, flux) for wave, flux in spectrum if flux > self.flux_min]

            if args.forcemono:
                spectrum = [(B.get_wavelength(), sum(fluxes))]

            # make a unit cell manager that the refiner will use to track the B-matrix
            aa, _, cc, _, _, _ = C_tru.get_unit_cell().parameters()
            ucell_man = TetragonalManager(a=a_init, c=c_init)

            # create the sim_data instance that the refiner will use to run diffBragg
            # create a nanoBragg crystal
            self.Fhkl_obs = open_flex(args.Fobs).as_amplitude_array()
            self.Fhkl_ref = None
            if args.Fref is not None:
                self.Fhkl_ref = open_flex(
                    args.Fref).as_amplitude_array()  # this reference miller array is used to track CC and R-factor
            if img_num == 0:  # only initialize the simulator after loading the first image
                self.initialize_simulator(C, B, spectrum, self.Fhkl_obs)

            # map the miller array to ASU
            Hi_asu = map_hkl_list(Hi, self.anomalous_flag, self.symbol)

            # copy the image as photons (NOTE: Dont forget to ditch its references!)
            img_in_photons = (img / args.gainval).astype('float32')

            # Here, takeout from the image only whats necessary to perform refinement
            # first filter the spot rois so they dont occur exactly at the boundary of the image (inclusive range in nB)
            assert len(img_in_photons.shape) == 3  # sanity
            nslow, nfast = img_in_photons[0].shape
            bboxes = array(bboxes)
            for i_bbox, (_, x2, _, y2) in enumerate(bboxes):
                if x2 == nfast:
                    bboxes[i_bbox][1] = x2 - 1  # update roi_xmax
                if y2 == nslow:
                    bboxes[i_bbox][3] = y2 - 1  # update roi_ymax
            # now cache the roi in nanoBragg format ((x1,x2), (y1,y1))
            # and also cache the pixels and the coordinates

            nanoBragg_rois = []  # special nanoBragg format
            xrel, yrel, roi_img = [], [], []
            for i_roi, (x1, x2, y1, y2) in enumerate(bboxes):
                nanoBragg_rois.append(((x1, x2), (y1, y2)))
                yr, xr = np_indices((y2 - y1 + 1, x2 - x1 + 1))
                xrel.append(xr)
                yrel.append(yr)
                pid = panel_ids[i_roi]
                roi_img.append(img_in_photons[pid, y1:y2 + 1, x1:x2 + 1])

            # make sure to clear that damn memory
            img = None
            img_in_photons = None
            del img  # not sure if needed here..
            del img_in_photons

            # peak at the memory usage of this rank
            # mem = getrusage(RUSAGE_SELF).ru_maxrss  # peak mem usage in KB
            # mem = mem / 1e6  # convert to GB
            mem = self._usage()

            # print "RANK %d: %.2g total pixels in %d/%d bboxes (file %d / %d); MemUsg=%2.2g GB" \
            #      % (rank, Ntot, len(bboxes), n_bboxes_total,  img_num +1, len(my_shots), mem)
            self.all_pix += Ntot

            # accumulate per-shot information
            self.global_image_id[img_num] = None  # TODO
            self.all_spot_roi[img_num] = bboxes
            self.all_abc_inits[img_num] = tilt_abc
            self.all_panel_ids[img_num] = panel_ids
            self.all_ucell_mans[img_num] = ucell_man
            self.all_spectra[img_num] = spectrum
            self.all_crystal_models[img_num] = C
            self.log_of_init_crystal_scales[
                img_num] = log_init_crystal_scale  # these should be the log of the initial crystal scale
            self.all_crystal_scales[img_num] = xtal_scale_truth
            self.all_crystal_GT[img_num] = C_tru
            self.all_xrel[img_num] = xrel
            self.all_yrel[img_num] = yrel
            self.all_nanoBragg_rois[img_num] = nanoBragg_rois
            self.all_roi_imgs[img_num] = roi_img
            self.all_fnames[img_num] = npz_path
            self.all_proc_fnames[img_num] = h.filename
            self.all_Hi[img_num] = Hi
            self.all_Hi_asu[img_num] = Hi_asu
            self.all_proc_idx[img_num] = proc_file_idx
            self.all_shot_idx[img_num] = shot_idx  # this is the index of the shot in the process*h5 file
            # NOTE all originZ for each panel are the same in the simulated data.. Not necessarily true for real data
            shot_originZ = self.SIM.detector[0].get_origin()[2]
            self.shot_originZ_init[img_num] = shot_originZ
            print(img_num)

        for h in self.my_open_files.values():
            h.close()