def test_bcc(self): lvs = get_base(self.lc2) target = np.eye(3) np.testing.assert_almost_equal(lvs, target) target = np.eye(3)*2*np.pi rlvs = get_reciprocal_base(self.lc2) np.testing.assert_almost_equal(rlvs, target)
def test_bcc(self): lvs = get_base(self.lc2) target = np.eye(3) np.testing.assert_almost_equal(lvs, target) target = np.eye(3) * 2 * np.pi rlvs = get_reciprocal_base(self.lc2) np.testing.assert_almost_equal(rlvs, target)
def test_hcp(self): lvs = get_base(self.lc1) rlvs = get_reciprocal_base(self.lc1) target_v = np.array([[+0.2950800, -0.1475400, +0.0000000], [+0.0000000, +0.2555468, +0.0000000], [+0.0000000, +0.0000000, +0.4685500]]) target_rv = np.array([[+21.293159, +0.000000, +0.000000], [+12.293611, +24.587222, -0.000000], [-0.000000, -0.000000, +13.409850]]) # test real lattice np.testing.assert_almost_equal(lvs, target_v) # test reciprocal lattice np.testing.assert_almost_equal(rlvs, target_rv, decimal=6)
def test_hcp(self): lvs = get_base(self.lc1) rlvs = get_reciprocal_base(self.lc1) target_v = np.array([ [+0.2950800, -0.1475400, +0.0000000], [+0.0000000, +0.2555468, +0.0000000], [+0.0000000, +0.0000000, +0.4685500]]) target_rv = np.array([ [+21.293159, +0.000000, +0.000000], [+12.293611, +24.587222, -0.000000], [-0.000000, -0.000000, +13.409850]]) # test real lattice np.testing.assert_almost_equal(lvs, target_v) # test reciprocal lattice np.testing.assert_almost_equal(rlvs, target_rv, decimal=6)
def grad_student(jobConfig): """The poor grad student who will perform the DAXM experiment""" n_voxels = int(jobConfig["n_voxels"]) hkls = pd.read_csv(jobConfig["DAXMConfig"]["hkllist"], sep='\t')[['h', 'k', 'l']].as_matrix() # extract config for each part DAXMConfig = jobConfig["DAXMConfig"] labConfig = jobConfig["labConfig"] StrainCalcConfig = jobConfig["StrainCalcConfig"] # setup virtual DAXM lab k0 = np.array(labConfig['k0']) # incident beam direction n_CCD = np.array(labConfig['n_CCD']) # detector normal E_xray = np.array(labConfig["X-ray Energy(KeV)"]) # in KeV detector_angularRange = float( labConfig["detector angular range"]) # in degrees # material: Al # NOTE: the shortcut used in the visible peak calculation requires a cubic material lc_AL = np.array([0.4050, 0.4050, 0.4050, 90, 90, 90]) # [nm,nm,nm,degree,degree,degree] # write header for the output file if ARGS["--new"]: with open(jobConfig["dataFileName"], 'w') as f: headerList = [ "voxelName", "angR", "magU", "n_visible", "n_fullq", "peakNoiseSigma", ] headerList += ["{}_F0".format(i + 1) for i in range(9)] # target F headerList += ["{}_FL2".format(i + 1) for i in range(9)] # least-squares guess headerList += ["{}_Fopt".format(i + 1) for i in range(9)] headerList += ["opt_successful", "opt_fun", "opt_nfev"] f.write("\t".join(headerList) + "\n") # convert the parameter range to log space _angR_lb, _angR_ub = map(np.log10, DAXMConfig["angR range"]) _magU_lb, _magU_ub = map(np.log10, DAXMConfig["magU range"]) for i in range(n_voxels): # _DAXMConfig is a per Voxel configuration _DAXMConfig = deepcopy(DAXMConfig) # generate visible peaks (planes, hkls) ## get n_visiblePeaks and n_fullQ: N(n_indexedPeaks) >= n(n_fullQ) unacceptable = True while unacceptable: n_indexedPeaks = int( np.random.choice(DAXMConfig["n_indexedPeaks"], 1)) n_fullQ = int(np.random.choice(DAXMConfig["n_fullQ"], 1)) if n_fullQ <= n_indexedPeaks: unacceptable = False ## get list of index planes based on a random crystal orientation unacceptable = True while unacceptable: xtal_orientation = Quaternion.fromRandom() visible_hkls = calc_visible_peaks( xtal_orientation, k0, n_CCD, E_xray, lc_AL, hkls, detector_angularRange=detector_angularRange, ) if len(visible_hkls) > n_indexedPeaks: indexed_plane = random_select_npeaks(visible_hkls, n_indexedPeaks) # prevent degenerated matrix due to parallel hkls if np.linalg.matrix_rank(indexed_plane) >= 3: unacceptable = False ## get scattering vectors # NOTE: # Since the crystal orientation is only useful for selecting diffractable planes, # the rest of the calculation (q and q0) can be directly done within xtal lattice # frame (XTL) regardless of the actual crystal orientation (makes the calcualtion # a lot simpler). ### frist, randomly generate a deformation gradient in xtal frame _DAXMConfig["angR"] = np.power( 10, np.random.random() * (_angR_ub - _angR_lb) + _angR_lb) _DAXMConfig["magU"] = np.power( 10, np.random.random() * (_magU_ub - _magU_lb) + _magU_lb) defgrad = make_random_defgrad(_DAXMConfig['angR'], _DAXMConfig['magU']) ### use the randomly generated defgrad to strain the scattering vectors recip_base = get_reciprocal_base(lc_AL) T, Bstar = defgrad, recip_base Tstar = np.transpose(np.linalg.inv(T)) Bstar_strained = np.dot(Tstar, Bstar) qs = np.zeros((3, n_indexedPeaks)) # random select n_fullQ to be full scattering vectors idx_fullq = np.random.choice(n_indexedPeaks, n_fullQ, replace=False) for arrayidx, milleridx in enumerate(indexed_plane): q_strained = np.dot(Bstar_strained, milleridx) qs[:, arrayidx] = q_strained if arrayidx in idx_fullq else normalize( q_strained) # setup DAXMConfig for each run # NOTE: # Noise analysis can be done when we have more access to the facility _DAXMConfig["whiteNoiseLevel"] = np.random.choice( np.array(DAXMConfig["peakPositionUncertainty/deg"])) qs_correct = np.copy(qs) for qsIdx in range(qs.shape[1]): qs[:, qsIdx] = perturb_vector( qs[:, qsIdx], np.random.normal(scale=_DAXMConfig["whiteNoiseLevel"]), ) # construct the voxel thisVoxel = DAXMvoxel( name="voxel_{}".format(i), ref_frame='XTL', coords=np.zeros(3), pattern_image="voxel_{}".format(i), scatter_vec=qs, plane=indexed_plane.T, recip_base=recip_base, peak=np.random.random((2, n_indexedPeaks)), depth=0, lattice_constant=lc_AL, ) # save the voxel to H5 archive thisVoxel.write(h5file=jobConfig["voxelArchive"]) # calculate the deformation gradient # NOTE: # notice the much cleaner and simpler interface in terms of strain quantification defgrad_L2 = thisVoxel.deformation_gradientL2() defgrad_opt = thisVoxel.deformation_gradient_opt(eps=1e0) # export data to file for analysis data = [ thisVoxel.name, _DAXMConfig["angR"], _DAXMConfig["magU"], n_indexedPeaks, n_fullQ, _DAXMConfig["whiteNoiseLevel"], ] data += list(defgrad.flatten()) # in XTAL frame!!! data += list(defgrad_L2.flatten()) # in XTAL frame!!! data += list(defgrad_opt.flatten()) # in XTAL frame!!! data += [ int(thisVoxel.opt_rst.success), # is optimization successful thisVoxel.opt_rst.fun, # fitness function final val thisVoxel.opt_rst.nfev, # number of iteration used ] with open(jobConfig["dataFileName"], 'a') as f: f.write("\t".join(map(str, data)) + "\n") # interactive monitoring if jobConfig["monitor"] and i % 1000 == 0: sys.stderr.write("|") elif jobConfig["monitor"] and i % 100 == 0: sys.stderr.write("*")