def _compose_core(is0, mu1, mu2, nu, mu1_axis, mu2_axis): # convert angles to radians mu1rad, mu2rad = mu1 / 1000.0, mu2 / 1000.0 # compose rotation matrices and their first order derivatives Mu1 = (mu1_axis).axis_and_angle_as_r3_rotation_matrix(mu1rad, deg=False) dMu1_dmu1 = dR_from_axis_and_angle(mu1_axis, mu1rad, deg=False) Mu2 = (mu2_axis).axis_and_angle_as_r3_rotation_matrix(mu2rad, deg=False) dMu2_dmu2 = dR_from_axis_and_angle(mu2_axis, mu2rad, deg=False) # compose new state Mu21 = Mu2 * Mu1 s0_new_dir = (Mu21 * is0).normalize() s0 = nu * s0_new_dir # calculate derivatives of the beam direction wrt angles: # 1) derivative wrt mu1 dMu21_dmu1 = Mu2 * dMu1_dmu1 ds0_new_dir_dmu1 = dMu21_dmu1 * is0 # 2) derivative wrt mu2 dMu21_dmu2 = dMu2_dmu2 * Mu1 ds0_new_dir_dmu2 = dMu21_dmu2 * is0 # calculate derivatives of the attached beam vector, converting # parameters back to mrad ds0_dval = [ ds0_new_dir_dmu1 * nu / 1000.0, ds0_new_dir_dmu2 * nu / 1000.0, s0_new_dir, ] return s0, ds0_dval
def _compose_core(iS, gamma1, gamma2, gamma1_axis, gamma2_axis): # convert angles to radians g1rad, g2rad = gamma1 / 1000.0, gamma2 / 1000.0 # compose rotation matrices and their first order derivatives G1 = (gamma1_axis).axis_and_angle_as_r3_rotation_matrix(g1rad, deg=False) dG1_dg1 = dR_from_axis_and_angle(gamma1_axis, g1rad, deg=False) G2 = (gamma2_axis).axis_and_angle_as_r3_rotation_matrix(g2rad, deg=False) dG2_dg2 = dR_from_axis_and_angle(gamma2_axis, g2rad, deg=False) # compose new state G21 = G2 * G1 S = G21 * iS # calculate derivatives of S wrt angles: # 1) derivative wrt gamma1 dG21_dg1 = G2 * dG1_dg1 dS_dg1 = dG21_dg1 * iS # 2) derivative wrt gamma2 dG21_dg2 = dG2_dg2 * G1 dS_dg2 = dG21_dg2 * iS # Convert derivatives back to mrad dS_dval = [dS_dg1 / 1000.0, dS_dg2 / 1000.0] return S, dS_dval
def _compose_core(is0, mu1, mu2, nu, mu1_axis, mu2_axis): # convert angles to radians mu1rad, mu2rad = mu1 / 1000., mu2 / 1000. # compose rotation matrices and their first order derivatives Mu1 = (mu1_axis).axis_and_angle_as_r3_rotation_matrix(mu1rad, deg=False) dMu1_dmu1 = dR_from_axis_and_angle(mu1_axis, mu1rad, deg=False) Mu2 = (mu2_axis).axis_and_angle_as_r3_rotation_matrix(mu2rad, deg=False) dMu2_dmu2 = dR_from_axis_and_angle(mu2_axis, mu2rad, deg=False) # compose new state Mu21 = Mu2 * Mu1 s0_new_dir = (Mu21 * is0).normalize() s0 = nu * s0_new_dir # calculate derivatives of the beam direction wrt angles: # 1) derivative wrt mu1 dMu21_dmu1 = Mu2 * dMu1_dmu1 ds0_new_dir_dmu1 = dMu21_dmu1 * is0 # 2) derivative wrt mu2 dMu21_dmu2 = dMu2_dmu2 * Mu1 ds0_new_dir_dmu2 = dMu21_dmu2 * is0 # calculate derivatives of the attached beam vector, converting # parameters back to mrad ds0_dval = [ds0_new_dir_dmu1 * nu / 1000., ds0_new_dir_dmu2 * nu / 1000., s0_new_dir] return s0, ds0_dval
def compose(self, t): """calculate state and derivatives for model at image number t""" # Extract orientation from the initial state U0 = self._initial_state # extract parameter sets from the internal list phi1_set, phi2_set, phi3_set = self._param # extract angles and other data at time t using the smoother phi1, phi1_weights, phi1_sumweights = self._smoother.value_weight(t, phi1_set) phi2, phi2_weights, phi2_sumweights = self._smoother.value_weight(t, phi2_set) phi3, phi3_weights, phi3_sumweights = self._smoother.value_weight(t, phi3_set) # calculate derivatives of angles wrt underlying parameters. # FIXME write up notes in orange notebook dphi1_dp = [e / phi1_sumweights for e in phi1_weights] dphi2_dp = [e / phi2_sumweights for e in phi2_weights] dphi3_dp = [e / phi3_sumweights for e in phi3_weights] # convert angles to radians phi1rad, phi2rad, phi3rad = (phi1 / 1000., phi2 / 1000., phi3 / 1000.) # compose rotation matrices and their first order derivatives wrt angle Phi1 = (phi1_set.axis).axis_and_angle_as_r3_rotation_matrix(phi1rad, deg=False) dPhi1_dphi1 = dR_from_axis_and_angle(phi1_set.axis, phi1rad, deg=False) Phi2 = (phi2_set.axis).axis_and_angle_as_r3_rotation_matrix(phi2rad, deg=False) dPhi2_dphi2 = dR_from_axis_and_angle(phi2_set.axis, phi2rad, deg=False) Phi3 = (phi3_set.axis).axis_and_angle_as_r3_rotation_matrix(phi3rad, deg=False) dPhi3_dphi3 = dR_from_axis_and_angle(phi3_set.axis, phi3rad, deg=False) Phi21 = Phi2 * Phi1 Phi321 = Phi3 * Phi21 # Compose new state self._U_at_t = Phi321 * U0 # calculate derivatives of the state wrt angle, convert back to mrad dU_dphi1 = Phi3 * Phi2 * dPhi1_dphi1 * U0 / 1000. dU_dphi2 = Phi3 * dPhi2_dphi2 * Phi1 * U0 / 1000. dU_dphi3 = dPhi3_dphi3 * Phi21 * U0 / 1000. # calculate derivatives of state wrt underlying parameters dU_dp1 = [dU_dphi1 * e for e in dphi1_dp] dU_dp2 = [dU_dphi2 * e for e in dphi2_dp] dU_dp3 = [dU_dphi3 * e for e in dphi3_dp] # store derivatives as list-of-lists self._dstate_dp = [dU_dp1, dU_dp2, dU_dp3] return
def compose(self): # extract parameters from the internal list dist, shift1, shift2, tau1, tau2, tau3 = self._param # convert angles to radians tau1rad = tau1.value / 1000.0 tau2rad = tau2.value / 1000.0 tau3rad = tau3.value / 1000.0 # compose rotation matrices and their first order derivatives Tau1 = (tau1.axis).axis_and_angle_as_r3_rotation_matrix(tau1rad, deg=False) dTau1_dtau1 = dR_from_axis_and_angle(tau1.axis, tau1rad, deg=False) Tau2 = (tau2.axis).axis_and_angle_as_r3_rotation_matrix(tau2rad, deg=False) dTau2_dtau2 = dR_from_axis_and_angle(tau2.axis, tau2rad, deg=False) Tau3 = (tau3.axis).axis_and_angle_as_r3_rotation_matrix(tau3rad, deg=False) dTau3_dtau3 = dR_from_axis_and_angle(tau3.axis, tau3rad, deg=False) # Compose the new state from scitbx.array_family import flex from dials_refinement_helpers_ext import multi_panel_compose ret = multi_panel_compose( flex.vec3_double( [self._initial_state[tag] for tag in ("d1", "d2", "dn")]), flex.double([p.value for p in self._param]), flex.vec3_double([p.axis for p in self._param]), self._model, flex.vec3_double(self._offsets), flex.vec3_double(self._dir1s), flex.vec3_double(self._dir2s), Tau1, dTau1_dtau1, Tau2, dTau2_dtau2, Tau3, dTau3_dtau3, ) # Store the results. The results come back as a single array, convert it to a 2D array self._multi_state_derivatives = [[ matrix.sqr(ret[j * len(self._offsets) + i]) for j in range(len(self._param)) ] for i in range(len(self._offsets))]
def compose(self): # extract direction from the initial state is0 = self._initial_state # extract parameters from the internal list mu1, mu2, nu = self._param # convert angles to radians mu1rad, mu2rad = mu1.value / 1000., mu2.value / 1000. # compose rotation matrices and their first order derivatives Mu1 = (mu1.axis).axis_and_angle_as_r3_rotation_matrix(mu1rad, deg=False) dMu1_dmu1 = dR_from_axis_and_angle(mu1.axis, mu1rad, deg=False) Mu2 = (mu2.axis).axis_and_angle_as_r3_rotation_matrix(mu2rad, deg=False) dMu2_dmu2 = dR_from_axis_and_angle(mu2.axis, mu2rad, deg=False) Mu21 = Mu2 * Mu1 ### Compose new state s0_new_dir = (Mu21 * is0).normalize() # now update the model with its new s0 self._model.set_s0(nu.value * s0_new_dir) ### calculate derivatives of the beam direction wrt angles # derivative wrt mu1 dMu21_dmu1 = Mu2 * dMu1_dmu1 ds0_new_dir_dmu1 = dMu21_dmu1 * is0 # derivative wrt mu2 dMu21_dmu2 = dMu2_dmu2 * Mu1 ds0_new_dir_dmu2 = dMu21_dmu2 * is0 ### calculate derivatives of the attached beam vector, converting ### parameters back to mrad, and store # derivative wrt mu1 self._dstate_dp[0] = ds0_new_dir_dmu1 * nu.value / 1000. # derivative wrt mu2 self._dstate_dp[1] = ds0_new_dir_dmu2 * nu.value / 1000. # derivative wrt nu self._dstate_dp[2] = s0_new_dir return
def compose(self): # extract parameters from the internal list dist, shift1, shift2, tau1, tau2, tau3 = self._param # convert angles to radians tau1rad = tau1.value / 1000. tau2rad = tau2.value / 1000. tau3rad = tau3.value / 1000. # compose rotation matrices and their first order derivatives Tau1 = (tau1.axis).axis_and_angle_as_r3_rotation_matrix(tau1rad, deg=False) dTau1_dtau1 = dR_from_axis_and_angle(tau1.axis, tau1rad, deg=False) Tau2 = (tau2.axis).axis_and_angle_as_r3_rotation_matrix(tau2rad, deg=False) dTau2_dtau2 = dR_from_axis_and_angle(tau2.axis, tau2rad, deg=False) Tau3 = (tau3.axis).axis_and_angle_as_r3_rotation_matrix(tau3rad, deg=False) dTau3_dtau3 = dR_from_axis_and_angle(tau3.axis, tau3rad, deg=False) # Compose the new state from dials_refinement_helpers_ext import multi_panel_compose from scitbx.array_family import flex ret = multi_panel_compose(flex.vec3_double([self._initial_state[tag] for tag in ('d1','d2','dn')]), flex.double([p.value for p in self._param]), flex.vec3_double([p.axis for p in self._param]), self._model, flex.vec3_double(self._offsets), flex.vec3_double(self._dir1s), flex.vec3_double(self._dir2s), Tau1, dTau1_dtau1, Tau2, dTau2_dtau2, Tau3, dTau3_dtau3) # Store the results. The results come back as a single array, convert it to a 2D array self._multi_state_derivatives = [[matrix.sqr(ret[j*len(self._offsets)+i]) \ for j in xrange(len(self._param))] \ for i in xrange(len(self._offsets))] return
def _compose_core(self, dist, shift1, shift2, tau1, tau2, tau3): # extract items from the initial state id1 = self._initial_state["d1"] id2 = self._initial_state["d2"] ioffset = self._initial_state["offset"] # convert angles to radians tau1rad = tau1.value / 1000.0 tau2rad = tau2.value / 1000.0 tau3rad = tau3.value / 1000.0 # compose rotation matrices and their first order derivatives Tau1 = (tau1.axis).axis_and_angle_as_r3_rotation_matrix(tau1rad, deg=False) dTau1_dtau1 = dR_from_axis_and_angle(tau1.axis, tau1rad, deg=False) Tau2 = (tau2.axis).axis_and_angle_as_r3_rotation_matrix(tau2rad, deg=False) dTau2_dtau2 = dR_from_axis_and_angle(tau2.axis, tau2rad, deg=False) Tau3 = (tau3.axis).axis_and_angle_as_r3_rotation_matrix(tau3rad, deg=False) dTau3_dtau3 = dR_from_axis_and_angle(tau3.axis, tau3rad, deg=False) Tau32 = Tau3 * Tau2 Tau321 = Tau32 * Tau1 # Compose new state # ================= # First the frame positioned at a distance from the lab origin P0 = dist.value * dist.axis # distance along initial detector normal Px = P0 + id1 # point at the end of d1 in lab frame Py = P0 + id2 # point at the end of d2 in lab frame # detector shift vector dsv = P0 + shift1.value * shift1.axis + shift2.value * shift2.axis # compose dorg point dorg = Tau321 * dsv - Tau32 * P0 + P0 # compose d1, d2 and dn and ensure frame remains orthonormal. d1 = (Tau321 * (Px - P0)).normalize() d2 = (Tau321 * (Py - P0)).normalize() dn = d1.cross(d2).normalize() # NB dn not actually used in this simple model; calculation left # here as a reminder for future extension d2 = dn.cross(d1) # compose new sensor origin o = dorg + ioffset[0] * d1 + ioffset[1] * d2 # keep the new state for return new_state = {"d1": d1, "d2": d2, "origin": o} # calculate derivatives of the state wrt parameters # ================================================= # Start with the dorg vector, where # dorg = Tau321 * dsv - Tau32 * P0 + P0 # derivative wrt dist dP0_ddist = dist.axis ddsv_ddist = dP0_ddist ddorg_ddist = Tau321 * ddsv_ddist - Tau32 * dP0_ddist + dP0_ddist # derivative wrt shift1 ddsv_dshift1 = shift1.axis ddorg_dshift1 = Tau321 * ddsv_dshift1 # derivative wrt shift2 ddsv_dshift2 = shift2.axis ddorg_dshift2 = Tau321 * ddsv_dshift2 # derivative wrt tau1 dTau321_dtau1 = Tau32 * dTau1_dtau1 ddorg_dtau1 = dTau321_dtau1 * dsv # derivative wrt tau2 dTau32_dtau2 = Tau3 * dTau2_dtau2 dTau321_dtau2 = dTau32_dtau2 * Tau1 ddorg_dtau2 = dTau321_dtau2 * dsv - dTau32_dtau2 * P0 # derivative wrt tau3 dTau32_dtau3 = dTau3_dtau3 * Tau2 dTau321_dtau3 = dTau32_dtau3 * Tau1 ddorg_dtau3 = dTau321_dtau3 * dsv - dTau32_dtau3 * P0 # Now derivatives of the direction d1, where # d1 = (Tau321 * (Px - P0)).normalize() # For calc of derivatives ignore the normalize(), which should # be unnecessary anyway as Px - P0 is a unit vector and Tau321 a # pure rotation. # derivative wrt dist # dPx_ddist = dist.axis; dP0_ddist = dist.axis, so these cancel dd1_ddist = matrix.col((0.0, 0.0, 0.0)) # derivative wrt shift1 dd1_dshift1 = matrix.col((0.0, 0.0, 0.0)) # derivative wrt shift2 dd1_dshift2 = matrix.col((0.0, 0.0, 0.0)) # derivative wrt tau1 dd1_dtau1 = dTau321_dtau1 * (Px - P0) # derivative wrt tau2 dd1_dtau2 = dTau321_dtau2 * (Px - P0) # derivative wrt tau3 dd1_dtau3 = dTau321_dtau3 * (Px - P0) # Derivatives of the direction d2, where # d2 = (Tau321 * (Py - P0)).normalize() # derivative wrt dist dd2_ddist = matrix.col((0.0, 0.0, 0.0)) # derivative wrt shift1 dd2_dshift1 = matrix.col((0.0, 0.0, 0.0)) # derivative wrt shift2 dd2_dshift2 = matrix.col((0.0, 0.0, 0.0)) # derivative wrt tau1 dd2_dtau1 = dTau321_dtau1 * (Py - P0) # derivative wrt tau2 dd2_dtau2 = dTau321_dtau2 * (Py - P0) # derivative wrt tau3 dd2_dtau3 = dTau321_dtau3 * (Py - P0) # Derivatives of the direction dn, where dn = d1.cross(d2).normalize() # These derivatives are not used, but are left as comments for understanding # derivative wrt dist # ddn_ddist = matrix.col((0.0, 0.0, 0.0)) # derivative wrt shift1 # ddn_dshift1 = matrix.col((0.0, 0.0, 0.0)) # derivative wrt shift2 # ddn_dshift2 = matrix.col((0.0, 0.0, 0.0)) # derivative wrt tau1. Product rule for cross product applies # ddn_dtau1 = dd1_dtau1.cross(d2) + d1.cross(dd2_dtau1) # derivative wrt tau2 # ddn_dtau2 = dd1_dtau2.cross(d2) + d1.cross(dd2_dtau2) # derivative wrt tau3 # ddn_dtau3 = dd1_dtau3.cross(d2) + d1.cross(dd2_dtau3) # calculate derivatives of the attached sensor matrix # =================================================== # sensor origin: # o = dorg + ioffset[0] * d1 + ioffset[1] * d2 # derivative wrt dist do_ddist = ddorg_ddist + ioffset[0] * dd1_ddist + ioffset[1] * dd2_ddist # derivative wrt shift1 do_dshift1 = ddorg_dshift1 + ioffset[0] * dd1_dshift1 + ioffset[ 1] * dd2_dshift1 # derivative wrt shift2 do_dshift2 = ddorg_dshift2 + ioffset[0] * dd1_dshift2 + ioffset[ 1] * dd2_dshift2 # derivative wrt tau1 do_dtau1 = ddorg_dtau1 + ioffset[0] * dd1_dtau1 + ioffset[1] * dd2_dtau1 # derivative wrt tau2 do_dtau2 = ddorg_dtau2 + ioffset[0] * dd1_dtau2 + ioffset[1] * dd2_dtau2 # derivative wrt tau3 do_dtau3 = ddorg_dtau3 + ioffset[0] * dd1_dtau3 + ioffset[1] * dd2_dtau3 # combine these vectors together into derivatives of the sensor # matrix d, converting angles back to mrad dd_dval = [] # derivative wrt dist dd_dval.append( matrix.sqr(dd1_ddist.elems + dd2_ddist.elems + do_ddist.elems).transpose()) # derivative wrt shift1 dd_dval.append( matrix.sqr(dd1_dshift1.elems + dd2_dshift1.elems + do_dshift1.elems).transpose()) # derivative wrt shift2 dd_dval.append( matrix.sqr(dd1_dshift2.elems + dd2_dshift2.elems + do_dshift2.elems).transpose()) # derivative wrt tau1 dd_dval.append( matrix.sqr(dd1_dtau1.elems + dd2_dtau1.elems + do_dtau1.elems).transpose() / 1000.0) # derivative wrt tau2 dd_dval.append( matrix.sqr(dd1_dtau2.elems + dd2_dtau2.elems + do_dtau2.elems).transpose() / 1000.0) # derivative wrt tau3 dd_dval.append( matrix.sqr(dd1_dtau3.elems + dd2_dtau3.elems + do_dtau3.elems).transpose() / 1000.0) return new_state, dd_dval
def compose(self): # extract items from the initial state id1 = self._initial_state["d1"] id2 = self._initial_state["d2"] # extract parameters from the internal list dist, shift1, shift2, tau1, tau2, tau3 = self._param # Extract the detector model detector = self._model # convert angles to radians tau1rad = tau1.value / 1000.0 tau2rad = tau2.value / 1000.0 tau3rad = tau3.value / 1000.0 # compose rotation matrices and their first order derivatives Tau1 = (tau1.axis).axis_and_angle_as_r3_rotation_matrix(tau1rad, deg=False) dTau1_dtau1 = dR_from_axis_and_angle(tau1.axis, tau1rad, deg=False) Tau2 = (tau2.axis).axis_and_angle_as_r3_rotation_matrix(tau2rad, deg=False) dTau2_dtau2 = dR_from_axis_and_angle(tau2.axis, tau2rad, deg=False) Tau3 = (tau3.axis).axis_and_angle_as_r3_rotation_matrix(tau3rad, deg=False) dTau3_dtau3 = dR_from_axis_and_angle(tau3.axis, tau3rad, deg=False) Tau32 = Tau3 * Tau2 Tau321 = Tau32 * Tau1 # Compose new state # ================= # First the frame positioned at a distance from the lab origin P0 = dist.value * dist.axis # distance along initial detector normal Px = P0 + id1 # point at the end of d1 in lab frame Py = P0 + id2 # point at the end of d2 in lab frame # detector shift vector dsv = P0 + shift1.value * shift1.axis + shift2.value * shift2.axis # compose dorg point dorg = Tau321 * dsv - Tau32 * P0 + P0 # compose new d1, d2 and dn and ensure frame remains orthonormal. d1 = (Tau321 * (Px - P0)).normalize() d2 = (Tau321 * (Py - P0)).normalize() dn = d1.cross(d2).normalize() d2 = dn.cross(d1) # compose new Panel origins origins = [ dorg + offset[0] * d1 + offset[1] * d2 + offset[2] * dn for offset in self._offsets ] # compose new Panel directions dir1s = [ vec[0] * d1 + vec[1] * d2 + vec[2] * dn for vec in self._dir1s ] dir2s = [ vec[0] * d1 + vec[1] * d2 + vec[2] * dn for vec in self._dir2s ] # now update the panels with their new position and orientation. for p, dir1, dir2, org in zip(detector, dir1s, dir2s, origins): p.set_frame(dir1, dir2, org) # calculate derivatives of the state wrt parameters # ================================================= # Start with the dorg vector, where # dorg = Tau321 * dsv - Tau32 * P0 + P0 # derivative wrt dist dP0_ddist = dist.axis ddsv_ddist = dP0_ddist ddorg_ddist = Tau321 * ddsv_ddist - Tau32 * dP0_ddist + dP0_ddist # derivative wrt shift1 ddsv_dshift1 = shift1.axis ddorg_dshift1 = Tau321 * ddsv_dshift1 # derivative wrt shift2 ddsv_dshift2 = shift2.axis ddorg_dshift2 = Tau321 * ddsv_dshift2 # derivative wrt tau1 dTau321_dtau1 = Tau32 * dTau1_dtau1 ddorg_dtau1 = dTau321_dtau1 * dsv # derivative wrt tau2 dTau32_dtau2 = Tau3 * dTau2_dtau2 dTau321_dtau2 = dTau32_dtau2 * Tau1 ddorg_dtau2 = dTau321_dtau2 * dsv - dTau32_dtau2 * P0 # derivative wrt tau3 dTau32_dtau3 = dTau3_dtau3 * Tau2 dTau321_dtau3 = dTau32_dtau3 * Tau1 ddorg_dtau3 = dTau321_dtau3 * dsv - dTau32_dtau3 * P0 # Now derivatives of the direction d1, where # d1 = (Tau321 * (Px - P0)).normalize() # For calc of derivatives ignore the normalize(), which should # be unnecessary anyway as Px - P0 is a unit vector and Tau321 a # pure rotation. # derivative wrt dist # dPx_ddist = dist.axis; dP0_ddist = dist.axis, so these cancel dd1_ddist = matrix.col((0.0, 0.0, 0.0)) # derivative wrt shift1 dd1_dshift1 = matrix.col((0.0, 0.0, 0.0)) # derivative wrt shift2 dd1_dshift2 = matrix.col((0.0, 0.0, 0.0)) # derivative wrt tau1 dd1_dtau1 = dTau321_dtau1 * (Px - P0) # derivative wrt tau2 dd1_dtau2 = dTau321_dtau2 * (Px - P0) # derivative wrt tau3 dd1_dtau3 = dTau321_dtau3 * (Px - P0) # Derivatives of the direction d2, where # d2 = (Tau321 * (Py - P0)).normalize() # derivative wrt dist dd2_ddist = matrix.col((0.0, 0.0, 0.0)) # derivative wrt shift1 dd2_dshift1 = matrix.col((0.0, 0.0, 0.0)) # derivative wrt shift2 dd2_dshift2 = matrix.col((0.0, 0.0, 0.0)) # derivative wrt tau1 dd2_dtau1 = dTau321_dtau1 * (Py - P0) # derivative wrt tau2 dd2_dtau2 = dTau321_dtau2 * (Py - P0) # derivative wrt tau3 dd2_dtau3 = dTau321_dtau3 * (Py - P0) # Derivatives of the direction dn, where # dn = d1.cross(d2).normalize() # derivative wrt dist ddn_ddist = matrix.col((0.0, 0.0, 0.0)) # derivative wrt shift1 ddn_dshift1 = matrix.col((0.0, 0.0, 0.0)) # derivative wrt shift2 ddn_dshift2 = matrix.col((0.0, 0.0, 0.0)) # derivative wrt tau1. Product rule for cross product applies ddn_dtau1 = dd1_dtau1.cross(d2) + d1.cross(dd2_dtau1) # derivative wrt tau2 ddn_dtau2 = dd1_dtau2.cross(d2) + d1.cross(dd2_dtau2) # derivative wrt tau3 ddn_dtau3 = dd1_dtau3.cross(d2) + d1.cross(dd2_dtau3) # reset stored derivatives for i in range(len(detector)): self._multi_state_derivatives[i] = [None] * len(self._dstate_dp) # calculate derivatives of the attached Panel matrices # ==================================================== for panel_id, (offset, dir1_new_basis, dir2_new_basis) in enumerate( zip(self._offsets, self._dir1s, self._dir2s)): # Panel origin: # o = dorg + offset[0] * d1 + offset[1] * d2 + offset[2] * dn # derivative wrt dist. NB only ddorg_ddist is not null! The other # elements are left here to aid understanding, but should be removed # when this class is ported to C++ for speed. do_ddist = (ddorg_ddist + offset[0] * dd1_ddist + offset[1] * dd2_ddist + offset[2] * ddn_ddist) # derivative wrt shift1. NB only ddorg_dshift1 is non-null. do_dshift1 = (ddorg_dshift1 + offset[0] * dd1_dshift1 + offset[1] * dd2_dshift1 + offset[2] * ddn_dshift1) # derivative wrt shift2. NB only ddorg_dshift2 is non-null. do_dshift2 = (ddorg_dshift2 + offset[0] * dd1_dshift2 + offset[1] * dd2_dshift2 + offset[2] * ddn_dshift2) # derivative wrt tau1 do_dtau1 = (ddorg_dtau1 + offset[0] * dd1_dtau1 + offset[1] * dd2_dtau1 + offset[2] * ddn_dtau1) # derivative wrt tau2 do_dtau2 = (ddorg_dtau2 + offset[0] * dd1_dtau2 + offset[1] * dd2_dtau2 + offset[2] * ddn_dtau2) # derivative wrt tau3 do_dtau3 = (ddorg_dtau3 + offset[0] * dd1_dtau3 + offset[1] * dd2_dtau3 + offset[2] * ddn_dtau3) # Panel dir1: # dir1 = dir1_new_basis[0] * d1 + dir1_new_basis[1] * d2 + # dir1_new_basis[2] * dn # derivative wrt dist. NB These are all null. ddir1_ddist = (dir1_new_basis[0] * dd1_ddist + dir1_new_basis[1] * dd2_ddist + dir1_new_basis[2] * ddn_ddist) # derivative wrt shift1. NB These are all null. ddir1_dshift1 = (dir1_new_basis[0] * dd1_dshift1 + dir1_new_basis[1] * dd2_dshift1 + dir1_new_basis[2] * ddn_dshift1) # derivative wrt shift2. NB These are all null. ddir1_dshift2 = (dir1_new_basis[0] * dd1_dshift2 + dir1_new_basis[1] * dd2_dshift2 + dir1_new_basis[2] * ddn_dshift2) # derivative wrt tau1 ddir1_dtau1 = (dir1_new_basis[0] * dd1_dtau1 + dir1_new_basis[1] * dd2_dtau1 + dir1_new_basis[2] * ddn_dtau1) # derivative wrt tau2 ddir1_dtau2 = (dir1_new_basis[0] * dd1_dtau2 + dir1_new_basis[1] * dd2_dtau2 + dir1_new_basis[2] * ddn_dtau2) # derivative wrt tau3 ddir1_dtau3 = (dir1_new_basis[0] * dd1_dtau3 + dir1_new_basis[1] * dd2_dtau3 + dir1_new_basis[2] * ddn_dtau3) # Panel dir2: # dir2 = dir2_new_basis[0] * d1 + dir2_new_basis[1] * d2 + # dir2_new_basis[2] * dn # derivative wrt dist. NB These are all null. ddir2_ddist = (dir2_new_basis[0] * dd1_ddist + dir2_new_basis[1] * dd2_ddist + dir2_new_basis[2] * ddn_ddist) # derivative wrt shift1. NB These are all null. ddir2_dshift1 = (dir2_new_basis[0] * dd1_dshift1 + dir2_new_basis[1] * dd2_dshift1 + dir2_new_basis[2] * ddn_dshift1) # derivative wrt shift2. NB These are all null. ddir2_dshift2 = (dir2_new_basis[0] * dd1_dshift2 + dir2_new_basis[1] * dd2_dshift2 + dir2_new_basis[2] * ddn_dshift2) # derivative wrt tau1 ddir2_dtau1 = (dir2_new_basis[0] * dd1_dtau1 + dir2_new_basis[1] * dd2_dtau1 + dir2_new_basis[2] * ddn_dtau1) # derivative wrt tau2 ddir2_dtau2 = (dir2_new_basis[0] * dd1_dtau2 + dir2_new_basis[1] * dd2_dtau2 + dir2_new_basis[2] * ddn_dtau2) # derivative wrt tau3 ddir2_dtau3 = (dir2_new_basis[0] * dd1_dtau3 + dir2_new_basis[1] * dd2_dtau3 + dir2_new_basis[2] * ddn_dtau3) # combine these vectors together into derivatives of the panel # matrix d and store them, converting angles back to mrad self._multi_state_derivatives[panel_id] = [ matrix.sqr(ddir1_ddist.elems + ddir2_ddist.elems + do_ddist.elems).transpose(), matrix.sqr(ddir1_dshift1.elems + ddir2_dshift1.elems + do_dshift1.elems).transpose(), matrix.sqr(ddir1_dshift2.elems + ddir2_dshift2.elems + do_dshift2.elems).transpose(), matrix.sqr(ddir1_dtau1.elems + ddir2_dtau1.elems + do_dtau1.elems).transpose() / 1000.0, matrix.sqr(ddir1_dtau2.elems + ddir2_dtau2.elems + do_dtau2.elems).transpose() / 1000.0, matrix.sqr(ddir1_dtau3.elems + ddir2_dtau3.elems + do_dtau3.elems).transpose() / 1000.0, ]
def compose(self): # reset the list that holds derivatives for i in range(len(self._model)): self._multi_state_derivatives[i] = [None] * len(self._dstate_dp) # loop over groups of panels collecting derivatives of the state wrt # parameters param = iter(self._param) for igp, pnl_ids in enumerate(self._panel_ids_by_group): # extract parameters from the internal list dist = next(param) shift1 = next(param) shift2 = next(param) tau1 = next(param) tau2 = next(param) tau3 = next(param) #param_vals = flex.double((dist.value, shift1.value, shift2.value, # tau1.value, tau2.value, tau3.value)) #param_axes = flex.vec3_double((dist.axis, shift1.axis, shift2.axis, # tau1.axis, tau2.axis, tau3.axis)) offsets = self._offsets[igp] dir1s = self._dir1s[igp] dir2s = self._dir2s[igp] # convert angles to radians tau1rad = tau1.value / 1000. tau2rad = tau2.value / 1000. tau3rad = tau3.value / 1000. # compose rotation matrices and their first order derivatives Tau1 = (tau1.axis).axis_and_angle_as_r3_rotation_matrix(tau1rad, deg=False) dTau1_dtau1 = dR_from_axis_and_angle(tau1.axis, tau1rad, deg=False) Tau2 = (tau2.axis).axis_and_angle_as_r3_rotation_matrix(tau2rad, deg=False) dTau2_dtau2 = dR_from_axis_and_angle(tau2.axis, tau2rad, deg=False) Tau3 = (tau3.axis).axis_and_angle_as_r3_rotation_matrix(tau3rad, deg=False) dTau3_dtau3 = dR_from_axis_and_angle(tau3.axis, tau3rad, deg=False) Tau32 = Tau3 * Tau2 Tau321 = Tau32 * Tau1 # Get items from the initial state for the group of interest initial_state = self._initial_state[igp] id1 = initial_state['d1'] id2 = initial_state['d2'] idn = initial_state['dn'] igp_offset = initial_state['gp_offset'] # Compose new state # ================= # First the frame positioned at a distance from the lab origin P0 = dist.value * dist.axis # distance along initial group normal Px = P0 + id1 # point at the end of d1 in lab frame Py = P0 + id2 # point at the end of d2 in lab frame # detector shift vector dsv = P0 + shift1.value * shift1.axis + shift2.value * shift2.axis # compose dorg point dorg = Tau321 * dsv - Tau32 * P0 + P0 # compose new d1, d2 and dn and ensure frame remains orthonormal. d1 = (Tau321 * (Px - P0)).normalize() d2 = (Tau321 * (Py - P0)).normalize() dn = d1.cross(d2).normalize() d2 = dn.cross(d1) # compose new group origin origin = dorg + igp_offset[0] * d1 + \ igp_offset[1] * d2 + \ igp_offset[2] * dn # assign back to the group frame self._groups[igp].set_frame(d1, d2, origin) # calculate derivatives of the state wrt parameters # ================================================= # Start with the dorg vector, where # dorg = Tau321 * dsv - Tau32 * P0 + P0 # derivative wrt dist dP0_ddist = dist.axis ddsv_ddist = dP0_ddist ddorg_ddist = Tau321 * ddsv_ddist - Tau32 * dP0_ddist + \ dP0_ddist # derivative wrt shift1 ddsv_dshift1 = shift1.axis ddorg_dshift1 = Tau321 * ddsv_dshift1 # derivative wrt shift2 ddsv_dshift2 = shift2.axis ddorg_dshift2 = Tau321 * ddsv_dshift2 # derivative wrt tau1 dTau321_dtau1 = Tau32 * dTau1_dtau1 ddorg_dtau1 = dTau321_dtau1 * dsv # derivative wrt tau2 dTau32_dtau2 = Tau3 * dTau2_dtau2 dTau321_dtau2 = dTau32_dtau2 * Tau1 ddorg_dtau2 = dTau321_dtau2 * dsv - dTau32_dtau2 * P0 # derivative wrt tau3 dTau32_dtau3 = dTau3_dtau3 * Tau2 dTau321_dtau3 = dTau32_dtau3 * Tau1 ddorg_dtau3 = dTau321_dtau3 * dsv - dTau32_dtau3 * P0 # Now derivatives of the direction d1, where # d1 = (Tau321 * (Px - P0)).normalize() # For calc of derivatives ignore the normalize(), which should # be unnecessary anyway as Px - P0 is a unit vector and Tau321 a # pure rotation. # derivative wrt dist # dPx_ddist = dist.axis; dP0_ddist = dist.axis, so these cancel dd1_ddist = matrix.col((0., 0., 0.)) # derivative wrt shift1 dd1_dshift1 = matrix.col((0., 0., 0.)) # derivative wrt shift2 dd1_dshift2 = matrix.col((0., 0., 0.)) # derivative wrt tau1 dd1_dtau1 = dTau321_dtau1 * (Px - P0) # derivative wrt tau2 dd1_dtau2 = dTau321_dtau2 * (Px - P0) # derivative wrt tau3 dd1_dtau3 = dTau321_dtau3 * (Px - P0) # Derivatives of the direction d2, where # d2 = (Tau321 * (Py - P0)).normalize() # derivative wrt dist dd2_ddist = matrix.col((0., 0., 0.)) # derivative wrt shift1 dd2_dshift1 = matrix.col((0., 0., 0.)) # derivative wrt shift2 dd2_dshift2 = matrix.col((0., 0., 0.)) # derivative wrt tau1 dd2_dtau1 = dTau321_dtau1 * (Py - P0) # derivative wrt tau2 dd2_dtau2 = dTau321_dtau2 * (Py - P0) # derivative wrt tau3 dd2_dtau3 = dTau321_dtau3 * (Py - P0) # Derivatives of the direction dn, where # dn = d1.cross(d2).normalize() # derivative wrt dist ddn_ddist = matrix.col((0., 0., 0.)) # derivative wrt shift1 ddn_dshift1 = matrix.col((0., 0., 0.)) # derivative wrt shift2 ddn_dshift2 = matrix.col((0., 0., 0.)) # derivative wrt tau1. Product rule for cross product applies ddn_dtau1 = dd1_dtau1.cross(d2) + d1.cross(dd2_dtau1) # derivative wrt tau2 ddn_dtau2 = dd1_dtau2.cross(d2) + d1.cross(dd2_dtau2) # derivative wrt tau3 ddn_dtau3 = dd1_dtau3.cross(d2) + d1.cross(dd2_dtau3) # calculate derivatives of the attached Panel matrices # ==================================================== for (panel_id, offset, dir1_new_basis, dir2_new_basis) in \ zip(pnl_ids, offsets, dir1s, dir2s): # Panel origin, which is calculated by: # o = dorg + offset[0] * d1 + offset[1] * d2 + offset[2] * dn # derivative wrt dist. NB only ddorg_ddist is not null! The other # elements are left here to aid understanding, but should be removed # when this class is ported to C++ for speed. do_ddist = ddorg_ddist + offset[0] * dd1_ddist + \ offset[1] * dd2_ddist + \ offset[2] * ddn_ddist # derivative wrt shift1. NB only ddorg_dshift1 is non-null. do_dshift1 = ddorg_dshift1 + offset[0] * dd1_dshift1 + \ offset[1] * dd2_dshift1 + \ offset[2] * ddn_dshift1 # derivative wrt shift2. NB only ddorg_dshift2 is non-null. do_dshift2 = ddorg_dshift2 + offset[0] * dd1_dshift2 + \ offset[1] * dd2_dshift2 + \ offset[2] * ddn_dshift2 # derivative wrt tau1 do_dtau1 = ddorg_dtau1 + offset[0] * dd1_dtau1 + \ offset[1] * dd2_dtau1 + \ offset[2] * ddn_dtau1 # derivative wrt tau2 do_dtau2 = ddorg_dtau2 + offset[0] * dd1_dtau2 + \ offset[1] * dd2_dtau2 + \ offset[2] * ddn_dtau2 # derivative wrt tau3 do_dtau3 = ddorg_dtau3 + offset[0] * dd1_dtau3 + \ offset[1] * dd2_dtau3 + \ offset[2] * ddn_dtau3 # Panel dir1: # dir1 = dir1_new_basis[0] * d1 + dir1_new_basis[1] * d2 + # dir1_new_basis[2] * dn # derivative wrt dist. NB These are all null. ddir1_ddist = dir1_new_basis[0] * dd1_ddist + \ dir1_new_basis[1] * dd2_ddist + \ dir1_new_basis[2] * ddn_ddist # derivative wrt shift1. NB These are all null. ddir1_dshift1 = dir1_new_basis[0] * dd1_dshift1 + \ dir1_new_basis[1] * dd2_dshift1 + \ dir1_new_basis[2] * ddn_dshift1 # derivative wrt shift2. NB These are all null. ddir1_dshift2 = dir1_new_basis[0] * dd1_dshift2 + \ dir1_new_basis[1] * dd2_dshift2 + \ dir1_new_basis[2] * ddn_dshift2 # derivative wrt tau1 ddir1_dtau1 = dir1_new_basis[0] * dd1_dtau1 + \ dir1_new_basis[1] * dd2_dtau1 + \ dir1_new_basis[2] * ddn_dtau1 # derivative wrt tau2 ddir1_dtau2 = dir1_new_basis[0] * dd1_dtau2 + \ dir1_new_basis[1] * dd2_dtau2 + \ dir1_new_basis[2] * ddn_dtau2 # derivative wrt tau3 ddir1_dtau3 = dir1_new_basis[0] * dd1_dtau3 + \ dir1_new_basis[1] * dd2_dtau3 + \ dir1_new_basis[2] * ddn_dtau3 # Panel dir2: # dir2 = dir2_new_basis[0] * d1 + dir2_new_basis[1] * d2 + # dir2_new_basis[2] * dn # derivative wrt dist. NB These are all null. ddir2_ddist = dir2_new_basis[0] * dd1_ddist + \ dir2_new_basis[1] * dd2_ddist + \ dir2_new_basis[2] * ddn_ddist # derivative wrt shift1. NB These are all null. ddir2_dshift1 = dir2_new_basis[0] * dd1_dshift1 + \ dir2_new_basis[1] * dd2_dshift1 + \ dir2_new_basis[2] * ddn_dshift1 # derivative wrt shift2. NB These are all null. ddir2_dshift2 = dir2_new_basis[0] * dd1_dshift2 + \ dir2_new_basis[1] * dd2_dshift2 + \ dir2_new_basis[2] * ddn_dshift2 # derivative wrt tau1 ddir2_dtau1 = dir2_new_basis[0] * dd1_dtau1 + \ dir2_new_basis[1] * dd2_dtau1 + \ dir2_new_basis[2] * ddn_dtau1 # derivative wrt tau2 ddir2_dtau2 = dir2_new_basis[0] * dd1_dtau2 + \ dir2_new_basis[1] * dd2_dtau2 + \ dir2_new_basis[2] * ddn_dtau2 # derivative wrt tau3 ddir2_dtau3 = dir2_new_basis[0] * dd1_dtau3 + \ dir2_new_basis[1] * dd2_dtau3 + \ dir2_new_basis[2] * ddn_dtau3 # combine these vectors together into derivatives of the panel # matrix d and store them, converting angles back to mrad i = igp * 6 # derivative wrt dist self._multi_state_derivatives[panel_id][i] = \ matrix.sqr(ddir1_ddist.elems + ddir2_ddist.elems + do_ddist.elems).transpose() # derivative wrt shift1 self._multi_state_derivatives[panel_id][i+1] = \ matrix.sqr(ddir1_dshift1.elems + ddir2_dshift1.elems + do_dshift1.elems).transpose() # derivative wrt shift2 self._multi_state_derivatives[panel_id][i+2] = \ matrix.sqr(ddir1_dshift2.elems + ddir2_dshift2.elems + do_dshift2.elems).transpose() # derivative wrt tau1 self._multi_state_derivatives[panel_id][i+3] = \ matrix.sqr(ddir1_dtau1.elems + ddir2_dtau1.elems + do_dtau1.elems).transpose() / 1000. # derivative wrt tau2 self._multi_state_derivatives[panel_id][i+4] = \ matrix.sqr(ddir1_dtau2.elems + ddir2_dtau2.elems + do_dtau2.elems).transpose() / 1000. # derivative wrt tau3 self._multi_state_derivatives[panel_id][i+5] = \ matrix.sqr(ddir1_dtau3.elems + ddir2_dtau3.elems + do_dtau3.elems).transpose() / 1000. return
def compose(self): # reset the list that holds derivatives for i in range(len(self._model)): self._multi_state_derivatives[i] = [None] * len(self._dstate_dp) # loop over groups of panels collecting derivatives of the state wrt # parameters param = iter(self._param) for igp, pnl_ids in enumerate(self._panel_ids_by_group): # extract parameters from the internal list dist = param.next() shift1 = param.next() shift2 = param.next() tau1 = param.next() tau2 = param.next() tau3 = param.next() #param_vals = flex.double((dist.value, shift1.value, shift2.value, # tau1.value, tau2.value, tau3.value)) #param_axes = flex.vec3_double((dist.axis, shift1.axis, shift2.axis, # tau1.axis, tau2.axis, tau3.axis)) offsets = self._offsets[igp] dir1s = self._dir1s[igp] dir2s = self._dir2s[igp] # convert angles to radians tau1rad = tau1.value / 1000. tau2rad = tau2.value / 1000. tau3rad = tau3.value / 1000. # compose rotation matrices and their first order derivatives Tau1 = (tau1.axis).axis_and_angle_as_r3_rotation_matrix(tau1rad, deg=False) dTau1_dtau1 = dR_from_axis_and_angle(tau1.axis, tau1rad, deg=False) Tau2 = (tau2.axis).axis_and_angle_as_r3_rotation_matrix(tau2rad, deg=False) dTau2_dtau2 = dR_from_axis_and_angle(tau2.axis, tau2rad, deg=False) Tau3 = (tau3.axis).axis_and_angle_as_r3_rotation_matrix(tau3rad, deg=False) dTau3_dtau3 = dR_from_axis_and_angle(tau3.axis, tau3rad, deg=False) Tau32 = Tau3 * Tau2 Tau321 = Tau32 * Tau1 # Get items from the initial state for the group of interest initial_state = self._initial_state[igp] id1 = initial_state['d1'] id2 = initial_state['d2'] idn = initial_state['dn'] igp_offset = initial_state['gp_offset'] # Compose new state # ================= # First the frame positioned at a distance from the lab origin P0 = dist.value * dist.axis # distance along initial group normal Px = P0 + id1 # point at the end of d1 in lab frame Py = P0 + id2 # point at the end of d2 in lab frame # detector shift vector dsv = P0 + shift1.value * shift1.axis + shift2.value * shift2.axis # compose dorg point dorg = Tau321 * dsv - Tau32 * P0 + P0 # compose new d1, d2 and dn and ensure frame remains orthonormal. d1 = (Tau321 * (Px - P0)).normalize() d2 = (Tau321 * (Py - P0)).normalize() dn = d1.cross(d2).normalize() d2 = dn.cross(d1) # compose new group origin origin = dorg + igp_offset[0] * d1 + \ igp_offset[1] * d2 + \ igp_offset[2] * dn # assign back to the group frame self._groups[igp].set_frame(d1, d2, origin) # calculate derivatives of the state wrt parameters # ================================================= # Start with the dorg vector, where # dorg = Tau321 * dsv - Tau32 * P0 + P0 # derivative wrt dist dP0_ddist = dist.axis ddsv_ddist = dP0_ddist ddorg_ddist = Tau321 * ddsv_ddist - Tau32 * dP0_ddist + \ dP0_ddist # derivative wrt shift1 ddsv_dshift1 = shift1.axis ddorg_dshift1 = Tau321 * ddsv_dshift1 # derivative wrt shift2 ddsv_dshift2 = shift2.axis ddorg_dshift2 = Tau321 * ddsv_dshift2 # derivative wrt tau1 dTau321_dtau1 = Tau32 * dTau1_dtau1 ddorg_dtau1 = dTau321_dtau1 * dsv # derivative wrt tau2 dTau32_dtau2 = Tau3 * dTau2_dtau2 dTau321_dtau2 = dTau32_dtau2 * Tau1 ddorg_dtau2 = dTau321_dtau2 * dsv - dTau32_dtau2 * P0 # derivative wrt tau3 dTau32_dtau3 = dTau3_dtau3 * Tau2 dTau321_dtau3 = dTau32_dtau3 * Tau1 ddorg_dtau3 = dTau321_dtau3 * dsv - dTau32_dtau3 * P0 # Now derivatives of the direction d1, where # d1 = (Tau321 * (Px - P0)).normalize() # For calc of derivatives ignore the normalize(), which should # be unnecessary anyway as Px - P0 is a unit vector and Tau321 a # pure rotation. # derivative wrt dist # dPx_ddist = dist.axis; dP0_ddist = dist.axis, so these cancel dd1_ddist = matrix.col((0., 0., 0.)) # derivative wrt shift1 dd1_dshift1 = matrix.col((0., 0., 0.)) # derivative wrt shift2 dd1_dshift2 = matrix.col((0., 0., 0.)) # derivative wrt tau1 dd1_dtau1 = dTau321_dtau1 * (Px - P0) # derivative wrt tau2 dd1_dtau2 = dTau321_dtau2 * (Px - P0) # derivative wrt tau3 dd1_dtau3 = dTau321_dtau3 * (Px - P0) # Derivatives of the direction d2, where # d2 = (Tau321 * (Py - P0)).normalize() # derivative wrt dist dd2_ddist = matrix.col((0., 0., 0.)) # derivative wrt shift1 dd2_dshift1 = matrix.col((0., 0., 0.)) # derivative wrt shift2 dd2_dshift2 = matrix.col((0., 0., 0.)) # derivative wrt tau1 dd2_dtau1 = dTau321_dtau1 * (Py - P0) # derivative wrt tau2 dd2_dtau2 = dTau321_dtau2 * (Py - P0) # derivative wrt tau3 dd2_dtau3 = dTau321_dtau3 * (Py - P0) # Derivatives of the direction dn, where # dn = d1.cross(d2).normalize() # derivative wrt dist ddn_ddist = matrix.col((0., 0., 0.)) # derivative wrt shift1 ddn_dshift1 = matrix.col((0., 0., 0.)) # derivative wrt shift2 ddn_dshift2 = matrix.col((0., 0., 0.)) # derivative wrt tau1. Product rule for cross product applies ddn_dtau1 = dd1_dtau1.cross(d2) + d1.cross(dd2_dtau1) # derivative wrt tau2 ddn_dtau2 = dd1_dtau2.cross(d2) + d1.cross(dd2_dtau2) # derivative wrt tau3 ddn_dtau3 = dd1_dtau3.cross(d2) + d1.cross(dd2_dtau3) # calculate derivatives of the attached Panel matrices # ==================================================== for (panel_id, offset, dir1_new_basis, dir2_new_basis) in \ zip(pnl_ids, offsets, dir1s, dir2s): # Panel origin, which is calculated by: # o = dorg + offset[0] * d1 + offset[1] * d2 + offset[2] * dn # derivative wrt dist. NB only ddorg_ddist is not null! The other # elements are left here to aid understanding, but should be removed # when this class is ported to C++ for speed. do_ddist = ddorg_ddist + offset[0] * dd1_ddist + \ offset[1] * dd2_ddist + \ offset[2] * ddn_ddist # derivative wrt shift1. NB only ddorg_dshift1 is non-null. do_dshift1 = ddorg_dshift1 + offset[0] * dd1_dshift1 + \ offset[1] * dd2_dshift1 + \ offset[2] * ddn_dshift1 # derivative wrt shift2. NB only ddorg_dshift2 is non-null. do_dshift2 = ddorg_dshift2 + offset[0] * dd1_dshift2 + \ offset[1] * dd2_dshift2 + \ offset[2] * ddn_dshift2 # derivative wrt tau1 do_dtau1 = ddorg_dtau1 + offset[0] * dd1_dtau1 + \ offset[1] * dd2_dtau1 + \ offset[2] * ddn_dtau1 # derivative wrt tau2 do_dtau2 = ddorg_dtau2 + offset[0] * dd1_dtau2 + \ offset[1] * dd2_dtau2 + \ offset[2] * ddn_dtau2 # derivative wrt tau3 do_dtau3 = ddorg_dtau3 + offset[0] * dd1_dtau3 + \ offset[1] * dd2_dtau3 + \ offset[2] * ddn_dtau3 # Panel dir1: # dir1 = dir1_new_basis[0] * d1 + dir1_new_basis[1] * d2 + # dir1_new_basis[2] * dn # derivative wrt dist. NB These are all null. ddir1_ddist = dir1_new_basis[0] * dd1_ddist + \ dir1_new_basis[1] * dd2_ddist + \ dir1_new_basis[2] * ddn_ddist # derivative wrt shift1. NB These are all null. ddir1_dshift1 = dir1_new_basis[0] * dd1_dshift1 + \ dir1_new_basis[1] * dd2_dshift1 + \ dir1_new_basis[2] * ddn_dshift1 # derivative wrt shift2. NB These are all null. ddir1_dshift2 = dir1_new_basis[0] * dd1_dshift2 + \ dir1_new_basis[1] * dd2_dshift2 + \ dir1_new_basis[2] * ddn_dshift2 # derivative wrt tau1 ddir1_dtau1 = dir1_new_basis[0] * dd1_dtau1 + \ dir1_new_basis[1] * dd2_dtau1 + \ dir1_new_basis[2] * ddn_dtau1 # derivative wrt tau2 ddir1_dtau2 = dir1_new_basis[0] * dd1_dtau2 + \ dir1_new_basis[1] * dd2_dtau2 + \ dir1_new_basis[2] * ddn_dtau2 # derivative wrt tau3 ddir1_dtau3 = dir1_new_basis[0] * dd1_dtau3 + \ dir1_new_basis[1] * dd2_dtau3 + \ dir1_new_basis[2] * ddn_dtau3 # Panel dir2: # dir2 = dir2_new_basis[0] * d1 + dir2_new_basis[1] * d2 + # dir2_new_basis[2] * dn # derivative wrt dist. NB These are all null. ddir2_ddist = dir2_new_basis[0] * dd1_ddist + \ dir2_new_basis[1] * dd2_ddist + \ dir2_new_basis[2] * ddn_ddist # derivative wrt shift1. NB These are all null. ddir2_dshift1 = dir2_new_basis[0] * dd1_dshift1 + \ dir2_new_basis[1] * dd2_dshift1 + \ dir2_new_basis[2] * ddn_dshift1 # derivative wrt shift2. NB These are all null. ddir2_dshift2 = dir2_new_basis[0] * dd1_dshift2 + \ dir2_new_basis[1] * dd2_dshift2 + \ dir2_new_basis[2] * ddn_dshift2 # derivative wrt tau1 ddir2_dtau1 = dir2_new_basis[0] * dd1_dtau1 + \ dir2_new_basis[1] * dd2_dtau1 + \ dir2_new_basis[2] * ddn_dtau1 # derivative wrt tau2 ddir2_dtau2 = dir2_new_basis[0] * dd1_dtau2 + \ dir2_new_basis[1] * dd2_dtau2 + \ dir2_new_basis[2] * ddn_dtau2 # derivative wrt tau3 ddir2_dtau3 = dir2_new_basis[0] * dd1_dtau3 + \ dir2_new_basis[1] * dd2_dtau3 + \ dir2_new_basis[2] * ddn_dtau3 # combine these vectors together into derivatives of the panel # matrix d and store them, converting angles back to mrad i = igp * 6 # derivative wrt dist self._multi_state_derivatives[panel_id][i] = \ matrix.sqr(ddir1_ddist.elems + ddir2_ddist.elems + do_ddist.elems).transpose() # derivative wrt shift1 self._multi_state_derivatives[panel_id][i+1] = \ matrix.sqr(ddir1_dshift1.elems + ddir2_dshift1.elems + do_dshift1.elems).transpose() # derivative wrt shift2 self._multi_state_derivatives[panel_id][i+2] = \ matrix.sqr(ddir1_dshift2.elems + ddir2_dshift2.elems + do_dshift2.elems).transpose() # derivative wrt tau1 self._multi_state_derivatives[panel_id][i+3] = \ matrix.sqr(ddir1_dtau1.elems + ddir2_dtau1.elems + do_dtau1.elems).transpose() / 1000. # derivative wrt tau2 self._multi_state_derivatives[panel_id][i+4] = \ matrix.sqr(ddir1_dtau2.elems + ddir2_dtau2.elems + do_dtau2.elems).transpose() / 1000. # derivative wrt tau3 self._multi_state_derivatives[panel_id][i+5] = \ matrix.sqr(ddir1_dtau3.elems + ddir2_dtau3.elems + do_dtau3.elems).transpose() / 1000. return
def _compose_core(self, dist, shift1, shift2, tau1, tau2, tau3): # extract items from the initial state id1 = self._initial_state['d1'] id2 = self._initial_state['d2'] ioffset = self._initial_state['offset'] # convert angles to radians tau1rad = tau1.value / 1000. tau2rad = tau2.value / 1000. tau3rad = tau3.value / 1000. # compose rotation matrices and their first order derivatives Tau1 = (tau1.axis).axis_and_angle_as_r3_rotation_matrix(tau1rad, deg=False) dTau1_dtau1 = dR_from_axis_and_angle(tau1.axis, tau1rad, deg=False) Tau2 = (tau2.axis).axis_and_angle_as_r3_rotation_matrix(tau2rad, deg=False) dTau2_dtau2 = dR_from_axis_and_angle(tau2.axis, tau2rad, deg=False) Tau3 = (tau3.axis).axis_and_angle_as_r3_rotation_matrix(tau3rad, deg=False) dTau3_dtau3 = dR_from_axis_and_angle(tau3.axis, tau3rad, deg=False) Tau32 = Tau3 * Tau2 Tau321 = Tau32 * Tau1 # Compose new state # ================= # First the frame positioned at a distance from the lab origin P0 = dist.value * dist.axis # distance along initial detector normal Px = P0 + id1 # point at the end of d1 in lab frame Py = P0 + id2 # point at the end of d2 in lab frame # detector shift vector dsv = P0 + shift1.value * shift1.axis + shift2.value * shift2.axis # compose dorg point dorg = Tau321 * dsv - Tau32 * P0 + P0 # compose d1, d2 and dn and ensure frame remains orthonormal. d1 = (Tau321 * (Px - P0)).normalize() d2 = (Tau321 * (Py - P0)).normalize() dn = d1.cross(d2).normalize() # NB dn not actually used in this simple model; calculation left # here as a reminder for future extension d2 = dn.cross(d1) # compose new sensor origin o = dorg + ioffset[0] * d1 + ioffset[1] * d2 # keep the new state for return new_state = {'d1':d1, 'd2':d2, 'origin':o} # calculate derivatives of the state wrt parameters # ================================================= # Start with the dorg vector, where # dorg = Tau321 * dsv - Tau32 * P0 + P0 # derivative wrt dist dP0_ddist = dist.axis ddsv_ddist = dP0_ddist ddorg_ddist = Tau321 * ddsv_ddist - Tau32 * dP0_ddist + \ dP0_ddist # derivative wrt shift1 ddsv_dshift1 = shift1.axis ddorg_dshift1 = Tau321 * ddsv_dshift1 # derivative wrt shift2 ddsv_dshift2 = shift2.axis ddorg_dshift2 = Tau321 * ddsv_dshift2 # derivative wrt tau1 dTau321_dtau1 = Tau32 * dTau1_dtau1 ddorg_dtau1 = dTau321_dtau1 * dsv # derivative wrt tau2 dTau32_dtau2 = Tau3 * dTau2_dtau2 dTau321_dtau2 = dTau32_dtau2 * Tau1 ddorg_dtau2 = dTau321_dtau2 * dsv - dTau32_dtau2 * P0 # derivative wrt tau3 dTau32_dtau3 = dTau3_dtau3 * Tau2 dTau321_dtau3 = dTau32_dtau3 * Tau1 ddorg_dtau3 = dTau321_dtau3 * dsv - dTau32_dtau3 * P0 # Now derivatives of the direction d1, where # d1 = (Tau321 * (Px - P0)).normalize() # For calc of derivatives ignore the normalize(), which should # be unnecessary anyway as Px - P0 is a unit vector and Tau321 a # pure rotation. # derivative wrt dist # dPx_ddist = dist.axis; dP0_ddist = dist.axis, so these cancel dd1_ddist = matrix.col((0., 0., 0.)) # derivative wrt shift1 dd1_dshift1 = matrix.col((0., 0., 0.)) # derivative wrt shift2 dd1_dshift2 = matrix.col((0., 0., 0.)) # derivative wrt tau1 dd1_dtau1 = dTau321_dtau1 * (Px - P0) # derivative wrt tau2 dd1_dtau2 = dTau321_dtau2 * (Px - P0) # derivative wrt tau3 dd1_dtau3 = dTau321_dtau3 * (Px - P0) # Derivatives of the direction d2, where # d2 = (Tau321 * (Py - P0)).normalize() # derivative wrt dist dd2_ddist = matrix.col((0., 0., 0.)) # derivative wrt shift1 dd2_dshift1 = matrix.col((0., 0., 0.)) # derivative wrt shift2 dd2_dshift2 = matrix.col((0., 0., 0.)) # derivative wrt tau1 dd2_dtau1 = dTau321_dtau1 * (Py - P0) # derivative wrt tau2 dd2_dtau2 = dTau321_dtau2 * (Py - P0) # derivative wrt tau3 dd2_dtau3 = dTau321_dtau3 * (Py - P0) # Derivatives of the direction dn, where # dn = d1.cross(d2).normalize() # derivative wrt dist ddn_ddist = matrix.col((0., 0., 0.)) # derivative wrt shift1 ddn_dshift1 = matrix.col((0., 0., 0.)) # derivative wrt shift2 ddn_dshift2 = matrix.col((0., 0., 0.)) # derivative wrt tau1. Product rule for cross product applies ddn_dtau1 = dd1_dtau1.cross(d2) + d1.cross(dd2_dtau1) # derivative wrt tau2 ddn_dtau2 = dd1_dtau2.cross(d2) + d1.cross(dd2_dtau2) # derivative wrt tau3 ddn_dtau3 = dd1_dtau3.cross(d2) + d1.cross(dd2_dtau3) # calculate derivatives of the attached sensor matrix # =================================================== # sensor origin: # o = dorg + ioffset[0] * d1 + ioffset[1] * d2 # derivative wrt dist do_ddist = ddorg_ddist + ioffset[0] * dd1_ddist + \ ioffset[1] * dd2_ddist # derivative wrt shift1 do_dshift1 = ddorg_dshift1 + ioffset[0] * dd1_dshift1 + \ ioffset[1] * dd2_dshift1 # derivative wrt shift2 do_dshift2 = ddorg_dshift2 + ioffset[0] * dd1_dshift2 + \ ioffset[1] * dd2_dshift2 # derivative wrt tau1 do_dtau1 = ddorg_dtau1 + ioffset[0] * dd1_dtau1 + \ ioffset[1] * dd2_dtau1 # derivative wrt tau2 do_dtau2 = ddorg_dtau2 + ioffset[0] * dd1_dtau2 + \ ioffset[1] * dd2_dtau2 # derivative wrt tau3 do_dtau3 = ddorg_dtau3 + ioffset[0] * dd1_dtau3 + \ ioffset[1] * dd2_dtau3 # combine these vectors together into derivatives of the sensor # matrix d, converting angles back to mrad dd_dval = [] # derivative wrt dist dd_dval.append(matrix.sqr(dd1_ddist.elems + dd2_ddist.elems + do_ddist.elems).transpose()) # derivative wrt shift1 dd_dval.append(matrix.sqr(dd1_dshift1.elems + dd2_dshift1.elems + do_dshift1.elems).transpose()) # derivative wrt shift2 dd_dval.append(matrix.sqr(dd1_dshift2.elems + dd2_dshift2.elems + do_dshift2.elems).transpose()) # derivative wrt tau1 dd_dval.append(matrix.sqr(dd1_dtau1.elems + dd2_dtau1.elems + do_dtau1.elems).transpose() / 1000.) # derivative wrt tau2 dd_dval.append(matrix.sqr(dd1_dtau2.elems + dd2_dtau2.elems + do_dtau2.elems).transpose() / 1000.) # derivative wrt tau3 dd_dval.append(matrix.sqr(dd1_dtau3.elems + dd2_dtau3.elems + do_dtau3.elems).transpose() / 1000.) return new_state, dd_dval
def compose(self): # extract items from the initial state id1 = self._initial_state['d1'] id2 = self._initial_state['d2'] idn = self._initial_state['dn'] # extract parameters from the internal list dist, shift1, shift2, tau1, tau2, tau3 = self._param # Extract the detector model detector = self._model # convert angles to radians tau1rad = tau1.value / 1000. tau2rad = tau2.value / 1000. tau3rad = tau3.value / 1000. # compose rotation matrices and their first order derivatives Tau1 = (tau1.axis).axis_and_angle_as_r3_rotation_matrix(tau1rad, deg=False) dTau1_dtau1 = dR_from_axis_and_angle(tau1.axis, tau1rad, deg=False) Tau2 = (tau2.axis).axis_and_angle_as_r3_rotation_matrix(tau2rad, deg=False) dTau2_dtau2 = dR_from_axis_and_angle(tau2.axis, tau2rad, deg=False) Tau3 = (tau3.axis).axis_and_angle_as_r3_rotation_matrix(tau3rad, deg=False) dTau3_dtau3 = dR_from_axis_and_angle(tau3.axis, tau3rad, deg=False) Tau32 = Tau3 * Tau2 Tau321 = Tau32 * Tau1 # Compose new state # ================= # First the frame positioned at a distance from the lab origin P0 = dist.value * dist.axis # distance along initial detector normal Px = P0 + id1 # point at the end of d1 in lab frame Py = P0 + id2 # point at the end of d2 in lab frame # detector shift vector dsv = P0 + shift1.value * shift1.axis + shift2.value * shift2.axis # compose dorg point dorg = Tau321 * dsv - Tau32 * P0 + P0 # compose new d1, d2 and dn and ensure frame remains orthonormal. d1 = (Tau321 * (Px - P0)).normalize() d2 = (Tau321 * (Py - P0)).normalize() dn = d1.cross(d2).normalize() d2 = dn.cross(d1) # compose new Panel origins origins = [dorg + offset[0] * d1 + \ offset[1] * d2 + \ offset[2] * dn for offset in self._offsets] # compose new Panel directions dir1s = [vec[0] * d1 + \ vec[1] * d2 + \ vec[2] * dn for vec in self._dir1s] dir2s = [vec[0] * d1 + \ vec[1] * d2 + \ vec[2] * dn for vec in self._dir2s] # now update the panels with their new position and orientation. for p, dir1, dir2, org in zip(detector, dir1s, dir2s, origins): p.set_frame(dir1, dir2, org) # calculate derivatives of the state wrt parameters # ================================================= # Start with the dorg vector, where # dorg = Tau321 * dsv - Tau32 * P0 + P0 # derivative wrt dist dP0_ddist = dist.axis ddsv_ddist = dP0_ddist ddorg_ddist = Tau321 * ddsv_ddist - Tau32 * dP0_ddist + \ dP0_ddist # derivative wrt shift1 ddsv_dshift1 = shift1.axis ddorg_dshift1 = Tau321 * ddsv_dshift1 # derivative wrt shift2 ddsv_dshift2 = shift2.axis ddorg_dshift2 = Tau321 * ddsv_dshift2 # derivative wrt tau1 dTau321_dtau1 = Tau32 * dTau1_dtau1 ddorg_dtau1 = dTau321_dtau1 * dsv # derivative wrt tau2 dTau32_dtau2 = Tau3 * dTau2_dtau2 dTau321_dtau2 = dTau32_dtau2 * Tau1 ddorg_dtau2 = dTau321_dtau2 * dsv - dTau32_dtau2 * P0 # derivative wrt tau3 dTau32_dtau3 = dTau3_dtau3 * Tau2 dTau321_dtau3 = dTau32_dtau3 * Tau1 ddorg_dtau3 = dTau321_dtau3 * dsv - dTau32_dtau3 * P0 # Now derivatives of the direction d1, where # d1 = (Tau321 * (Px - P0)).normalize() # For calc of derivatives ignore the normalize(), which should # be unnecessary anyway as Px - P0 is a unit vector and Tau321 a # pure rotation. # derivative wrt dist # dPx_ddist = dist.axis; dP0_ddist = dist.axis, so these cancel dd1_ddist = matrix.col((0., 0., 0.)) # derivative wrt shift1 dd1_dshift1 = matrix.col((0., 0., 0.)) # derivative wrt shift2 dd1_dshift2 = matrix.col((0., 0., 0.)) # derivative wrt tau1 dd1_dtau1 = dTau321_dtau1 * (Px - P0) # derivative wrt tau2 dd1_dtau2 = dTau321_dtau2 * (Px - P0) # derivative wrt tau3 dd1_dtau3 = dTau321_dtau3 * (Px - P0) # Derivatives of the direction d2, where # d2 = (Tau321 * (Py - P0)).normalize() # derivative wrt dist dd2_ddist = matrix.col((0., 0., 0.)) # derivative wrt shift1 dd2_dshift1 = matrix.col((0., 0., 0.)) # derivative wrt shift2 dd2_dshift2 = matrix.col((0., 0., 0.)) # derivative wrt tau1 dd2_dtau1 = dTau321_dtau1 * (Py - P0) # derivative wrt tau2 dd2_dtau2 = dTau321_dtau2 * (Py - P0) # derivative wrt tau3 dd2_dtau3 = dTau321_dtau3 * (Py - P0) # Derivatives of the direction dn, where # dn = d1.cross(d2).normalize() # derivative wrt dist ddn_ddist = matrix.col((0., 0., 0.)) # derivative wrt shift1 ddn_dshift1 = matrix.col((0., 0., 0.)) # derivative wrt shift2 ddn_dshift2 = matrix.col((0., 0., 0.)) # derivative wrt tau1. Product rule for cross product applies ddn_dtau1 = dd1_dtau1.cross(d2) + d1.cross(dd2_dtau1) # derivative wrt tau2 ddn_dtau2 = dd1_dtau2.cross(d2) + d1.cross(dd2_dtau2) # derivative wrt tau3 ddn_dtau3 = dd1_dtau3.cross(d2) + d1.cross(dd2_dtau3) # reset stored derivatives for i in range(len(detector)): self._multi_state_derivatives[i] = [None] * len(self._dstate_dp) # calculate derivatives of the attached Panel matrices # ==================================================== for panel_id, (offset, dir1_new_basis, dir2_new_basis) in enumerate( zip(self._offsets, self._dir1s, self._dir2s)): # Panel origin: # o = dorg + offset[0] * d1 + offset[1] * d2 + offset[2] * dn # derivative wrt dist. NB only ddorg_ddist is not null! The other # elements are left here to aid understanding, but should be removed # when this class is ported to C++ for speed. do_ddist = ddorg_ddist + offset[0] * dd1_ddist + \ offset[1] * dd2_ddist + \ offset[2] * ddn_ddist # derivative wrt shift1. NB only ddorg_dshift1 is non-null. do_dshift1 = ddorg_dshift1 + offset[0] * dd1_dshift1 + \ offset[1] * dd2_dshift1 + \ offset[2] * ddn_dshift1 # derivative wrt shift2. NB only ddorg_dshift2 is non-null. do_dshift2 = ddorg_dshift2 + offset[0] * dd1_dshift2 + \ offset[1] * dd2_dshift2 + \ offset[2] * ddn_dshift2 # derivative wrt tau1 do_dtau1 = ddorg_dtau1 + offset[0] * dd1_dtau1 + \ offset[1] * dd2_dtau1 + \ offset[2] * ddn_dtau1 # derivative wrt tau2 do_dtau2 = ddorg_dtau2 + offset[0] * dd1_dtau2 + \ offset[1] * dd2_dtau2 + \ offset[2] * ddn_dtau2 # derivative wrt tau3 do_dtau3 = ddorg_dtau3 + offset[0] * dd1_dtau3 + \ offset[1] * dd2_dtau3 + \ offset[2] * ddn_dtau3 # Panel dir1: # dir1 = dir1_new_basis[0] * d1 + dir1_new_basis[1] * d2 + # dir1_new_basis[2] * dn # derivative wrt dist. NB These are all null. ddir1_ddist = dir1_new_basis[0] * dd1_ddist + \ dir1_new_basis[1] * dd2_ddist + \ dir1_new_basis[2] * ddn_ddist # derivative wrt shift1. NB These are all null. ddir1_dshift1 = dir1_new_basis[0] * dd1_dshift1 + \ dir1_new_basis[1] * dd2_dshift1 + \ dir1_new_basis[2] * ddn_dshift1 # derivative wrt shift2. NB These are all null. ddir1_dshift2 = dir1_new_basis[0] * dd1_dshift2 + \ dir1_new_basis[1] * dd2_dshift2 + \ dir1_new_basis[2] * ddn_dshift2 # derivative wrt tau1 ddir1_dtau1 = dir1_new_basis[0] * dd1_dtau1 + \ dir1_new_basis[1] * dd2_dtau1 + \ dir1_new_basis[2] * ddn_dtau1 # derivative wrt tau2 ddir1_dtau2 = dir1_new_basis[0] * dd1_dtau2 + \ dir1_new_basis[1] * dd2_dtau2 + \ dir1_new_basis[2] * ddn_dtau2 # derivative wrt tau3 ddir1_dtau3 = dir1_new_basis[0] * dd1_dtau3 + \ dir1_new_basis[1] * dd2_dtau3 + \ dir1_new_basis[2] * ddn_dtau3 # Panel dir2: # dir2 = dir2_new_basis[0] * d1 + dir2_new_basis[1] * d2 + # dir2_new_basis[2] * dn # derivative wrt dist. NB These are all null. ddir2_ddist = dir2_new_basis[0] * dd1_ddist + \ dir2_new_basis[1] * dd2_ddist + \ dir2_new_basis[2] * ddn_ddist # derivative wrt shift1. NB These are all null. ddir2_dshift1 = dir2_new_basis[0] * dd1_dshift1 + \ dir2_new_basis[1] * dd2_dshift1 + \ dir2_new_basis[2] * ddn_dshift1 # derivative wrt shift2. NB These are all null. ddir2_dshift2 = dir2_new_basis[0] * dd1_dshift2 + \ dir2_new_basis[1] * dd2_dshift2 + \ dir2_new_basis[2] * ddn_dshift2 # derivative wrt tau1 ddir2_dtau1 = dir2_new_basis[0] * dd1_dtau1 + \ dir2_new_basis[1] * dd2_dtau1 + \ dir2_new_basis[2] * ddn_dtau1 # derivative wrt tau2 ddir2_dtau2 = dir2_new_basis[0] * dd1_dtau2 + \ dir2_new_basis[1] * dd2_dtau2 + \ dir2_new_basis[2] * ddn_dtau2 # derivative wrt tau3 ddir2_dtau3 = dir2_new_basis[0] * dd1_dtau3 + \ dir2_new_basis[1] * dd2_dtau3 + \ dir2_new_basis[2] * ddn_dtau3 # combine these vectors together into derivatives of the panel # matrix d and store them, converting angles back to mrad self._multi_state_derivatives[panel_id] = \ [matrix.sqr(ddir1_ddist.elems + ddir2_ddist.elems + do_ddist.elems).transpose(), matrix.sqr(ddir1_dshift1.elems + ddir2_dshift1.elems + do_dshift1.elems).transpose(), matrix.sqr(ddir1_dshift2.elems + ddir2_dshift2.elems + do_dshift2.elems).transpose(), matrix.sqr(ddir1_dtau1.elems + ddir2_dtau1.elems + do_dtau1.elems).transpose() / 1000., matrix.sqr(ddir1_dtau2.elems + ddir2_dtau2.elems + do_dtau2.elems).transpose() / 1000., matrix.sqr(ddir1_dtau3.elems + ddir2_dtau3.elems + do_dtau3.elems).transpose() / 1000.] return