def constrain(self, constraints): #algorithm 1. Use pre-defined crystal_systems to give hard-coded restraints. # dps_core.constrainment.s_minimizer uses LBFGS minimizer to adapt # all 9 components of the orientation matrix. This gives the best-fit # to the starting matrix (better than algorithm #2), but the disadvantage # is that it is keyed to the crystal_system descriptors. It is therefore # not adapted to all small-molecule space groups (monoclinics), # and will not take into account non-standard settings. if constraints in [ "triclinic", "monoclinic", 'orthorhombic', 'tetragonal', "cubic", "rhombohedral", 'hexagonal' ]: from rstbx.dps_core.constrainment import s_minimizer S = s_minimizer(self, constraint=constraints) return S.newOrientation() #algorithm 2: Tensor_rank_2 symmetrization # Advantages: constraints are calculated directly from the space # group, so will account for non-standard settings. # Disadvantages: drift away from starting orientation is greater than # for algorithm #1. from cctbx.sgtbx import space_group if isinstance(constraints, space_group): from rstbx.symmetry.constraints import AGconvert converter = AGconvert() converter.forward(self) average_cell = constraints.average_unit_cell(self.unit_cell()) converter.validate_and_setG( average_cell.reciprocal().metrical_matrix()) return Orientation(converter.back(), basis_type.reciprocal)
def symmetrize(self): converter = AGconvert() converter.forward(self.orientation) # allows subsequent back-conversion of symmetrized # takes member-data orientation; returns symmetrized metrical matrix uc = self.orientation.unit_cell() avg = self.space_group.average_unit_cell(uc) # assumes direct-space cell sym_mm = avg.reciprocal().metrical_matrix() converter.validate_and_setG(sym_mm) self.orientation = converter.back_as_orientation()
def symmetrize(self): converter = AGconvert() converter.forward(self.orientation) # allows subsequent back-conversion of symmetrized # takes member-data orientation; returns symmetrized metrical matrix uc = self.orientation.unit_cell() avg = self.space_group.average_unit_cell(uc) # assumes direct-space cell sym_mm = avg.reciprocal().metrical_matrix() converter.validate_and_setG(sym_mm) self.orientation = converter.back_as_orientation()
def forward_independent_parameters(self): # returns the independent parameters given the set_orientation() B matrix self.Bconverter=AGconvert() self.Bconverter.forward(self.orientation) return self.reduce(metrical_matrix = self.Bconverter.G)
class symmetrize_reduce_enlarge(object): # symmetrize the metrical matrix & # reduce the number of parameters to reflect symmetry # also, provide back transform to increase # number of parameters back to six def __init__(self, space_group): self.space_group = space_group self.constraints = sgtbx.tensor_rank_2_constraints( space_group=self.space_group,reciprocal_space=True) def set_orientation(self, orientation, length_unit=1.E-10): #provide orientation as either an A matrix (Rossmann) or B matrix (Busing & Levy) # data type can be either scitbx.matrix.sqr or scitbx::mat3 # in either the reciprocal or direct space setting # or as a cctbx.crystal_orientation.crystal_orientation # if space group is not triclinic the orientation matrix should be close to # symmetrized, but exact symmetrization is done by averaging within the constructor. # length unit defaults to 1.E-10 meters = 1 Angstrom if "direct_matrix" in dir(orientation): self.orientation = orientation # data is already a cctbx orientation else: from cctbx.crystal_orientation import crystal_orientation which_setting = [crystal_orientation(orientation,True), crystal_orientation(orientation,False)] #kludgy test for space setting: unit cell volume is never < 100 Angstroms^3 conversion_to_A3 = (length_unit*length_unit*length_unit)/1.E-30 select = [a.unit_cell().volume()*conversion_to_A3 > 100. for a in which_setting] self.orientation = which_setting[select.index(True)] def symmetrize(self): converter = AGconvert() converter.forward(self.orientation) # allows subsequent back-conversion of symmetrized # takes member-data orientation; returns symmetrized metrical matrix uc = self.orientation.unit_cell() avg = self.space_group.average_unit_cell(uc) # assumes direct-space cell sym_mm = avg.reciprocal().metrical_matrix() converter.validate_and_setG(sym_mm) self.orientation = converter.back_as_orientation() # it is assumed that metrical_matrix and independent are in reciprocal setting def reduce(self,metrical_matrix): # takes 6-parameter metrical matrix, returns reduced number of independent parameters return self.constraints.independent_params(all_params=metrical_matrix) def enlarge(self,independent): # takes reduced number independent parameters, returns 6-parameter metrical matrix u_star = self.constraints.all_params(independent_params=tuple(independent)) assert len(u_star) == 6 return u_star def forward_independent_parameters(self): # returns the independent parameters given the set_orientation() B matrix self.Bconverter=AGconvert() self.Bconverter.forward(self.orientation) return self.reduce(metrical_matrix = self.Bconverter.G) def forward_gradients(self): #Specifically for refinement of the B-matrix parameters. from rstbx.symmetry.constraints.g_gradients import g_gradients gradient_engine = g_gradients(agadaptor = self.Bconverter, symred = self) return gradient_engine.dB_dp() def backward_orientation(self,independent): # given new values of the independent parameters, back-calculate and # set the new orientation matrix new_mm = self.enlarge(independent) self.Bconverter.validate_and_setG(new_mm) self.orientation = self.Bconverter.back_as_orientation() return self.orientation
def parameter_based_model_one_frame_detail(self,frame_id,iframe,all_model): PIXEL_SZ = 0.11 # mm/pixel SIGN = -1. if iframe < self.n_refined_frames: detector_origin = col((-self.FRAMES["beam_x"][iframe] + SIGN * PIXEL_SZ * self.frame_translations.x[2*iframe], -self.FRAMES["beam_y"][iframe] + SIGN * PIXEL_SZ * self.frame_translations.x[1+2*iframe], 0.)) self.OUTPUT["beam_x"][iframe] = -detector_origin[0] self.OUTPUT["beam_y"][iframe] = -detector_origin[1] else: detector_origin = col((-self.FRAMES["beam_x"][iframe],-self.FRAMES["beam_y"][iframe],0.)) if not self.bandpass_models.has_key(frame_id): reserve_orientation = self.FRAMES["orientation"][iframe] effective_orientation = reserve_orientation #Not necessary to apply the 3 offset rotations; they have apparently # been applied already.\ # .rotate_thru((1,0,0),self.FRAMES["rotation100_rad"][iframe] # ).rotate_thru((0,1,0),self.FRAMES["rotation010_rad"][iframe] # ).rotate_thru((0,0,1),self.FRAMES["rotation001_rad"][iframe]) crystal = symmetry(unit_cell=effective_orientation.unit_cell(),space_group = "P1") indices = all_model.frame_indices(frame_id) parameters = parameters_bp3( indices=indices, orientation=effective_orientation, incident_beam=col(correction_vectors.INCIDENT_BEAM), packed_tophat=col((1.,1.,0.)), detector_normal=col(correction_vectors.DETECTOR_NORMAL), detector_fast=col((0.,1.,0.)),detector_slow=col((1.,0.,0.)), pixel_size=col((PIXEL_SZ,PIXEL_SZ,0)), pixel_offset=col((0.,0.,0.0)), distance=self.FRAMES["distance"][iframe], detector_origin=detector_origin ) #print "PARAMETER check ", effective_orientation #print "PARAMETER distance", self.FRAMES['distance'][iframe] #print "PARAMETER origin ", detector_origin ucbp3 = bandpass_gaussian(parameters=parameters) ucbp3.set_active_areas( self.tiles ) #self.params.effective_tile_boundaries integration_signal_penetration=0.0 # easier to calculate distance derivatives ucbp3.set_sensor_model( thickness_mm = 0.5, mu_rho = 8.36644, # CS_PAD detector at 1.3 Angstrom signal_penetration = integration_signal_penetration) #ucbp3.set_subpixel( flex.double(tp038_trans_values) ) #back off this; let minimizer figure it out. half_mosaicity_rad = self.FRAMES["half_mosaicity_deg"][iframe] * pi/180. ucbp3.set_mosaicity(half_mosaicity_rad) ucbp3.set_bandpass(self.FRAMES["wave_HE_ang"][iframe],self.FRAMES["wave_LE_ang"][iframe]) ucbp3.set_orientation(effective_orientation) ucbp3.set_domain_size(self.FRAMES["domain_size_ang"][iframe]) ucbp3.set_vector_output_pointers(self.vector_data, frame_id,iframe<self.n_refined_frames) if not self.bandpass_models.has_key("best_index"): from labelit.dptbx import lepage M = lepage.character(effective_orientation) s = len(M.best()) for index in M.best(): index['counter'] = s s-=1 if index["max_angular_difference"]==0.0: best_index = index break self.bandpass_models["best_index"] = best_index self.bandpass_models["constraints"] = tensor_rank_2_constraints(space_group=best_index['reduced_group'],reciprocal_space=True) self.bandpass_models["n_independent"] = self.bandpass_models["constraints"].n_independent_params() self.bandpass_models[frame_id]=ucbp3 if iframe < self.n_refined_frames: self.bandpass_models[frame_id].set_detector_origin(detector_origin) self.bandpass_models[frame_id].set_distance( self.FRAMES["distance"][iframe] + self.frame_distances.x[iframe]) self.OUTPUT["distance"][iframe] = self.FRAMES["distance"][iframe] + self.frame_distances.x[iframe] #half_mosaicity_rad = self.FRAMES["half_mosaicity_deg"][iframe] * pi/180. + \ # self.half_mosaicity_rad.x[iframe] #self.bandpass_models[frame_id].set_mosaicity(half_mosaicity_rad) reserve_orientation = self.FRAMES["orientation"][iframe] effective_orientation = reserve_orientation.rotate_thru((0,0,1),self.frame_rotz.x[iframe]) effective_orientation = effective_orientation.rotate_thru((0,1,0),self.frame_roty.x[iframe]) effective_orientation = effective_orientation.rotate_thru((1,0,0),self.frame_rotx.x[iframe]) convert = AGconvert() convert.forward(effective_orientation) u_independent = list(self.bandpass_models["constraints"].independent_params(all_params=convert.G)) for x in xrange(self.bandpass_models["n_independent"]): u_independent[x] *= self.g_factor.x[x+6*iframe] u_star = self.bandpass_models["constraints"].all_params(independent_params=tuple(u_independent)) convert.validate_and_setG(u_star) effective_orientation = convert.back_as_orientation() self.OUTPUT["orientation"][iframe]=effective_orientation self.bandpass_models[frame_id].set_orientation(effective_orientation) mean_wave = (self.FRAMES["wave_HE_ang"][iframe] + self.FRAMES["wave_LE_ang"][iframe])/2. #mean_wave *= self.mean_energy_factor.x[iframe] bandpassHW =(self.FRAMES["wave_LE_ang"][iframe] - self.FRAMES["wave_HE_ang"][iframe])/2. self.bandpass_models[frame_id].set_bandpass(mean_wave - bandpassHW, mean_wave + bandpassHW) return detector_origin
def forward_independent_parameters(self): # returns the independent parameters given the set_orientation() B matrix self.Bconverter=AGconvert() self.Bconverter.forward(self.orientation) return self.reduce(metrical_matrix = self.Bconverter.G)
class symmetrize_reduce_enlarge(object): # symmetrize the metrical matrix & # reduce the number of parameters to reflect symmetry # also, provide back transform to increase # number of parameters back to six def __init__(self, space_group): self.space_group = space_group self.constraints = sgtbx.tensor_rank_2_constraints( space_group=self.space_group,reciprocal_space=True) def set_orientation(self, orientation, length_unit=1.E-10): #provide orientation as either an A matrix (Rossmann) or B matrix (Busing & Levy) # data type can be either scitbx.matrix.sqr or scitbx::mat3 # in either the reciprocal or direct space setting # or as a cctbx.crystal_orientation.crystal_orientation # if space group is not triclinic the orientation matrix should be close to # symmetrized, but exact symmetrization is done by averaging within the constructor. # length unit defaults to 1.E-10 meters = 1 Angstrom if "direct_matrix" in dir(orientation): self.orientation = orientation # data is already a cctbx orientation else: from cctbx.crystal_orientation import crystal_orientation which_setting = [crystal_orientation(orientation,True), crystal_orientation(orientation,False)] #kludgy test for space setting: unit cell volume is never < 70 Angstroms^3 conversion_to_A3 = (length_unit*length_unit*length_unit)/1.E-30 select = [a.unit_cell().volume()*conversion_to_A3 > 70. for a in which_setting] self.orientation = which_setting[select.index(True)] def symmetrize(self): converter = AGconvert() converter.forward(self.orientation) # allows subsequent back-conversion of symmetrized # takes member-data orientation; returns symmetrized metrical matrix uc = self.orientation.unit_cell() avg = self.space_group.average_unit_cell(uc) # assumes direct-space cell sym_mm = avg.reciprocal().metrical_matrix() converter.validate_and_setG(sym_mm) self.orientation = converter.back_as_orientation() # it is assumed that metrical_matrix and independent are in reciprocal setting def reduce(self,metrical_matrix): # takes 6-parameter metrical matrix, returns reduced number of independent parameters return self.constraints.independent_params(all_params=metrical_matrix) def enlarge(self,independent): # takes reduced number independent parameters, returns 6-parameter metrical matrix u_star = self.constraints.all_params(independent_params=tuple(independent)) assert len(u_star) == 6 return u_star def forward_independent_parameters(self): # returns the independent parameters given the set_orientation() B matrix self.Bconverter=AGconvert() self.Bconverter.forward(self.orientation) return self.reduce(metrical_matrix = self.Bconverter.G) def forward_gradients(self): #Specifically for refinement of the B-matrix parameters. from rstbx.symmetry.constraints.g_gradients import g_gradients gradient_engine = g_gradients(agadaptor = self.Bconverter, symred = self) return gradient_engine.dB_dp() def backward_orientation(self,independent): # given new values of the independent parameters, back-calculate and # set the new orientation matrix new_mm = self.enlarge(independent) self.Bconverter.validate_and_setG(new_mm) self.orientation = self.Bconverter.back_as_orientation() return self.orientation
def finite_difference_test(orient): from rstbx.symmetry.constraints import AGconvert as AG from labelit.symmetry.metricsym.a_g_conversion import pp from libtbx.tst_utils import approx_equal adaptor = AG() adaptor.forward(orient) grad = g_gradients(adaptor, symred=None) epsilon = 1.E-10 dAij_dphi = grad.get_all_da()[0] AGback = AG() F = [] for x in [-1., 1.]: AGback.setAngles(adaptor.phi + x * epsilon, adaptor.psi, adaptor.theta) AGback.G = adaptor.G F.append(flex.double(AGback.back())) diff_mat = (F[1] - F[0]) / (2. * epsilon) rule = "dAij_dphi: Analytical gradient vs. finite difference gradient\n"+\ pp(list(dAij_dphi))+"\n"+\ pp(diff_mat) if not (approx_equal(dAij_dphi, diff_mat, 1.E-7)): raise Exception(rule) dAij_dpsi = grad.get_all_da()[1] AGback = AG() F = [] for x in [-1., 1.]: AGback.setAngles(adaptor.phi, adaptor.psi + x * epsilon, adaptor.theta) AGback.G = adaptor.G F.append(flex.double(AGback.back())) diff_mat = (F[1] - F[0]) / (2. * epsilon) rule = "dAij_dpsi: Analytical gradient vs. finite difference gradient\n"+\ pp(list(dAij_dpsi))+"\n"+\ pp(diff_mat) if not (approx_equal(dAij_dpsi, diff_mat, 1.E-7)): raise Exception(rule) dAij_dtheta = grad.get_all_da()[2] AGback = AG() F = [] for x in [-1., 1.]: AGback.setAngles(adaptor.phi, adaptor.psi, adaptor.theta + x * epsilon) AGback.G = adaptor.G F.append(flex.double(AGback.back())) diff_mat = (F[1] - F[0]) / (2. * epsilon) rule = "dAij_dtheta: Analytical gradient vs. finite difference gradient\n"+\ pp(list(dAij_dtheta))+"\n"+\ pp(diff_mat) if not (approx_equal(dAij_dtheta, diff_mat, 1.E-7)): raise Exception(rule) g0, g1, g2, g3, g4, g5 = adaptor.G dAij_dg0 = grad.get_all_da()[3] AGback = AG() F = [] for x in [-1., 1.]: AGback.setAngles(adaptor.phi, adaptor.psi, adaptor.theta) AGback.G = (g0 + x * epsilon, g1, g2, g3, g4, g5) F.append(flex.double(AGback.back())) diff_mat = (F[1] - F[0]) / (2. * epsilon) rule = "dAij_dg0: Analytical gradient vs. finite difference gradient\n"+\ pp(list(dAij_dg0))+"\n"+\ pp(diff_mat) if not (approx_equal(dAij_dg0, diff_mat, 1.E-7)): raise Exception(rule) dAij_dg1 = grad.get_all_da()[4] AGback = AG() F = [] for x in [-1., 1.]: AGback.setAngles(adaptor.phi, adaptor.psi, adaptor.theta) AGback.G = (g0, g1 + x * epsilon, g2, g3, g4, g5) F.append(flex.double(AGback.back())) diff_mat = (F[1] - F[0]) / (2. * epsilon) rule = "dAij_dg1: Analytical gradient vs. finite difference gradient\n"+\ pp(list(dAij_dg1))+"\n"+\ pp(diff_mat) if not (approx_equal(dAij_dg1, diff_mat, 1.E-7)): raise Exception(rule) dAij_dg2 = grad.get_all_da()[5] AGback = AG() F = [] for x in [-1., 1.]: AGback.setAngles(adaptor.phi, adaptor.psi, adaptor.theta) AGback.G = (g0, g1, g2 + x * epsilon, g3, g4, g5) F.append(flex.double(AGback.back())) diff_mat = (F[1] - F[0]) / (2. * epsilon) rule = "dAij_dg2: Analytical gradient vs. finite difference gradient\n"+\ pp(list(dAij_dg2))+"\n"+\ pp(diff_mat) if not (approx_equal(dAij_dg2, diff_mat, 1.E-6)): raise Exception(rule) dAij_dg3 = grad.get_all_da()[6] AGback = AG() F = [] for x in [-1., 1.]: AGback.setAngles(adaptor.phi, adaptor.psi, adaptor.theta) AGback.G = (g0, g1, g2, g3 + x * epsilon, g4, g5) F.append(flex.double(AGback.back())) diff_mat = (F[1] - F[0]) / (2. * epsilon) rule = "dAij_dg3: Analytical gradient vs. finite difference gradient\n"+\ pp(list(dAij_dg3))+"\n"+\ pp(diff_mat) if not (approx_equal(dAij_dg3, diff_mat, 1.E-7)): raise Exception(rule) dAij_dg4 = grad.get_all_da()[7] AGback = AG() F = [] for x in [-1., 1.]: AGback.setAngles(adaptor.phi, adaptor.psi, adaptor.theta) AGback.G = (g0, g1, g2, g3, g4 + x * epsilon, g5) F.append(flex.double(AGback.back())) diff_mat = (F[1] - F[0]) / (2. * epsilon) rule = "dAij_dg4: Analytical gradient vs. finite difference gradient\n"+\ pp(list(dAij_dg4))+"\n"+\ pp(diff_mat) if not (approx_equal(dAij_dg4, diff_mat, 1.E-7)): raise Exception(rule) dAij_dg5 = grad.get_all_da()[8] AGback = AG() F = [] for x in [-1., 1.]: AGback.setAngles(adaptor.phi, adaptor.psi, adaptor.theta) AGback.G = (g0, g1, g2, g3, g4, g5 + x * epsilon) F.append(flex.double(AGback.back())) diff_mat = (F[1] - F[0]) / (2. * epsilon) rule = "dAij_dg5: Analytical gradient vs. finite difference gradient\n"+\ pp(list(dAij_dg5))+"\n"+\ pp(diff_mat) if not (approx_equal(dAij_dg5, diff_mat, 1.E-6)): raise Exception(rule)