Source code for LaueTools.multigrainsSimulator

r"""
Module to compute Laue Patterns from several crystals in various geometry

Main author is J. S. Micha:   micha [at] esrf [dot] fr

version July 2019
from LaueTools package for python2 hosted in

http://sourceforge.net/projects/lauetools/

or for python3 and 2 in

https://gitlab.esrf.fr/micha/lauetools
"""
import sys
import numpy as np

if sys.version_info.major == 3:
    from . import dict_LaueTools as DictLT
    from . import generaltools as GT
    from . import lauecore as LAUE
    from . import LaueGeometry as LTGeo
    from . import CrystalParameters as CP

else:
    import dict_LaueTools as DictLT
    import generaltools as GT
    import lauecore as LAUE
    import LaueGeometry as LTGeo
    import CrystalParameters as CP

try:
    WXPYTHON = True
    import wx
except ImportError:
    WXPYTHON = False

[docs]def Read_GrainListparameter(param): r""" Read dictionary of input key parameters for simulation """ # Elem, Extinc, Transf_a, Rot, Bmatrix, Transf_c, GrainName, transform = param key_material, Extinc, Transf_a, Rot, Bmatrix, Transf_c = param[:6] GrainName = str(param[6]) # print "param in Read_GrainListparameter",param Extinctions = DictLT.dict_Extinc[str(Extinc)] Transform_labframe = DictLT.dict_Transforms[Transf_a] orientMatrix = DictLT.dict_Rot[Rot] B_matrix = DictLT.dict_Vect[Bmatrix] Transform_crystalframe = DictLT.dict_Transforms[Transf_c] return ([key_material, Extinctions, Transform_labframe, orientMatrix, B_matrix, Transform_crystalframe], GrainName, )
[docs]def Construct_GrainsParameters_parametric(SelectGrains_parametric): r""" return list of simulation parameters for each grain set (mother and children grains) """ list_selectgrains_param = [] # keys from dialogs were in reverse order # self.SelectGrains_parametric == parametric_Grain_Dialog().SelectGrains for key_grain in sorted(SelectGrains_parametric.keys()): # print "self.SelectGrains_parametric[key_grain]",self.SelectGrains_parametric[key_grain] list_selectgrains_param.append(Read_GrainListparameter(SelectGrains_parametric[key_grain])) # print list_selectgrains_param return list_selectgrains_param
[docs]def dosimulation_parametric(_list_param, Transform_params=None, SelectGrains=None, emax=25.0, emin=5.0, detectordistance=68.7, detectordiameter=165.0, posCEN=(1024.0, 1024.0), cameraAngles=(0.0, 0.0), gauge=None, kf_direction="Z>0", pixelsize=165.0 / 2048, dictmaterials=DictLT.dict_Materials): r""" Simulation of orientation or deformation gradient. From parent grain simulate a list of transformations (deduced by a parametric variation) _list_param : list of parameters for each grain [grain parameters, grain name] posCEN =(Xcen, Ycen) cameraAngles =(Xbet, Xgam) :return: (list_twicetheta, list_chi, list_energy, list_Miller, list_posX, list_posY, ParentGrainName_list, list_ParentGrain_transforms, calib, total_nb_grains) TODO:simulate for any camera position TODO: simulate spatial distribution of laue pattern origin """ print("\n\n********* Starting dosimulation_parametric *********\n\n") # Number_ParentGrains parent grains Number_ParentGrains = len(_list_param) # Extracting parent grains simluation param and name # creating list of simulation parameters for parent grains ListParam = [] ParentGrainName_list = [] for m in range(Number_ParentGrains): # print "_list_param[m]", _list_param[m] _paramsimul, _grainname = _list_param[m] elem = np.shape(np.array(_paramsimul[0])) # print "elem parametric",elem # convert EULER angles to matrix in case of 3 input elements if np.shape(np.array(_paramsimul[2])) == (3,): _paramsimul[2] = GT.fromEULERangles_toMatrix(_paramsimul[2]) ListParam.append(_paramsimul) ParentGrainName_list.append(_grainname) # print "ListParam in dosimulation_parametric", ListParam print("ParentGrainName_list", ParentGrainName_list) # Calculating Laue spots of each parent grain ---------------------------- print("Doing simulation with %d parent grains" % Number_ParentGrains) list_twicetheta = [] list_chi = [] list_energy = [] list_Miller = [] list_posX = [] list_posY = [] total_nb_grains = 0 # list of [Parent grain index,Number of corresponding transforms, transform_type] list_ParentGrain_transforms = [] if gauge and WXPYTHON: gaugecount = 0 gauge.SetValue(gaugecount) # gauge count max has been set to 1000*Number_ParentGrains # loop over parent grains for parentgrain_index in range(Number_ParentGrains): # read simulation parameters name_of_grain = ParentGrainName_list[parentgrain_index] print("\n\n %d, name_of_grain: %s" % (parentgrain_index, name_of_grain)) Laue_classic_param = ListParam[parentgrain_index] key_material, Extinc, Ta, U, B, Tc = Laue_classic_param # from combos # build GrainSimulParam GrainSimulParam = [0, 0, 0, 0] # user has entered his own B matrix if key_material == "inputB": # print "\n**************" # print "using Bmatrix containing lattice parameter" # print "****************\n" # take then parameters from combos GrainSimulParam[0] = B GrainSimulParam[1] = Extinc GrainSimulParam[2] = np.dot(np.dot(Ta, U), Tc) GrainSimulParam[3] = "inputB" # user uses a pre defined B matrix contain in material dictionnary # (need to read lattice parameter or element definition # then compute B matrix) elif key_material != "inputB": grain = CP.Prepare_Grain(key_material, np.eye(3), dictmaterials=dictmaterials) # print "grain in dosimulation_parametric() input Element",grain # B0, Extinc0, U0, key = grain # U0 is identity B0, _, U0, _ = grain # U0 is identity # new B matrix newB = np.dot(Tc, np.dot(B, B0)) # Extinction is overwritten by value in comboExtinc newExtinc = Extinc # new U matrix newU = np.dot(Ta, np.dot(U, U0)) GrainSimulParam = [newB, newExtinc, newU, key_material] print("Using following parameters from Material Dict.") print(DictLT.dict_Materials[key_material]) # --- Simulate print("GrainSimulParam in dosimulation_parametric() input Element") print(GrainSimulParam) spots2pi = LAUE.getLaueSpots(DictLT.CST_ENERGYKEV / emax, DictLT.CST_ENERGYKEV / emin, [GrainSimulParam], # bracket because of a list of one grain [[""]], fastcompute=0, fileOK=0, verbose=0, kf_direction=kf_direction, dictmaterials=dictmaterials) # q vectors in lauetools frame, miller indices # print "spots2pi",spots2pi # --------- [list of 3D vectors],[list of corresponding Miller indices] # remove Parent Grain Laue spots too close from detector border vicinity Qvectors_ParentGrain, HKLs_ParentGrain = LAUE.filterQandHKLvectors(spots2pi, detectordistance, detectordiameter, kf_direction) # Qvectors_ParentGrain, HKLs_ParentGrain = spots2pi if gauge and WXPYTHON: gaugecount += 100 # print "gaugecount += 100",gaugecount gauge.SetValue(gaugecount) wx.Yield() # --- Calculating small deviations(rotations and strain) # --- from parent grains according to transform # print " in simul Transform_params",Transform_params # print " in simul SelectGrains",SelectGrains # get transform if Transform_params is None: Transform_listparam = [""] elif Transform_params is not None: Transform_params[""] = [""] # print "SelectGrains[name_of_grain]",SelectGrains[name_of_grain] Transform_listparam = Transform_params[SelectGrains[name_of_grain][7]] if Transform_listparam == "": Transform_listparam = [""] # print "Transform_listparam",Transform_listparam nb_transforms = 1 print("GrainSimulParam", GrainSimulParam) matrix_list = [np.eye(3)] # matrix giving a*,b*,c* in absolute x, y,z frame # this matrix is used for strain a*,b*,c* are NORMALIZED: # this is a B matrix used in q= U B G* formalism # this matrix represents also an initial orientation # old way # InitMat = Bmatrix # # matrix of additional dilatation in Reciprocal space of a* b* c* of the lattice giving the proper length of a*,b*,c* # mat_dilatinRS = np.array([[Laue_classic_param[1][0],0, 0],[0, Laue_classic_param[1][1],0],[0, 0,Laue_classic_param[1][2]]]) # in a* b* c* frame # # Rotation matrix from initial orientation to the given orientation Newpostion = R oldposition in x, y,z frame # matOrient_pure = np.array(Laue_classic_param[2]) # # full matrix containing # matOrient = np.dot(matOrient_pure, np.dot(InitMat, mat_dilatinRS)) # U * B *(diagonal three elements reciprocal dilatation matrix) # print "matOrient in dosimulation_parametric",matOrient # Calculates matOrient which is U*B in q = U*B*Gstar matOrient = np.dot(GrainSimulParam[2], GrainSimulParam[0]) if Transform_listparam != "": # print "Transform_listparam[0]",Transform_listparam[0] if Transform_listparam[0] == "r_axis": axis_list = Transform_listparam[2] angle_list = Transform_listparam[1] nb_transforms = len(angle_list) elif Transform_listparam[0] in ("r_axis_d", "r_axis_d_slipsystem"): axis_list = Transform_listparam[2] # print "axis_list before orientation in d frame", axis_list angle_list = Transform_listparam[1] nb_transforms = len(angle_list) # axis coordinate change from abc frame(direct crystal) to a*b*c* frame( reciprocal crystal) axis_list_c = np.array([CP.fromrealframe_to_reciprocalframe(ax, GrainSimulParam[0]) for ax in axis_list]) # print "axis_list_c", axis_list_c # axis coordinate change from a*b*c* frame(crystal) to absolute frame axis_list = np.dot(matOrient, axis_list_c.T).T # print "axis_list in absolute frame from d frame", axis_list # general transform expressed in absolute lauetools frame elif Transform_listparam[0] == "r_axis_c": axis_list = Transform_listparam[2] # print "axis_list before orientation in c frame",axis_list angle_list = Transform_listparam[1] nb_transforms = len(angle_list) # axis coordinate change from hkl frame(crystal) to absolute frame axis_list = np.dot(matOrient, axis_list.T).T # print "axis_list in absolute frame from c frame", axis_list # general transform expressed in absolute lauetools frame elif Transform_listparam[0] == "r_mat": matrix_list = Transform_listparam[1] nb_transforms = len(matrix_list) # general transform expressed in crystal frame elif Transform_listparam[0] == "r_mat_d": raise ValueError("r_mat_d matrix transform with d frame is not implemented yet") elif Transform_listparam[0] == "r_mat_c": # print "using r_mat_c" matrix_list = Transform_listparam[1] nb_transforms = len(matrix_list) # then convert transform in absolute lauetools frame for k in range(nb_transforms): matrix_list[k] = np.dot( matOrient, np.dot(matrix_list[k], np.linalg.inv(matOrient))) # matrix_list[k] = np.dot(inv(matOrient),np.dot(matrix_list[k],matOrient)) # transform is a list of tensile transforms elif isinstance(Transform_listparam[0], list): # is a list of 's_axis' or 's_axis_c liststrainframe = Transform_listparam[0] # list of 3 arrays, each array contains the nb_transforms axis # (array of three elements) _axis_list = Transform_listparam[2] # list of 3 arrays, each array contains the nb_transforms strain factor factor_list = Transform_listparam[1] # print "axis_list in c frame",_axis_list # print "factor_list",factor_list nb_transforms = len(factor_list[0]) axis_list = [np.ones(3) for k in range(3)] # loop over the three proposed axial strain in simulation board for mm in range(3): if liststrainframe[mm] == "s_axis_c": axis_list[mm] = np.dot( matOrient, np.transpose(_axis_list[mm])).T else: axis_list[mm] = _axis_list[mm] # print "axis_list in a frame",axis_list # print "Transform_listparam[2]",Transform_listparam[2] # print "HKLs_ParentGrain", HKLs_ParentGrain # print "nb_transforms", nb_transforms # print "Transform_listparam[0]", Transform_listparam[0] calib = [detectordistance, posCEN[0], posCEN[1], cameraAngles[0], cameraAngles[1]] # ----------------------------------------------------- # loop over child grains derived from transformation of a single parent grain for ChildGrain_index in range(nb_transforms): # Qvectors_ParentGrain is used to create Qvectors_ParentGrain for each chold grain # according to the transform # print "Qvectors_ParentGrain", Qvectors_ParentGrain # Geometrical transforms for each case # loop over reciprocal lattice vectors is done with numpy array functions # for rotation around axis expressed in any frame if Transform_listparam[0] in ("r_axis", "r_axis_c", "r_axis_d", "r_axis_d_slipsystem"): # print "angle, axis",angle_list[ChildGrain_index],axis_list[ChildGrain_index] qvectors_ChildGrain = GT.rotate_around_u( Qvectors_ParentGrain[0], angle_list[ChildGrain_index], u=axis_list[ChildGrain_index]) # list of spot which are on camera(without harmonics) # hkl are common to all child grains spots2pi = [qvectors_ChildGrain], HKLs_ParentGrain # for general transform expressed in any frame elif (Transform_listparam[0] == "r_mat" or Transform_listparam[0] in ("r_mat_c", "r_mat_d") or Transform_listparam == "" or Transform_listparam == [""]): # general transformation is applied to q vector # expressed in lauetools absolute frame qvectors_ChildGrain = np.dot( matrix_list[ChildGrain_index], Qvectors_ParentGrain[0].T).T # if 0: # print(" 10 first transpose(Qvectors_ParentGrain[0])", # Qvectors_ParentGrain[0].T[:, :10]) # print("%d / %d" % (ChildGrain_index, nb_transforms)) # print("current matrix", matrix_list[ChildGrain_index]) # print(np.shape(qvectors_ChildGrain)) # print("GrainSimulParam", GrainSimulParam) # print("qvectors_ChildGrain", qvectors_ChildGrain[:10]) # list of spot which are on camera(without harmonics) spots2pi = [qvectors_ChildGrain], HKLs_ParentGrain # for the three consecutive axial strains elif isinstance(Transform_listparam[0], list): first_traction = GT.tensile_along_u( Qvectors_ParentGrain[0], factor_list[0][ChildGrain_index], u=axis_list[0][ChildGrain_index]) second_traction = GT.tensile_along_u( first_traction, factor_list[1][ChildGrain_index], u=axis_list[1][ChildGrain_index]) qvectors_ChildGrain = GT.tensile_along_u( second_traction, factor_list[2][ChildGrain_index], u=axis_list[2][ChildGrain_index]) # list of spots for a child grain (on camera + without harmonics) spots2pi = [qvectors_ChildGrain], HKLs_ParentGrain # if 0: # print(" 10 first transpose(Qvectors_ParentGrain[0])", # Qvectors_ParentGrain[0][:10]) # print(np.shape(qvectors_ChildGrain)) # print("GrainSimulParam", GrainSimulParam) # print("qvectors_ChildGrain", qvectors_ChildGrain[:10]) else: # no transformation pass # test whether there is at least one Laue spot in the camera for elem in spots2pi[0]: if len(elem) == 0: print("There is at least one child grain without peaks on CCD camera for ChildGrain_index= %.3f" % ChildGrain_index) break # --------------------------------- # filter spots to keep those in camera, filter harmonics try: # print("kf_direction = (in dosimulationparametric)", kf_direction) if kf_direction == "Z>0" or isinstance( kf_direction, list): # or isinstance(kf_direction, np.array): Laue_spot_list = LAUE.filterLaueSpots(spots2pi, fileOK=0, fastcompute=0, detectordistance=detectordistance, detectordiameter=detectordiameter*1.2, # * 1.2, # avoid losing some spots in large transformation kf_direction=kf_direction, HarmonicsRemoval=1, pixelsize=pixelsize) # for elem in Laue_spot_list[0][:10]: # print elem # print "Laue_spot_list[0][0].Twicetheta" # print Laue_spot_list[0][0].Twicetheta if gauge and WXPYTHON: gaugecount = gaugecount + 900 / nb_transforms gauge.SetValue(gaugecount) wx.Yield() # print "ChildGrain_index 900%nb_transforms",ChildGrain_index, gaugecount Listspots = Laue_spot_list[0] twicetheta = [spot.Twicetheta for spot in Listspots] chi = [spot.Chi for spot in Listspots] energy = [spot.EwaldRadius * DictLT.CST_ENERGYKEV for spot in Listspots] Miller_ind = [list(spot.Millers) for spot in Listspots] calib = [detectordistance, posCEN[0], posCEN[1], cameraAngles[0], cameraAngles[1]] # print("calib parameters in dosimulation_parametric") # print(calib) # print("pixelsize", pixelsize) # print("framedim", framedim) posx, posy = LTGeo.calc_xycam_from2thetachi(twicetheta, chi, calib, pixelsize=pixelsize, kf_direction=kf_direction)[:2] # vecRR = [spot.Qxyz for spot in Laue_spot_list[0]] #uf_lab in JSM LaueTools frame list_twicetheta.append(twicetheta) list_chi.append(chi) list_energy.append(energy) list_Miller.append(Miller_ind) list_posX.append(posx.tolist()) list_posY.append(posy.tolist()) # success = 1 elif kf_direction in ("Y<0", "Y>0"): # TODO: patch for test: detectordistance = 126.5 Laue_spot_list = LAUE.filterLaueSpots(spots2pi, fileOK=0, fastcompute=0, detectordistance=detectordistance, detectordiameter=detectordiameter, # * 1.2, # avoid losing some spots in large transformation kf_direction=kf_direction, HarmonicsRemoval=1, pixelsize=pixelsize) # for elem in Laue_spot_list[0][:10]: # print elem # print "Laue_spot_list[0][0].Twicetheta" # print Laue_spot_list[0][0].Twicetheta if gauge and WXPYTHON: gaugecount = gaugecount + 900 / nb_transforms gauge.SetValue(gaugecount) wx.Yield() # print "ChildGrain_index 900%nb_transforms",ChildGrain_index, gaugecount twicetheta = [spot.Twicetheta for spot in Laue_spot_list[0]] chi = [spot.Chi for spot in Laue_spot_list[0]] energy = [spot.EwaldRadius * DictLT.CST_ENERGYKEV for spot in Laue_spot_list[0]] Miller_ind = [list(spot.Millers) for spot in Laue_spot_list[0]] calib = [detectordistance, posCEN[0], posCEN[1], cameraAngles[0], cameraAngles[1]] posx, posy = LTGeo.calc_xycam_from2thetachi(twicetheta, chi, calib, pixelsize=pixelsize, kf_direction=kf_direction)[:2] # posx, posy, theta0 = LTGeo.calc_xycam_from2thetachi(twicetheta, chi, calib, pixelsize = self.pixelsize) posx = [spot.Xcam for spot in Laue_spot_list[0]] posy = [spot.Ycam for spot in Laue_spot_list[0]] # vecRR = [ # spot.Qxyz for spot in Laue_spot_list[0] # ] # uf_lab in JSM frame # print "twicetheta",twicetheta # print "2*th0",(2*theta0).tolist() list_twicetheta.append(twicetheta) list_chi.append(chi) list_energy.append(energy) list_Miller.append(Miller_ind) list_posX.append(posx) list_posY.append(posy) # success = 1 elif kf_direction in ("X>0", "X<0"): # transmission mode or back reflection mode # print("spots2pi",spots2pi) Laue_spot_list = LAUE.filterLaueSpots(spots2pi, fileOK=0, fastcompute=0, detectordistance=detectordistance, detectordiameter=detectordiameter*1.2, # * 1.2, # avoid losing some spots in large transformation kf_direction=kf_direction, HarmonicsRemoval=1, pixelsize=pixelsize) if Laue_spot_list is None: list_twicetheta.append([]) list_chi.append([]) list_energy.append([]) list_Miller.append([]) list_posX.append([]) list_posY.append([]) continue # print("Laue_spot_list",Laue_spot_list) # for elem in Laue_spot_list[0]: # print('transmission spots',elem) # print "Laue_spot_list[0][0].Twicetheta" # print Laue_spot_list[0][0].Twicetheta if gauge and WXPYTHON: gaugecount = gaugecount + 900 / nb_transforms gauge.SetValue(gaugecount) wx.Yield() # print "ChildGrain_index 900%nb_transforms",ChildGrain_index, gaugecount twicetheta = [spot.Twicetheta for spot in Laue_spot_list[0]] chi = [spot.Chi for spot in Laue_spot_list[0]] energy = [spot.EwaldRadius * DictLT.CST_ENERGYKEV for spot in Laue_spot_list[0]] Miller_ind = [list(spot.Millers) for spot in Laue_spot_list[0]] posx, posy = LTGeo.calc_xycam_from2thetachi(twicetheta, chi, calib, pixelsize=pixelsize, kf_direction=kf_direction)[:2] posx = posx.tolist() posy = posy.tolist() # posx, posy, theta0 = LTGeo.calc_xycam_from2thetachi(twicetheta, chi, calib, pixelsize = self.pixelsize) # posx = [spot.Xcam for spot in Laue_spot_list[0]] # posy = [spot.Ycam for spot in Laue_spot_list[0]] # vecRR = [spot.Qxyz for spot in Laue_spot_list[0]] # uf_lab in JSM frame # print "twicetheta",twicetheta # print "2*th0",(2*theta0).tolist() list_twicetheta.append(twicetheta) list_chi.append(chi) list_energy.append(energy) list_Miller.append(Miller_ind) list_posX.append(posx) list_posY.append(posy) # success = 1 except UnboundLocalError: txt = "With theses parameters, there are no peaks in the CCD frame!!\n" txt += "for transform with t = %.3f\n" % ChildGrain_index txt += "It may seem that the transform you have designed has a too large amplitude\n" txt += "-Try then to reduce the variation range of t\n" txt += "-Or reduce ratio between extrema in input matrix transform\n\n" # success = 0 break # end of loop over transforms(or children grains) transform_type = "parametric" print("Transform_listparam in dosimultion", Transform_listparam) if not isinstance(Transform_listparam[0], list): if Transform_listparam[0].endswith("slipsystem"): transform_type = "slipsystem" list_ParentGrain_transforms.append([parentgrain_index, nb_transforms, transform_type]) total_nb_grains += nb_transforms if gauge and WXPYTHON: gaugecount += (parentgrain_index + 1) * 1000 gauge.SetValue(gaugecount) wx.Yield() # print "(parentgrain_index+1)*1000",gaugecount # end of loop over parent grains------------------------------- print("total_nb_grains (cumulated from single and grains assembly):", total_nb_grains) # 1 grain data lists are listed i.e. use list_twicetheta[0] etc. # polygrain use list_twicetheta print("List of Grain Name", ParentGrainName_list) print("Number_ParentGrains of parent grains", Number_ParentGrains) print("Number_ParentGrains of spots in grain0", len(list_twicetheta[0])) print('list_ParentGrain_transforms', list_ParentGrain_transforms) data = (list_twicetheta, list_chi, list_energy, list_Miller, list_posX, list_posY, ParentGrainName_list, list_ParentGrain_transforms, calib, total_nb_grains) return data
if __name__ == "__main__": print('test of multigrainSimulator.py')