myaxis = np.array([0, 1, 0]) # must be in [x, y, z] order print('Q aligned along ', ref_axis_outplane, ":", myaxis) angle = simu.angle_vectors(ref_vector=np.array([q[2], q[1], q[0]]) / np.linalg.norm(q), test_vector=myaxis) print("Angle between q and", ref_axis_outplane, "=", angle, "deg") print("Angle with y in zy plane", np.arctan(q[0] / q[1]) * 180 / np.pi, "deg") print("Angle with y in xy plane", np.arctan(-q[2] / q[1]) * 180 / np.pi, "deg") print("Angle with z in xz plane", 180 + np.arctan(q[2] / q[0]) * 180 / np.pi, "deg") support, phase = pu.rotate_crystal( arrays=(support, phase), axis_to_align=myaxis, debugging=(True, False), title=('support', 'phase'), reference_axis=np.array([q[2], q[1], q[0]]) / np.linalg.norm(q)) original_obj = support * np.exp(1j * phase) del phase, support gc.collect() ################################################################################################## # compensate padding in order to keep reciprocal space resolution (detector pixel size) constant # ################################################################################################## # compensate padding in real space print('\nOriginal voxel size', voxel_size, 'nm') dqz = 2 * np.pi / (nz * voxel_size * 10) # in inverse angstroms dqy = 2 * np.pi / (ny * voxel_size * 10) # in inverse angstroms dqx = 2 * np.pi / (nx * voxel_size * 10) # in inverse angstroms
np.savez_compressed(datadir + 'S' + str(scan) + "_amp" + phase_fieldname + comment + '_LAB', amp=amp, phase=phase) print("VTK spacing :", str('{:.2f}'.format(voxel_size)), "nm") # save amp & phase to VTK before rotation in crystal frame # in VTK, x is downstream, y vertical, z inboard, thus need to flip the last axis gu.save_to_vti(filename=os.path.join(datadir, "S"+str(scan)+"_amp-"+phase_fieldname+"_LAB"+comment+".vti"), voxel_size=(voxel_size, voxel_size, voxel_size), tuple_array=(amp, phase), tuple_fieldnames=('amp', phase_fieldname), amplitude_threshold=0.01) ############################################################################ # put back the crystal in its frame, by aligning q onto the reference axis # ############################################################################ if not xrayutils_ortho: print('\nAligning Q along ', ref_axis_q, ":", myaxis) amp = pu.rotate_crystal(array=amp, axis_to_align=np.array([q[2], q[1], q[0]])/np.linalg.norm(q), reference_axis=myaxis, debugging=debug) phase = pu.rotate_crystal(array=phase, axis_to_align=np.array([q[2], q[1], q[0]])/np.linalg.norm(q), reference_axis=myaxis, debugging=debug) ################################################################ # calculate the strain depending on which axis q is aligned on # ################################################################ support = np.zeros(amp.shape) support[amp > isosurface_strain*amp.max()] = 1 zcom, ycom, xcom = center_of_mass(support) del support gc.collect() strain = pu.get_strain(phase=phase, planar_distance=planar_dist, voxel_size=voxel_size, reference_axis=ref_axis_q)
old_voxelsize=(dz_real, dy_real, dx_real), new_voxelsize=voxel_size) else: # no need to interpolate voxel_size = dz_real, dy_real, dx_real # in nm if data_frame == 'laboratory': # the object must be rotated into the crystal frame before the strain calculation print( 'Rotating the object in the crystal frame for the strain calculation' ) amp, phase = pu.rotate_crystal( arrays=(abs(obj_ortho), np.angle(obj_ortho)), is_orthogonal=True, reciprocal_space=False, voxel_size=voxel_size, debugging=(True, False), axis_to_align=np.array([q[2], q[1], q[0]]) / np.linalg.norm(q), reference_axis=axis_to_array_xyz[ref_axis_q], title=('amp', 'phase')) obj_ortho = amp * np.exp( 1j * phase) # here the phase is again wrapped in [-pi pi[ del amp, phase del avg_obj gc.collect() ###################################################### # center the object (centering based on the modulus) # ######################################################
obj = abs(obj) numz, numy, numx = obj.shape print("Initial data size: (", numz, ',', numy, ',', numx, ')') ############################# # rotate the reconstruction # ############################# new_shape = [int(1.2 * numz), int(1.2 * numy), int(1.2 * numx)] obj = pu.crop_pad(array=obj, output_shape=new_shape, debugging=False) numz, numy, numx = obj.shape print("Cropped/padded data size before rotating: (", numz, ',', numy, ',', numx, ')') print('Rotating object to have the crystallographic axes along array axes') obj = pu.rotate_crystal(array=obj, axis_to_align=axis_outofplane, reference_axis=np.array([0, 1, 0]), debugging=True) # out of plane alignement obj = pu.rotate_crystal(array=obj, axis_to_align=axis_inplane, reference_axis=np.array([1, 0, 0]), debugging=True) # inplane alignement ################################################# # pad array to obtain the desired field of view # ################################################## amp = np.copy(obj) amp = np.flip( amp, 2 ) # mayavi expect xyz, but we provide downstream/upward/outboard which is not in the correct order amp = amp / amp.max() amp[amp < threshold_isosurface] = 0
if ref_axis_outplane == "x": myaxis = np.array([1, 0, 0]) # must be in [x, y, z] order elif ref_axis_outplane == "y": myaxis = np.array([0, 1, 0]) # must be in [x, y, z] order elif ref_axis_outplane == "z": myaxis = np.array([0, 0, 1]) # must be in [x, y, z] order else: ref_axis_outplane = "y" myaxis = np.array([0, 1, 0]) # must be in [x, y, z] order print('Q aligned along ', ref_axis_outplane, ":", myaxis) angle = pu.plane_angle(np.array([q[2], q[1], q[0]]) / np.linalg.norm(q), myaxis) print("Angle between q and", ref_axis_outplane, "=", angle, "deg") print("Angle with y in zy plane", np.arctan(q[0] / q[1]) * 180 / np.pi, "deg") print("Angle with y in xy plane", np.arctan(-q[2] / q[1]) * 180 / np.pi, "deg") print("Angle with z in xz plane", 180 + np.arctan(q[2] / q[0]) * 180 / np.pi, "deg") support = pu.rotate_crystal(support, axis_to_align=myaxis, reference_axis=np.array([q[2], q[1], q[0]]) / np.linalg.norm(q), debugging=True) phase = pu.rotate_crystal(phase, axis_to_align=myaxis, reference_axis=np.array([q[2], q[1], q[0]]) / np.linalg.norm(q), debugging=False) original_obj = support * np.exp(1j * phase) del phase, support gc.collect() ################################################################################################## # compensate padding in order to keep reciprocal space resolution (detector pixel size) constant # ################################################################################################## # compensate padding in real space print('\nOriginal voxel size', voxel_size, 'nm') dqz = 2 * np.pi / (nz * voxel_size * 10) # in inverse angstroms dqy = 2 * np.pi / (ny * voxel_size * 10) # in inverse angstroms dqx = 2 * np.pi / (nx * voxel_size * 10) # in inverse angstroms
nbz, nby, nbx = obj.shape ################# # rotate object # ################# if align_axes: assert len(align_axes) == len( ref_axes), 'align_axes and ref_axes should have the same length' new_shape = [int(1.2 * nbz), int(1.2 * nby), int(1.2 * nbx)] obj = pu.crop_pad(array=obj, output_shape=new_shape, debugging=False) nbz, nby, nbx = obj.shape print('Rotating object to have the crystallographic axes along array axes') for axis, ref_axis in zip(align_axes, ref_axes): print('axis to align, reference axis:', axis, ref_axis) obj = pu.rotate_crystal(array=obj, axis_to_align=axis, reference_axis=ref_axis, debugging=True) # out of plane alignement ################### # apply threshold # ################### if not np.isnan(threshold): obj[obj < threshold] = 0 ############# # check ROI # ############# if len(roi) == 6: print('Crop/pad the reconstruction to accommodate the ROI') obj = pu.crop_pad( array=obj,