def get_projection_matrix(dim_pixel, dim_readout): """The get_projection_matrix() function returns the projection matrices in homogeneous coordinates between readout frame and fractional row and column indices. The forward transform maps coordinates in the readout frame, i.e. [x, y, z, 1], to readout indices, i.e. [i, j, 1], where i and j are the row and column indices, respectively. The backward transform provides the inverse. The get_projection_matrix() function assumes that coordinates in the readout frame are pixel centers. XXX Bad name! Better readout2metric(), readout_projection_matrices()? @note If coordinates in the readout frame are the top, left corner of the pixel, pass dim_readout=(readout_width_in_pixels + 1, readout_height_in_pixels + 1). @param dim_pixel Two-tuple of pixel width and height, in meters @param dim_readout Two-tuple of readout width and height, in pixels @return Two-tuple of the forward and backward projection matrices """ Pb = matrix.rec( elems=(0, +dim_pixel[0], dim_pixel[0] * (1 - dim_readout[0]) / 2, -dim_pixel[1], 0, dim_pixel[1] * (dim_readout[1] - 1) / 2, 0, 0, 0, 0, 0, 1), n=(4, 3)) Pf = matrix.rec(elems=(0, -1 / dim_pixel[1], 0, (dim_readout[1] - 1) / 2, +1 / dim_pixel[0], 0, 0, (dim_readout[0] - 1) / 2, 0, 0, 0, 1), n=(3, 4)) return (Pf, Pb)
def remove_cone_around_axis (array, axis, cone_radius) : assert (cone_radius < 90) and (cone_radius >= 0) from scitbx.matrix import rec unit_cell = array.unit_cell() indices = array.indices() rc_vectors = unit_cell.reciprocal_space_vector(indices) v1 = rec(unit_cell.reciprocal_space_vector(tuple(axis)), (3,1)) n_hkl = indices.size() data = array.data() sigmas = array.sigmas() angle_high = 180 - cone_radius i = 0 while (i < len(indices)) : v2 = rec(rc_vectors[i], (3,1)) #print v1, v2 angle = math.degrees(v1.angle(v2)) if (angle <= cone_radius) or (angle >= angle_high) : del rc_vectors[i] del indices[i] del data[i] if (sigmas is not None) : del sigmas[i] else : i += 1 delta_n_hkl = n_hkl - indices.size() return (n_hkl, delta_n_hkl)
def remove_cone_around_axis(array, axis, cone_radius): assert (cone_radius < 90) and (cone_radius >= 0) from scitbx.matrix import rec unit_cell = array.unit_cell() indices = array.indices() rc_vectors = unit_cell.reciprocal_space_vector(indices) v1 = rec(unit_cell.reciprocal_space_vector(tuple(axis)), (3, 1)) n_hkl = indices.size() data = array.data() sigmas = array.sigmas() angle_high = 180 - cone_radius i = 0 while (i < len(indices)): v2 = rec(rc_vectors[i], (3, 1)) #print v1, v2 angle = math.degrees(v1.angle(v2)) if (angle <= cone_radius) or (angle >= angle_high): del rc_vectors[i] del indices[i] del data[i] if (sigmas is not None): del sigmas[i] else: i += 1 delta_n_hkl = n_hkl - indices.size() return (n_hkl, delta_n_hkl)
def hessian_transform(self, original_hessian, adp_constraints): constraint_matrix_tensor = matrix.rec( adp_constraints.gradient_sum_matrix(), adp_constraints.gradient_sum_matrix().focus()) hessian_matrix = matrix.rec( original_hessian, original_hessian.focus()) ## now create an expanded matrix rows=adp_constraints.gradient_sum_matrix().focus()[0]+1 columns=adp_constraints.gradient_sum_matrix().focus()[1]+1 expanded_constraint_array = flex.double(rows*columns,0) count_new=0 count_old=0 for ii in range(rows): for jj in range(columns): if (ii>0): if (jj>0): expanded_constraint_array[count_new]=\ constraint_matrix_tensor[count_old] count_old+=1 count_new+=1 ## place the first element please expanded_constraint_array[0]=1 result=matrix.rec( expanded_constraint_array, (rows, columns) ) #print result.mathematica_form() new_hessian = result * hessian_matrix * result.transpose() result = flex.double(new_hessian) result.resize(flex.grid( new_hessian.n ) ) return(result)
def run(args): if (len(args) == 0): args = ["--help"] from libtbx.option_parser import libtbx_option_parser import libtbx.load_env command_line = (libtbx_option_parser( usage="%s [options] space_group_symbol ..." % libtbx.env.dispatcher_name) .option(None, "--primitive", action="store_true", help="Convert centred space groups to primitive setting.") .option(None, "--symops", action="store_true", help="Show list of symmetry operations.") ).process(args=args) co = command_line.options from cctbx import sgtbx args = command_line.args if (args == ["all"]): args = [str(no) for no in xrange(1,230+1)] for symbol in args: sgi = sgtbx.space_group_info(symbol=symbol) if (co.primitive): sgi = sgi.primitive_setting() sgi.show_summary() gr = sgi.group() print " Crystal system:", gr.crystal_system() print " Point group type:", gr.point_group_type() print " Laue group type:", gr.laue_group_type() print " Number of symmetry operations:", gr.order_z() print " Lattice centering operations:", gr.n_ltr() if (gr.n_ltr() != 1): print " Number of symmetry operations in primitive setting:", \ gr.order_p() if (gr.is_centric()): s = gr(0, 1, 0) else: s = None print " Center of inversion:", s print " Dimensionality of continuous allowed origin shifts:", \ sgi.number_of_continuous_allowed_origin_shifts() ssi_vm = sgi.structure_seminvariants().vectors_and_moduli() print " Structure-seminvariant vectors and moduli:", \ len(ssi_vm) if (len(ssi_vm) != 0): for vm in ssi_vm: print " (%2d, %2d, %2d)" % vm.v, "%2d" % vm.m print " Direct-space asymmetric unit:" dau = sgi.direct_space_asu() print " Number of faces: %d" % len(dau.cuts) for cut in dau.cuts: print " " + cut.as_xyz() print " ADP constraint matrix:" _ = sgi.group().adp_constraints().gradient_sum_matrix() from scitbx import matrix print matrix.rec(tuple(_), _.focus()).mathematica_form( one_row_per_line=True, prefix=" ") if (co.symops): print " List of symmetry operations:" for s in sgi.group(): print " %s" % str(s) print
def get_projection_matrix(dim_pixel, dim_readout): """The get_projection_matrix() function returns the projection matrices in homogeneous coordinates between readout frame and fractional row and column indices. The forward transform maps coordinates in the readout frame, i.e. [x, y, z, 1], to readout indices, i.e. [i, j, 1], where i and j are the row and column indices, respectively. The backward transform provides the inverse. The get_projection_matrix() function assumes that coordinates in the readout frame are pixel centers. XXX Bad name! Better readout2metric(), readout_projection_matrices()? @note If coordinates in the readout frame are the top, left corner of the pixel, pass dim_readout=(readout_width_in_pixels + 1, readout_height_in_pixels + 1). @param dim_pixel Two-tuple of pixel width and height, in meters @param dim_readout Two-tuple of readout width and height, in pixels @return Two-tuple of the forward and backward projection matrices """ Pb = matrix.rec( elems=( 0, +dim_pixel[0], dim_pixel[0] * (1 - dim_readout[0]) / 2, -dim_pixel[1], 0, dim_pixel[1] * (dim_readout[1] - 1) / 2, 0, 0, 0, 0, 0, 1, ), n=(4, 3), ) Pf = matrix.rec( elems=( 0, -1 / dim_pixel[1], 0, (dim_readout[1] - 1) / 2, +1 / dim_pixel[0], 0, 0, (dim_readout[0] - 1) / 2, 0, 0, 0, 1, ), n=(3, 4), ) return (Pf, Pb)
def exercise_rigu(): ins = """ CELL 0.71073 7.772741 8.721603 10.863736 90 102.9832 90 ZERR 2 0.000944 0.001056 0.001068 0 0.0107 0 LATT -1 SYMM -X,0.5+Y,-Z SFAC C H O UNIT 24 44 22 RIGU 0.0001 0.0001 O4 C C12 C12 1 -0.12812 0.06329 -0.17592 11.00000 0.01467 0.02689 0.02780 = -0.00379 0.00441 -0.00377 O4 3 0.08910 0.02721 0.02186 11.00000 0.02001 0.03168 0.03125 = -0.00504 0.00144 -0.00274 C 1 -0.05545 -0.04221 -0.06528 11.00000 0.01560 0.02699 0.02581 = -0.00481 0.00597 -0.00068 HKLF 4 END """ sio = StringIO(ins) import iotbx.shelx as shelx model = shelx.parse_smtbx_refinement_model(file=sio) sites_cart = model.structure.sites_cart() u_cart = model.structure.scatterers().extract_u_cart( model.structure.unit_cell()) arp = adp_restraint_params(sites_cart=sites_cart, u_cart=u_cart) for rp in model._proxies['rigu']: rr = adp_restraints.rigu(arp, rp) U1 = matrix.sym(sym_mat3=u_cart[rp.i_seqs[0]]) U2 = matrix.sym(sym_mat3=u_cart[rp.i_seqs[1]]) vz = matrix.col(sites_cart[rp.i_seqs[1]]) - matrix.col( sites_cart[rp.i_seqs[0]]) vy = vz.ortho() vx = vy.cross(vz) R = matrix.rec( vx.normalize().elems + vy.normalize().elems + vz.normalize().elems, (3, 3)) # with this matrix we can only test Z component as X and Y will differ dU = ((R * U1) * R.transpose() - (R * U2) * R.transpose()).as_sym_mat3() assert approx_equal(dU[2], rr.delta_33()) #with the original matrix all components should match R1 = matrix.rec(rr.RM(), (3, 3)) dU = ((R1 * U1) * R1.transpose() - (R1 * U2) * R1.transpose()).as_sym_mat3() assert approx_equal(dU[2], rr.delta_33()) assert approx_equal(dU[4], rr.delta_13()) assert approx_equal(dU[5], rr.delta_23()) # check the raw gradients against the reference implementation for x, y in zip(rr.reference_gradients(R1), rr.raw_gradients()): for idx in range(0, 6): assert approx_equal(x[idx], y[idx]) for x, y in zip(rigu_finite_diff(R1, U1), rr.raw_gradients()): for idx in range(0, 6): assert approx_equal(x[idx], y[idx])
def exercise_impl(svd_impl_name, use_fortran): import scitbx.linalg svd_impl = getattr(scitbx.linalg, "lapack_%s" % svd_impl_name) from scitbx.array_family import flex from scitbx import matrix from libtbx.test_utils import approx_equal # for diag in [0, 1]: for n in xrange(1, 11): a = flex.double(flex.grid(n, n), 0) for i in xrange(n): a[(i, i)] = diag a_inp = a.deep_copy() svd = svd_impl(a=a, use_fortran=use_fortran) if svd is None: if not use_fortran: print "Skipping tests: lapack_%s not available." % svd_impl_name return assert svd.info == 0 assert approx_equal(svd.s, [diag] * n) assert svd.u.all() == (n, n) assert svd.vt.all() == (n, n) mt = flex.mersenne_twister(seed=0) for m in xrange(1, 11): for n in xrange(1, 11): a = matrix.rec(elems=tuple(mt.random_double(m * n) * 4 - 2), n=(m, n)) svd = svd_impl(a=a.transpose().as_flex_double_matrix(), use_fortran=use_fortran) assert svd.info == 0 sigma = matrix.diag(svd.s) # min(m,n) x min(m,n) # FORTRAN layout, so transpose u = matrix.rec(svd.u, svd.u.all()).transpose() vt = matrix.rec(svd.vt, svd.vt.all()).transpose() assert approx_equal(u * sigma * vt, a) # a = matrix.rec(elems=[0.47, 0.10, -0.21, -0.21, -0.03, 0.35], n=(3, 2)) svd = svd_impl(a=a.transpose().as_flex_double_matrix(), use_fortran=use_fortran) assert svd.info == 0 assert approx_equal(svd.s, [0.55981345199567534, 0.35931726783538481]) # again remember column-major storage assert approx_equal( svd.u, [ 0.81402078804155853, -0.5136261274467826, 0.27121644094748704, -0.42424674329757839, -0.20684171439391938, 0.88160717215094342, ], ) assert approx_equal(svd.vt, [0.8615633693608673, -0.50765003750177129, 0.50765003750177129, 0.8615633693608673])
def exercise_impl(svd_impl_name, use_fortran): import scitbx.linalg svd_impl = getattr(scitbx.linalg, "lapack_%s" % svd_impl_name) from scitbx.array_family import flex from scitbx import matrix from libtbx.test_utils import approx_equal # for diag in [0, 1]: for n in range(1, 11): a = flex.double(flex.grid(n, n), 0) for i in range(n): a[(i, i)] = diag a_inp = a.deep_copy() svd = svd_impl(a=a, use_fortran=use_fortran) if (svd is None): if (not use_fortran): print("Skipping tests: lapack_%s not available." % svd_impl_name) return assert svd.info == 0 assert approx_equal(svd.s, [diag] * n) assert svd.u.all() == (n, n) assert svd.vt.all() == (n, n) mt = flex.mersenne_twister(seed=0) for m in range(1, 11): for n in range(1, 11): a = matrix.rec(elems=tuple(mt.random_double(m * n) * 4 - 2), n=(m, n)) svd = svd_impl(a=a.transpose().as_flex_double_matrix(), use_fortran=use_fortran) assert svd.info == 0 sigma = matrix.diag(svd.s) # min(m,n) x min(m,n) # FORTRAN layout, so transpose u = matrix.rec(svd.u, svd.u.all()).transpose() vt = matrix.rec(svd.vt, svd.vt.all()).transpose() assert approx_equal(u * sigma * vt, a) # a = matrix.rec(elems=[0.47, 0.10, -0.21, -0.21, -0.03, 0.35], n=(3, 2)) svd = svd_impl(a=a.transpose().as_flex_double_matrix(), use_fortran=use_fortran) assert svd.info == 0 assert approx_equal(svd.s, [0.55981345199567534, 0.35931726783538481]) # again remember column-major storage assert approx_equal(svd.u, [ 0.81402078804155853, -0.5136261274467826, 0.27121644094748704, -0.42424674329757839, -0.20684171439391938, 0.88160717215094342 ]) assert approx_equal(svd.vt, [ 0.8615633693608673, -0.50765003750177129, 0.50765003750177129, 0.8615633693608673 ])
def get_flex_image(self, brightness, **kwargs): # This functionality has migrated to # rstbx.slip_viewer.tile_generation._get_flex_image_multitile(). # XXX Still used by iotbx/command_line/detector_image_as_png.py #raise DeprecationWarning( # "xfel.cftbx.cspad_detector.get_flex_image() is deprecated") # no kwargs supported at present from xfel.cftbx.detector.metrology import get_projection_matrix # E maps picture coordinates onto metric Cartesian coordinates, # i.e. [row, column, 1 ] -> [x, y, z, 1]. Both frames share the # same origin, but the first coordinate of the screen coordinate # system increases downwards, while the second increases towards # the right. XXX Is this orthographic projection the only one # that makes any sense? E = rec(elems=[ 0, +self._pixel_size[1], 0, -self._pixel_size[0], 0, 0, 0, 0, 0, 0, 0, 1 ], n=[4, 3]) # P: [x, y, z, 1] -> [row, column, 1]. Note that self._asic_focus # needs to be flipped. Pf = get_projection_matrix( self._pixel_size, (self._asic_focus[1], self._asic_focus[0]))[0] # XXX Add ASIC:s in order? If a point is contained in two ASIC:s # simultaneously, it will be assigned to the ASIC defined first. # XXX Use a Z-buffer instead? nmemb = 0 for key, asic in six.iteritems(self._tiles): # Create my_flex_image and rawdata on the first iteration. if ("rawdata" not in locals()): rawdata = flex.double(flex.grid(self.size1, self.size2)) my_flex_image = generic_flex_image( rawdata=rawdata, binning=1, size1_readout=self._asic_focus[0], size2_readout=self._asic_focus[1], brightness=brightness, saturation=self._saturation) rawdata.matrix_paste_block_in_place(block=asic, i_row=nmemb * self._asic_padded[0], i_column=0) nmemb += 1 # key is guaranteed to exist in self._matrices as per # readHeader(). Last row of self._matrices[key][0] is always # [0, 0, 0, 1]. T = Pf * self._matrices[key][0] * E R = sqr([T(0, 0), T(0, 1), T(1, 0), T(1, 1)]) t = col([T(0, 2), T(1, 2)]) my_flex_image.add_transformation_and_translation(R, t) my_flex_image.followup_brightness_scale() return my_flex_image
def __init__(O, type, qE): assert type in ["euler_params", "euler_angles_xyz"] if (type == "euler_params"): if (len(qE.elems) == 3): qE = euler_angles_xyz_qE_as_euler_params_qE(qE=qE) else: if (len(qE.elems) == 4): qE = euler_params_qE_as_euler_angles_xyz_qE(qE=qE) O.type = type O.qE = qE O.q_size = len(qE) # if (type == "euler_params"): O.unit_quaternion = qE.normalize() # RBDA, bottom of p. 86 O.E = RBDA_Eq_4_12(q=O.unit_quaternion) else: O.E = RBDA_Eq_4_7(q=qE) # O.Tps = matrix.rt((O.E, (0,0,0))) O.Tsp = matrix.rt((O.E.transpose(), (0,0,0))) O.Xj = T_as_X(O.Tps) O.S = matrix.rec(( 1,0,0, 0,1,0, 0,0,1, 0,0,0, 0,0,0, 0,0,0), n=(6,3))
def glm(x, p=None): from math import exp, sqrt, log, factorial, lgamma from scitbx import matrix from scipy.stats import poisson beta0 = 0 if p is None: p = [1.0] * len(x) X = matrix.rec([1] * len(x), (len(x), 1)) c = 1.345 while True: n = beta0 mu = exp(n) z = [n + (xx - mu) / mu for xx in x] w = [pp * mu for pp in p] r = [(xx - mu) / sqrt(mu) for xx in x] w2 = [huber(rr, c) for rr in r] W = matrix.diag(w) # W2 = matrix.diag(w2) Z = matrix.col(z) beta = (X.transpose() * W * X).inverse() * X.transpose() * W * z print(beta) if abs(beta[0] - beta0) < 1e-3: break beta0 = beta[0] # W12 = matrix.diag([sqrt(ww) for ww in w]) # H = W12 * X * (X.transpose() * W * X).inverse() * X.transpose() * W12 mu = exp(n) return mu
def get_panel_fast_slow(self, serial): """Get the average x- and y-coordinates of all the ASIC:s in the panel with serial @p serial. This is done by back-transforming the centre's of each ASIC to the screen (sort of) coordinate system. This is more robust than getting the panel positions directly. """ from xfel.cftbx.detector.metrology import get_projection_matrix center = col([self._asic_focus[0] / 2, self._asic_focus[1] / 2, 1]) fast, nmemb, slow = 0, 0, 0 # Use the pixel size for the ASIC to construct the final # projection matrix. for p in self._metrology_params.detector.panel: if (p.serial != serial): continue for s in p.sensor: for a in s.asic: E = rec(elems=[+1 / a.pixel_size[0], 0, 0, 0, 0, -1 / a.pixel_size[1], 0, 0], n=[2, 4]) Pb = get_projection_matrix(a.pixel_size, a.dimension)[1] Tb = self._matrices[(0, p.serial, s.serial, a.serial)][1] t = E * Tb * Pb * center fast += t(0, 0) slow += t(1, 0) nmemb += 1 if (nmemb == 0): return (0, 0) return (fast / nmemb, slow / nmemb)
def glm33(X, Y, B, P): from math import exp, sqrt, log, factorial, lgamma from scitbx import matrix from scipy.stats import poisson X = matrix.rec(list(X), X.all()) Y = matrix.col(list(Y)) B = matrix.col(list(B)) P = matrix.col(list(P)) while True: n = X * B mu = matrix.col([exp(nn) for nn in n]) z = [(yy - mui) / mui for yy, mui in zip(Y, mu)] w = [pp * mui for pp, mui in zip(P, mu)] W = matrix.diag(w) Z = matrix.col(z) delta = (X.transpose() * W * X).inverse() * X.transpose() * W * z relE = sqrt( sum([d * d for d in delta]) / max(1e-10, sum([d * d for d in B]))) B = B + delta # print relE if relE < 1e-3: break return B
def update_rot_tran(self, x): """ Convert the refinable parameters, rotations angles and scaled translations, back to rotation matrices and translation vectors and updates the transforms_obj (ncs_restraints_group_list) !!! IN PLACE !!! Args: x : a flex.double of the form (theta_1,psi_1,phi_1,tx_1,ty_1,tz_1,.. theta_n,psi_n,phi_n,tx_n/s,ty_n/s,tz_n/s). where n is the number of transformations. Returns: Nothing """ i = 0 for gr in self: copies = [] for tr in gr.copies: the, psi, phi = x[i * 6:i * 6 + 3] rot = scitbx.rigid_body.rb_mat_xyz(the=the, psi=psi, phi=phi, deg=False) tran = matrix.rec(x[i * 6 + 3:i * 6 + 6], (3, 1)) tr.r = (rot.rot_mat()) tr.t = tran copies.append(tr) i += 1 gr.copies = copies
def exercise_derivatives(space_group_info, out): crystal_symmetry = space_group_info.any_compatible_crystal_symmetry( volume=1000) space_group = space_group_info.group() adp_constraints = space_group.adp_constraints() m = adp_constraints.row_echelon_form() print >> out, matrix.rec(m, (m.size()//6, 6)).mathematica_form( one_row_per_line=True) print >> out, list(adp_constraints.independent_indices) u_cart_p1 = adptbx.random_u_cart() u_star_p1 = adptbx.u_cart_as_u_star(crystal_symmetry.unit_cell(), u_cart_p1) u_star = space_group.average_u_star(u_star_p1) miller_set = miller.build_set( crystal_symmetry=crystal_symmetry, d_min=3, anomalous_flag=False) for h in miller_set.indices(): grads_fin = d_dw_d_u_star_finite(h=h, u_star=u_star) print >> out, "grads_fin:", list(grads_fin) grads_ana = d_dw_d_u_star_analytical(h=h, u_star=u_star) print >> out, "grads_ana:", list(grads_ana) compare_derivatives(grads_ana, grads_fin) curvs_fin = d2_dw_d_u_star_d_u_star_finite(h=h, u_star=u_star) print >> out, "curvs_fin:", list(curvs_fin) curvs_ana = d2_dw_d_u_star_d_u_star_analytical(h=h, u_star=u_star) print >> out, "curvs_ana:", list(curvs_ana) compare_derivatives(curvs_ana, curvs_fin) # u_indep = adp_constraints.independent_params(u_star) grads_indep_fin = d_dw_d_u_indep_finite( adp_constraints=adp_constraints, h=h, u_indep=u_indep) print >> out, "grads_indep_fin:", list(grads_indep_fin) grads_indep_ana = flex.double(adp_constraints.independent_gradients( all_gradients=list(grads_ana))) print >> out, "grads_indep_ana:", list(grads_indep_ana) compare_derivatives(grads_indep_ana, grads_indep_fin) curvs_indep_fin = d2_dw_d_u_indep_d_u_indep_finite( adp_constraints=adp_constraints, h=h, u_indep=u_indep) print >> out, "curvs_indep_fin:", list(curvs_indep_fin) curvs_indep_ana = adp_constraints.independent_curvatures( all_curvatures=curvs_ana) print >> out, "curvs_indep_ana:", list(curvs_indep_ana) compare_derivatives(curvs_indep_ana, curvs_indep_fin) # curvs_indep_mm = None if (str(space_group_info) == "P 1 2 1"): assert list(adp_constraints.independent_indices) == [0,1,2,4] curvs_indep_mm = p2_curv(h, u_star) elif (str(space_group_info) == "P 4"): assert list(adp_constraints.independent_indices) == [1,2] curvs_indep_mm = p4_curv(h, u_star) elif (str(space_group_info) in ["P 3", "P 6"]): assert list(adp_constraints.independent_indices) == [2,3] curvs_indep_mm = p3_curv(h, u_star) elif (str(space_group_info) == "P 2 3"): assert list(adp_constraints.independent_indices) == [2] curvs_indep_mm = p23_curv(h, u_star) if (curvs_indep_mm is not None): curvs_indep_mm = flex.double( curvs_indep_mm).matrix_symmetric_as_packed_u() print >> out, "curvs_indep_mm:", list(curvs_indep_mm) compare_derivatives(curvs_indep_ana, curvs_indep_mm)
def glm33(X, Y, B, P): from math import exp , sqrt, log, factorial, lgamma from scitbx import matrix from scipy.stats import poisson X = matrix.rec(list(X), X.all()) Y = matrix.col(list(Y)) B = matrix.col(list(B)) P = matrix.col(list(P)) while True: n = X * B mu = matrix.col([exp(nn) for nn in n]) z = [(yy - mui) / mui for yy, mui in zip(Y, mu)] w = [pp * mui for pp, mui in zip(P, mu)] W = matrix.diag(w) Z = matrix.col(z) delta = (X.transpose() * W * X).inverse() * X.transpose()*W*z relE = sqrt(sum([d*d for d in delta])/max(1e-10, sum([d*d for d in B]))) B = B + delta # print relE if relE < 1e-3: break return B
def glm(x, p=None): from math import exp, sqrt, log, factorial, lgamma from scitbx import matrix from scipy.stats import poisson beta0 = 0 if p is None: p = [1.0] * len(x) X = matrix.rec([1] * len(x), (len(x), 1)) c = 1.345 while True: n = beta0 mu = exp(n) z = [n + (xx - mu) / mu for xx in x] w = [pp * mu for pp in p] r = [(xx - mu) / sqrt(mu) for xx in x] w2 = [huber(rr, c) for rr in r] W = matrix.diag(w) # W2 = matrix.diag(w2) Z = matrix.col(z) beta = (X.transpose() * W * X).inverse() * X.transpose() * W * z print beta if abs(beta[0] - beta0) < 1e-3: break beta0 = beta[0] # W12 = matrix.diag([sqrt(ww) for ww in w]) # H = W12 * X * (X.transpose() * W * X).inverse() * X.transpose() * W12 mu = exp(n) return mu
def get_flex_image(self, brightness, **kwargs): # This functionality has migrated to # rstbx.slip_viewer.tile_generation._get_flex_image_multitile(). # XXX Still used by iotbx/command_line/detector_image_as_png.py #raise DeprecationWarning( # "xfel.cftbx.cspad_detector.get_flex_image() is deprecated") # no kwargs supported at present from xfel.cftbx.detector.metrology import get_projection_matrix # E maps picture coordinates onto metric Cartesian coordinates, # i.e. [row, column, 1 ] -> [x, y, z, 1]. Both frames share the # same origin, but the first coordinate of the screen coordinate # system increases downwards, while the second increases towards # the right. XXX Is this orthographic projection the only one # that makes any sense? E = rec(elems=[0, +self._pixel_size[1], 0, -self._pixel_size[0], 0, 0, 0, 0, 0, 0, 0, 1], n=[4, 3]) # P: [x, y, z, 1] -> [row, column, 1]. Note that self._asic_focus # needs to be flipped. Pf = get_projection_matrix(self._pixel_size, (self._asic_focus[1], self._asic_focus[0]))[0] # XXX Add ASIC:s in order? If a point is contained in two ASIC:s # simultaneously, it will be assigned to the ASIC defined first. # XXX Use a Z-buffer instead? nmemb = 0 for key, asic in self._tiles.iteritems(): # Create my_flex_image and rawdata on the first iteration. if ("rawdata" not in locals()): rawdata = flex.double(flex.grid(self.size1, self.size2)) my_flex_image = generic_flex_image( rawdata=rawdata, size1_readout=self._asic_focus[0], size2_readout=self._asic_focus[1], brightness=brightness, saturation=self._saturation) rawdata.matrix_paste_block_in_place( block=asic, i_row=nmemb * self._asic_padded[0], i_column=0) nmemb += 1 # key is guaranteed to exist in self._matrices as per # readHeader(). Last row of self._matrices[key][0] is always # [0, 0, 0, 1]. T = Pf * self._matrices[key][0] * E R = sqr([T(0, 0), T(0, 1), T(1, 0), T(1, 1)]) t = col([T(0, 2), T(1, 2)]) my_flex_image.add_transformation_and_translation(R, t) my_flex_image.followup_brightness_scale() return my_flex_image
def RBDA_Eq_4_13(q): p0, p1, p2, p3 = q return matrix.rec(( -p1, -p2, -p3, p0, -p3, p2, p3, p0, -p1, -p2, p1, p0), n=(4,3)) * 0.5
def exercise_isotropic_adp(): i_seqs = (0,) weight = 2 u_cart = ((1,2,3,5,2,8),) u_iso = (0,) use_u_aniso = (True,) p = adp_restraints.isotropic_adp_proxy( i_seqs=i_seqs, weight=weight) assert p.i_seqs == i_seqs assert approx_equal(p.weight, weight) i = adp_restraints.isotropic_adp(u_cart=u_cart[0], weight=weight) expected_deltas = (-1, 0, 1, 5, 2, 8) expected_gradients = (-4, 0, 4, 40, 16, 64) assert approx_equal(i.weight, weight) assert approx_equal(i.deltas(), expected_deltas) assert approx_equal(i.rms_deltas(), 4.5704364002673632) assert approx_equal(i.residual(), 376.0) assert approx_equal(i.gradients(), expected_gradients) gradients_aniso_cart = flex.sym_mat3_double(1, (0,0,0,0,0,0)) gradients_iso = flex.double(1,0) proxies = adp_restraints.shared_isotropic_adp_proxy([p,p]) u_cart = flex.sym_mat3_double(u_cart) u_iso = flex.double(u_iso) use_u_aniso = flex.bool(use_u_aniso) params = adp_restraint_params(u_cart=u_cart, u_iso=u_iso, use_u_aniso=use_u_aniso) residuals = adp_restraints.isotropic_adp_residuals(params, proxies=proxies) assert approx_equal(residuals, (i.residual(),i.residual())) deltas_rms = adp_restraints.isotropic_adp_deltas_rms(params, proxies=proxies) assert approx_equal(deltas_rms, (i.rms_deltas(),i.rms_deltas())) residual_sum = adp_restraints.isotropic_adp_residual_sum( params, proxies=proxies, gradients_aniso_cart=gradients_aniso_cart ) assert approx_equal(residual_sum, 752.0) fd_grads_aniso, fd_grads_iso = finite_difference_gradients( restraint_type=adp_restraints.isotropic_adp, proxy=p, u_cart=u_cart, u_iso=u_iso, use_u_aniso=use_u_aniso ) for g,e in zip(gradients_aniso_cart, fd_grads_aniso): assert approx_equal(g, matrix.col(e)*2) # # check frame invariance of residual # u_cart = matrix.sym(sym_mat3=(0.1,0.2,0.05,0.03,0.02,0.01)) a = adp_restraints.isotropic_adp( u_cart=u_cart.as_sym_mat3(), weight=1) expected_residual = a.residual() gen = flex.mersenne_twister() for i in range(20): R = matrix.rec(gen.random_double_r3_rotation_matrix(),(3,3)) u_cart_rot = R * u_cart * R.transpose() a = adp_restraints.isotropic_adp( u_cart=u_cart_rot.as_sym_mat3(), weight=1) assert approx_equal(a.residual(), expected_residual)
def as_4x4_rational(self): r = self.r().as_rational().elems t = self.t().as_rational().elems zero = rational.int(0) one = rational.int(1) return matrix.rec((r[0], r[1], r[2], t[0], r[3], r[4], r[5], t[1], r[6], r[7], r[8], t[2], zero, zero, zero, one), (4, 4))
def determine_effective_scan_axis(gonio): x = gonio.rotate_vector(0.0, 1, 0, 0) y = gonio.rotate_vector(0.0, 0, 1, 0) z = gonio.rotate_vector(0.0, 0, 0, 1) R = matrix.rec(x + y + z, (3, 3)).transpose() x1 = gonio.rotate_vector(1.0, 1, 0, 0) y1 = gonio.rotate_vector(1.0, 0, 1, 0) z1 = gonio.rotate_vector(1.0, 0, 0, 1) R1 = matrix.rec(x1 + y1 + z1, (3, 3)).transpose() RA = R1 * R.inverse() rot = r3_rotation_axis_and_angle_from_matrix(RA) return rot.axis, rot.angle(deg = True)
def cbf_gonio_to_effective_axis_fixed_old(cbf_gonio): '''Given a cbf goniometer handle, first determine the real rotation axis, then determine the fixed component of rotation which is rotated about this axis.''' # First construct the real rotation axis, as the difference in rotating # the identity matrix at the end of the scan and the beginning. x = cbf_gonio.rotate_vector(0.0, 1, 0, 0) y = cbf_gonio.rotate_vector(0.0, 0, 1, 0) z = cbf_gonio.rotate_vector(0.0, 0, 0, 1) R = matrix.rec(x + y + z, (3, 3)).transpose() x1 = cbf_gonio.rotate_vector(1.0, 1, 0, 0) y1 = cbf_gonio.rotate_vector(1.0, 0, 1, 0) z1 = cbf_gonio.rotate_vector(1.0, 0, 0, 1) R1 = matrix.rec(x1 + y1 + z1, (3, 3)).transpose() RA = R1 * R.inverse() rot = r3_rotation_axis_and_angle_from_matrix(RA) # Then, given this, determine the component of the scan which is fixed - # which will need to be with respect to the unrotated axis. N.B. this # will not be unique, but should be correct modulo a free rotation about # the shifted axis. start = cbf_gonio.get_rotation_range()[0] # want positive rotations => if negative invert axis axis = matrix.col(rot.axis) angle = rot.angle() if angle < 0: axis = -1 * axis # common sense would suggest in here that if the angle is -ve should # be made +ve - works OK for omega scans but not phi scans, probably # incomplete goniometer definition problem... # start = -start S = axis.axis_and_angle_as_r3_rotation_matrix(start, deg=True) return axis, S.inverse() * R
def setUp(self): # set_test_matrix self.rot1 = flex.vec3_double([ (-0.317946, -0.173437, 0.932111), ( 0.760735, -0.633422, 0.141629), ( 0.565855, 0.754120, 0.333333)]) self.rot2 = flex.vec3_double([ (0 , 0 , 1), (0.784042, -0.620708, 0), (0.620708, 0.784042, 0)]) self.rot3 = flex.vec3_double([ ( 0 , 0 , -1), ( 0.097445, -0.995241, 0), (-0.995241, -0.097445, 0)]) # Angles for rot, in radians self.rot_angles1 = flex.double( (-0.4017753, 1.2001985, 2.6422171)) self.rot_angles2 = flex.double( (-0.4017753, math.pi/2, 2.6422171)) self.rot_angles3 = flex.double( (-0.4017753, -math.pi/2, 2.6422171)) self.rot_angles1_deg = flex.double( (-0.4017753, 1.2001985, 2.6422171)) * 180/math.pi self.rotation1 = matrix.sqr(self.rot1.as_double()) self.rotation2 = matrix.sqr(self.rot2.as_double()) self.rotation3 = matrix.sqr(self.rot3.as_double()) self.translation1 = matrix.rec((0.5,-0.5,0),(3,1)) self.translation2 = matrix.rec((0,0,0),(3,1)) self.translation3 = matrix.rec((0,1,2),(3,1)) self.r_t = [[self.rotation1, self.translation1], [self.rotation2, self.translation2], [self.rotation3, self.translation3]] self.pdb_inp = iotbx.pdb.input(source_info=None, lines=test_pdb_str) self.tr_obj1 = ncs.input( hierarchy=self.pdb_inp.construct_hierarchy(), rotations=[self.rotation1,self.rotation2], translations=[self.translation1,self.translation2]) self.tr_obj2 = ncs.input( hierarchy=self.pdb_inp.construct_hierarchy(), rotations=[self.rotation1,self.rotation2,self.rotation3], translations=[self.translation1,self.translation2,self.translation3]) self.ncs_restraints_group_list = \ self.tr_obj1.get_ncs_restraints_group_list()
def as_4x4_rational(self): r = self.r().as_rational().elems t = self.t().as_rational().elems zero = rational.int(0) one = rational.int(1) return matrix.rec(( r[0], r[1], r[2], t[0], r[3], r[4], r[5], t[1], r[6], r[7], r[8], t[2], zero, zero, zero, one), (4, 4))
def cbf_gonio_to_effective_axis(cbf_gonio): '''Given a cbf goniometer handle, determine the real rotation axis.''' x = cbf_gonio.rotate_vector(0.0, 1, 0, 0) y = cbf_gonio.rotate_vector(0.0, 0, 1, 0) z = cbf_gonio.rotate_vector(0.0, 0, 0, 1) R = matrix.rec(x + y + z, (3, 3)).transpose() x1 = cbf_gonio.rotate_vector(1.0, 1, 0, 0) y1 = cbf_gonio.rotate_vector(1.0, 0, 1, 0) z1 = cbf_gonio.rotate_vector(1.0, 0, 0, 1) R1 = matrix.rec(x1 + y1 + z1, (3, 3)).transpose() RA = R1 * R.inverse() axis = r3_rotation_axis_and_angle_from_matrix(RA).axis return axis
def run_cplusplus(self): decomp = decompose_tls_matrices( T=self.T_M.as_sym_mat3(), L=self.L_M.as_sym_mat3(), S=self.S_M.as_mat3(), l_and_s_in_degrees=False, verbose=False, tol=self. eps, # This is used through the code to determine when something is non-zero eps= 1e-08, # This is currently hardcoded in the truncate function as a separate value t_S_formula=(self.find_t_S_using_formula if self.find_t_S_using_formula is not None else 'Force'), t_S_value=(self.force_t_S if self.force_t_S is not None else 0.0), ) # Check result if not decomp.is_valid(): raise Sorry(decomp.error()) # Unpack results required for finalise object # Invert the rotation matrices from the c++ implementation as R_ML defined differently self.R_ML = matrix.sqr(decomp.R_ML).transpose() self.R_MV = matrix.sqr(decomp.R_MV).transpose() R_MtoL = self.R_ML.transpose() # Libration rms around L-axes self.Lxx = decomp.l_amplitudes[0]**2 self.Lyy = decomp.l_amplitudes[1]**2 self.Lzz = decomp.l_amplitudes[2]**2 # Unit vectors defining three Libration axes self.l_x = matrix.rec(decomp.l_axis_directions[0], (3, 1)) self.l_y = matrix.rec(decomp.l_axis_directions[1], (3, 1)) self.l_z = matrix.rec(decomp.l_axis_directions[2], (3, 1)) # Rotation axes pass through the points in the L base self.w = group_args( w_lx=R_MtoL * decomp.l_axis_intersections[0], # Transform output to L frame w_ly=R_MtoL * decomp.l_axis_intersections[1], w_lz=R_MtoL * decomp.l_axis_intersections[2], ) # Correlation shifts sx,sy,sz for libration self.sx = decomp.s_amplitudes[0] self.sy = decomp.s_amplitudes[1] self.sz = decomp.s_amplitudes[2] # Vectors defining three Vibration axes self.v_x_M = matrix.rec(decomp.v_axis_directions[0], (3, 1)) self.v_y_M = matrix.rec(decomp.v_axis_directions[1], (3, 1)) self.v_z_M = matrix.rec(decomp.v_axis_directions[2], (3, 1)) # Vibrational axes in the M basis self.v_x = R_MtoL * decomp.v_axis_directions[0] self.v_y = R_MtoL * decomp.v_axis_directions[1] self.v_z = R_MtoL * decomp.v_axis_directions[2] # Vibration rms along V-axes self.tx = decomp.v_amplitudes[0] self.ty = decomp.v_amplitudes[1] self.tz = decomp.v_amplitudes[2]
def setUp(self): # set_test_matrix self.rot1 = flex.vec3_double([(-0.317946, -0.173437, 0.932111), (0.760735, -0.633422, 0.141629), (0.565855, 0.754120, 0.333333)]) self.rot2 = flex.vec3_double([(0, 0, 1), (0.784042, -0.620708, 0), (0.620708, 0.784042, 0)]) self.rot3 = flex.vec3_double([(0, 0, -1), (0.097445, -0.995241, 0), (-0.995241, -0.097445, 0)]) # Angles for rot, in radians self.rot_angles1 = flex.double((-0.4017753, 1.2001985, 2.6422171)) self.rot_angles2 = flex.double((-0.4017753, math.pi / 2, 2.6422171)) self.rot_angles3 = flex.double((-0.4017753, -math.pi / 2, 2.6422171)) self.rot_angles1_deg = flex.double( (-0.4017753, 1.2001985, 2.6422171)) * 180 / math.pi self.rotation1 = matrix.sqr(self.rot1.as_double()) self.rotation2 = matrix.sqr(self.rot2.as_double()) self.rotation3 = matrix.sqr(self.rot3.as_double()) self.translation1 = matrix.rec((0.5, -0.5, 0), (3, 1)) self.translation2 = matrix.rec((0, 0, 0), (3, 1)) self.translation3 = matrix.rec((0, 1, 2), (3, 1)) self.r_t = [[self.rotation1, self.translation1], [self.rotation2, self.translation2], [self.rotation3, self.translation3]] self.pdb_inp = iotbx.pdb.input(source_info=None, lines=test_pdb_str) self.tr_obj1 = ncs.input( hierarchy=self.pdb_inp.construct_hierarchy(), rotations=[self.rotation1, self.rotation2], translations=[self.translation1, self.translation2]) self.tr_obj2 = ncs.input( hierarchy=self.pdb_inp.construct_hierarchy(), rotations=[self.rotation1, self.rotation2, self.rotation3], translations=[ self.translation1, self.translation2, self.translation3 ]) self.ncs_restraints_group_list = \ self.tr_obj1.get_ncs_restraints_group_list()
def check(a, b, c, expected_free_vars, expected_sol): m = [] t = [] for i in range(3): m.append([a[i], b[i]]) t.append(c[i]) m_orig = matrix.rec(flat_list(m), (3,2)) t_orig = list(t) free_vars = row_echelon.form_rational(m, t) assert free_vars == expected_free_vars sol = row_echelon.back_substitution_rational(m, t, free_vars, [3, 11]) assert sol == expected_sol if (sol is not None): assert list(m_orig * sol) == t_orig
def check(a, b, c, expected_free_vars, expected_sol): m = [] t = [] for i in xrange(3): m.append([a[i], b[i]]) t.append(c[i]) m_orig = matrix.rec(flat_list(m), (3,2)) t_orig = list(t) free_vars = row_echelon.form_rational(m, t) assert free_vars == expected_free_vars sol = row_echelon.back_substitution_rational(m, t, free_vars, [3, 11]) assert sol == expected_sol if (sol is not None): assert list(m_orig * sol) == t_orig
def shape_vertices(self): result = set() cuts = self.cuts n_cuts = len(cuts) for i0 in xrange(0,n_cuts-2): for i1 in xrange(i0+1,n_cuts-1): for i2 in xrange(i1+1,n_cuts): m = matrix.rec(cuts[i0].n+cuts[i1].n+cuts[i2].n,(3,3)) d = m.determinant() if (d != 0): m_inv = m.co_factor_matrix_transposed() * (r1/d) b = matrix.col([-cuts[i0].c,-cuts[i1].c,-cuts[i2].c]) vertex = m_inv * b if (self.is_inside(vertex, shape_only=True)): result.add(vertex.elems) return sorted(result)
def cbf_gonio_to_effective_axis_fixed(cbf_gonio): axis = matrix.col(cbf_gonio.get_rotation_axis()) start, increment = cbf_gonio.get_rotation_range() # xia2-56 handle gracefully reverse turning goniometers - this assumes # that the angles will be correctly inverted in the scan factory if increment < 0: start = -start increment = -increment axis = -axis x = cbf_gonio.rotate_vector(0.0, 1, 0, 0) y = cbf_gonio.rotate_vector(0.0, 0, 1, 0) z = cbf_gonio.rotate_vector(0.0, 0, 0, 1) R = matrix.rec(x + y + z, (3, 3)).transpose() S = axis.axis_and_angle_as_r3_rotation_matrix(start, deg=True) fixed = S.inverse() * R return axis, fixed
def update_rot_tran(x, transforms_obj=None, ncs_restraints_group_list=None): """ Convert the refinable parameters, rotations angles and scaled translations, back to rotation matrices and translation vectors and updates the transforms_obj (ncs_restraints_group_list) Args: x : a flex.double of the form (theta_1,psi_1,phi_1,tx_1,ty_1,tz_1,.. theta_n,psi_n,phi_n,tx_n/s,ty_n/s,tz_n/s). where n is the number of transformations. transforms_obj : (ncs_group_object) containing information on Rotation matrices, Translation vectors and NCS ncs_restraints_group_list : a list of ncs_restraint_group objects Returns: The same type of input object with converted transforms """ assert bool(transforms_obj) == (not bool(ncs_restraints_group_list)) if transforms_obj: ncs_restraints_group_list = transforms_obj.get_ncs_restraints_group_list( ) if ncs_restraints_group_list: i = 0 for gr in ncs_restraints_group_list: copies = [] for tr in gr.copies: the, psi, phi = x[i * 6:i * 6 + 3] rot = scitbx.rigid_body.rb_mat_xyz(the=the, psi=psi, phi=phi, deg=False) tran = matrix.rec(x[i * 6 + 3:i * 6 + 6], (3, 1)) tr.r = (rot.rot_mat()) tr.t = tran copies.append(tr) i += 1 gr.copies = copies if transforms_obj: transforms_obj.update_using_ncs_restraints_group_list( ncs_restraints_group_list) return transforms_obj else: return ncs_restraints_group_list
def update_rot_tran(x,transforms_obj=None,ncs_restraints_group_list=None): """ Convert the refinable parameters, rotations angles and scaled translations, back to rotation matrices and translation vectors and updates the transforms_obj (ncs_restraints_group_list) Args: x : a flex.double of the form (theta_1,psi_1,phi_1,tx_1,ty_1,tz_1,.. theta_n,psi_n,phi_n,tx_n/s,ty_n/s,tz_n/s). where n is the number of transformations. transforms_obj : (ncs_group_object) containing information on Rotation matrices, Translation vectors and NCS ncs_restraints_group_list : a list of ncs_restraint_group objects Returns: The same type of input object with converted transforms """ assert bool(transforms_obj) == (not bool(ncs_restraints_group_list)) if transforms_obj: ncs_restraints_group_list = transforms_obj.get_ncs_restraints_group_list() if ncs_restraints_group_list: i = 0 for gr in ncs_restraints_group_list: copies = [] for tr in gr.copies: the,psi,phi =x[i*6:i*6+3] rot = scitbx.rigid_body.rb_mat_xyz( the=the, psi=psi, phi=phi, deg=False) tran = matrix.rec(x[i*6+3:i*6+6],(3,1)) tr.r = (rot.rot_mat()) tr.t = tran copies.append(tr) i += 1 gr.copies = copies if transforms_obj: transforms_obj.update_using_ncs_restraints_group_list( ncs_restraints_group_list) return transforms_obj else: return ncs_restraints_group_list
def roundoff(val, precision=3, as_string=False): ''' round off all floats in a list (or tuple) of list (or tuples) recursively using round2() defined above as in: >>> math_utils.roundoff( [12.3454, 7.4843, ["foo", (35.3581, -0.3856, [4.2769, 3.2147] )] ]) [12.345, 7.484, ['foo', (35.358, -0.386, [4.277, 3.215])]] If value is less than 10**-precision or greater than 10**precision then return with scientific notation ''' if isinstance(val, float): if math.isnan(val): return float("nan") if abs(val) < float("1e-%d" % precision) or abs(val) > float( "9e%d" % precision): fstr = "%" + "%d" % precision fstr += ".%de" % precision val2str = fstr % val if as_string: return val2str return float(val2str) return round2(val, precision) if isinstance(val, list): for i, v in enumerate(val): val[i] = roundoff(v, precision) if isinstance(val, tuple): val = list(val) for i, v in enumerate(val): val[i] = roundoff(v, precision) val = tuple(val) if isinstance(val, matrix.sqr): val = list(val) for i, v in enumerate(val): val[i] = roundoff(v, precision) val = matrix.sqr(val) if isinstance(val, matrix.rec): valn = val.n val = list(val) for i, v in enumerate(val): val[i] = roundoff(v, precision) val = matrix.rec(elems=val, n=valn) return val
def glm33(x, p): from math import exp, sqrt, log, factorial, lgamma from scitbx import matrix from scipy.stats import poisson beta0 = 0 while True: n = beta0 mu = exp(n) z = [(xx - mu) / mu for xx in x] w = [pp * mu for pp in p] W = matrix.diag(w) Z = matrix.col(z) X = matrix.rec([1] * len(z), (len(z), 1)) H = X * (X.transpose() * W * X).inverse() * X.transpose() * W H = [H[i + i * len(z)] for i in range(len(z))] MSE = sum((xx - mu)**2 for xx in x) / len(x) r = [xx - mu for xx in x] D = [rr * rr / (1 * MSE) * (hh / (1 - hh)**2) for rr, hh in zip(r, H)] N = sum(1 for d in D if d > 4 / len(x)) # print X.transpose()*W*z # print (W*X)[0] # print (X.transpose()*W*X).inverse()[0] delta = (X.transpose() * W * X).inverse() * X.transpose() * W * z # print delta relE = sqrt( sum([d * d for d in delta]) / max(1e-10, sum([d * d for d in [beta0]]))) beta0 = beta0 + delta[0] # print relE if relE < 1e-3: break return exp(beta0)
def __init__(O, type, qE): assert type in ["euler_params", "euler_angles_xyz"] if (type == "euler_params"): if (len(qE.elems) == 3): qE = euler_angles_xyz_qE_as_euler_params_qE(qE=qE) else: if (len(qE.elems) == 4): qE = euler_params_qE_as_euler_angles_xyz_qE(qE=qE) O.type = type O.qE = qE O.q_size = len(qE) # if (type == "euler_params"): O.unit_quaternion = qE.normalize() # RBDA, bottom of p. 86 O.E = RBDA_Eq_4_12(q=O.unit_quaternion) else: O.E = RBDA_Eq_4_7(q=qE) # O.Tps = matrix.rt((O.E, (0, 0, 0))) O.Tsp = matrix.rt((O.E.transpose(), (0, 0, 0))) O.Xj = T_as_X(O.Tps) O.S = matrix.rec( (1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0), n=(6, 3))
def glm33(x, p): from math import exp , sqrt, log, factorial, lgamma from scitbx import matrix from scipy.stats import poisson beta0 = 0 while True: n = beta0 mu = exp(n) z = [(xx - mu) / mu for xx in x] w = [pp * mu for pp in p] W = matrix.diag(w) Z = matrix.col(z) X = matrix.rec([1]*len(z), (len(z),1)) H = X*(X.transpose() *W* X).inverse() * X.transpose()*W H = [H[i+i*len(z)] for i in range(len(z))] MSE = sum((xx-mu)**2 for xx in x) / len(x) r = [xx - mu for xx in x] D = [rr*rr / (1 * MSE) * (hh / (1-hh)**2) for rr, hh in zip(r, H)] N = sum(1 for d in D if d > 4 / len(x)) # print X.transpose()*W*z # print (W*X)[0] # print (X.transpose()*W*X).inverse()[0] delta = (X.transpose() * W * X).inverse() * X.transpose()*W*z # print delta relE = sqrt(sum([d*d for d in delta])/max(1e-10, sum([d*d for d in [beta0]]))) beta0 = beta0 + delta[0] # print relE if relE < 1e-3: break return exp(beta0)
def get_panel_fast_slow(self, serial): """Get the average x- and y-coordinates of all the ASIC:s in the panel with serial @p serial. This is done by back-transforming the centre's of each ASIC to the screen (sort of) coordinate system. This is more robust than getting the panel positions directly. """ from xfel.cftbx.detector.metrology import get_projection_matrix center = col([self._asic_focus[0] / 2, self._asic_focus[1] / 2, 1]) fast, nmemb, slow = 0, 0, 0 # Use the pixel size for the ASIC to construct the final # projection matrix. for p in self._metrology_params.detector.panel: if (p.serial != serial): continue for s in p.sensor: for a in s.asic: E = rec(elems=[ +1 / a.pixel_size[0], 0, 0, 0, 0, -1 / a.pixel_size[1], 0, 0 ], n=[2, 4]) Pb = get_projection_matrix(a.pixel_size, a.dimension)[1] Tb = self._matrices[(0, p.serial, s.serial, a.serial)][1] t = E * Tb * Pb * center fast += t(0, 0) slow += t(1, 0) nmemb += 1 if (nmemb == 0): return (0, 0) return (fast / nmemb, slow / nmemb)
def _calc_cell_parameter_sd(self): from scitbx.math.lefebvre import matrix_inverse_error_propagation from scitbx.math import angle_derivative_wrt_vectors from math import pi, acos, sqrt # self._cov_B is the covariance matrix of elements of the B matrix. We # need to construct the covariance matrix of elements of the # transpose of B. The vector of elements of B is related to the # vector of elements of its transpose by a permutation, P. P = matrix.sqr((1,0,0,0,0,0,0,0,0, 0,0,0,1,0,0,0,0,0, 0,0,0,0,0,0,1,0,0, 0,1,0,0,0,0,0,0,0, 0,0,0,0,1,0,0,0,0, 0,0,0,0,0,0,0,1,0, 0,0,1,0,0,0,0,0,0, 0,0,0,0,0,1,0,0,0, 0,0,0,0,0,0,0,0,1)) # We can use P to replace var_cov with the covariance matrix of # elements of the transpose of B. var_cov = P*self._cov_B*P # From B = (O^-1)^T we can convert this # to the covariance matrix of the real space orthogonalisation matrix Bt = self._B.transpose() O = Bt.inverse() cov_O = matrix_inverse_error_propagation(Bt, var_cov) # The real space unit cell vectors are given by vec_a = (O * matrix.col((1,0,0))) vec_b = (O * matrix.col((0,1,0))) vec_c = (O * matrix.col((0,0,1))) # So the unit cell parameters are a, b, c = vec_a.length(), vec_b.length(), vec_c.length() alpha = acos(vec_b.dot(vec_c) / (b*c)) beta = acos(vec_a.dot(vec_c) / (a*c)) gamma = acos(vec_a.dot(vec_b) / (a*b)) # The estimated errors are calculated by error propagation from cov_O. In # each case we define a function F(O) that converts the matrix O into the # unit cell parameter of interest. To do error propagation to get the # variance of that cell parameter we need the Jacobian of the function. # This is a 1*9 matrix of derivatives in the order of the elements of O # # / dF dF dF dF dF dF dF dF dF \ # J = | ---, ---, ---, ---, ---, ---, ---, ---, --- | # \ da1 db1 dc1 da2 db2 dc2 da3 db3 dc3 / # # For cell length |a|, F = sqrt(a1^2 + a2^2 + a3^2) jacobian = matrix.rec( (vec_a[0]/a, 0, 0, vec_a[1]/a, 0, 0, vec_a[2]/a, 0, 0), (1, 9)) var_a = (jacobian * cov_O * jacobian.transpose())[0] # For cell length |b|, F = sqrt(b1^2 + b2^2 + b3^2) jacobian = matrix.rec( (0, vec_b[0]/b, 0, 0, vec_b[1]/b, 0, 0, vec_b[2]/b, 0), (1, 9)) var_b = (jacobian * cov_O * jacobian.transpose())[0] # For cell length |c|, F = sqrt(c1^2 + c2^2 + c3^2) jacobian = matrix.rec( (0, 0, vec_c[0]/c, 0, 0, vec_c[1]/c, 0, 0, vec_c[2]/c), (1, 9)) jacobian_t = jacobian.transpose() var_c = (jacobian * cov_O * jacobian.transpose())[0] # For cell volume (a X b).c, # F = c1(a2*b3 - b2*a3) + c2(a3*b1 - b3*a1) + c3(a1*b2 - b1*a2) a1, a2, a3 = vec_a b1, b2, b3 = vec_b c1, c2, c3 = vec_c jacobian = matrix.rec((c3*b2 - c2*b3, c1*b3 - c3*b1, c2*b1 - c1*b2, c2*a3 - c3*a2, c3*a1 - c1*a3, c1*a2 - c2*a1, a2*b3 - b2*a3, a3*b1 - b3*a1, a1*b2 - b1*a2), (1,9)) jacobian_t = jacobian.transpose() var_V = (jacobian * cov_O * jacobian.transpose())[0] self._cell_volume_sd = sqrt(var_V) # For the unit cell angles we need to calculate derivatives of the angles # with respect to the elements of O dalpha_db, dalpha_dc = angle_derivative_wrt_vectors(vec_b, vec_c) dbeta_da, dbeta_dc = angle_derivative_wrt_vectors(vec_a, vec_c) dgamma_da, dgamma_db = angle_derivative_wrt_vectors(vec_a, vec_b) # For angle alpha, F = acos( b.c / |b||c|) jacobian = matrix.rec( (0, dalpha_db[0], dalpha_dc[0], 0, dalpha_db[1], dalpha_dc[1], 0, dalpha_db[2], dalpha_dc[2]), (1, 9)) var_alpha = (jacobian * cov_O * jacobian.transpose())[0] # For angle beta, F = acos( a.c / |a||c|) jacobian = matrix.rec( (dbeta_da[0], 0, dbeta_dc[0], dbeta_da[1], 0, dbeta_dc[1], dbeta_da[2], 0, dbeta_dc[2]), (1, 9)) var_beta = (jacobian * cov_O * jacobian.transpose())[0] # For angle gamma, F = acos( a.b / |a||b|) jacobian = matrix.rec( (dgamma_da[0], dgamma_db[0], 0, dgamma_da[1], dgamma_db[1], 0, dgamma_da[2], dgamma_db[2], 0), (1, 9)) var_gamma = (jacobian * cov_O * jacobian.transpose())[0] # Symmetry constraints may mean variances of the angles should be zero. # Floating point error could lead to negative variances. Ensure these are # caught before taking their square root! var_alpha = max(0, var_alpha) var_beta = max(0, var_beta) var_gamma = max(0, var_gamma) from math import pi rad2deg = 180. / pi self._cell_sd = (sqrt(var_a), sqrt(var_b), sqrt(var_c), sqrt(var_alpha) * rad2deg, sqrt(var_beta) * rad2deg, sqrt(var_gamma) * rad2deg) return
def __init__(self, ub_beg, ub_end, axis, s0, dmin, margin = 3): # the source vector and wavelength self._source = -s0 self._wavelength = 1 / sqrt(s0.dot(s0)) self._wavelength_sq = self._wavelength**2 # the rotation axis self._axis = axis # the resolution limit self._dstarmax = 1 / dmin self._dstarmax2 = self._dstarmax**2 # Margin by which to expand limits. Mosflm uses 3. self._margin = int(margin) # Determine the permutation order of columns of the setting matrix. Use # the setting from the beginning for this. # As a side-effect set self._permutation. col1, col2, col3 = self._permute_axes(ub_beg) # Thus set the reciprocal lattice axis vectors, in permuted order # p, q and r for both orientations rl_vec = [ub_beg.extract_block(start=(0,0), stop=(3,1)), ub_beg.extract_block(start=(0,1), stop=(3,2)), ub_beg.extract_block(start=(0,2), stop=(3,3))] self._rlv_beg = [rl_vec[col1], rl_vec[col2], rl_vec[col3]] rl_vec = [ub_end.extract_block(start=(0,0), stop=(3,1)), ub_end.extract_block(start=(0,1), stop=(3,2)), ub_end.extract_block(start=(0,2), stop=(3,3))] self._rlv_end = [rl_vec[col1], rl_vec[col2], rl_vec[col3]] # Set permuted setting matrices self._p_beg = matrix.sqr(self._rlv_beg[0].elems + self._rlv_beg[1].elems + self._rlv_beg[2].elems).transpose() self._p_end = matrix.sqr(self._rlv_end[0].elems + self._rlv_end[1].elems + self._rlv_end[2].elems).transpose() ## Define a new coordinate system concentric with the Ewald sphere. ## ## X' = X - source_x ## Y' = Y - source_y ## Z' = Z - source_z ## ## X = P' h' ## - = - ## / p11 p12 p13 -source_X \ ## where h' = (p, q, r, 1)^T and P' = | p21 p22 p23 -source_y | ## - = \ p31 p32 p33 -source_z / ## # Calculate P' matrices for the beginning and end settings pp_beg = matrix.rec(self._p_beg.elems[0:3] + (-1.*self._source[0],) + self._p_beg.elems[3:6] + (-1.*self._source[1],) + self._p_beg.elems[6:9] + (-1.*self._source[2],), n=(3, 4)) pp_end = matrix.rec(self._p_end.elems[0:3] + (-1.*self._source[0],) + self._p_end.elems[3:6] + (-1.*self._source[1],) + self._p_end.elems[6:9] + (-1.*self._source[2],), n=(3, 4)) # Various quantities of interest are obtained from the reciprocal metric # tensor T of P'. These quantities are to be used (later) for solving # the intersection of a line of constant p, q index with the Ewald # sphere. It is efficient to calculate these before the outer loop. So, # calculate T for both beginning and end settings t_beg = (pp_beg.transpose() * pp_beg).as_list_of_lists() t_end = (pp_end.transpose() * pp_end).as_list_of_lists() # quantities that are constant with p, beginning orientation self._cp_beg = [t_beg[2][2], t_beg[2][3]**2, t_beg[0][2] * t_beg[2][3] - t_beg[0][3] * t_beg[2][2], t_beg[0][2]**2 - t_beg[0][0] * t_beg[2][2], t_beg[1][2] * t_beg[2][3] - t_beg[1][3] * t_beg[2][2], t_beg[0][2] * t_beg[1][2] - t_beg[0][1] * t_beg[2][2], t_beg[1][2]**2 - t_beg[1][1] * t_beg[2][2], 2.0 * t_beg[0][2], 2.0 * t_beg[1][2], t_beg[0][0], t_beg[1][1], 2.0 * t_beg[0][1], 2.0 * t_beg[2][3], 2.0 * t_beg[1][3], 2.0 * t_beg[0][3]] # quantities that are constant with p, end orientation self._cp_end = [t_end[2][2], t_end[2][3]**2, t_end[0][2] * t_end[2][3] - t_end[0][3] * t_end[2][2], t_end[0][2]**2 - t_end[0][0] * t_end[2][2], t_end[1][2] * t_end[2][3] - t_end[1][3] * t_end[2][2], t_end[0][2] * t_end[1][2] - t_end[0][1] * t_end[2][2], t_end[1][2]**2 - t_end[1][1] * t_end[2][2], 2.0 * t_end[0][2], 2.0 * t_end[1][2], t_end[0][0], t_end[1][1], 2.0 * t_end[0][1], 2.0 * t_end[2][3], 2.0 * t_end[1][3], 2.0 * t_end[0][3]] ## The following are set during the generation of indices # planes of constant p tangential to the Ewald sphere self._ewald_p_lim_beg = None self._ewald_p_lim_end = None # planes of constant p touching the circle of intersection between the # Ewald and resolution limiting spheres self._res_p_lim_beg = None self._res_p_lim_end = None # looping p limits self._p_lim = None return
def exercise_rational(): from scitbx.matrix import row_echelon from scitbx import matrix from libtbx.utils import flat_list from boost_adaptbx.boost import rational import random rng = random.Random(0) # m = [[0]] t = [0] free_vars = row_echelon.form_rational(m, t) assert m == [[0]] assert t == [0] assert free_vars == [0] sol = row_echelon.back_substitution_rational(m, t, free_vars, [1]) assert sol == [1] sol = row_echelon.back_substitution_rational(m, None, free_vars, [2]) assert sol == [2] # m = [[0]] t = [1] free_vars = row_echelon.form_rational(m, t) assert m == [[0]] assert t == [1] assert free_vars == [0] sol = row_echelon.back_substitution_rational(m, t, free_vars, [1]) assert sol is None # m = [[1]] t = [2] free_vars = row_echelon.form_rational(m, t) assert m == [[1]] assert t == [2] assert free_vars == [] sol = row_echelon.back_substitution_rational(m, t, free_vars, [1]) assert sol == [2] # def rr(): return rational.int(rng.randrange(-5,6), rng.randrange(1,10)) # for i_trial in range(10): for nr in [1,2,3]: for nc in [1,2,3]: m = [] for ir in range(nr): m.append([rr() for ic in range(nc)]) m_orig = matrix.rec(flat_list(m), (nr,nc)) sol_orig = [rr() for ic in range(nc)] t_orig = list(m_orig * matrix.col(sol_orig)) t = list(t_orig) free_vars = row_echelon.form_rational(m, t) sol = [None] * nc for ic in free_vars: sol[ic] = sol_orig[ic] sol = row_echelon.back_substitution_rational(m, t, free_vars, sol) assert sol is not None assert sol.count(None) == 0 assert sol == sol_orig sol = [1] * nc sol = row_echelon.back_substitution_rational(m, None, free_vars, sol) assert sol is not None assert (m_orig * matrix.col(sol)).dot() == 0 # for i_trial in range(10): from itertools import count for i in count(10): a = matrix.col([rr(), rr(), rr()]) b = matrix.col([rr(), rr(), rr()]) if (a.cross(b).dot() != 0): break else: raise RuntimeError p = rng.randrange(-5,6) q = rng.randrange(-5,6) def check(a, b, c, expected_free_vars, expected_sol): m = [] t = [] for i in range(3): m.append([a[i], b[i]]) t.append(c[i]) m_orig = matrix.rec(flat_list(m), (3,2)) t_orig = list(t) free_vars = row_echelon.form_rational(m, t) assert free_vars == expected_free_vars sol = row_echelon.back_substitution_rational(m, t, free_vars, [3, 11]) assert sol == expected_sol if (sol is not None): assert list(m_orig * sol) == t_orig check(a, b, p*a+q*b, [], [p,q]) check(a, b, a.cross(b), [], None) check(a, 5*a, -7*a, [1], [-62,11]) check(a, 5*a, b, [1], None) check([0,0,0], [0,0,0], [0,0,0], [0,1], [3,11])
def __init__(self, xray_structure, name='??', **kwds): super(xray_structure_viewer, self).__init__( unit_cell=xray_structure.unit_cell(), orthographic=True, light_position=(-1, 1, 1, 0), **kwds) assert self.bonding in ("covalent", "all") assert self.bonding != "all" or self.distance_cutoff is not None self.xray_structure = xs = xray_structure self.setWindowTitle("%s in %s" % (name, xs.space_group().type().hall_symbol())) sites_frac = xs.sites_frac() self.set_extent(sites_frac.min(), sites_frac.max()) self.is_unit_cell_shown = False sites_cart = self.sites_cart = xs.sites_cart() thermal_tensors = xs.extract_u_cart_plus_u_iso() self.ellipsoid_to_sphere_transforms = {} self.scatterer_indices = flex.std_string() self.scatterer_labels = flex.std_string() for i, (sc, site, u_cart) in enumerate(itertools.izip(xs.scatterers(), sites_cart, thermal_tensors)): t = quadrics.ellipsoid_to_sphere_transform(site, u_cart) self.ellipsoid_to_sphere_transforms.setdefault( sc.element_symbol(), quadrics.shared_ellipsoid_to_sphere_transforms()).append(t) self.scatterer_indices.append("# %i" % i) self.scatterer_labels.append(sc.label) self.labels = None self.label_font = QtGui.QFont("Arial Black", pointSize=18) if self.bonding == "covalent": radii = [ covalent_radii.table(elt).radius() for elt in xs.scattering_type_registry().type_index_pairs_as_dict() ] buffer_thickness = 2*max(radii) + self.covalent_bond_tolerance asu_mappings = xs.asu_mappings(buffer_thickness=buffer_thickness) bond_table = crystal.pair_asu_table(asu_mappings) bond_table.add_covalent_pairs(xs.scattering_types(), tolerance=self.covalent_bond_tolerance) elif self.bonding == "all": asu_mappings = xs.asu_mappings(buffer_thickness=self.distance_cutoff) bond_table = crystal.pair_asu_table(asu_mappings) bond_table.add_all_pairs(self.distance_cutoff) pair_sym_table = bond_table.extract_pair_sym_table( all_interactions_from_inside_asu=True) self.bonds = flex.vec3_double() self.bonds.reserve(len(xs.scatterers())) uc = self.xray_structure.unit_cell() frac = mat.rec(uc.fractionalization_matrix(), (3,3)) inv_frac = frac.inverse() site_symms = xs.site_symmetry_table() scatt = self.xray_structure.scatterers() for i, neighbours in enumerate(pair_sym_table): x0 = sites_cart[i] sc0 = scatt[i] for j, ops in neighbours.items(): sc1 = scatt[j] if sc0.scattering_type == 'H' and sc1.scattering_type == 'H': continue for op in ops: if op.is_unit_mx(): x1 = sites_cart[j] else: x1 = uc.orthogonalize(op*sites_frac[j]) op_cart = inv_frac*mat.rec(op.r().as_double(), (3,3))*frac u1 = (op_cart *mat.sym(sym_mat3=thermal_tensors[j]) *op_cart.transpose()) t = quadrics.ellipsoid_to_sphere_transform(x1, u1.as_sym_mat3()) self.ellipsoid_to_sphere_transforms[sc1.element_symbol()].append(t) self.sites_cart.append(x1) op_lbl = (" [%s]" % op).lower() self.scatterer_indices.append("# %i%s" % (j, op_lbl)) self.scatterer_labels.append("%s%s" % (sc1.label, op_lbl)) self.bonds.append(x0) self.bonds.append(x1)
def glm2(y): from math import sqrt, exp, floor, log from scipy.stats import poisson from scitbx import matrix from dials.array_family import flex y = flex.double(y) x = flex.double([1.0 for yy in y]) w = flex.double([1.0 for yy in y]) X = matrix.rec(x, (len(x), 1)) c = 1.345 beta = matrix.col([0]) maxiter = 10 accuracy = 1e-3 for iter in range(maxiter): ni = flex.double([1.0 for xx in x]) sni = flex.sqrt(ni) eta = flex.double(X * beta) mu = flex.exp(eta) dmu_deta = flex.exp(eta) Vmu = mu sVF = flex.sqrt(Vmu) residP = (y - mu) * sni / sVF phi = 1 sV = sVF * sqrt(phi) residPS = residP / sqrt(phi) H = flex.floor(mu * ni - c * sni * sV) K = flex.floor(mu * ni + c * sni * sV) # print min(H) dpH = flex.double([poisson(mui).pmf(Hi) for mui, Hi in zip(mu, H)]) dpH1 = flex.double([poisson(mui).pmf(Hi - 1) for mui, Hi in zip(mu, H)]) dpK = flex.double([poisson(mui).pmf(Ki) for mui, Ki in zip(mu, K)]) dpK1 = flex.double([poisson(mui).pmf(Ki - 1) for mui, Ki in zip(mu, K)]) pHm1 = flex.double([poisson(mui).cdf(Hi - 1) for mui, Hi in zip(mu, H)]) pKm1 = flex.double([poisson(mui).cdf(Ki - 1) for mui, Ki in zip(mu, K)]) pH = pHm1 + dpH # = ppois(H,*) pK = pKm1 + dpK # = ppois(K,*) E2f = mu * (dpH1 - dpH - dpK1 + dpK) + pKm1 - pHm1 Epsi = c * (1.0 - pK - pH) + (mu / sV) * (dpH - dpK) Epsi2 = c * c * (pH + 1.0 - pK) + E2f EpsiS = c * (dpH + dpK) + E2f / sV psi = flex.double([huber(rr, c) for rr in residPS]) cpsi = psi - Epsi temp = cpsi * w * sni / sV * dmu_deta EEqMat = [0] * len(X) for j in range(X.n_rows()): for i in range(X.n_columns()): k = i + j * X.n_columns() EEqMat[k] = X[k] * temp[j] EEqMat = matrix.rec(EEqMat, (X.n_rows(), X.n_columns())) EEq = [] for i in range(EEqMat.n_columns()): col = [] for j in range(EEqMat.n_rows()): k = i + j * EEqMat.n_columns() col.append(EEqMat[k]) EEq.append(sum(col) / len(col)) EEq = matrix.col(EEq) DiagB = EpsiS / (sni * sV) * w * (ni * dmu_deta) ** 2 B = matrix.diag(DiagB) H = (X.transpose() * B * X) / len(y) dbeta = H.inverse() * EEq beta_new = beta + dbeta relE = sqrt(sum([d * d for d in dbeta]) / max(1e-10, sum([d * d for d in beta]))) beta = beta_new # print relE if relE < accuracy: break weights = [min(1, c / abs(r)) for r in residPS] eta = flex.double(X * beta) mu = flex.exp(eta) return beta
from scipy.stats import linregress from scipy.spatial.transform import Rotation from simtbx.nanoBragg import sim_data from scitbx.matrix import sqr, rec from cctbx import uctbx from dxtbx.model import Crystal ucell = (70, 60, 50, 90.0, 110, 90.0) symbol = "C121" a_real, b_real, c_real = sqr(uctbx.unit_cell(ucell).orthogonalization_matrix()).transpose().as_list_of_lists() C = Crystal(a_real, b_real, c_real, symbol) # random raotation rotation = Rotation.random(num=1, random_state=101)[0] Q = rec(rotation.as_quat(), n=(4, 1)) rot_ang, rot_axis = Q.unit_quaternion_as_axis_and_angle() C.rotate_around_origin(rot_axis, rot_ang) S = sim_data.SimData(use_default_crystal=True) S.crystal.dxtbx_crystal = C spectrum = S.beam.spectrum wave, flux = spectrum[0] Nwave = 5 waves = np.linspace(wave-wave*0.002, wave+wave*0.002, Nwave) fluxes = np.ones(Nwave) * flux / Nwave lambda0_GT = 0 lambda1_GT = 1 S.beam.spectrum = list(zip(waves, fluxes))
def exercise_rational(): from scitbx.matrix import row_echelon from scitbx import matrix from libtbx.utils import flat_list from boost import rational import random rng = random.Random(0) # m = [[0]] t = [0] free_vars = row_echelon.form_rational(m, t) assert m == [[0]] assert t == [0] assert free_vars == [0] sol = row_echelon.back_substitution_rational(m, t, free_vars, [1]) assert sol == [1] sol = row_echelon.back_substitution_rational(m, None, free_vars, [2]) assert sol == [2] # m = [[0]] t = [1] free_vars = row_echelon.form_rational(m, t) assert m == [[0]] assert t == [1] assert free_vars == [0] sol = row_echelon.back_substitution_rational(m, t, free_vars, [1]) assert sol is None # m = [[1]] t = [2] free_vars = row_echelon.form_rational(m, t) assert m == [[1]] assert t == [2] assert free_vars == [] sol = row_echelon.back_substitution_rational(m, t, free_vars, [1]) assert sol == [2] # def rr(): return rational.int(rng.randrange(-5,6), rng.randrange(1,10)) # for i_trial in xrange(10): for nr in [1,2,3]: for nc in [1,2,3]: m = [] for ir in xrange(nr): m.append([rr() for ic in xrange(nc)]) m_orig = matrix.rec(flat_list(m), (nr,nc)) sol_orig = [rr() for ic in xrange(nc)] t_orig = list(m_orig * matrix.col(sol_orig)) t = list(t_orig) free_vars = row_echelon.form_rational(m, t) sol = [None] * nc for ic in free_vars: sol[ic] = sol_orig[ic] sol = row_echelon.back_substitution_rational(m, t, free_vars, sol) assert sol is not None assert sol.count(None) == 0 assert sol == sol_orig sol = [1] * nc sol = row_echelon.back_substitution_rational(m, None, free_vars, sol) assert sol is not None assert (m_orig * matrix.col(sol)).dot() == 0 # for i_trial in xrange(10): from itertools import count for i in count(10): a = matrix.col([rr(), rr(), rr()]) b = matrix.col([rr(), rr(), rr()]) if (a.cross(b).dot() != 0): break else: raise RuntimeError p = rng.randrange(-5,6) q = rng.randrange(-5,6) def check(a, b, c, expected_free_vars, expected_sol): m = [] t = [] for i in xrange(3): m.append([a[i], b[i]]) t.append(c[i]) m_orig = matrix.rec(flat_list(m), (3,2)) t_orig = list(t) free_vars = row_echelon.form_rational(m, t) assert free_vars == expected_free_vars sol = row_echelon.back_substitution_rational(m, t, free_vars, [3, 11]) assert sol == expected_sol if (sol is not None): assert list(m_orig * sol) == t_orig check(a, b, p*a+q*b, [], [p,q]) check(a, b, a.cross(b), [], None) check(a, 5*a, -7*a, [1], [-62,11]) check(a, 5*a, b, [1], None) check([0,0,0], [0,0,0], [0,0,0], [0,1], [3,11])
def df_d_params(self): tphkl = 2 * math.pi * matrix.col(self.hkl) h, k, l = self.hkl d_exp_huh_d_u_star = matrix.col( [h**2, k**2, l**2, 2 * h * k, 2 * h * l, 2 * k * l]) for i_scatterer, scatterer in enumerate(self.scatterers): site_symmetry_ops = None if (self.site_symmetry_table.is_special_position(i_scatterer)): site_symmetry_ops = self.site_symmetry_table.get(i_scatterer) site_constraints = site_symmetry_ops.site_constraints() if (scatterer.flags.use_u_aniso()): adp_constraints = site_symmetry_ops.adp_constraints() w = scatterer.weight() wwo = scatterer.weight_without_occupancy() if (not scatterer.flags.use_u_aniso()): huh = scatterer.u_iso * self.d_star_sq dw = math.exp(mtps * huh) gaussian = self.scattering_type_registry.gaussian_not_optional( scattering_type=scatterer.scattering_type) f0 = gaussian.at_d_star_sq(self.d_star_sq) ffp = f0 + scatterer.fp fdp = scatterer.fdp ff = ffp + 1j * fdp d_site = matrix.col([0, 0, 0]) if (not scatterer.flags.use_u_aniso()): d_u_iso = 0 d_u_star = None else: d_u_iso = None d_u_star = matrix.col([0, 0, 0, 0, 0, 0]) d_occ = 0j d_fp = 0j d_fdp = 0j for s in self.space_group: r = s.r().as_rational().as_float() s_site = s * scatterer.site alpha = matrix.col(s_site).dot(tphkl) if (scatterer.flags.use_u_aniso()): s_u_star_s = r * matrix.sym( sym_mat3=scatterer.u_star) * r.transpose() huh = (matrix.row(self.hkl) * s_u_star_s).dot( matrix.col(self.hkl)) dw = math.exp(mtps * huh) e = cmath.exp(1j * alpha) site_gtmx = r.transpose() d_site += site_gtmx * (w * dw * ff * e * 1j * tphkl) if (not scatterer.flags.use_u_aniso()): d_u_iso += w * dw * ff * e * mtps * self.d_star_sq else: u_star_gtmx = matrix.sqr( tensor_rank_2_gradient_transform_matrix(r)) d_u_star += u_star_gtmx * (w * dw * ff * e * mtps * d_exp_huh_d_u_star) d_occ += wwo * dw * ff * e d_fp += w * dw * e d_fdp += w * dw * e * 1j if (site_symmetry_ops is not None): gsm = site_constraints.gradient_sum_matrix() gsm = matrix.rec(elems=gsm, n=gsm.focus()) d_site = gsm * d_site if (scatterer.flags.use_u_aniso()): gsm = adp_constraints.gradient_sum_matrix() gsm = matrix.rec(elems=gsm, n=gsm.focus()) d_u_star = gsm * d_u_star result = flex.complex_double(d_site) if (not scatterer.flags.use_u_aniso()): result.append(d_u_iso) else: result.extend(flex.complex_double(d_u_star)) result.extend(flex.complex_double([d_occ, d_fp, d_fdp])) yield result
def _get_flex_image_multipanel(panels, raw_data, brightness=1.0, show_untrusted=False): # From xfel.cftbx.cspad_detector.readHeader() and # xfel.cftbx.cspad_detector.get_flex_image(). XXX Is it possible to # merge this with _get_flex_image() above? XXX Move to dxtbx Format # class (or a superclass for multipanel images)? from math import ceil from iotbx.detectors import generic_flex_image from libtbx.test_utils import approx_equal from scitbx.array_family import flex from scitbx.matrix import col, rec, sqr from xfel.cftbx.detector.metrology import get_projection_matrix assert len(panels) == len(raw_data) # Determine next multiple of eight of the largest panel size. for data in raw_data: if 'data_max_focus' not in locals(): data_max_focus = data.focus() else: data_max_focus = (max(data_max_focus[0], data.focus()[0]), max(data_max_focus[1], data.focus()[1])) data_padded = (8 * int(ceil(data_max_focus[0] / 8)), 8 * int(ceil(data_max_focus[1] / 8))) # Assert that all saturated values are equal and not None. While # dxtbx records a separated trusted_range for each panel, # generic_flex_image supports only accepts a single common value for # the saturation. for panel in panels: if 'saturation' not in locals(): saturation = panel.get_trusted_range()[1] else: assert approx_equal(saturation, panel.get_trusted_range()[1]) assert 'saturation' in locals() and saturation is not None # Create rawdata and my_flex_image before populating it. rawdata = flex.double( flex.grid(len(panels) * data_padded[0], data_padded[1])) my_flex_image = generic_flex_image( rawdata=rawdata, size1_readout=data_max_focus[0], size2_readout=data_max_focus[1], brightness=brightness, saturation=saturation, show_untrusted=show_untrusted ) # XXX If a point is contained in two panels simultaneously, it will # be assigned to the panel defined first. XXX Use a Z-buffer # instead? for i in range(len(panels)): # Determine the pixel size for the panel (in meters), as pixel # sizes need not be identical. data = raw_data[i] panel = panels[i] pixel_size = (panel.get_pixel_size()[0] * 1e-3, panel.get_pixel_size()[1] * 1e-3) if len(panels) == 24 and panels[0].get_image_size() == (2463,195): #print "DLS I23 12M" rawdata.matrix_paste_block_in_place( block=data.as_double(), i_row=i * data_padded[0], i_column=0) # XXX hardcoded panel height and row gap my_flex_image.add_transformation_and_translation((1,0,0,1), (-i*(195+17),0)) continue elif len(panels) == 120 and panels[0].get_image_size() == (487,195): i_row = i // 5 i_col = i % 5 #print i_row, i_col #print data_padded #print "DLS I23 12M" rawdata.matrix_paste_block_in_place( block=data.as_double(), i_row=i * data_padded[0], i_column=0) # XXX hardcoded panel height and row gap my_flex_image.add_transformation_and_translation( (1,0,0,1), (-i_row*(195+17),-i_col*(487+7))) continue # Get unit vectors in the fast and slow directions, as well as the # the locations of the origin and the center of the panel, in # meters. fast = col(panel.get_fast_axis()) slow = col(panel.get_slow_axis()) origin = col(panel.get_origin()) * 1e-3 # Viewer will show an orthographic projection of the data onto a plane perpendicular to 0 0 1 projection_normal = col((0.,0.,1.)) beam_to_origin_proj = origin.dot(projection_normal)*projection_normal projected_origin = origin - beam_to_origin_proj center = projected_origin \ + (data.focus()[0] - 1) / 2 * pixel_size[1] * slow \ + (data.focus()[1] - 1) / 2 * pixel_size[0] * fast normal = slow.cross(fast).normalize() # Determine rotational and translational components of the # homogeneous transformation that maps the readout indices to the # three-dimensional laboratory frame. Rf = sqr(( fast(0, 0), fast(1, 0), fast(2, 0), -slow(0, 0), -slow(1, 0), -slow(2, 0), normal(0, 0), normal(1, 0), normal(2, 0))) tf = -Rf * center Tf = sqr((Rf(0, 0), Rf(0, 1), Rf(0, 2), tf(0, 0), Rf(1, 0), Rf(1, 1), Rf(1, 2), tf(1, 0), Rf(2, 0), Rf(2, 1), Rf(2, 2), tf(2, 0), 0, 0, 0, 1)) # E maps picture coordinates onto metric Cartesian coordinates, # i.e. [row, column, 1 ] -> [x, y, z, 1]. Both frames share the # same origin, but the first coordinate of the screen coordinate # system increases downwards, while the second increases towards # the right. XXX Is this orthographic projection the only one # that makes any sense? E = rec(elems=[0, +pixel_size[1], 0, -pixel_size[0], 0, 0, 0, 0, 0, 0, 0, 1], n=[4, 3]) # P: [x, y, z, 1] -> [row, column, 1]. Note that data.focus() # needs to be flipped to give (horizontal, vertical) size, # i.e. (width, height). Pf = get_projection_matrix( pixel_size, (data.focus()[1], data.focus()[0]))[0] rawdata.matrix_paste_block_in_place( block=data.as_double(), i_row=i * data_padded[0], i_column=0) # Last row of T is always [0, 0, 0, 1]. T = Pf * Tf * E R = sqr((T(0, 0), T(0, 1), T(1, 0), T(1, 1))) t = col((T(0, 2), T(1, 2))) #print i,R[0],R[1],R[2],R[3],t[0],t[1] my_flex_image.add_transformation_and_translation(R, t) my_flex_image.followup_brightness_scale() return my_flex_image
def glm(x, p = None): from math import exp , sqrt, log, factorial, lgamma from scitbx import matrix from scipy.stats import poisson beta0 = 0 if p is None: p = [1.0] * len(x) while True: n = beta0 mu = exp(n) z = [n + (xx - mu) / mu for xx in x] w = [pp * mu for pp in p] W = matrix.diag(w) Z = matrix.col(z) X = matrix.rec([1]*len(z), (len(z),1)) beta = (X.transpose() * W * X).inverse() * X.transpose()*W*z if abs(beta[0] - beta0) < 1e-3: break beta0 = beta[0] n = beta[0] mu = exp(n) z = [n + (xx - mu) / mu for xx in x] w = [pp * mu for pp in p] W = matrix.diag(w) Z = matrix.col(z) X = matrix.rec([1]*len(z), (len(z),1)) W12 = matrix.diag([sqrt(ww) for ww in w]) H = X * (X.transpose()*W*X).inverse() * X.transpose() r = [(xx - mu) / mu for xx in x] sum1 = 0 sum2 = 0 sum3 = 0 D = [] for xx in x: d = 0 if xx != 0: d += xx * log(xx) d -= xx * log(mu) d -= (xx - mu) D.append(2*d) # r = [] # for xx in x: # if xx == 0: # r.append(0) # else: # r.append(2*(log(xx) - log(mu))) # D = [] # for i in range(len(r)): # h = H[i+i*H.n[0]] # d = (r[i]/(1 - h))**2 * h/1.0 # D.append(d) # print min(x), max(x) print min(D), max(D), F(1, len(x)) return exp(beta[0]), max(D) > F(1, len(x))
def _get_flex_image_multipanel( panels, raw_data, beam, brightness=1.0, binning=1, show_untrusted=False, color_scheme=0, ): # From xfel.cftbx.cspad_detector.readHeader() and # xfel.cftbx.cspad_detector.get_flex_image(). XXX Is it possible to # merge this with _get_flex_image() above? XXX Move to dxtbx Format # class (or a superclass for multipanel images)? from math import ceil from iotbx.detectors import generic_flex_image from libtbx.test_utils import approx_equal from scitbx.array_family import flex from scitbx.matrix import col, rec, sqr from xfel.cftbx.detector.metrology import get_projection_matrix assert len(panels) == len(raw_data), (len(panels), len(raw_data)) # Determine next multiple of eight of the largest panel size. for data in raw_data: if "data_max_focus" not in locals(): data_max_focus = data.focus() else: data_max_focus = ( max(data_max_focus[0], data.focus()[0]), max(data_max_focus[1], data.focus()[1]), ) data_padded = ( 8 * int(ceil(data_max_focus[0] / 8)), 8 * int(ceil(data_max_focus[1] / 8)), ) # Assert that all saturated values are equal and not None. While # dxtbx records a separated trusted_range for each panel, # generic_flex_image supports only accepts a single common value for # the saturation. for panel in panels: if "saturation" not in locals(): saturation = panel.get_trusted_range()[1] else: assert approx_equal(saturation, panel.get_trusted_range()[1]) assert "saturation" in locals() and saturation is not None # Create rawdata and my_flex_image before populating it. rawdata = flex.double( flex.grid(len(panels) * data_padded[0], data_padded[1])) my_flex_image = generic_flex_image( rawdata=rawdata, binning=binning, size1_readout=data_max_focus[0], size2_readout=data_max_focus[1], brightness=brightness, saturation=saturation, show_untrusted=show_untrusted, color_scheme=color_scheme, ) # Calculate the average beam center across all panels, in meters # not sure this makes sense for detector which is not on a plane? beam_center = col((0, 0, 0)) npanels = 0 for panel in panels: try: beam_center += col(panel.get_beam_centre_lab(beam.get_s0())) npanels += 1 except RuntimeError: # catch DXTBX_ASSERT for no intersection pass beam_center /= npanels / 1e-3 # XXX If a point is contained in two panels simultaneously, it will # be assigned to the panel defined first. XXX Use a Z-buffer # instead? for i, panel in enumerate(panels): # Determine the pixel size for the panel (in meters), as pixel # sizes need not be identical. data = raw_data[i] pixel_size = ( panel.get_pixel_size()[0] * 1e-3, panel.get_pixel_size()[1] * 1e-3, ) if len(panels) == 24 and panels[0].get_image_size() == (2463, 195): rawdata.matrix_paste_block_in_place(block=data.as_double(), i_row=i * data_padded[0], i_column=0) # XXX hardcoded panel height and row gap my_flex_image.add_transformation_and_translation( (1, 0, 0, 1), (-i * (195 + 17), 0)) continue elif len(panels) == 120 and panels[0].get_image_size() == (487, 195): i_row = i // 5 i_col = i % 5 rawdata.matrix_paste_block_in_place(block=data.as_double(), i_row=i * data_padded[0], i_column=0) # XXX hardcoded panel height and row gap my_flex_image.add_transformation_and_translation( (1, 0, 0, 1), (-i_row * (195 + 17), -i_col * (487 + 7))) continue # Get unit vectors in the fast and slow directions, as well as the # the locations of the origin and the center of the panel, in # meters. The origin is taken w.r.t. to average beam center of all # panels. This avoids excessive translations that can result from # rotations around the laboratory origin. Related to beam centre above # and dials#380 not sure this is right for detectors which are not # coplanar since system derived from first panel... fast = col(panel.get_fast_axis()) slow = col(panel.get_slow_axis()) origin = col(panel.get_origin()) * 1e-3 - beam_center center = (origin + (data.focus()[0] - 1) / 2 * pixel_size[1] * slow + (data.focus()[1] - 1) / 2 * pixel_size[0] * fast) normal = slow.cross(fast).normalize() # Determine rotational and translational components of the # homogeneous transformation that maps the readout indices to the # three-dimensional laboratory frame. Rf = sqr(( fast(0, 0), fast(1, 0), fast(2, 0), -slow(0, 0), -slow(1, 0), -slow(2, 0), normal(0, 0), normal(1, 0), normal(2, 0), )) tf = -Rf * center Tf = sqr(( Rf(0, 0), Rf(0, 1), Rf(0, 2), tf(0, 0), Rf(1, 0), Rf(1, 1), Rf(1, 2), tf(1, 0), Rf(2, 0), Rf(2, 1), Rf(2, 2), tf(2, 0), 0, 0, 0, 1, )) # E maps picture coordinates onto metric Cartesian coordinates, # i.e. [row, column, 1 ] -> [x, y, z, 1]. Both frames share the # same origin, but the first coordinate of the screen coordinate # system increases downwards, while the second increases towards # the right. XXX Is this orthographic projection the only one # that makes any sense? E = rec( elems=[ 0, +pixel_size[1], 0, -pixel_size[0], 0, 0, 0, 0, 0, 0, 0, 1 ], n=[4, 3], ) # P: [x, y, z, 1] -> [row, column, 1]. Note that data.focus() # needs to be flipped to give (horizontal, vertical) size, # i.e. (width, height). Pf = get_projection_matrix(pixel_size, (data.focus()[1], data.focus()[0]))[0] rawdata.matrix_paste_block_in_place(block=data.as_double(), i_row=i * data_padded[0], i_column=0) # Last row of T is always [0, 0, 0, 1]. T = Pf * Tf * E R = sqr((T(0, 0), T(0, 1), T(1, 0), T(1, 1))) t = col((T(0, 2), T(1, 2))) my_flex_image.add_transformation_and_translation(R, t) my_flex_image.followup_brightness_scale() return my_flex_image
def __init__(self, ub_beg, ub_end, axis, s0, dmin, margin=3): # the source vector and wavelength self._source = -s0 self._wavelength = 1 / sqrt(s0.dot(s0)) self._wavelength_sq = self._wavelength**2 # the rotation axis self._axis = axis # the resolution limit self._dstarmax = 1 / dmin self._dstarmax2 = self._dstarmax**2 # Margin by which to expand limits. Mosflm uses 3. self._margin = int(margin) # Determine the permutation order of columns of the setting matrix. Use # the setting from the beginning for this. # As a side-effect set self._permutation. col1, col2, col3 = self._permute_axes(ub_beg) # Thus set the reciprocal lattice axis vectors, in permuted order # p, q and r for both orientations rl_vec = [ ub_beg.extract_block(start=(0, 0), stop=(3, 1)), ub_beg.extract_block(start=(0, 1), stop=(3, 2)), ub_beg.extract_block(start=(0, 2), stop=(3, 3)) ] self._rlv_beg = [rl_vec[col1], rl_vec[col2], rl_vec[col3]] rl_vec = [ ub_end.extract_block(start=(0, 0), stop=(3, 1)), ub_end.extract_block(start=(0, 1), stop=(3, 2)), ub_end.extract_block(start=(0, 2), stop=(3, 3)) ] self._rlv_end = [rl_vec[col1], rl_vec[col2], rl_vec[col3]] # Set permuted setting matrices self._p_beg = matrix.sqr(self._rlv_beg[0].elems + self._rlv_beg[1].elems + self._rlv_beg[2].elems).transpose() self._p_end = matrix.sqr(self._rlv_end[0].elems + self._rlv_end[1].elems + self._rlv_end[2].elems).transpose() ## Define a new coordinate system concentric with the Ewald sphere. ## ## X' = X - source_x ## Y' = Y - source_y ## Z' = Z - source_z ## ## X = P' h' ## - = - ## / p11 p12 p13 -source_X \ ## where h' = (p, q, r, 1)^T and P' = | p21 p22 p23 -source_y | ## - = \ p31 p32 p33 -source_z / ## # Calculate P' matrices for the beginning and end settings pp_beg = matrix.rec( self._p_beg.elems[0:3] + (-1. * self._source[0], ) + self._p_beg.elems[3:6] + (-1. * self._source[1], ) + self._p_beg.elems[6:9] + (-1. * self._source[2], ), n=(3, 4)) pp_end = matrix.rec( self._p_end.elems[0:3] + (-1. * self._source[0], ) + self._p_end.elems[3:6] + (-1. * self._source[1], ) + self._p_end.elems[6:9] + (-1. * self._source[2], ), n=(3, 4)) # Various quantities of interest are obtained from the reciprocal metric # tensor T of P'. These quantities are to be used (later) for solving # the intersection of a line of constant p, q index with the Ewald # sphere. It is efficient to calculate these before the outer loop. So, # calculate T for both beginning and end settings t_beg = (pp_beg.transpose() * pp_beg).as_list_of_lists() t_end = (pp_end.transpose() * pp_end).as_list_of_lists() # quantities that are constant with p, beginning orientation self._cp_beg = [ t_beg[2][2], t_beg[2][3]**2, t_beg[0][2] * t_beg[2][3] - t_beg[0][3] * t_beg[2][2], t_beg[0][2]**2 - t_beg[0][0] * t_beg[2][2], t_beg[1][2] * t_beg[2][3] - t_beg[1][3] * t_beg[2][2], t_beg[0][2] * t_beg[1][2] - t_beg[0][1] * t_beg[2][2], t_beg[1][2]**2 - t_beg[1][1] * t_beg[2][2], 2.0 * t_beg[0][2], 2.0 * t_beg[1][2], t_beg[0][0], t_beg[1][1], 2.0 * t_beg[0][1], 2.0 * t_beg[2][3], 2.0 * t_beg[1][3], 2.0 * t_beg[0][3] ] # quantities that are constant with p, end orientation self._cp_end = [ t_end[2][2], t_end[2][3]**2, t_end[0][2] * t_end[2][3] - t_end[0][3] * t_end[2][2], t_end[0][2]**2 - t_end[0][0] * t_end[2][2], t_end[1][2] * t_end[2][3] - t_end[1][3] * t_end[2][2], t_end[0][2] * t_end[1][2] - t_end[0][1] * t_end[2][2], t_end[1][2]**2 - t_end[1][1] * t_end[2][2], 2.0 * t_end[0][2], 2.0 * t_end[1][2], t_end[0][0], t_end[1][1], 2.0 * t_end[0][1], 2.0 * t_end[2][3], 2.0 * t_end[1][3], 2.0 * t_end[0][3] ] ## The following are set during the generation of indices # planes of constant p tangential to the Ewald sphere self._ewald_p_lim_beg = None self._ewald_p_lim_end = None # planes of constant p touching the circle of intersection between the # Ewald and resolution limiting spheres self._res_p_lim_beg = None self._res_p_lim_end = None # looping p limits self._p_lim = None return
def _calc_cell_parameter_sd(self): # self._cov_B is the covariance matrix of elements of the B matrix. We # need to construct the covariance matrix of elements of the # transpose of B. The vector of elements of B is related to the # vector of elements of its transpose by a permutation, P. P = matrix.sqr(( 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, )) # We can use P to replace var_cov with the covariance matrix of # elements of the transpose of B. var_cov = P * self._cov_B * P # From B = (O^-1)^T we can convert this # to the covariance matrix of the real space orthogonalisation matrix Bt = self._B.transpose() O = Bt.inverse() # noqa: E741, is name of the matrix cov_O = matrix_inverse_error_propagation(Bt, var_cov) # The real space unit cell vectors are given by vec_a = O * matrix.col((1, 0, 0)) vec_b = O * matrix.col((0, 1, 0)) vec_c = O * matrix.col((0, 0, 1)) # So the unit cell parameters are a, b, c = vec_a.length(), vec_b.length(), vec_c.length() # alpha = acos(vec_b.dot(vec_c) / (b * c)) # beta = acos(vec_a.dot(vec_c) / (a * c)) # gamma = acos(vec_a.dot(vec_b) / (a * b)) # The estimated errors are calculated by error propagation from cov_O. In # each case we define a function F(O) that converts the matrix O into the # unit cell parameter of interest. To do error propagation to get the # variance of that cell parameter we need the Jacobian of the function. # This is a 1*9 matrix of derivatives in the order of the elements of O # # / dF dF dF dF dF dF dF dF dF \ # J = | ---, ---, ---, ---, ---, ---, ---, ---, --- | # \ da1 db1 dc1 da2 db2 dc2 da3 db3 dc3 / # # For cell length |a|, F = sqrt(a1^2 + a2^2 + a3^2) jacobian = matrix.rec( (vec_a[0] / a, 0, 0, vec_a[1] / a, 0, 0, vec_a[2] / a, 0, 0), (1, 9)) var_a = (jacobian * cov_O * jacobian.transpose())[0] # For cell length |b|, F = sqrt(b1^2 + b2^2 + b3^2) jacobian = matrix.rec( (0, vec_b[0] / b, 0, 0, vec_b[1] / b, 0, 0, vec_b[2] / b, 0), (1, 9)) var_b = (jacobian * cov_O * jacobian.transpose())[0] # For cell length |c|, F = sqrt(c1^2 + c2^2 + c3^2) jacobian = matrix.rec( (0, 0, vec_c[0] / c, 0, 0, vec_c[1] / c, 0, 0, vec_c[2] / c), (1, 9)) var_c = (jacobian * cov_O * jacobian.transpose())[0] # For cell volume (a X b).c, # F = c1(a2*b3 - b2*a3) + c2(a3*b1 - b3*a1) + c3(a1*b2 - b1*a2) a1, a2, a3 = vec_a b1, b2, b3 = vec_b c1, c2, c3 = vec_c jacobian = matrix.rec( ( c3 * b2 - c2 * b3, c1 * b3 - c3 * b1, c2 * b1 - c1 * b2, c2 * a3 - c3 * a2, c3 * a1 - c1 * a3, c1 * a2 - c2 * a1, a2 * b3 - b2 * a3, a3 * b1 - b3 * a1, a1 * b2 - b1 * a2, ), (1, 9), ) var_V = (jacobian * cov_O * jacobian.transpose())[0] self._cell_volume_sd = sqrt(var_V) # For the unit cell angles we need to calculate derivatives of the angles # with respect to the elements of O dalpha_db, dalpha_dc = angle_derivative_wrt_vectors(vec_b, vec_c) dbeta_da, dbeta_dc = angle_derivative_wrt_vectors(vec_a, vec_c) dgamma_da, dgamma_db = angle_derivative_wrt_vectors(vec_a, vec_b) # For angle alpha, F = acos( b.c / |b||c|) jacobian = matrix.rec( ( 0, dalpha_db[0], dalpha_dc[0], 0, dalpha_db[1], dalpha_dc[1], 0, dalpha_db[2], dalpha_dc[2], ), (1, 9), ) var_alpha = (jacobian * cov_O * jacobian.transpose())[0] # For angle beta, F = acos( a.c / |a||c|) jacobian = matrix.rec( ( dbeta_da[0], 0, dbeta_dc[0], dbeta_da[1], 0, dbeta_dc[1], dbeta_da[2], 0, dbeta_dc[2], ), (1, 9), ) var_beta = (jacobian * cov_O * jacobian.transpose())[0] # For angle gamma, F = acos( a.b / |a||b|) jacobian = matrix.rec( ( dgamma_da[0], dgamma_db[0], 0, dgamma_da[1], dgamma_db[1], 0, dgamma_da[2], dgamma_db[2], 0, ), (1, 9), ) var_gamma = (jacobian * cov_O * jacobian.transpose())[0] # Symmetry constraints may mean variances of the angles should be zero. # Floating point error could lead to negative variances. Ensure these are # caught before taking their square root! var_alpha = max(0, var_alpha) var_beta = max(0, var_beta) var_gamma = max(0, var_gamma) rad2deg = 180.0 / pi self._cell_sd = ( sqrt(var_a), sqrt(var_b), sqrt(var_c), sqrt(var_alpha) * rad2deg, sqrt(var_beta) * rad2deg, sqrt(var_gamma) * rad2deg, )