#pragma rtGlobals=1 // Use modern global access method. #pragma ModuleName=Indexing #pragma IgorVersion = 6.0 #pragma version = 2.27 #include "microGeometry", version>=2.47 #include "WinView", version>=1.90 #include "LatticeSym", version>=3.32 Menu "micro" SubMenu "Crystal Lattice" "Set Crystal Lattice...", /Q, MakeLatticeParametersPanel("") // "Set Crystal Lattice...",setLattice() // help={"Define the crystal structure and lattice to be used"} "Show Crystal Lattice",/Q,showLattice() help={"Shows the crystal structure and lattice that is currently defined"} "d[hkl]",/Q,get_dhkl(NaN,NaN,NaN) help={"show d-spacing for the hkl reflection"} End "Load WinView File...", LoadWinViewFile("") help={"Load a WinView Image from the file, and then display the image. If you just want to display a loaded file, go to 'WinView' menu"} MenuItemIfWaveClassExists("Remove Background from Image...","speImage","DIMS:2"),RemoveBackgroundImage($"",NaN) help={"remove background from an image, do not use on depth sotred images"} MenuItemIfWaveClassExists("Fit Peaks on Image...","speImage*","DIMS:2"),FitPeaks($"",NaN,NaN) help={"Identify peaks in an Image, does not do any background removal"} MenuItemIfWaveClassExists(" TESTING, Fit Peaks step-wise on Image...","speImageNoBkg;speImage","DIMS:2"), FitPeaksStepWise($"",NaN,NaN,NaN,NaN) help={"Identify peaks in an Image, does not do any background removal, uses a simple threshold to find peaks"} MenuItemIfWaveClassExists(" TESTING, Fit Peaks on Image...","speImageNoBkg;speImage","DIMS:2"),FitPeaksNew($"",NaN,NaN) help={"Identify peaks in an Image, does not do any background removal, uses a simple threshold to find peaks"} MenuItemIfWaveClassExists(" OLD Remove Bkg & Fit Peaks on Image...","speImage","DIMS:2"),OLD_removeBkg_FitPeaks($"",NaN,NaN) help={"removes bkg and then finds and fits peaks, do not use anymore"} pkLIstWinViewMenuItem(" Reset Fitted Peak list from boxes"),setFittedPeaksFromList($"",NaN,pkList) help={"reset list of peaks for fitting to the boxes on an image plot"} MenuItemIfWaveClassExists("Index and Display...","FittedPeakList","DIMS:2,MAXCOLS:11,MINCOLS:11"),IndexAndDisplay($"",NaN,NaN,NaN,NaN,NaN,NaN,NaN) help={"Index the identified peaks, using the defined lattice, and then show it all on a plot"} MenuItemIfWaveClassExists(" Refine Strain","IndexedPeakList",""),DeviatoricStrainRefine(NaN) help={"compute deviatoric strain for the pattern just idexed"} MenuItemIfWaveClassExists(" Re-Draw hkl tags","IndexedPeakList",""),DisplayResultOfIndexing($"",NaN) help={"for an image plot, clear old hkl tags (if any) and redraw new ones using results of an indexing"} MenuItemIfWaveClassExists(" Clear hkl tags off Graph","IndexedPeakList",""),ClearhklOffGraph("") help={"clear the hkl tags off of an image"} MenuItemIfWaveClassExists(" Report Sheet of Indexed Image","IndexedPeakList",""),MakeIndexingReportSheet() // " Report Sheet of Indexed Image",MakeIndexingReportSheet() help={"if the top window is an images showing the hkl's, this makes a layout with reflections for printing"} MenuItemIfWaveClassExists(" calc energy of [hkl]","IndexedPeakList",""),EnergyOfhkl($"",NaN,NaN,NaN,NaN) help={"calculate the energy of an hkl using the current indexing"} // SubMenu("Tables") MenuItemsWaveClassOnGraph("Report angle between two cursors","speImage*",""),/Q,AngleBetweenTwoPoints($"",nan, nan,nan,nan) SubMenu(MenuItemIfWaveClassExists("Tables","FittedPeakList;IndexedPeakList","")) MenuItemIfWaveClassExists("Fitted Peaks","FittedPeakList",""),TableFullPeakList($"") help={"Show table of identified peak positions"} MenuItemIfWaveClassExists("Indexed Peaks","IndexedPeakList",""),TableFullPeakIndexed($"") help={"Show table of indexed peaks"} MenuItemIfWaveClassExists("Strain Peaks","IndexedPeakList;StrainPeakList",""),TableFullPeakStrain($"") help={"Show table of peaks from the strain refinement"} End End Menu "GraphMarquee", dynamic "-" MenuItemIndexPeak("Indexed Peak Info"),/Q,IndexedPeakInfoFromMarquee() End // Function/S MenuItemIndexPeak(item) String item GetMarquee/Z if (!V_flag) return "("+item endif if (strlen(GetUserData("","","Indexing"))<1) return "("+item endif return item End Static Constant hc = 1.239841857 // keV-nm Function IndexAndDisplay(FullPeakList,keVmaxCalc,keVmaxTest,angleTolerance,hp,kp,lp,cone) Wave FullPeakList // contains the result of a peak fitting Variable keVmaxCalc // 17, maximum energy to calculate (keV) Variable keVmaxTest // 26, maximum energy to test (keV) [-t] Variable angleTolerance // 0.25, angular tolerance (deg) Variable hp,kp,lp // preferred hkl Variable cone // angle from preferred hkl, (0 < cone < 180¡) if (NumVarOrDefault("root:Packages:geometry:PanelValues:dirty",0)) // geo waiting Variable/G root:Packages:geometry:PanelValues:dirty=0 DoAlert 0,"You have made changes in the geometry panel, deal with them first" MakeGeometryParametersPanel("") return 1 endif Variable badWave = !WaveExists(FullPeakList) if (!badWave) badWave = (DimSize(FullPeakList,0)<1 || DimSize(FullPeakList,1)!=11) endif Variable badNums= !(keVmaxCalc>1 && keVmaxCalc<40) || !(keVmaxTest>1 && keVmaxTest<51) badNums += !(angleTolerance>=0.01 && angleTolerance<10) badNums += numtype(hp+kp+lp) badNums += !(cone>1 && cone<180) badNums += (abs(hp)+abs(kp)+abs(lp))==0 if (badWave || badNums) keVmaxCalc = (keVmaxCalc>1 && keVmaxCalc<40) ? keVmaxCalc : 17 keVmaxTest = (keVmaxTest>1 && keVmaxTest<51) ? keVmaxTest : 26 angleTolerance = (angleTolerance>=0.01 && angleTolerance<10) ? angleTolerance : 0.25 hp = numtype(hp) ? 0 : hp kp = numtype(kp) ? 0 : kp lp = numtype(lp) ? 2 : lp cone = (cone>1 && cone<180) ? cone : 72 String hkl sprintf hkl,"%d, %d, %d",hp,kp,lp Prompt hkl,"preferred hkl of center" Prompt cone,"max angle¡ from hkl prefer to spot" String peakListStr=SelectString(badWave,NameOfWave(FullPeakList),"FullPeakList") // Prompt peakListStr,"wave with fitted peaks",popup,WaveList("*Peak*",";","DIMS:2,MAXCOLS:11,MINCOLS:11") // Prompt peakListStr,"wave with fitted peaks",popup,WaveList_Tags("fittedIgorImage","peakFile","*","DIMS:2,MAXCOLS:11,MINCOLS:11") Prompt peakListStr,"wave with fitted peaks",popup,reverseList(WaveListClass("FittedPeakList","*","DIMS:2,MAXCOLS:11,MINCOLS:11")) Prompt keVmaxCalc,"max energy for searching (keV)" Prompt keVmaxTest,"max energy for matching (keV)" Prompt angleTolerance "max angle¡ between peak & hkl" DoPrompt/Help="3D-Xray Diffraction[Indexing]" "index",peakListStr,keVmaxCalc,hkl,keVmaxTest,cone,angleTolerance if (V_flag) return 1 endif sscanf hkl,"%d, %d, %d", hp,kp,lp printf "IndexAndDisplay(%s,%g,%g,%g, %d,%d,%d,%g)\r",peakListStr,keVmaxCalc,keVmaxTest,angleTolerance,hp,kp,lp,cone Wave FullPeakList=$peakListStr badWave = !WaveExists(FullPeakList) if (!badWave) badWave = (DimSize(FullPeakList,0)<1 || DimSize(FullPeakList,1)!=11) endif badNums= !(keVmaxCalc>1 && keVmaxCalc<40) || !(keVmaxTest>1 && keVmaxTest<51) badNums += !(angleTolerance>=0.01 && angleTolerance<10) badNums += numtype(hp+kp+lp) + !(cone>1 && cone<180) badNums += (abs(hp)+abs(kp)+abs(lp))==0 if (badWave || badNums) DoAlert 0, "Invalid inputs sent to IndexAndDisplay()" return 1 endif endif Wave FullPeakIndexed=$(runEulerCommand(FullPeakList,keVmaxCalc,keVmaxTest,angleTolerance,hp,kp,lp,cone)) if (!WaveExists(FullPeakIndexed)) return 1 endif String wnote = note(FullPeakIndexed) Variable NpatternsFound = NumberByKey("NpatternsFound",wnote,"=") Variable Nindexed = NumberByKey("Nindexed",wnote,"=") Variable NiData = NumberByKey("NiData",wnote,"=") Variable executionTime = NumberByKey("executionTime",wnote,"=") Variable rms_error = NumberByKey("rms_error0",wnote,"=") if (ItemsInList(GetRTStackInfo(0))<2 || stringmatch(StringFromList(0,GetRTStackInfo(0)),"IndexButtonProc")) if (executionTime<60) printf "from Euler, found %d patterns, indexed %d out of %d spots with rms=%g¡ in %g sec\r",NpatternsFound,Nindexed,NiData,rms_error,executionTime else printf "from Euler, found %d patterns, indexed %d out of %d spots with rms=%g¡ in %s (%g sec)\r",NpatternsFound,Nindexed,NiData, rms_error,Secs2Time(executionTime,5,1),executionTime endif DoAlert 1, "Examine fit on a picture" if (V_flag==1) DisplayResultOfIndexing(FullPeakIndexed,NaN) endif endif return 0 // if (V_flag!=1) // return 0 // endif // // get a graph of the image at the front, with boxes on to the front // Variable newPlot=0 // String imageName // name of image to look at // imageName = StringByKey("fittedIgorImage",wnote,"=") // if (!strlen(imageName)) // imageName = StringByKey("rawIgorImage",wnote,"=") // endif // if (exists(imageName)!=1) // return 1 // cannot display a non-existant image // endif // Wave image = $imageName // String win = FindGraphWithImage(image)// find a graph already showing that imageName // if (strlen(win)) // DoWindow/F $win // bring window with image to the top // else // Graph_imageMake(image,1) // no window exists, so make one showing image // newPlot = 1 // endif // NVAR boxesOn=boxesOn // boxesOn = 0 // ButtonProc_Boxes("") // make sure that boxes are on // // Variable wid=NumberByKey("minSpotSeparation",wnote,"=") // wid = numtype(wid) ? 30 : wid // width of the cross // Variable i, N=DimSize(FullPeakIndexed,0) // SetDrawLayer UserFront // draw the X's // for (i=0;i0) // more than 1, so ask String wName="" Prompt wName,"Indexed Peak List",popup,wList DoPrompt "Indexed Peak List",wName if (V_flag) return 1 endif Wave FullPeakIndexed = $wName endif endif badWave = !WaveExists(FullPeakIndexed) if (!badWave) badWave = (DimSize(FullPeakIndexed,0)<1 || DimSize(FullPeakIndexed,1)!=11) endif String wnote = note(FullPeakIndexed) Variable NpatternsFound = max(DimSize(FullPeakIndexed,2),1) NpatternsFound = min(NpatternsFound,NumberByKey("NpatternsFound",wnote,"=")) if (NpatternsFound<1) return 1 elseif (!(NpatternsFound!=1)) pattern = 0 elseif (!(pattern>=0)) pattern = 0 Prompt pattern, "pattern number to fit [0,"+num2istr(NpatternsFound-1)+",]",popup,expandRange("0-"+num2istr(NpatternsFound-1),";") DoPrompt "pattern number",pattern if (V_flag) return 1 endif pattern = min(NpatternsFound-1,pattern-1) endif if (!(pattern>=0)) return 1 endif // get a graph of the image at the front, with boxes on to the front Wave image = $"" // init to NULL String imageName // name of image to look at String win // name of window displaying image imageName = StringByKey("fittedIgorImage",wnote,"=") if (exists(imageName)==1) Wave image = $imageName win = FindGraphWithImage(image) endif if (strlen(win)<1) // found fitted image, but no window, see if raw window is open Wave rawimage = $(StringByKey("rawIgorImage",wnote,"=")) win = FindGraphWithImage(rawimage) endif if (!WaveExists(image)) // could not find the fitted image, try for raw image imageName = StringByKey("rawIgorImage",wnote,"=") Wave image = $imageName win = FindGraphWithImage(image) endif if (!WaveExists(image)) // could not find the image return 1 endif if (strlen(win)) DoWindow/F $win // bring window with image to the top else Graph_imageMake(image,1) // no window exists, so make one showing image endif NVAR boxesOn=boxesOn boxesOn = 0 ButtonProc_Boxes("") // make sure that boxes are on ClearhklOffGraph("") String peakListName = StringByKey("peakListWave", wnote,"=") if (strlen(peakListName)) SetWindow kwTopWin userdata(FitPeaks )="FullPeakList="+peakListName endif Variable wid = (NumberByKey("maxPeakWidth",wnote,"=")+NumberByKey("minSpotSeparation",wnote,"="))/2 wid = numtype(wid) ? NumberByKey("minSpotSeparation",wnote,"=") : wid // wid = numtype(wid) ? 30 : wid // width of the cross wid = numtype(wid) ? 20 : wid // width of the cross Variable N=DimSize(FullPeakIndexed,0) Variable px,py SetDrawLayer UserFront // draw the X's for (i=0;i=N) DoAlert 0,"No indexed peak is in the Marquee" return NaN endif Variable h=FullPeakIndexed[i][3][ip], k=FullPeakIndexed[i][4][ip], l=FullPeakIndexed[i][5][ip] Variable Intens=FullPeakIndexed[i][6][ip], keV=FullPeakIndexed[i][7][ip],angleErr=FullPeakIndexed[i][8][ip] Variable Np = NumberByKey("NpatternsFound",note(FullPeakIndexed),"=") if (Np>1) printf "Indexed peak %d at pixel(%g, %g), in pattern %d of %d, hkl=(%d %d %d), Intensity=%g, Energy=%.4f keV, angleErr=%.3f (deg)\r",i,px,py,ip,Np,h,k,l,Intens,keV,angleErr else printf "Indexed peak %d at pixel(%g, %g), hkl=(%d %d %d), Intensity=%g, Energy=%.4f keV, angleErr=%.3f (deg)\r",i,px,py,h,k,l,Intens,keV,angleErr endif End // This puts up a window with info about an indexed peak on the current graph, when you shift-click on a spot // // if (exists("getIndexedPeakInfoHook")==6) // SetWindow Graph1 hook(peakInfo)=getIndexedPeakInfoHook // endif // // Function getIndexedPeakInfoHook(s) // Command=fitted peak, Shift=Indexed peak, & Command-Shift=strained peak STRUCT WMWinHookStruct &s // use shift to look at the indexing result, use command to look at fitted peaks String win = (s.winName) if (!(s.eventMod&10) || s.keycode) // eventMod==2 is shift key, 8 is command, and no regular key held down Tag/K/N=indexedPeakInfo/W=$win return 0 // shift key not down, ignore endif Variable useIndex = s.eventMod&2 // eventMod==2 is shift key, use info from indexed peaks Variable useFitted = s.eventMod&8 // eventMod==8 is command key, use info from fitted peaks Variable useStrain = useIndex && useFitted useFitted = useFitted && !useStrain // both means use strain String imageName = StringFromList(0,ImageNameList(win,";")) Wave image = ImageNameToWaveRef(win,StringFromList(0,ImageNameList(win,";"))) if (!WaveExists(image)) return 1 elseif (WaveDims(image)!=2) return 1 endif GetWindow $win psize Variable vert = limit((s.mouseLoc.v-V_top)/(V_bottom-V_top),0,1) // fractional position on graph Variable horiz = limit((s.mouseLoc.h-V_left)/(V_right-V_left),0,1) Variable mx,my // pixel position at the mouse-click GetAxis/W=$win/Q bottom if (V_flag) return 1 endif mx = (V_max-V_min)*horiz + V_min GetAxis/W=$win/Q left if (V_flag) return 1 endif my = (V_min-V_max)*vert + V_max String tagStr="", wnote, str Variable h,k,l, angleErr,keV,SpaceGroup Variable dist2, m Variable px,py,i,N Variable ip = NumberByKey("patternNum",GetUserData("","","Indexing"),"=") // pattern number ip = (ip<0 || numtype(ip)) ? 0 : ip Wave FullPeakIndexed=$(StringByKey("FullPeakIndexed",GetUserData("","","Indexing"),"=")) if (WaveExists(FullPeakIndexed)) ip = limit(ip,0,max(DimSize(FullPeakIndexed,2)-1,0)) Wave PeaksForStrain=$( GetWavesDataFolder(FullPeakIndexed,1)+"PeaksForStrain") endif useStrain = useStrain && (modDate(PeaksForStrain) >= modDate(FullPeakIndexed)) // only use strain if not stale useStrain = useStrain && (NumberByKey("patternNum", note(PeaksForStrain),"=")==ip) useIndex = useIndex && !useStrain if (useFitted) // examining fitted peaks Wave FullPeakList=$(StringByKey("FullPeakList",GetUserData("","","FitPeaks"),"=")) if (!WaveExists(FullPeakList)) return 0 endif dist2=Inf m=-1 // find the indexed peak closest to the mouse-click N=DimSize(FullPeakList,0) for (i=0;i0) sprintf str,"hkl=(%d %d %d), %.4f keV\rpixel(%.2f, %.2f), #%d, %d\rangleErr=%.4f (deg)",h,k,l,keV,px,py,m,ip,angleErr else sprintf str,"hkl=(%d %d %d), %.4f keV\rpixel(%.2f, %.2f), #%d\rangleErr=%.4f (deg)",h,k,l,keV,px,py,m,angleErr endif tagStr = "\\Zr090Indexed peak position\r" + str tagStr += SelectString(numtype(SpaceGroup),"\r"+getSymString(SpaceGroup)+" Space Group #"+num2istr(SpaceGroup),"") else // show strain data px = PeaksForStrain[m][11] py = PeaksForStrain[m][12] sprintf str,"pixel(%.2f, %.2f)\r%.4f keV\rhkl=(%d %d %d), #%d",px,py, PeaksForStrain[m][10],h,k,l,m tagStr = "\\Zr090Strained peak position\r" + str endif endif px = limit(px,0,DimSize(image,0)-1) // needed in case (px,py) is outside the image py = limit(py,0,DimSize(image,1)-1) Variable index = round(px) + DimSize(image,0)*round(py) // convert px,py back to index into image GetAxis/W=$win/Q bottom horiz = (px-V_min)/ (V_max-V_min) GetAxis/W=$win/Q left vert = (py-V_max)/(V_min-V_max) Variable x0 = horiz<0.5 ? 5 : -5, y0 = vert<0.5 ? -5 : 5 String anchor = SelectString(horiz<0.5,"R","L")+ SelectString(vert<0.5,"B","T") Tag/C/N=indexedPeakInfo/W=$win/A=$anchor/F=2/L=2/X=(x0)/Y=(y0)/P=1 $imageName,index,tagStr return 1 // 1 means do not send back to Igor for more processing End Function MakeIndexingReportSheet() // make a report of the indexation using the top graph String gName = StringFromList(0,WinList("*",";","WIN:1")) String list = GetUserData(gName,"","Indexing") Wave FullPeakIndexed = $(StringByKey("FullPeakIndexed",list,"=")) Variable ip = NumberByKey("patternNum",list,"=") ip = numtype(ip) || ip<0 ? 0 : ip if (!WaveExists(FullPeakIndexed)) DoAlert 0,"cannot find indexed peaks on the top graph" return 1 endif String imageName = StringFromList(0,ImageNameList(gName,";")) Wave image = ImageNameToWaveRef(gName,imageName) String str, textOut="\\Zr150"+imageName+SelectString(ip,""," pattern "+num2istr(ip)) if (WaveExists(image)) String dateExposed="", imageFileName="" dateExposed = StringByKey("dateExposed",note(image),"=") imageFileName = StringByKey("imageFileName",note(image),"=") sprintf str,"\\Zr075 from file '%s' taken on %s",imageFileName,dateExposed textOut += str endif Wave FullPeakIndexed=$(GetWavesDataFolder(image,1)+"FullPeakIndexed") str = ParagraphsFromIndexing(FullPeakIndexed,ip) String par1 = StringFromLIst(0,str), par2 = StringFromLIst(1,str) NewLayout/C=1/K=1/P=Portrait AppendLayoutObject/F=1/R=(43,23,582,506) graph $gName if (strlen(par1)) TextBox/N=text0/C/F=0/T={31,80,126,177,216,252,288,324,360}/A=LT/X=6/Y=69.67 par1 endif if (strlen(par2)) TextBox/N=text1/C/F=0/T={31,80,126,177,216,252,288,324,360}/A=RT/X=6/Y=69.67 par2 endif TextBox/N=text2/F=0/X=4.70/Y=66.80 textOut Textbox/C/N=stamp0/F=0/A=RB/X=0.1/Y=0.1 "\\Z06\\{\"%s %s\",date(), time()}" Textbox/C/N=stamp1/F=0/A=LB/X=0.1/Y=0.1 "\\Z06\\{\"%s\",CornerStamp1_()}"+":"+WinName(0, 1) End // Static Function/S ParagraphsFromIndexing(fpi,ip) Wave fpi // usually FullPeakIndexed Variable ip // pattern number (usually 0) String line, par1="",par2="" String topLine = "\\Z09#\t(hkl)\tIntens\tkeV\t err(deg)" Variable i, N = DimSize(fpi,0) for (i=0;ii) N = min(N,i+20) for (;i1 && keVmaxCalc<40) || !(keVmaxTest>1 && keVmaxTest<51) badNums += !(angleTolerance>=0.01 && angleTolerance<10) badNums += numtype(hp+kp++lp) badNums += !(cone>1 && cone<180) if (badNums) DoAlert 0, "Invalid inputs sent to runEulerCommand()" printf "runEulerCommand(%s,%g,%g,%g)\r",FullPeakList,keVmaxCalc,keVmaxTest,angleTolerance return "" elseif (!WaveExists(FullPeakList)) DoAlert 0, "the in put wave does not exist in runEulerCommand()" return "" elseif (DimSize(FullPeakList,0)<1 || DimSize(FullPeakList,1)!=11) DoAlert 0, "Full peak list '"+NameOfWave(FullPeakList)+"' is empty or the wrong size" return "" endif // first write the command file to drive Euler String upath=SpecialDirPath("Temporary",0,1,0) // local path (probably unix path) for the command line String mpath=SpecialDirPath("Temporary",0,0,0) // mac style path for use only within Igor PathInfo home if (V_flag) // the path "home" exists, use it mpath = S_path upath = SelectString(strsearch(S_path,systemUserName()+":",0)==0,"","Macintosh HD:Users:")+S_path // this if is due to bad paths from File Vault upath = ReplaceString(":",upath,"/") // convert from mac to unix separators upath = "/Volumes/"+upath endif NewPath/O/Q/Z EulerCalcFolder, mpath // need a new path name since "home" may not exist if (V_flag) DoAlert 0, "Unable to create path to do Euler calculation, try saving the experiment first." return "" endif String peakFile="generic_Peaks.txt" // name of file with input peak positions if(FullPeakList2Qfile(FullPeakList,peakFile,"EulerCalcFolder"))// convert peaks to a Qlist+intens, and write to a file return "" // nothing happened endif String EulerPath = ParseFilePath(1,FunctionPath("runEulerCommand"),":",1,0)+"Euler" // path to the Euler executable String cmd = "get POSIX path of file \"" + EulerPath + "\"" ExecuteScriptText/Z cmd if (V_Flag) return "" endif EulerPath = S_value[1,StrLen(S_value)-2] // trim quotes // EulerPath = ReplaceString(" ",EulerPath,"\\\\ ") // change spaces to escaped spaces sprintf cmd "do shell script \"cd \\\"%s\\\" ; \\\"%s\\\" -k %g -t %g -a %g -h %d %d %d -c %g -f %s\"",upath,EulerPath,keVmaxCalc,keVmaxTest,angleTolerance,hp,kp,lp,cone,peakFile // -n max num. of spots from data file to use ExecuteScriptText cmd if (ItemsInList(GetRTStackInfo(0))<2) // print everything if run from command line printf S_value endif Variable i = strsearch(S_value,"writing output to file '",0) if (i<0) DoAlert 0, "failure in runEulerCommand()" print "\r\r" print cmd print "\r\r" print S_value return "" // there is no index file endif String line = S_value[i,Inf] i = strsearch(line,"'",0)+1 line = line[i,Inf] String indexFile = line[0,strsearch(line,"'",0)-1] if (!strlen(indexFile)) DoAlert 0, "in runEulerCommand(), cannot find the index file" print "\r\r" print S_value return "" // there is no index file endif return readIndexFile(indexFile,"EulerCalcFolder") End //Function/S runEulerCommand(FullPeakList,keVmaxCalc,keVmaxTest,angleTolerance,hp,kp,lp,cone) // Wave FullPeakList // Variable keVmaxCalc // 14, maximum energy to calculate (keV) // Variable keVmaxTest // 26, maximum energy to test (keV) [-t] // Variable angleTolerance // 0.25, angular tolerance (deg) // Variable hp,kp,lp // preferred hkl // Variable cone // angle from preferred hkl, (0 < cone < 180¡) // // Variable badNums= !(keVmaxCalc>1 && keVmaxCalc<40) || !(keVmaxTest>1 && keVmaxTest<40) // badNums += !(angleTolerance>=0.01 && angleTolerance<10) // badNums += numtype(hp+kp++lp) // badNums += !(cone>1 && cone<180) // if (badNums) //// if (!(keVmaxCalc>1 && keVmaxCalc<40) || !(keVmaxTest>1 && keVmaxTest<40) || !(angleTolerance>0.02 && angleTolerance<10)) // DoAlert 0, "Invalid inputs sent to runEulerCommand()" // printf "runEulerCommand(%s,%g,%g,%g)\r",FullPeakList,keVmaxCalc,keVmaxTest,angleTolerance // return "" // elseif (!WaveExists(FullPeakList)) // DoAlert 0, "the in put wave does not exist in runEulerCommand()" // return "" // elseif (DimSize(FullPeakList,0)<1 || DimSize(FullPeakList,1)!=11) // DoAlert 0, "Full peak list '"+NameOfWave(FullPeakList)+"' is empty or the wrong size" // return "" // endif // // // first write the command file to drive Euler // PathInfo home // if (!V_flag) // DoAlert 0, "the Igor path 'home' does not exist!, you need to first save this experiment." // return "" // endif //// print "Mac path is ",S_path //// String path = ReplaceString(":",S_path[strsearch(S_path,":",0),Inf],"/") // String path = "/Volumes/"+ReplaceString(":",S_path,"/") // String peakFile="generic_Peaks.txt" // name of file with input peak positions // // if(FullPeakList2Qfile(FullPeakList,peakFile))// convert peaks to a Qlist+intens, and write to a file // return "" // nothing happened // endif // //// String EulerPath = "/Users/tischler/dev/Euler/build/Debug/Euler" //// String EulerPath = "/Users/tischler/dev/Eulersvntest/trunk/build/Debug/Euler" // String EulerPath = ParseFilePath(1,FunctionPath("runEulerCommand"),":",1,0) // EulerPath = ReplaceString(":",EulerPath[strsearch(EulerPath,":",0),Inf],"/")+"Euler" // String cmd //// sprintf cmd "do shell script \"cd \\\"%s\\\" ; %s -k %g -t %g -a %g -f %s\"",path,EulerPath,keVmaxCalc,keVmaxTest,angleTolerance,peakFile //// sprintf cmd "do shell script \"cd \\\"%s\\\" ; %s -k %g -t %g -a %g -h %d %d %d -c %g -f %s\"",path,EulerPath,keVmaxCalc,keVmaxTest,angleTolerance,hp,kp,lp,cone,peakFile //// sprintf cmd "do shell script \"cd \\\"%s\\\" ; \\\"%s\\\" -k %g -t %g -a %g -h %d %d %d -c %g -f %s\"",path,EulerPath,14,36,0.25,0,0,2,72,peakFile // sprintf cmd "do shell script \"cd \\\"%s\\\" ; \\\"%s\\\" -k %g -t %g -a %g -h %d %d %d -c %g -f %s\"",path,EulerPath,keVmaxCalc,keVmaxTest,angleTolerance,hp,kp,lp,cone,peakFile //// -n max num. of spots from data file to use // ExecuteScriptText cmd // if (ItemsInList(GetRTStackInfo(0))<2) // print everything if run from command line // printf S_value // endif // Variable i = strsearch(S_value,"writing output to file '",0) // if (i<0) // DoAlert 0, "failure in runEulerCommand()" // print "\r\r" // print cmd // print "\r\r" // print S_value // return "" // there is no index file // endif // String line = S_value[i,Inf] // i = strsearch(line,"'",0)+1 // line = line[i,Inf] // String indexFile = line[0,strsearch(line,"'",0)-1] // if (!strlen(indexFile)) // DoAlert 0, "in runEulerCommand(), cannot find the index file" // print "\r\r" // print S_value // return "" // there is no index file // endif // return readIndexFile(indexFile,"home") //End // // read an index file and create an array to hold the results, return array name Static Function/S readIndexFile(indexFile,path) String indexFile // name of index file, the output from Euler String path // name of Igor path to go with indexFile Variable f = OpenFileOf_ftype(indexFile,"IndexFile",path)// open an index file if (f<1) return "" // could not get any info from indexFile endif FStatus f String buffer="" buffer = PadString(buffer,V_logEOF-V_filePos,0x20) FBinRead f, buffer // read entire file into buffer Close f buffer = ReplaceString("\r\n",buffer,"\n") // ensure that line term is a new-line only buffer = ReplaceString("\n\r",buffer,"\n") buffer = ReplaceString("\r",buffer,"\n") Variable Nbuf = strlen(buffer) STRUCT microGeometry geo if (FillGeometryStructDefault(geo)) //fill the geometry structure with test values DoAlert 0, "no geometry structure found, did you forget to set it?" return GetWavesDataFolder(FullPeakIndexed,2) // can not compute (px,py), but still a valid result endif Variable ipattern=0 // number of current patterns Variable i1,i0 = strsearch(buffer,"$pattern"+num2istr(ipattern),0) // put into "key=value" everything up pattern ipattern i0= i0<0 ? Inf : i0-1 String wnote = keyStrFromBuffer(buffer[0,i0]) Variable Npatterns = NumberByKey("NpatternsFound",wnote,"=") if (!(Npatterns>0)) return "" endif Variable startx,groupx, starty,groupy startx = NumberByKey("startx",wnote,"=") groupx = NumberByKey("groupx",wnote,"=") starty = NumberByKey("starty",wnote,"=") groupy = NumberByKey("groupy",wnote,"=") startx = numtype(startx) ? 1 : startx groupx = numtype(groupx) ? 1 : groupx starty = numtype(starty) ? 1 : starty groupy = numtype(groupy) ? 1 : groupy Make/N=3/O/D runEulerCommand_qBL, runEulerCommand_qW Wave qBL=runEulerCommand_qBL, qW=runEulerCommand_qW Make/N=3/O/D runEulerCommand_qhat Wave qvec = runEulerCommand_qhat String list1 Variable/C pz Variable qx,qy,qz,hh,kk,ll,int,keV,err Variable Ni=-1, cols,i,val do i0 +=1 // range of header info for this pattern i1 = strsearch(buffer,"\n$array"+num2istr(ipattern),i0) list1 = keyStrFromBuffer(buffer[i0,i1]) list1 = RemoveByKey("pattern"+num2istr(ipattern),list1,"=") wnote = MergeKeywordLists(wnote,list1,0,"=","") // buffer is now the data (and the leading $arrayN line) i0 = i1+1 i1 = strsearch(buffer,"$pattern"+num2istr(ipattern+1),i0) i1 = (i1<1 ? Nbuf : i1)-1 sscanf buffer[i0,i1],"$array%d %d %d",i,cols,i if (ipattern==0) // for first pattern, make the output wave Ni = i Make/N=(Ni,cols+1,Npatterns)/O FullPeakIndexed// make is long enough to also hold the pixel positions (an extra 2 cols) FullPeakIndexed = NaN elseif (i>Ni) Ni = i Redimension/N=(Ni,cols+1,Npatterns) FullPeakIndexed endif i0 = strsearch(buffer,"\n",i0+1)+1 // start of first data for (i=0;i32) printf "The file must start with '%s', but the first line is '%s'\r",ftype,line Close f return 0 endif endif return f End // Static Function/S keyStrFromBuffer(buffer)// get key list from the buffer String buffer // long sting with line feeds, each line is of the form: "$tag value // comment\n" Variable N=strlen(buffer) Variable i0,i1 // indicies into buffer String tagName, value // the found tag and value (if they exist) String line // one line of buffer String list="" // the result buffer = ReplaceString("\r\n",buffer,"\n") // ensure that line term is a new-line only buffer = ReplaceString("\n\r",buffer,"\n") buffer = ReplaceString("\r",buffer,"\n") i0 = 0 i1 = strsearch(buffer,"\n",i0) do line = buffer[i0,i1] // one line from the buffer tagValueFromLine(line,tagName,value) // get tag and value from this line if (strlen(tagName) && !keyInList(tagName,list,"=","")) // valid tag, and not yet in list list = ReplaceStringByKey(tagName,list,value,"=") endif i0 = i1+1 i1 = strsearch(buffer,"\n",i0) i1 = (i1<0) ? N-1 : i1 while(i0=0) line = line[0,i-1] endif for (i=0;char2num(line[i+1])>32;i+=1) // find end of tag, it ends with a space or lower endfor tagName = line[1,i] if (strlen(tagName)<1) // no tag return "" endif for (i=i+1;char2num(line[i])<=32;i+=1) // find first non-white space, start of value endfor value = line[i,Inf] // value associated with tagName for (i=strlen(value)-1;char2num(value[i])<=32 && i>0;i-=1) // strip off trailing whitespace endfor value = ReplaceString(";",value[0,i],":") // cannot have a semicolon or equals in the value return ReplaceStringByKey(tagName,"",value,"=") End //Function test() // Variable f // Open/M="test file of tagged lines"/P=home/R/T="TEXT" f as "Macintosh HD:Users:tischler:data:Sector 34:August 2006:calibration:generic_Index.txt" // print S_fileName // FStatus f // print "V_logEOF=",V_logEOF // String buffer="" // buffer = PadString(buffer,V_logEOF,0x20) // FBinRead f, buffer // Close f // print "strlen(buffer) = ",strlen(buffer) // String list = keyStrFromBuffer(buffer) // print list //End // //Function test() // String tagName,value,line // line = "$EulerAngles {-171.29728810, 149.32171846, 229.41456865} // Euler angles for this pattern (deg)\n" // String output = tagValueFromLine(line,tagName,value) // printf "tagName = '%s'\r",tagName // printf "value = '%s'\r",value // printf "output = '%s'\r",output //End // remove bkg from an image, identify the peaks, and fit them all Function/S RemoveBackgroundImage(rawImage,fractionBkg) Wave rawImage // the raw image from the spe file Variable fractionBkg // fraction of image that is background, use something like 0.99 or 0.995 (even 0.7 works OK) Variable printIt = ItemsInList(GetRTStackInfo(0))<2 || stringmatch(StringFromList(0,GetRTStackInfo(0)),"IndexButtonProc") if (!WaveExists(rawImage) || WaveDims(rawImage)!=2 || !(fractionBkg==limit(fractionBkg,1e-3,1))) String imageName = SelectString(WaveExists(rawImage),"",NameOfWave(rawImage)) fractionBkg = fractionBkg==limit(fractionBkg,1e-3,1) ? fractionBkg : 0.8 Prompt imageName,"name of image with peaks to find",popup,reverseList(WaveListClass("speImage","*","DIMS:2")) Prompt fractionBkg,"fraction of image that is background, usually in range [0.7, 0.995]" DoPrompt/Help="3D-Xray Diffraction[Fit Peaks]" "peak fitting",imageName,fractionBkg if (V_flag) return "" endif Wave rawImage = $imageName printf "FitPeaks(%s,%g)\r",imageName,fractionBkg printIt = 1 endif if (!WaveExists(rawImage) || WaveDims(rawImage)!=2 || !(fractionBkg==limit(fractionBkg,1e-3,1))) return "" endif Variable timer=startMSTimer // Variable timer1 = startMSTimer Variable thresh = numpnts(rawImage)*fractionBkg WaveStats/Q/M=1 rawImage Make/N=200/D/O FitPeaks_Hist Variable i for (i=-1;i<10 || numtype(i);) // keep expanding the histogram range while i<10, I want i to be bigger than 10 SetScale/I x,V_min,V_max,"",FitPeaks_Hist // lower high end of histogram to zoom in around zero Histogram/B=2 rawImage,FitPeaks_Hist Integrate/P FitPeaks_Hist/D=FitPeaks_Hist_INT // integrate the histogram i=BinarySearchInterp(FitPeaks_Hist_INT,thresh) // find point where FitPeaks_Hist_INT[i] == thresh V_max = numtype(i) ? V_max/2 : pnt2x(FitPeaks_Hist_INT,i+4) endfor // print "first part took ",stopMSTimer(timer1)/1e6,"sec" // timer1 = startMSTimer thresh = DimDelta(FitPeaks_Hist,0)*i + DimOffset(FitPeaks_Hist,0) ImageThreshold/Q/T=(thresh)/M=0 rawImage // create M_ImageThresh Wave M_ImageThresh=M_ImageThresh ImageStats/M=1 M_ImageThresh Variable fracBlack = V_avg*V_npnts/255/V_npnts // printf "number of points in peak is %d out of %d points (%.2f%%)\r",fracBlack*V_npnts,V_npnts,fracBlack*100 Make/N=(9,9)/O/B/U RemoveBackgroundImage_black RemoveBackgroundImage_black = 255 for(;fracBlack<0.10;) // loop until fracBlack is atleast 10% Imagemorphology/S=RemoveBackgroundImage_black/O BinaryDilation M_ImageThresh ImageThreshold/Q/T=(2)/M=0 M_ImageThresh ImageStats/M=1 M_ImageThresh fracBlack = V_avg*V_npnts/255/V_npnts // printf "number of points in peak is %d out of %d points (%.2f%%)\r",fracBlack*V_npnts,V_npnts,fracBlack*100 endfor ImageTransform/O invert M_ImageThresh // M_ImageThresh = !M_ImageThresh // print "second part took ",stopMSTimer(timer1)/1e6,"sec" // timer1 = startMSTimer ImageInterpolate /f={.125,.125} bilinear rawImage Redimension/S M_InterpolatedImage KillWaves/Z FitPeaks_rawImage_smaller Rename M_InterpolatedImage FitPeaks_rawImage_smaller // make a source image using fewer pixels // print "\t\t1st interpolate part took ",stopMSTimer(timer1)/1e6,"sec" // timer1 = startMSTimer ImageInterpolate /f={.125,.125} bilinear M_ImageThresh // make a mask with fewer pixels KillWaves/Z FitPeaks_mask_smaller Rename M_InterpolatedImage FitPeaks_mask_smaller Redimension/B/U FitPeaks_mask_smaller ImageRemoveBackground/F/R=FitPeaks_mask_smaller/P=2/W FitPeaks_rawImage_smaller // creates M_RemovedBackground, uses 3rd order polynomial Wave W_BackgroundCoeff=W_BackgroundCoeff // print W_BackgroundCoeff // print "\t\t2nd interpolate part took ",stopMSTimer(timer1)/1e6,"sec" // timer1 = startMSTimer ImageInterpolate /f={8,8} bilinear M_RemovedBackground // creates M_InterpolatedImage, a bkg with full number of pixels Wave M_InterpolatedImage=M_InterpolatedImage String outName = NameOfWave(rawImage)+"NoBkg" String fldr = GetWavesDataFolder(rawImage,1) if (CheckName(fldr+outName,1)) outName = CleanupName(outName,0) endif outName = fldr+outName Duplicate/O rawImage $outName Wave noBkg = $outName String wnote=ReplaceStringByKey("rawIgorImage",note(rawImage),GetWavesDataFolder(rawImage,2),"=") wnote = ReplaceNumberByKey("fractionBkg",wnote,fractionBkg,"=") wnote = ReplaceStringByKey("waveClass",wnote,"speImageNoBkg","=") Note/K noBkg, wnote Redimension/I noBkg // signed int32 version of rawImage noBkg = rawImage - M_InterpolatedImage[p][q] // p,q because M_InterpolatedImage is smaller Variable sec0=stopMSTimer(timer)/1e6 if (printIt) printf "removing background took %g sec\r",sec0 printf " result stored in the wave '%s'\r", GetWavesDataFolder(noBkg,2) endif KillWaves/Z FitPeaks_rawImage_smaller,FitPeaks_mask_smaller, M_ImageThresh, M_RemovedBackground, M_InterpolatedImage, W_BackgroundCoeff KillWaves/Z FitPeaks_Hist_INT,FitPeaks_Hist, RemoveBackgroundImage_black return GetWavesDataFolder(noBkg,2) End // First get a background: // 1) down sample the image by 2 (could be 4) // 2) do a median filter to get a background level for each pixel // 3) gaussian filter the background to smooth it // 4) upsample to get a background the correct size // Subtract this background from the original image // and median filter (only 5) and gauss smooth to get rid of specks // Thresold this image to generate a mask of regions that represent the peak locations (an ROI) // Examine each region in the ROI separately, fitting a gaussian Function/S FitPeaksWithSeedFill(image,minPeakWidth,maxPeakWidth,minSep,threshAboveAvg,[mask,maxNu,whoami]) Wave image // the image from the spe file Variable minPeakWidth // minimum width for an acceptable peak (pixels) Variable maxPeakWidth // maximum width for an acceptable peak (pixels) Variable minSep // minimum separation between two peaks (pixels) Variable threshAboveAvg // threshold above average value, use 25 Wave mask // starting mask for the fit (this mask is unchanged by this routine) Variable maxNu // maximum number of peaks to find, normally goes to completion Variable whoami // if passed, then just return the name of this routine if (!ParamIsDefault(whoami)) return GetRTStackInfo(1) endif maxNu = ParamIsDefault(maxNu) ? Inf : maxNu String imageName Variable printIt = ItemsInList(GetRTStackInfo(0))<2 || stringmatch(StringFromList(0,GetRTStackInfo(0)),"IndexButtonProc") if (!WaveExists(image) || WaveDims(image)!=2 || !(minPeakWidth>0) || !(maxPeakWidth>0) || !(minSep>3) || !(threshAboveAvg>0)) imageName = SelectString(WaveExists(image),"",NameOfWave(image)) minPeakWidth = minPeakWidth>.5 ? minPeakWidth : 1.2 maxPeakWidth = maxPeakWidth>.5 ? maxPeakWidth : 70 minSep = minSep>minPeakWidth ? minSep : 50 threshAboveAvg = threshAboveAvg>0 ? threshAboveAvg : 20 Prompt imageName,"name of image with peaks to find",popup,reverseList(WaveListClass("speImageNoBkg;speImage","*","DIMS:2")) Prompt minPeakWidth,"minimum allowed width of a peak" Prompt maxPeakWidth,"maximum allowed width of a peak" Prompt minSep,"minimum distance between two peaks, reject peaks closer than this" Prompt threshAboveAvg,"min peak height" DoPrompt/Help="3D-Xray Diffraction[Fit Peaks]" "peak fitting",imageName,minPeakWidth,maxPeakWidth,minSep,threshAboveAvg if (V_flag) return "" endif Wave image = $imageName printf "FitPeaksWithSeedFill(%s,%g,%g,%g,%g)\r",imageName,minPeakWidth,maxPeakWidth,minSep,threshAboveAvg printIt = 1 endif if (!WaveExists(image) || WaveDims(image)!=2 || !(minPeakWidth>0) || !(maxPeakWidth>0) || !(minSep>3) || !(threshAboveAvg>0)) return "" endif imageName = GetWavesDataFolder(image,2) Variable Nx=DimSize(image,0), Ny=DimSize(image,1) if (Nx<2 || Ny<2) return "" endif Variable timer=startMSTimer Variable Nfilt=20 Variable downSample = NumVarOrDefault("downSample", 2 ) // could be 4 (don't be greedy), 1 also works but is slow Duplicate/O image FitPeaksSeedFill_smth // image to use when finding next hot pixel Wave imageS = FitPeaksSeedFill_smth Redimension/D imageS ImageInterpolate/PXSZ={(downSample),(downSample)} Pixelate imageS // down sample the image to get background Wave M_PixelatedImage=M_PixelatedImage // Variable Ndown = Nfilt/downSample Variable Ndown = max(7,round(Nfilt/downSample)) MatrixFilter/N=(Ndown)/M=(Ndown*Ndown*0.5) median M_PixelatedImage MatrixFilter/N=(2*Nfilt) gauss M_PixelatedImage // this is now the background ImageInterpolate/F={(downSample),(downSample)} bilinear M_PixelatedImage // up sample the background Wave M_InterpolatedImage=M_InterpolatedImage Variable rowsToAdd = DimSize(image,0)-DimSize(M_InterpolatedImage,0) // redimension to exactly the right size Variable colsToAdd = DimSize(image,1)-DimSize(M_InterpolatedImage,1) ImageTransform/N={(rowsToAdd),(colsToAdd)}/O padimage M_InterpolatedImage ImageStats M_InterpolatedImage Variable bkg = V_rms imageS = image - M_InterpolatedImage MatrixFilter/N=5 median imageS MatrixFilter/N=10 gauss imageS ImageThreshold/T=(threshAboveAvg)/I imageS Wave M_ImageThresh=M_ImageThresh Duplicate/O M_ImageThresh FitPeaks_ImageMask if (ParamIsDefault(mask)) // preset FitPeaks_ImageMask with 'mask' if it was passed and is valid if (WaveExists(mask) && DimSize(mask,0)==Nx && DimSize(mask,1)==Ny) // if mask exists and is right size, use it as starting point FitPeaks_ImageMask = mask || FitPeaks_ImageMask endif endif Duplicate/O imageS FitPeaksWithSeedFill_weights__ // weights to use in the peak fitting Wave weights = FitPeaksWithSeedFill_weights__ String str Make/O/T JZT_Constraints={"K3 > 0.1","K5 > 0.1","K6 > 0","K6 < 1","","","",""} sprintf str,"K3 > %g",minPeakWidth/100 JZT_Constraints[0] = str sprintf str,"K5 > %g",minPeakWidth/100 JZT_Constraints[1] = str sprintf str,"K2 > %g",-maxPeakWidth JZT_Constraints[4] = str sprintf str,"K2 < %g",DimOffset(image,0) + (DimSize(image,0)-1)*DimDelta(image,0) + maxPeakWidth JZT_Constraints[5] = str sprintf str,"K4 > %g",-maxPeakWidth JZT_Constraints[6] = str sprintf str,"K4 < %g",DimOffset(image,1) + (DimSize(image,1)-1)*DimDelta(image,1) + maxPeakWidth JZT_Constraints[7] = str // sprintf str,"K1 > %g",-100*threshAboveAvg // JZT_Constraints[8] = str Variable Nu=0, Nlen=50 Make/N=(Nlen,11)/O FullPeakList FullPeakList = NaN String wnote = note(image) wnote = ReplaceNumberByKey("minPeakWidth",wnote,minPeakWidth,"=") wnote = ReplaceNumberByKey("maxPeakWidth",wnote,maxPeakWidth,"=") wnote = ReplaceNumberByKey("minSpotSeparation",wnote,minSep,"=") wnote = ReplaceNumberByKey("threshAboveAvg",wnote,threshAboveAvg,"=") wnote = ReplaceStringByKey("fittedIgorImage",wnote,GetWavesDataFolder(image,2),"=") wnote = ReplaceStringByKey("waveClass",wnote,"FittedPeakList","=") SetDimLabel 1,0,x0,FullPeakList ; SetDimLabel 1,1,y0,FullPeakList SetDimLabel 1,2,x0Err,FullPeakList ; SetDimLabel 1,3,y0Err,FullPeakList SetDimLabel 1,4,fwx,FullPeakList ; SetDimLabel 1,5,fwy,FullPeakList SetDimLabel 1,6,fwxErr,FullPeakList ; SetDimLabel 1,7,fwyErr,FullPeakList SetDimLabel 1,8,correlation,FullPeakList ; SetDimLabel 1,9,correlationErr,FullPeakList SetDimLabel 1,10,area,FullPeakList Note/K FullPeakList,wnote Variable fw= ( 2*sqrt(2*ln(2)) ) // this factor corrects for 2-d sigma to FWHM, apply to K3, K5, and the corresponding errors Variable xx,yy,fwx,fwy,sigX,sigY, amp // holds the resutls of gaussian fit Variable px,py, left,right,top,bot, err, i do // DoUpdate ImageStats/M=1/R=FitPeaks_ImageMask imageS // find the highest point if (V_maxmaxPeakWidth || sigY>maxPeakWidth || numtype(sigX+sigY) ) // errors bars are huge if (!(min(fwx,fwy)>minPeakWidth) || !(max(fwx,fwy)bkg) || err) // cannot have spots too wide or too narrow continue endif for (i=0;i=Nlen) // FullPeakList is too short, extend it Nlen += 50 Redimension/N=(Nlen,11) FullPeakList endif FullPeakList[Nu][0]=xx ; FullPeakList[Nu][1]=yy FullPeakList[Nu][2]=sigX ; FullPeakList[Nu][3]=sigY FullPeakList[Nu][4]=fwx ; FullPeakList[Nu][5]=fwy FullPeakList[Nu][6]=W_sigma[3]*fw ; FullPeakList[Nu][7]=W_sigma[5]*fw FullPeakList[Nu][8]=W_coef[6] ; FullPeakList[Nu][9]=W_sigma[6] FullPeakList[Nu][10]=W_coef[1]*fwx*fwy Nu += 1 while(Nu0) || !(maxPeakWidth>0) || !(minSep>3) || !(threshAboveAvg>0)) imageName = SelectString(WaveExists(image),"",NameOfWave(image)) minPeakWidth = minPeakWidth>.5 ? minPeakWidth : 1.2 maxPeakWidth = maxPeakWidth>.5 ? maxPeakWidth : 10 minSep = minSep>minPeakWidth ? minSep : 40 threshAboveAvg = threshAboveAvg>0 ? threshAboveAvg : 100 Prompt imageName,"name of image with peaks to find",popup,reverseList(WaveListClass("speImageNoBkg;speImage","*","DIMS:2")) Prompt minPeakWidth,"minimum allowed width of a peak" Prompt maxPeakWidth,"maximum allowed width of a peak" Prompt minSep,"minimum distance between two peaks" Prompt threshAboveAvg,"min peak height" DoPrompt/Help="3D-Xray Diffraction[Fit Peaks]" "peak fitting",imageName,minPeakWidth,maxPeakWidth,minSep,threshAboveAvg if (V_flag) return "" endif Wave image = $imageName printf "FitPeaksStepWise(%s,%g,%g,%g,%g)\r",imageName,minPeakWidth,maxPeakWidth,minSep,threshAboveAvg printIt = 1 endif if (!WaveExists(image) || WaveDims(image)!=2 || !(minPeakWidth>0) || !(maxPeakWidth>0) || !(minSep>3) || !(threshAboveAvg>0)) return "" endif imageName = GetWavesDataFolder(image,2) Variable Nx=DimSize(image,0), Ny=DimSize(image,1) if (Nx<2 || Ny<2) return "" endif Variable timer0=startMSTimer Duplicate/O image FitPeaksStepWise_smth // image to use when finding next hot pixel Wave imageS = FitPeaksStepWise_smth Redimension/D imageS imageS = image[p][q]<=0 ? NaN : image[p][q] MatrixFilter/N=3 min imageS ImageStats/M=1/Q imageS // find the average value Variable threshold = threshAboveAvg+max(V_avg,0) // the actual threshold, only consider pixels above this level if (printIt) printf "average for the image = %g, so only consider pixels values above %g\r",V_avg,threshold endif Make/N=(Nx,Ny)/O/B/U FitPeaks_ImageMask // make a mask for this image FitPeaks_ImageMask = 0 // set to 0, this includes all of the image if (ParamIsDefault(mask)) // preset FitPeaks_ImageMask with 'mask' if it was passed and is valid if (WaveExists(mask) && DimSize(mask,0)==Nx && DimSize(mask,1)==Ny) // if mask exists and is right size, use it as starting point FitPeaks_ImageMask = !(!mask[p][q]) endif endif Duplicate/O image image_weights_temp_ // weights to use in the peak fitting Wave weights = image_weights_temp_ weights = FitPeaks_ImageMask<1 Make/N=(3,3)/O/U/I FitPeaks_3x3 Make/O/T JZT_Constraints={"K3 > 0","K5 > 0","K6 > 0","K6 < 1"} Variable Nu=0, Nlen=50 Make/N=(Nlen,11)/O FullPeakList FullPeakList = NaN String wnote = note(image) wnote = ReplaceNumberByKey("minPeakWidth",wnote,minPeakWidth,"=") wnote = ReplaceNumberByKey("maxPeakWidth",wnote,maxPeakWidth,"=") wnote = ReplaceNumberByKey("minSpotSeparation",wnote,minSep,"=") wnote = ReplaceNumberByKey("threshAboveAvg",wnote,threshAboveAvg,"=") wnote = ReplaceStringByKey("fittedIgorImage",wnote,GetWavesDataFolder(image,2),"=") wnote = ReplaceStringByKey("waveClass",wnote,"FittedPeakList","=") SetDimLabel 1,0,x0,FullPeakList ; SetDimLabel 1,1,y0,FullPeakList SetDimLabel 1,2,x0Err,FullPeakList ; SetDimLabel 1,3,y0Err,FullPeakList SetDimLabel 1,4,fwx,FullPeakList ; SetDimLabel 1,5,fwy,FullPeakList SetDimLabel 1,6,fwxErr,FullPeakList ; SetDimLabel 1,7,fwyErr,FullPeakList SetDimLabel 1,8,correlation,FullPeakList ; SetDimLabel 1,9,correlationErr,FullPeakList SetDimLabel 1,10,area,FullPeakList Variable fw= ( 2*sqrt(2*ln(2)) ) // this factor corrects for 2-d sigma to FWHM, apply to K3, K5, and the corresponding errors Variable xx,yy,fwx,fwy,sigX,sigY,amp,sigAmp // holds the resutls of gaussian fit Variable px,py, left,right,top,bot do // DoUpdate ImageStats/M=1/R=FitPeaks_ImageMask imageS // find the highest point if (V_maxthreshold)) // this is a lone pixel image[px][py] = V_avg // set lone pixels to surrounding average, and continue FitPeaks_ImageMask[px][py] = 255 weights[px][py] = 0 continue endif // fit a gaussian about px,py left = limit(floor(px-maxPeakWidth/2),0,Nx-1) // box to use for fitting right = limit(ceil(px+maxPeakWidth/2),0,Nx-1) top = limit(floor(py-maxPeakWidth/2),0,Ny-1) bot = limit(ceil(py+maxPeakWidth/2),0,Ny-1) if (FitGaussianPeak(image,left,right,top,bot,weight=weights)) // returns 0 == OK, non-zero if error FitPeaks_ImageMask[left,right][top,bot] = 255 // extend the FitPeaks_ImageMask to reject spots within maxPeakWidth weights[left,right][top,bot] = 0 continue endif Wave W_coef=W_coef, W_sigma=W_sigma xx = W_coef[2] yy = W_coef[4] fwx = abs(W_coef[3] * fw) fwy = abs(W_coef[5] * fw) sigX = W_sigma[2] sigY = W_sigma[4] amp = abs(W_coef[1]) sigAmp = W_sigma[2] // if (ItemsInList(GetRTStackInfo(0))<2) // printf "%d Gaussian peak in at (%.2f±%.2f, %.2f±%.2f) with FWHM of (%.2f±%.2f, %.2f±%.2f), amp=%g\r",Nu,xx,sigX,yy,sigY,fwx,W_sigma[3]*fw,fwy,W_sigma[5]*fw,W_coef[1]*fwx*fwy // endif if (min(fwx,fwy)maxPeakWidth || sigX>maxPeakWidth || sigY>maxPeakWidth || amp=Nlen) // FullPeakList is too short, extend it Nlen += 50 Redimension/N=(Nlen,11) FullPeakList endif FullPeakList[Nu][0]=xx ; FullPeakList[Nu][1]=yy FullPeakList[Nu][2]=sigX ; FullPeakList[Nu][3]=sigY FullPeakList[Nu][4]=fwx ; FullPeakList[Nu][5]=fwy FullPeakList[Nu][6]=W_sigma[3]*fw ; FullPeakList[Nu][7]=W_sigma[5]*fw FullPeakList[Nu][8]=W_coef[6] ; FullPeakList[Nu][9]=W_sigma[6] FullPeakList[Nu][10]=W_coef[1]*fwx*fwy Nu += 1 while(Nu 0","K5 > 0","K6 > 0","K6 < 1"} Variable V_FitOptions=4, V_FitError=0,V_FitQuitReason=0 V_FitOptions=4 if (noWeight) CurveFit/Q/N Gauss2D image[left,right][bottom,top]/C=JZT_Constraints else CurveFit/Q/N Gauss2D image[left,right][bottom,top]/C=JZT_Constraints/W=weight endif if (!V_FitError) // if no error, but constraints failed, set bit 5 as error anyhow Wave W_coef = W_coef V_FitError += (W_coef[3]<-1e-7 || W_coef[5]<-1e-7 || W_coef[6]<-1e-7 || W_coef[6]>1.0001) ? 32 : 0 endif return V_FitError End //Static Function FitGaussianPeak(image,left,right,bottom,top,[weight]) // returns 1 if error, 0 is OK // // the result is passed to calling function by W_coef or {K0, K1, ... K6} // // this fits a 2-d gaussina to a region on an image. The region is selected with a marquee in an image plot, or specified // Wave image // Variable left, right, bottom, top // range to use for fit // Wave weight // Variable noWeight = ParamIsDefault(weight) // // // set up for the gaussian fit // Wave JZT_Constraints=JZT_Constraints // = {"K3 > 0","K5 > 0","K6 > 0","K6 < 1"} // Variable V_FitOptions=4, V_FitError=0,V_FitQuitReason=0 // V_FitOptions=4 // if (noWeight) // CurveFit/Q/N Gauss2D image[left,right][bottom,top]/C=JZT_Constraints // else // CurveFit/Q/N Gauss2D image[left,right][bottom,top]/C=JZT_Constraints/W=weight // endif // // if (!V_FitError) // if no error, but constraints failed, set bit 5 as error anyhow // Wave W_coef = W_coef // V_FitError += (W_coef[3]<-1e-7 || W_coef[5]<-1e-7 || W_coef[6]<-1e-7 || W_coef[6]>1.0001) ? 32 : 0 // endif // return V_FitError //End // identify the peaks, and fit them all (no background removal) Function/S FitPeaksNew(image,threshAboveAvg,dist) Wave image // the image from the spe file Variable threshAboveAvg // threshold above average value Variable dist // minimum distance between spots, spots have to be at least this far apart (pixels) String imageName Variable printIt = ItemsInList(GetRTStackInfo(0))<2 || stringmatch(StringFromList(0,GetRTStackInfo(0)),"IndexButtonProc") if (!WaveExists(image) || WaveDims(image)!=2 || !(threshAboveAvg>0) || !(dist>3)) imageName = SelectString(WaveExists(image),"",NameOfWave(image)) threshAboveAvg = threshAboveAvg>0 ? threshAboveAvg : 100 dist = dist>3 ? dist : 30 Prompt imageName,"name of image with peaks to find",popup,reverseList(WaveListClass("speImageNoBkg;speImage","*","DIMS:2")) Prompt threshAboveAvg,"fraction of image that is background, usually in range [0.7, 0.995], use 0 to skip bkg removal" Prompt dist, "minimum distance (pixels) between any two peaks (use ~30 for unbinned Si)" DoPrompt/Help="3D-Xray Diffraction[Fit Peaks]" "peak fitting",imageName,threshAboveAvg,dist if (V_flag) return "" endif Wave image = $imageName printf "FitPeaks(%s,%g,%g)\r",imageName,threshAboveAvg,dist printIt = 1 endif if (!WaveExists(image) || WaveDims(image)!=2 || !(threshAboveAvg>0) || !(dist>3)) return "" endif imageName = GetWavesDataFolder(image,2) Variable Nx=DimSize(image,0), Ny=DimSize(image,1) Variable timer0=startMSTimer ImageStats/M=1/Q image // find the average value Variable threshold = threshAboveAvg+V_avg // the actual threshold, only consider pixels above this level if (printIt) print "average for the image = ",V_avg endif Duplicate/O image, FitPeaks_ImageMask Wave FitPeaks_ImageMask=FitPeaks_ImageMask Redimension/B/U FitPeaks_ImageMask // make a mask for the image FitPeaks_ImageMask = 0 // set to 0, this includes all of the image Variable localAvg // average of local spots (not including center) Make/N=(3,3)/O/U/I FitPeaks_3x3 Variable xx,yy,fwx,fwy,sigX,sigY Variable fw= ( 2*sqrt(2*ln(2)) ) // this factor corrects for 2-d sigma to FWHM, apply to K3, K5, and the corresponding errors Make/N=(50,11)/O FullPeakList FullPeakList = NaN String wnote = note(image) wnote = ReplaceNumberByKey("minSpotSeparation",wnote,dist,"=") wnote = ReplaceNumberByKey("threshAboveAvg",wnote,threshAboveAvg,"=") wnote = ReplaceStringByKey("fittedIgorImage",wnote,GetWavesDataFolder(image,2),"=") wnote = ReplaceStringByKey("waveClass",wnote,"FittedPeakList","=") Note/K FullPeakList,wnote SetDimLabel 1,0,x0,FullPeakList ; SetDimLabel 1,1,y0,FullPeakList SetDimLabel 1,2,x0Err,FullPeakList ; SetDimLabel 1,3,y0Err,FullPeakList SetDimLabel 1,4,fwx,FullPeakList ; SetDimLabel 1,5,fwy,FullPeakList SetDimLabel 1,6,fwxErr,FullPeakList ; SetDimLabel 1,7,fwyErr,FullPeakList SetDimLabel 1,8,correlation,FullPeakList ; SetDimLabel 1,9,correlationErr,FullPeakList SetDimLabel 1,10,area,FullPeakList Variable i Variable px,py, left,right,top,bot Variable Nu=0, Nlen=50 do ImageStats/M=1/R=FitPeaks_ImageMask image // find the highest point if (V_maxthreshold)) // this is a lone pixel image[px][py] = localAvg // set lone pixels to local average, and continue FitPeaks_ImageMask[px][py] = 255 continue endif // fit a gaussian about px,py left = limit(px-dist/2,0,Nx-1) right = limit(px+dist/2,0,Nx-1) top = limit(py-dist/2,0,Ny-1) bot = limit(py+dist/2,0,Ny-1) if (FitOneGaussianPeak(imageName,left,right,top,bot)) // returns 0 == OK, non-zero if error FitPeaks_ImageMask[left,right][top,bot] = 255 // extend the FitPeaks_ImageMask to include this spot continue endif Wave W_coef=W_coef, W_sigma=W_sigma xx = W_coef[2] yy = W_coef[4] fwx = W_coef[3] * fw fwy = W_coef[5] * fw sigX = W_sigma[2] sigY = W_sigma[4] if (fwx>dist || fwy>dist || fwx<1 || fwy<1 || sigX>dist || sigY>dist) // cannot have spots wider than dist FitPeaks_ImageMask[left,right][top,bot] = 255 // extend the FitPeaks_ImageMask to include this spot continue endif // printf "%d %d Gaussian peak in at (%.2f±%.2f, %.2f±%.2f) with FWHM of (%.2f±%.2f, %.2f±%.2f), amp=%g\r",i,Nu,xx,sigX,yy,sigY,fwx,W_sigma[3]*fw,fwy,W_sigma[5]*fw,W_coef[1]*fwx*fwy // check here that the found xx,yy is not too close to existing peaks (if if is stamp out with roi again) for (i=0;i=Nlen) // FullPeakList is too short, extend it Nlen += 50 Redimension/N=(Nlen,11) FullPeakList endif if (printIt) printf "found Gaussian start @ (%d, %d)=%d with left=%.1f, right=%.1f, top=%.1f, bot=%.1f result=(%.3f, %.3f)\r",px,py,image[px][py],left,right,top,bot,xx,yy endif FullPeakList[Nu][0]=xx ; FullPeakList[Nu][1]=yy FullPeakList[Nu][2]=sigX ; FullPeakList[Nu][3]=sigY FullPeakList[Nu][4]=fwx ; FullPeakList[Nu][5]=fwy FullPeakList[Nu][6]=W_sigma[3]*fw ; FullPeakList[Nu][7]=W_sigma[5]*fw FullPeakList[Nu][8]=W_coef[6] ; FullPeakList[Nu][9]=W_sigma[6] FullPeakList[Nu][10]=W_coef[1]*fwx*fwy Nu += 1 FitPeaks_ImageMask[left,right][top,bot] = 255 // extend the FitPeaks_ImageMask to include this spot while(1) Redimension/N=(Nu,11) FullPeakList String/G pkLIst="" String str for (i=0;i0))) String imageName = SelectString(WaveExists(image),"",NameOfWave(image)) fractionBkg = fractionBkg==limit(fractionBkg,1e-3,1) ? fractionBkg : 0.9 dist = dist>0 ? dist : 30 Prompt imageName,"name of image with peaks to find",popup,reverseList(WaveListClass("speImage*","*","DIMS:2")) Prompt fractionBkg,"fraction of image that is background, usually in range [0.7, 0.995]" Prompt dist, "minimum distance (pixels) between any two peaks (use ~30 for unbinned Si)" DoPrompt/Help="3D-Xray Diffraction[Fit Peaks]" "peak fitting",imageName,fractionBkg,dist if (V_flag) return "" endif Wave image = $imageName printf "FitPeaks(%s,%g,%g)\r",imageName,fractionBkg,dist printIt = 1 endif if (!WaveExists(image) || WaveDims(image)!=2 || !(fractionBkg==limit(fractionBkg,1e-3,1) || !(dist>0))) return "" endif Variable timer=startMSTimer // timer2 = startMSTimer Make/N=100/O hist_ SetScale/P x 0,2,"", hist_ Histogram/B=2 image,hist_ // print "\t\tHistogram part took ",stopMSTimer(timer2)/1e6,"sec" Variable i = BinarySearchInterp(hist_, hist_(0)/10) i = numtype(i) ? numpnts(hist_)/2 : i Variable cutOff = pnt2x(hist_,i) // Variable cutOff = pnt2x(hist_,BinarySearchInterp(hist_, hist_(0)/10)) printf "search for peaks above a threshold of %g\r",cutOff // print "cutOff=",cutOff // threshold in image wave for finding peaks // timer2 = startMSTimer Duplicate/O image,FitPeaks_mask_bigger ImageThreshold/O/Q/I/T=(cutOff)/M=0 FitPeaks_mask_bigger // print "\t\tmaking mask part took ",stopMSTimer(timer2)/1e6,"sec" DoUpdate // timer2 = startMSTimer Variable id = dist>20 ? 5 : 1 // Imagemorphology/O/E=5 BinaryDilation FitPeaks_mask_bigger Imagemorphology/O/E=(id) BinaryDilation FitPeaks_mask_bigger // print "\t\tImagemorphology part took ",stopMSTimer(timer2)/1e6,"sec" // timer2 = startMSTimer ImageAnalyzeParticles/A=5/M=3/Q stats FitPeaks_mask_bigger KillWaves/Z M_RawMoments,M_Particle Sort/R W_ImageObjArea,W_ImageObjArea,W_SpotX,W_SpotY,W_circularity,W_rectangularity,W_ImageObjPerimeter,W_xmin,W_xmax,W_ymin,W_ymax // print "\t\tImageAnalyzeParticles part took ",stopMSTimer(timer2)/1e6,"sec" // timer2 = startMSTimer i = reFit_GaussianPkList(image,dist) // print "\t\t refitting the peaks took ",stopMSTimer(timer2)/1e6,"sec" Variable sec0=stopMSTimer(timer)/1e6 if (printIt) printf "fitted %d peaks, this all took %g sec\r",i,sec0 printf " result stored in the wave '%s'\r", GetWavesDataFolder(image,2) endif Wave FullPeakList=FullPeakList KillWaves/Z hist_, W_sigma,W_coef,W_ParamConfidenceInterval, FitPeaks_mask_bigger KillWaves/Z W_xmin,W_xmax,W_ymin,W_ymax,W_circularity,W_rectangularity,W_ImageObjPerimeter,W_ImageObjArea,W_SpotX,W_SpotY return GetWavesDataFolder(image,2) End // remove bkg from an image, identify the peaks, and fit them all Function/S OLD_removeBkg_FitPeaks(rawImage,fractionBkg,dist) Wave rawImage // the raw image from the spe file Variable fractionBkg // fraction of image that is background, use something like 0.99 or 0.995 (even 0.7 works OK) Variable dist // minimum distance between spots, spots have to be at least this far apart (pixels) Variable printIt = ItemsInList(GetRTStackInfo(0))<2 if (!WaveExists(rawImage) || WaveDims(rawImage)!=2 || !(fractionBkg==limit(fractionBkg,1e-3,1) || !(dist>0))) String imageName = SelectString(WaveExists(rawImage),"",NameOfWave(rawImage)) fractionBkg = fractionBkg==limit(fractionBkg,1e-3,1) ? fractionBkg : 0.8 dist = dist>0 ? dist : 30 // Prompt imageName,"name of image with peaks to find",popup,WaveList("*",";","DIMS:2") // Prompt imageName,"name of image with peaks to find",popup,WaveList_Tags("imageFileName","rawIgorImage","*","DIMS:2") Prompt imageName,"name of image with peaks to find",popup,reverseList(WaveListClass("speImage","*","DIMS:2")) Prompt fractionBkg,"fraction of image that is background, usually in range [0.7, 0.995]" Prompt dist, "minimum distance (pixels) between any two peaks (use ~30 for unbinned Si)" DoPrompt/Help="3D-Xray Diffraction[Fit Peaks]" "peak fitting",imageName,fractionBkg,dist if (V_flag) return "" endif Wave rawImage = $imageName printf "FitPeaks(%s,%g,%g)\r",imageName,fractionBkg,dist printIt = 1 endif if (!WaveExists(rawImage) || WaveDims(rawImage)!=2 || !(fractionBkg==limit(fractionBkg,1e-3,1) || !(dist>0))) return "" endif // Variable timer=startMSTimer Variable timer0=startMSTimer Variable thresh = numpnts(rawImage)*fractionBkg WaveStats/Q/M=1 rawImage Make/N=200/D/O FitPeaks_Hist Variable i for (i=-1;i<10 || numtype(i);) // keep expanding the histogram range while i<10, I want i to be bigger than 10 SetScale/I x,V_min,V_max,"",FitPeaks_Hist // lower high end of histogram to zoom in around zero Histogram/B=2 rawImage,FitPeaks_Hist Integrate/P FitPeaks_Hist/D=FitPeaks_Hist_INT // integrate the histogram i=BinarySearchInterp(FitPeaks_Hist_INT,thresh) // find point where FitPeaks_Hist_INT[i] == thresh V_max = numtype(i) ? V_max/2 : pnt2x(FitPeaks_Hist_INT,i+4) endfor // print "first part took ",stopMSTimer(timer)/1e6,"sec" // timer = startMSTimer thresh = DimDelta(FitPeaks_Hist,0)*i + DimOffset(FitPeaks_Hist,0) ImageThreshold/Q/T=(thresh)/M=0 rawImage // create M_ImageThresh Wave M_ImageThresh=M_ImageThresh ImageStats/M=1 M_ImageThresh Variable fracBlack = V_avg*V_npnts/255/V_npnts // printf "number of points in peak is %d out of %d points (%.2f%%)\r",fracBlack*V_npnts,V_npnts,fracBlack*100 Make/N=(9,9)/O/B/U black black = 255 for(;fracBlack<0.10;) // loop until fracBlack is atleast 10% Imagemorphology/S=black/O BinaryDilation M_ImageThresh ImageThreshold/Q/T=(2)/M=0 M_ImageThresh ImageStats/M=1 M_ImageThresh fracBlack = V_avg*V_npnts/255/V_npnts // printf "number of points in peak is %d out of %d points (%.2f%%)\r",fracBlack*V_npnts,V_npnts,fracBlack*100 endfor ImageTransform/O invert M_ImageThresh // M_ImageThresh = !M_ImageThresh // print "second part took ",stopMSTimer(timer)/1e6,"sec" // timer = startMSTimer // Variable timer2 = startMSTimer ImageInterpolate /f={.125,.125} bilinear rawImage Redimension/S M_InterpolatedImage KillWaves/Z FitPeaks_rawImage_smaller Rename M_InterpolatedImage FitPeaks_rawImage_smaller // make a source image using fewer pixels // print "\t\t1st interpolate part took ",stopMSTimer(timer2)/1e6,"sec" // timer2 = startMSTimer ImageInterpolate /f={.125,.125} bilinear M_ImageThresh // make a mask with fewer pixels KillWaves/Z FitPeaks_mask_smaller Rename M_InterpolatedImage FitPeaks_mask_smaller Redimension/B/U FitPeaks_mask_smaller ImageRemoveBackground/F/R=FitPeaks_mask_smaller/P=2/W FitPeaks_rawImage_smaller // creates M_RemovedBackground, uses 3rd order polynomial Wave W_BackgroundCoeff=W_BackgroundCoeff // print W_BackgroundCoeff // print "\t\t2nd interpolate part took ",stopMSTimer(timer2)/1e6,"sec" // timer2 = startMSTimer ImageInterpolate /f={8,8} bilinear M_RemovedBackground // creates M_InterpolatedImage, a bkg with full number of pixels Wave M_InterpolatedImage=M_InterpolatedImage String outName = NameOfWave(rawImage)+"NoBkg" String fldr = GetWavesDataFolder(rawImage,1) if (CheckName(fldr+outName,1)) outName = CleanupName(outName,0) endif outName = fldr+outName Duplicate/O rawImage $outName Wave noBkg = $outName String wnote=ReplaceStringByKey("rawIgorImage",note(rawImage),GetWavesDataFolder(rawImage,2),"=") wnote = ReplaceNumberByKey("fractionBkg",wnote,fractionBkg,"=") wnote = ReplaceNumberByKey("minSpotSeparation",wnote,dist,"=") wnote = ReplaceStringByKey("waveClass",wnote,"speImageNoBkg","=") Note/K noBkg, wnote Redimension/I noBkg // signed int32 version of rawImage noBkg = rawImage - M_InterpolatedImage[p][q] // p,q because M_InterpolatedImage is smaller // print "\t\t",DimSize(rawImage,0),DimSize(rawImage,1) // print "\t\t",DimSize(noBkg,0),DimSize(noBkg,1) // print "\t\t",DimSize(M_InterpolatedImage,0),DimSize(M_InterpolatedImage,1) // print "\t\t3rd interpolate part took ",stopMSTimer(timer2)/1e6,"sec" // timer2 = startMSTimer Make/N=100/O hist_ SetScale/P x 0,2,"", hist_ Histogram/B=2 noBkg,hist_ // print "\t\tHistogram part took ",stopMSTimer(timer2)/1e6,"sec" i = BinarySearchInterp(hist_, hist_(0)/10) i = numtype(i) ? numpnts(hist_)/2 : i Variable cutOff = pnt2x(hist_,i) // Variable cutOff = pnt2x(hist_,BinarySearchInterp(hist_, hist_(0)/10)) printf "after background removal search for peaks above a threshold of %g\r",cutOff // print "cutOff=",cutOff // threshold in NoBkg wave for finding peaks // timer2 = startMSTimer Duplicate/O noBkg,FitPeaks_mask_bigger ImageThreshold/O/Q/I/T=(cutOff)/M=0 FitPeaks_mask_bigger // print "\t\tmaking mask part took ",stopMSTimer(timer2)/1e6,"sec" DoUpdate // timer2 = startMSTimer Variable id = dist>20 ? 5 : 1 // Imagemorphology/O/E=5 BinaryDilation FitPeaks_mask_bigger Imagemorphology/O/E=(id) BinaryDilation FitPeaks_mask_bigger // print "\t\tImagemorphology part took ",stopMSTimer(timer2)/1e6,"sec" // timer2 = startMSTimer ImageAnalyzeParticles/A=5/M=3/Q stats FitPeaks_mask_bigger KillWaves/Z M_RawMoments,M_Particle Sort/R W_ImageObjArea,W_ImageObjArea,W_SpotX,W_SpotY,W_circularity,W_rectangularity,W_ImageObjPerimeter,W_xmin,W_xmax,W_ymin,W_ymax // print "\t\tImageAnalyzeParticles part took ",stopMSTimer(timer2)/1e6,"sec" // timer2 = startMSTimer i = reFit_GaussianPkList(noBkg,dist) // print "\t\t refitting the peaks took ",stopMSTimer(timer2)/1e6,"sec" // print "fancy part took ",stopMSTimer(timer)/1e6,"sec" Variable sec0=stopMSTimer(timer0)/1e6 if (printIt) printf "found and fitted %d peaks, this all took %g sec\r",i,sec0 // print "peak finding and fitting all took ",sec0,"sec" printf " result stored in the wave '%s'\r", GetWavesDataFolder(noBkg,2) endif Wave FullPeakList=FullPeakList KillWaves/Z hist_, W_sigma,W_coef,W_ParamConfidenceInterval KillWaves/Z FitPeaks_rawImage_smaller,FitPeaks_mask_smaller, M_ImageThresh, M_RemovedBackground, M_InterpolatedImage, W_BackgroundCoeff KillWaves/Z FitPeaks_Hist_INT,FitPeaks_Hist, black, FitPeaks_mask_bigger KillWaves/Z W_xmin,W_xmax,W_ymin,W_ymax,W_circularity,W_rectangularity,W_ImageObjPerimeter,W_ImageObjArea,W_SpotX,W_SpotY return GetWavesDataFolder(noBkg,2) End // Fit every peak from the output of ImageAnalyzeParticles, it sets the string pkList based on the fits // it also sets FullPeakList[][11] which contains the exact info about the fit of each peak Static Function reFit_GaussianPkList(image,dist) Wave image Variable dist // minimum distance between spots (pixels) Wave W_spotX=W_spotX, W_spotY=W_spotY Wave W_xmin=W_xmin, W_xmax=W_xmax, W_ymin=W_ymin, W_ymax=W_ymax if (exists("pkLIst")!=2) String/G pkLIst="" endif SVAR pkList = pkList pkList = "" String str String imageName = GetWavesDataFolder(image,2) Variable Nx=DimSize(image,0), Ny=DimSize(image,1) Variable j,i,N=numpnts(W_spotX),err Variable fw= ( 2*sqrt(2*ln(2)) ) // this factor corrects for 2-d sigma to FWHM, apply to K3, K5, and the corresponding errors Variable fwx,fwy,sigX,sigY Variable xx,yy, tooClose, Nu=0 Variable left,right,top,bot Make/N=(N,11)/O FullPeakList String wnote = ReplaceStringByKey("fittedIgorImage",note(image),GetWavesDataFolder(image,2),"=") wnote = ReplaceStringByKey("waveClass",wnote,"FittedPeakList","=") Note/K FullPeakList,wnote SetDimLabel 1,0,x0,FullPeakList ; SetDimLabel 1,1,y0,FullPeakList SetDimLabel 1,2,x0Err,FullPeakList ; SetDimLabel 1,3,y0Err,FullPeakList SetDimLabel 1,4,fwx,FullPeakList ; SetDimLabel 1,5,fwy,FullPeakList SetDimLabel 1,6,fwxErr,FullPeakList ; SetDimLabel 1,7,fwyErr,FullPeakList SetDimLabel 1,8,correlation,FullPeakList ; SetDimLabel 1,9,correlationErr,FullPeakList SetDimLabel 1,10,area,FullPeakList FullPeakList = NaN for (i=0;idist || fwy>dist || fwx<1 || fwy<1 || sigX>dist || sigY>dist) // cannot have spots wider than dist continue endif // printf "%d %d Gaussian peak in at (%.2f±%.2f, %.2f±%.2f) with FWHM of (%.2f±%.2f, %.2f±%.2f), amp=%g\r",i,Nu,xx,sigX,yy,sigY,fwx,W_sigma[3]*fw,fwy,W_sigma[5]*fw,W_coef[1]*fwx*fwy tooClose = 0 // check that this spot is not too close to another already included for (j=0;j0)) String wList = reverseList(WaveListClass("speImage*","*","DIMS:2")), wName="" Prompt dist,"minimum distance between peaks (pixels)" Prompt wName,"Indexed Peak List",popup,wList if (dist>0 && ItemsInList(wList)==1) // only need image, and there is only one image Wave image = $(StringFromList(0,wList)) else if (dist>0) // only need image, and need to ask DoPrompt "image to use",wName Wave image = $wName elseif (WaveExists(image)) // only need dist DoPrompt "dist between peakst",dist else // need both image and dist DoPrompt "image to use",wName,dist Wave image = $wName endif if (V_flag) return 0 endif endif sprintf str, "setFittedPeaksFromList(%s,%g,\"%s\")",GetWavesDataFolder(image,2),dist,peaks print str[0,390] endif if (!WaveExists(image) || !(dist>0)) return 0 endif if (exists("pkLIst")!=2) String/G pkLIst="" endif SVAR pkList = pkList pkList = "" String imageName = GetWavesDataFolder(image,2) Variable Nx=DimSize(image,0), Ny=DimSize(image,1) Variable j,i,N=ItemsInList(peaks),err,xx,yy Make/N=(N)/O peakxx_,peakyy_,peakInt_ // re-order the points by peak intensity for (i=0;idist*2 || fwy>dist*2 || fwx<1 || fwy<1 || sigX>dist || sigY>dist) // cannot have spots wider than 2*dist continue endif for (j=0,tooClose=0;j0) // check for a valid Q wenge2IdealBeamline(geo,qhat,qBL) Qs[m][0,2] = qBL[q] Qs[m][3] = FullPeakList[i][10] // the intensity m += 1 endif endfor KillWaves/Z FullPeakList2Qfile_qhat, FullPeakList2Qfile_qBL N = m Variable refNum Open/C="R*ch"/P=$pathName/T="TEXT" refNum as fname if (!strlen(S_fileName)) DoAlert 0, "Cannot open file '"+fname+"'" KillWaves/Z FullPeakList2Qfile_Q return 1 endif String str Variable val fprintf refNum,"$PeaksFile\n" fprintf refNum,"$latticeParameters { %g, %g, %g, %g, %g, %g }// using nm and degrees\n",xtal.a,xtal.b,xtal.c,xtal.alpha,xtal.beta,xtal.gam fprintf refNum,"$lengthUnit nm // length unit for lattice constants a,b,c\n" fprintf refNum,"$SpaceGroup %d // Structure number from International Tables\n",xtal.SpaceGroup fprintf refNum,"$latticeStructure %d // Structure number from International Tables\n",xtal.SpaceGroup // if (WhichListItem("IndexLots",GetRTStackInfo(0))<0 && WhichListItem("FillMovieOfOneScan",GetRTStackInfo(0))<0) if (WhichListItem("FullPeakList2Qfile",GetRTStackInfo(0))<=2 || WhichListItem("IndexButtonProc",GetRTStackInfo(0))>=0) DoAlert 0, "remember to remove the '$latticeStructure' in FullPeakList2Qfile()" endif // fprintf refNum,"$SpaceGroup %d // Structure number from International Tables\n",xtal.SpaceGroup str = StringByKey("imageFileName",wnote,"=") if (strlen(str)) fprintf refNum,"$imageFileName %s // name of image file read in by Igor\n",str endif fprintf refNum,"$peakListWave %s // Igor wave containng list of peak positions\n",GetWavesDataFolder(FullPeakList,2) val = NumberByKey("exposure",wnote,"=") if (!numtype(val)) fprintf refNum,"$exposure %g // CCD exposure of original image (sec)\n",val endif str = StringByKey("dateExposed",wnote,"=") if (strlen(str)) fprintf refNum,"$dateExposed %s // date of original CCD image\n",str endif str = StringByKey("rawIgorImage",wnote,"=") if (strlen(str)) fprintf refNum,"$rawIgorImage %s // name of Igor image wave\n",str endif str = StringByKey("fittedIgorImage",wnote,"=") if (strlen(str)) fprintf refNum,"$fittedIgorImage %s // name of flattened Igor image wave used to fit peaks\n",str endif val = NumberByKey("fractionBkg",wnote,"=") if (!numtype(val)) fprintf refNum,"$fractionBkg %g // in peak analysis, the given fraction of image that is bkg\n",val endif val = NumberByKey("minSpotSeparation",wnote,"=") if (!numtype(val)) fprintf refNum,"$minSpotSeparation %g // in peak analysis, min separaion between spots (pixels)\n",val endif val = NumberByKey("minPeakWidth",wnote,"=") if (!numtype(val)) fprintf refNum,"$minPeakWidth %g // in peak analysis, min allowed fwhm for a spot (pixels)\n",val endif val = NumberByKey("maxPeakWidth",wnote,"=") if (!numtype(val)) fprintf refNum,"$maxPeakWidth %g // in peak analysis, max allowed fwhm for a spot (pixels)\n",val endif val = NumberByKey("totalPeakIntensity",wnote,"=") if (!numtype(val)) fprintf refNum,"$totalPeakIntensity %g // sum of the areas of all fitted peaks\n",val endif val = NumberByKey("totalIntensity",wnote,"=") if (!numtype(val)) fprintf refNum,"$totalIntensity %g // sum of all the intensity in the image\n",val endif val = NumberByKey("startx",wnote,"=") // write the ROI of the image if (!numtype(val)) fprintf refNum,"$startx %g // ROI of the SPE file\n",val endif val = NumberByKey("groupx",wnote,"=") if (!numtype(val)) fprintf refNum,"$groupx %g\n",val endif val = NumberByKey("starty",wnote,"=") if (!numtype(val)) fprintf refNum,"$starty %g\n",val endif val = NumberByKey("groupy",wnote,"=") if (!numtype(val)) fprintf refNum,"$groupy %g\n",val endif fprintf refNum,"\n// the following table contains xyz compotnents of G^ and the integral of the peak\n" fprintf refNum,"$N_Ghat+Intens %d // number of G^ vectors\n",N for (i=0;i0) // check for a valid Q // Qs[m][0,2] = qhat[q] // Qs[m][3] = FullPeakList[i][10] // the intensity // m += 1 // endif // endfor // N = m // // Variable refNum // Open/C="R*ch"/P=home/T="TEXT" refNum as fname // if (!strlen(S_fileName)) // DoAlert 0, "Cannot open file '"+fname+"'" // KillWaves/Z FullPeakList2Qfile_Q, FullPeakList2Qfile_qhat // return 1 // endif // //// String str, wnote=note(FullPeakList) // String str // Variable val // fprintf refNum,"$PeaksFile\n" // fprintf refNum,"$latticeParameters { %g, %g, %g, %g, %g, %g }// using nm and degrees\n",xtal.a,xtal.b,xtal.c,xtal.alpha,xtal.beta,xtal.gam // fprintf refNum,"$lengthUnit nm // length unit for lattice constants a,b,c\n" // fprintf refNum,"$SpaceGroup %d // Structure number from International Tables\n",xtal.SpaceGroup // str = StringByKey("imageFileName",wnote,"=") // if (strlen(str)) // fprintf refNum,"$imageFileName %s // name of image file read in by Igor\n",str // endif // val = NumberByKey("exposure",wnote,"=") // if (!numtype(val)) // fprintf refNum,"$exposure %g // CCD exposure of original image (sec)\n",val // endif // str = StringByKey("dateExposed",wnote,"=") // if (strlen(str)) // fprintf refNum,"$dateExposed %s // date of original CCD image\n",str // endif // str = StringByKey("rawIgorImage",wnote,"=") // if (strlen(str)) // fprintf refNum,"$rawIgorImage %s // name of Igor image wave\n",str // endif // str = StringByKey("fittedIgorImage",wnote,"=") // if (strlen(str)) // fprintf refNum,"$fittedIgorImage %s // name of flattened Igor image wave used to fit peaks\n",str // endif // val = NumberByKey("fractionBkg",wnote,"=") // if (!numtype(val)) // fprintf refNum,"$fractionBkg %g // in peak analysis, the given fraction of image that is bkg\n",val // endif // val = NumberByKey("minSpotSeparation",wnote,"=") // if (!numtype(val)) // fprintf refNum,"$minSpotSeparation %g // in peak analysis, min separaion between spots (pixels)\n",val // endif // val = NumberByKey("startx",wnote,"=") // write the ROI of the image // if (!numtype(val)) // fprintf refNum,"$startx %g // ROI of the SPE file\n",val // endif // val = NumberByKey("groupx",wnote,"=") // if (!numtype(val)) // fprintf refNum,"$groupx %g\n",val // endif // val = NumberByKey("starty",wnote,"=") // if (!numtype(val)) // fprintf refNum,"$starty %g\n",val // endif // val = NumberByKey("groupy",wnote,"=") // if (!numtype(val)) // fprintf refNum,"$groupy %g\n",val // endif // // fprintf refNum,"\n// the following table contains xyz compotnents of G^ and the integral of the peak\n" // fprintf refNum,"$N_Ghat+Intens %d // number of G^ vectors\n",N // for (i=0;i0) DoWindow/F $table return 0 endif Edit/K=1/W=(5,44,891,684) w.ld ModifyTable width(Point)=30,title(w.d)="Fitted Peaks",width(w.l)=20 ModifyTable format(w.d)=3,width(w.d)=74 End Function TableFullPeakIndexed(w) Wave w if (!WaveExists(w)) String list = reverseList(WaveListClass("IndexedPeakList","*","")) Variable i = ItemsInLIst(list) if (i<1) DoAlert 0, "No waves of this type in current folder" return 1 elseif (i==1) Wave w = $StringFromList(0,list) else String wName = StringFromList(i-1,list) Prompt wName, "Wave with list of indexed peaks",popup,list DoPrompt "FullPeakIndexed",wName if (V_flag) return 1 endif Wave w = $wName endif if (!WaveExists(w)) DoAlert 0, "No waves of name "+wName return 1 endif endif String table = FindTableWithWave(w) if (strlen(table)>0) DoWindow/F $table return 0 endif Edit/K=1/W=(5,44,891,684) w.ld ModifyTable width(Point)=30,title(w.d)="Indexed Peaks",width(w.l)=20 ModifyTable format(w.d)=3,width(w.d)=74 End Function TableFullPeakStrain(w) Wave w if (!WaveExists(w)) String list = reverseList(WaveListClass("StrainPeakList","*","")) Variable i = ItemsInLIst(list) if (i<1) DoAlert 0, "No waves of this type in current folder" return 1 elseif (i==1) Wave w = $StringFromList(0,list) else String wName = StringFromList(i-1,list) Prompt wName, "Wave with list of indexed peaks",popup,list DoPrompt "FullPeakIndexed",wName if (V_flag) return 1 endif Wave w = $wName endif if (!WaveExists(w)) DoAlert 0, "No waves of name "+wName return 1 endif endif String table = FindTableWithWave(w) if (strlen(table)>0) DoWindow/F $table return 0 endif Edit/K=1/W=(5,44,1035,681) w.ld ModifyTable width(Point)=30,title(w.d)="Strain Peaks",width(w.l)=20 ModifyTable format(w.d)=3,width(w.d)=74 End // find hkl that is paralllel to the input and allowed Static Function CloseAllowedhkl(SpaceGroup,in,out) Wave in,out // input and output hkl Variable SpaceGroup // Space Group number from International tables out = abs(round(in*60)/60) out = out[p]>0 ?out[p] : Inf WaveStats/Q/M=1 out Variable minh = abs(in[V_minloc]) // smallest non-zero value, e.g. for {0,2,7}, minh=2 out = round(in[p]/minh*12) out = out[p]==0 ? 0 : out[p] // get rid of "-0" Variable h=out[0], k=out[1], l=out[2] lowestAllowedHKL(h,k,l,SpaceGroup) // convert hkl to allowed reflection out = {h,k,l} return 0 End Function EnergyOfhkl(FullPeakIndexed,pattern,h,k,l) Wave FullPeakIndexed Variable pattern Variable h,k,l Variable i if (!WaveExists(FullPeakIndexed)) String wList = reverseList(WaveListClass("IndexedPeakList","*","")) i = ItemsInList(wList) if (i==1) // only one, so choose it Wave FullPeakIndexed = $(StringFromList(0,wList)) elseif(i>0) // more than 1, so ask String wName="" Prompt wName,"Indexed Peak List",popup,wList DoPrompt "Indexed Peak List",wName if (V_flag) return NaN endif Wave FullPeakIndexed = $wName endif endif if (!WaveExists(FullPeakIndexed)) DoAlert 0, "cannot find wave of indexed peak information 'FullPeakIndexed'" return NaN endif Variable Np = max(DimSize(FullPeakIndexed,2),1) pattern = (Np==1) ? 0 : pattern // need to fix this so it takes the user data from the graph, not the panel if (numtype(pattern)) pattern = NumberByKey("patternNum",Getuserdata("","","Indexing"),"=") endif if (Np>1 && (pattern<0 || pattern>=Np || numtype(pattern))) pattern = pattern>=0 ? pattern : 0 Prompt pattern, "pattern to choose [0,"+num2istr(Np-1)+",]",popup,expandRange("0-"+num2istr(Np-1),";") DoPrompt "pattern number",pattern if (V_flag || !(pattern>=0)) return NaN endif pattern -= 1 endif pattern = pattern>=0 ? pattern : 0 if (numtype(h+k+l)) Prompt h, "H" Prompt k, "K" Prompt l, "L" DoPrompt "(hkl)",h,k,l if (V_flag || numtype(h+k+l)) return NaN endif endif if (numtype(h+k+l)) return NaN endif Variable d // d-spacing Variable as0,as1,as2 // componenets of a* Variable bs0,bs1,bs2 // componenets of b* Variable cs0,cs1,cs2 // componenets of c* Make/N=3/O/D EnergyOfhkl_qvec,EnergyOfhkl_ki={0,0,1} Wave qvec=EnergyOfhkl_qvec, ki=EnergyOfhkl_ki String recip_lattice = StringByKey("recip_lattice"+num2istr(pattern),note(FullPeakIndexed),"=") // the starting point sscanf recip_lattice, "{{%g,%g,%g}{%g,%g,%g}{%g,%g,%g}}",as0,as1,as2,bs0,bs1,bs2,cs0,cs1,cs2 if (V_flag!=9) DoAlert 0, "Unable to read recip_lattice" return NaN endif qvec[0] = h*as0 + k*bs0 + l*cs0 qvec[1] = h*as1 + k*bs1 + l*cs1 qvec[2] = h*as2 + k*bs2 + l*cs2 d = 2*PI/normalize(qvec) Variable sineTheta = -MatrixDot(qvec,ki) // sin(theta) = -ki dot qhat Variable keV = hc/(2*d*sineTheta) // energy if (ItemsInList(GetRTStackInfo(0))<2 || stringmatch(StringFromList(0,GetRTStackInfo(0)),"IndexButtonProc")) Variable px=NaN, py=NaN STRUCT microGeometry geo if (!FillGeometryStructDefault(geo)) //fill the geometry structure with test values String wnote = note(qvec) Variable startx,groupx, starty,groupy startx = NumberByKey("startx",wnote,"=") groupx = NumberByKey("groupx",wnote,"=") starty = NumberByKey("starty",wnote,"=") groupy = NumberByKey("groupy",wnote,"=") startx = numtype(startx) ? 1 : startx groupx = numtype(groupx) ? 1 : groupx starty = numtype(starty) ? 1 : starty groupy = numtype(groupy) ? 1 : groupy IdealBeamLine2wenge(geo,qvec,qvec) Variable/C pz = q2pixel(geo,qvec) px = (real(pz)-(startx-1)-(groupx-1)/2)/groupx // change to binned pixels py = (imag(pz)-(starty-1)-(groupy-1)/2)/groupy // pixels are still zero based endif printf "for %s pattern #%d, d[(%s)] = %.9g nm, E(%s) = %.4f keV (theta=%.3f¡)",NameOfWave(FullPeakIndexed),pattern,hkl2str(h,k,l),d,hkl2str(h,k,l),keV,asin(sineTheta)*180/PI if (numtype(px+py)==0) printf " should be at pixel [%.2f, %.2f]",px,py endif printf "\r" endif KillWaves/Z EnergyOfhkl_qvec, EnergyOfhkl_ki return keV End // find angle between two Qvectors from points on an image Function AngleBetweenTwoPoints(image,px0,py0,px1,py1) Wave image Variable px0,py0 // first pixel (in binning of image) Variable px1,py1 // second pixel (in binning of image) Variable printIt = (ItemsInList(GetRTStackInfo(0))<2) if (!WaveExists(image)) // use image on top graph if not passed Wave image = ImageNameToWaveRef("",StringFromList(0,ImageNameList("",";"))) endif if (!WaveExists(image)) if (printIt) DoAlert 0, "could not find the image" endif return 1 endif if (numtype(px0+py0+px1+py1)) // bad pixels, use cursors A and B String infoA=CsrInfo(A), infoB=CsrInfo(B) if (strlen(infoA)>1 && strlen(infoB)>1) px0 = hcsr(A) ; py0 = vcsr(A) px1 = hcsr(B) ; py1 = vcsr(B) endif endif if (numtype(px0+py0+px1+py1)) // bad pixels, use cursors A and B if (printIt) DoAlert 0, "could not get the two pixel positions" endif return 1 endif STRUCT microGeometry geo if (FillGeometryStructDefault(geo)) //fill the geometry structure with test values if (printIt) DoAlert 0, "no geometry structure found, did you forget to set it?" endif return 1 endif String wnote = note(image) Variable startx,groupx, starty,groupy // ROI of the original image startx = NumberByKey("startx",wnote,"=") groupx = NumberByKey("groupx",wnote,"=") starty = NumberByKey("starty",wnote,"=") groupy = NumberByKey("groupy",wnote,"=") startx = numtype(startx) ? 1 : startx groupx = numtype(groupx) ? 1 : groupx starty = numtype(starty) ? 1 : starty groupy = numtype(groupy) ? 1 : groupy Make/N=3/O/D AngleBetweenTwoPoints_qhat1, AngleBetweenTwoPoints_qhat2 Wave qhat1=AngleBetweenTwoPoints_qhat1, qhat2=AngleBetweenTwoPoints_qhat2 Variable angle // angle between points (degree) Variable px,py px = (startx-1) + groupx*px0 + (groupx-1)/2 // change to un-binned pixels py = (starty-1) + groupy*py0 + (groupy-1)/2 // pixels are still zero based pixel2q(geo,px,py,qhat1) // in Wenge-coord system px = (startx-1) + groupx*px1 + (groupx-1)/2 // change to un-binned pixels py = (starty-1) + groupy*py1 + (groupy-1)/2 // pixels are still zero based pixel2q(geo,px,py,qhat2) // in Wenge-coord system Variable cosine = limit(MatrixDot(qhat1,qhat2),-1,1) KillWaves/Z AngleBetweenTwoPoints_qhat1, AngleBetweenTwoPoints_qhat2 angle = acos(cosine)*180/PI if (printIt) printf "Between points [%.2f, %.2f], and [%.2f, %.2f] the angle between Q vectors is %.3f¡\r",px0,py0,px1,py1,angle endif return angle End // if the image cannot be found in existing graphs, it returns empty string Function/S FindGraphWithImage(image) // find the graph window which contains the specified image Wave image if (!WaveExists(image)) return "" endif String name, name0=GetWavesDataFolder(image,2) String ilist, win,wlist = WinList("*",";","WIN:1") Variable i,Ni, m,Nm=ItemsInList(wlist) for (m=0;m2) // coords must be 1, 2, or 3 return "" endif Wave FullPeakList=FullPeakList, FullPeakIndexed=FullPeakIndexed if (!WaveExists(FullPeakList) || !WaveExists(FullPeakIndexed)) return "" endif STRUCT microGeometry geo if (FillGeometryStructDefault(geo)) //fill the geometry structure with test values DoAlert 0, "no geometry structure found, did you forget to set it?" return "" endif Variable printIt=0, patternMax=DimSize(FullPeakIndexed,2)-1 if (patternMax>0 && !(pattern>=0 && pattern<=patternMax)) // need to ask for the pattern number pattern = limit(pattern, 0, patternMax ) Prompt pattern, "indexed pattern number to refine [0,"+num2istr(patternMax)+"]" DoPrompt "pattern num",pattern if (V_flag) return "" endif else pattern = 0 // only one pattern is present, just use it endif Variable N=DimSize(FullPeakIndexed,0) printIt = printIt || ((ItemsInList(GetRTStackInfo(0))<2) || stringmatch(StringFromList(0,GetRTStackInfo(0)),"IndexButtonProc")) KillWaves/Z epsilon,epsilonXHF,epsilonSample if (N0) printf "For pattern %d of [0, %d]\r",pattern,patternMax endif printf "starting reciprocal lattice, a* = {%+.6f, %+.6f, %+.6f} (1/nm)\r",as0,as1,as2 printf " b* = {%+.6f, %+.6f, %+.6f}\r",bs0,bs1,bs2 printf " c* = {%+.6f, %+.6f, %+.6f}\r",cs0,cs1,cs2 endif Make/N=3/O/D qhat_PeaksForStrain, qhat_PeaksForStrain2 Wave qhat = qhat_PeaksForStrain Wave qhat2 = qhat_PeaksForStrain2 Make/N=(N,14)/O/D PeaksForStrain=NaN SetDimLabel 1,0,h,PeaksForStrain ; SetDimLabel 1,1,k,PeaksForStrain ; SetDimLabel 1,2,l,PeaksForStrain SetDimLabel 1,3,fitQx,PeaksForStrain ; SetDimLabel 1,4,fitQy,PeaksForStrain ; SetDimLabel 1,5,fitQz,PeaksForStrain SetDimLabel 1,6,indexQx,PeaksForStrain ; SetDimLabel 1,7,indexQy,PeaksForStrain ; SetDimLabel 1,8,indexQz,PeaksForStrain SetDimLabel 1,9,fit_Intens,PeaksForStrain; SetDimLabel 1,10,keV,PeaksForStrain SetDimLabel 1,11,pixelX,PeaksForStrain; SetDimLabel 1,12,pixelY,PeaksForStrain; SetDimLabel 1,13,angErr,PeaksForStrain PeaksForStrain[][0,2] = FullPeakIndexed[p][q+3][pattern] // set the hkl String wnote = ReplaceNumberByKey("patternNum","",pattern,"=") wnote = ReplaceNumberByKey("cslen",wnote,norm(cstar),"=") wnote = ReplaceNumberByKey("cs2",wnote,cs2,"=") wnote = ReplaceStringByKey("waveClass",wnote,"StrainPeakList","=") Note/K PeaksForStrain,wnote Variable Nj=DimSize(Qs,0), cosMax, jmax, dot // find the measured peak that goes with each indexed peak (in Q^) Variable i,j,m, h,k,l for (i=0,m=0;icosMax) cosMax = dot jmax = j endif endfor if (jmax>=0) qhat2 = Qs[jmax][p] // closest fitted peak to this hkl normalize(qhat2) PeaksForStrain[m][3,5] = qhat2[q-3] // store fitted q^, and its intensity PeaksForStrain[m][9] = Qs[jmax][3] m += 1 endif endfor N = m KillWaves/Z qhat_PeaksForStrain2 Redimension/N=(N,14) PeaksForStrain if (N XHF coordinates (45¡ about X) rho = 0 rho[0][0] = 1 rho[1,2][1,2] = 1/sqrt(2) rho[2][1] *= -1 MatrixOp/O epsilonXHF = rho x epsilon x Inv(rho) // get epsilon in the XHF coordinate system rho[2][1] *= 1/sqrt(2) // now rho transforms BL --> "sample system" (uses outward surface normal for sample at 45¡) rho[1][2] *= 1/sqrt(2) MatrixOp/O epsilonSample = rho x epsilon x Inv(rho) // get epsilon in the Sample coordinate system KillWaves/Z rho Variable startx,groupx, starty,groupy startx = NumberByKey("startx",note(FullPeakIndexed),"=") groupx = NumberByKey("groupx",note(FullPeakIndexed),"=") starty = NumberByKey("starty",note(FullPeakIndexed),"=") groupy = NumberByKey("groupy",note(FullPeakIndexed),"=") startx = numtype(startx) ? 1 : startx groupx = numtype(groupx) ? 1 : groupx starty = numtype(starty) ? 1 : starty groupy = numtype(groupy) ? 1 : groupy Variable/C pz Variable sine, d, keV Make/N=3/O/D fithat_PeaksForStrain Wave fithat = fithat_PeaksForStrain for (i=0;i 1e-15 ? 1 : 0 // print diagCheck // // end of chek String wName = UniqueName("sqrtMat",1,0) Duplicate/O symmetricMat $wName Wave D = $wName // holds the diagonal wave D = (p==q) ? sqrt(eigenValues[p]) : 0 // put sqrt(eigen values) on the diagonal MatrixOp/O symmetricMat = V x D x Inv(V) // transform back, putting root into original matrix KillWaves/Z W_eigenValues, M_eigenVectors, D return 0 End // // returns mismatch between the given reciprocal lattice and the measured spots Function latticeMismatch(PeaksForStrain,as0,as1,as2,bs0,bs1,bs2,cs0,cs1) Wave PeaksForStrain Variable as0,as1,as2,bs0,bs1,bs2,cs0,cs1 Variable N = DimSize(PeaksForStrain,0) Variable cslen = NumberByKey("cslen",note(PeaksForStrain),"=") Variable cs2 = sqrt(cslen^2 - cs0^2 - cs1^2)*sign(NumberByKey("cs2",note(PeaksForStrain),"=")) Wave qhat=qhat_latticeMismatch, ghat=ghat_latticeMismatch if (!WaveExists(qhat) || !WaveExists(ghat)) Make/N=3/O/D qhat_latticeMismatch, ghat_latticeMismatch Wave qhat=qhat_latticeMismatch, ghat=ghat_latticeMismatch endif Wave astar=astar_latticeMismatch, bstar=bstar_latticeMismatch, cstar=cstar_latticeMismatch if (!WaveExists(astar) || !WaveExists(bstar) || !WaveExists(cstar)) Make/N=3/O/D astar_latticeMismatch,bstar_latticeMismatch,cstar_latticeMismatch Wave astar=astar_latticeMismatch, bstar=bstar_latticeMismatch, cstar=cstar_latticeMismatch endif astar = {as0,as1,as2} bstar = {bs0,bs1,bs2} cstar = {cs0,cs1,cs2} Variable i,j, h,k,l, err=0 Variable weight, SumWeight for (i=0,SumWeight=0; i0) // check for a valid Q wenge2IdealBeamline(geo,qhat,qBL) // convert to beam line coords, normalize and save normalize(qBL) Qs[m][0,2] = qBL[q] Qs[m][3] = max(FullPeakList[i][10],0) // save intensity too m += 1 endif endfor KillWaves/Z FullPeakList2Qfile_qhat, FullPeakList2Qfile_qBL N = m Redimension/N=(N,4) FullPeakList2Qfile_Q ImageStats/M=1/G={0,N-1,3,3} FullPeakList2Qfile_Q FullPeakList2Qfile_Q[][3] /= V_max return GetWavesDataFolder(FullPeakList2Qfile_Q,2) End // End of Index strain refinement // ========================================================================= // ========================================================================= // ========================================================================= // ========================================================================= // Start of Index set panel Function/T FillIndexParametersPanel(strStruct,hostWin,left,top) String strStruct // optional passed value of xtal structure, this is used if passed String hostWin // name of home window Variable left, top // offsets from the left and top NewDataFolder/O root:Packages:micro // ensure that the needed data folders exist NewDataFolder/O root:Packages:micro:Index String/G root:Packages:Lattices:PanelValues:desc Variable/G root:Packages:micro:Index:h_e Variable/G root:Packages:micro:Index:k_e Variable/G root:Packages:micro:Index:l_e NVAR h=root:Packages:micro:Index:h_e NVAR k=root:Packages:micro:Index:k_e NVAR l=root:Packages:micro:Index:l_e SetWindow kwTopWin,userdata(IndexPanelName)=hostWin+"#IndexPanel" NewPanel/K=1/W=(left,top,left+221,top+445)/HOST=$hostWin ModifyPanel frameStyle=0, frameInset=0 RenameWindow #,IndexPanel Button buttonLoadSPE,pos={17,5},size={80,20},proc=IndexButtonProc,title="Load SPE" Button buttonLoadSPE,help={"Load a WinView Image from the file, and then display the image."} Button buttonViewSPE,pos={111,5},size={80,20},proc=IndexButtonProc,title="View SPE" Button buttonViewSPE,help={"Display an existing WinView Image that is already loaded"} Button buttonBkgRemove,pos={29,40},size={160,20},proc=IndexButtonProc,title="Remove Background" Button buttonBkgRemove,help={"remove background from an image, do not use on depth sotred images"} Button buttonFitPeaks,pos={29,65},size={160,20},proc=IndexButtonProc,title="Fit Peaks" Button buttonFitPeaks,help={"Identify peaks in an Image, does not do any background removal"} Button buttonPeaksFromBoxes,pos={29,90},size={160,20},proc=IndexButtonProc,title="set peaks from boxes" Button buttonPeaksFromBoxes,help={"reset list of peaks for fitting to the boxes on an image plot"} Button buttonIndex,pos={29,125},size={160,20},proc=IndexButtonProc,title="Index & Display" Button buttonIndex,help={"Index the identified peaks, using the defined lattice, and then show it all on a plot"} PopupMenu popuphklTags,pos={69,150},size={76,20},proc=hklTagsPopMenuProc,title="hkl Tags..." PopupMenu popuphklTags,help={"re-draw or clear the hkl tags from a plot"} PopupMenu popuphklTags,fSize=14 PopupMenu popuphklTags,mode=0,value= #"\"Re-Draw hkl tags;Clear hkl tags off Graph\"" Button buttonStrainRefine,pos={29,175},size={160,20},proc=IndexButtonProc,title="Strain Refine" Button buttonStrainRefine,help={"after indexing, use this to refine the lattice and find the deviatoric strain"} Button buttonReportIndex,pos={29,205},size={160,20},proc=IndexButtonProc,title="Make Report Sheet" Button buttonReportIndex,help={"if the top window is an images showing the hkl's, this makes a layout with reflections for printing"} Button buttonCalcEnergyIndex,pos={29,235},size={160,20},proc=IndexButtonProc,title="Calc Energy of (hkl)" Button buttonCalcEnergyIndex,help={"calculate the energy of an hkl using the current indexing"} SetVariable h_IndexEneVar,pos={27,257},size={50,15},proc=CalcE_SetVarProc,title="H" SetVariable h_IndexEneVar,value= root:Packages:micro:Index:h_e SetVariable k_IndexEneVar,pos={91,257},size={50,15},proc=CalcE_SetVarProc,title="K" SetVariable k_IndexEneVar,value= root:Packages:micro:Index:k_e SetVariable L_IndexEneVar,pos={155,257},size={50,15},proc=CalcE_SetVarProc,title="L" SetVariable L_IndexEneVar,value= root:Packages:micro:Index:l_e PopupMenu popupTables,pos={62,290},size={66,20},proc=TablesPopMenuProc,title="Display Tables..." PopupMenu popupTables,help={"Show table of identified peak positions indexed peaks, or the peaks for strain refinement"} PopupMenu popupTables,fSize=14,mode=0,value= #"\"Fitted Peaks;Indexed Peaks;Strain Peaks\"" if (exists("IndexLots")==6) SetDrawLayer UserBack SetDrawEnv linethick= 2 DrawLine 0,330,221,330 Button buttonIndexLots,pos={29,340},size={160,20},proc=IndexButtonProc,title="Index Lots" Button buttonIndexLots,help={"index lots of images"} Button buttonWrite3dFile,pos={39,365},size={160,20},proc=IndexButtonProc,title="Write 3d Orients file" Button buttonWrite3dFile,help={"Write 3d Orientations file"} Button buttonFindClosestPoint,pos={39,390},size={160,20},proc=IndexButtonProc,title="find closest point" Button buttonFindClosestPoint,help={"find point in original indexing list that is closest to the cursor"} Button buttonIndexingListTable,pos={39,415},size={160,20},proc=IndexButtonProc,title="Indexing List Table" Button buttonIndexingListTable,help={"Make a table of the indexing list"} else Button buttonInitIndexLots,pos={29,340},size={150,50},title="Init IndexLots\rpackage",proc=LoadPackageButtonProc Button buttonInitIndexLots,help={"Load Package for Indexing Lots of Images"} endif EnableDisableIndexControls(hostWin+"#IndexPanel") return "#IndexPanel" End // OverRide Function EnableDisableIndexControls(win) // here to enable/disable String win // window (or sub window) to use Variable d Button buttonLoadSPE,win=$win,disable=0 // always OK to load an image d = strlen(WaveListClass("spe*","*","DIMS:2"))<1 ? 2 : 0 Button buttonViewSPE,win=$win,disable= d d = strlen(WaveListClass("speImage","*","DIMS:2"))<1 ? 2 : 0 Button buttonBkgRemove,win=$win,disable= d d = strlen(WaveListClass("speImage*","*","DIMS:2"))<1 ? 2 : 0 Button buttonFitPeaks,win=$win,disable= d d = strlen(StrVarOrDefault("pkList","")) ? 0 : 2 Button buttonPeaksFromBoxes,win=$win,disable= d d = strlen(WaveListClass("FittedPeakList","*","DIMS:2,MAXCOLS:11,MINCOLS:11"))<1 ? 2 : 0 Button buttonIndex,win=$win,disable= d d = (strlen(WaveListClass("FittedPeakList","*","DIMS:2,MAXCOLS:11,MINCOLS:11")) && strlen(WaveListClass("IndexedPeakList","*",""))) ? 0 : 2 Button buttonStrainRefine,win=$win,disable= d d = strlen(WaveListClass("IndexedPeakList","*",""))<1 ? 2 : 0 PopupMenu popuphklTags,win=$win,disable= d Button buttonReportIndex,win=$win,disable= d Button buttonCalcEnergyIndex,win=$win,disable= d if (d) SetVariable h_IndexEneVar,win=$win,noedit=1,frame=0,disable= d SetVariable k_IndexEneVar,win=$win,noedit=1,frame=0,disable= d SetVariable L_IndexEneVar,win=$win,noedit=1,frame=0,disable= d else SetVariable h_IndexEneVar,win=$win,noedit=0,frame=2,disable= d SetVariable k_IndexEneVar,win=$win,noedit=0,frame=2,disable= d SetVariable L_IndexEneVar,win=$win,noedit=0,frame=2,disable= d endif d = strlen(WaveListClass("FittedPeakList;IndexedPeakList","*",""))<1 ? 2 : 0 PopupMenu popupTables,win=$win,disable= d if (exists("IndexLots")==6) Button buttonIndexLots,win=$win,disable= 0 // always OK to do this d = strlen(WaveListClass("indexationResultList","*","TEXT:1"))<1 ? 2 : 0 Button buttonWrite3dFile,win=$win,disable= d d = strlen(WaveListClass("OrientationSliceWave*","*",""))<1 ? 2 : 0 Button buttonFindClosestPoint,win=$win,disable= d d = strlen(WaveListClass("indexationResultList*","*","TEXT:1"))<1 ? 2 : 0 Button buttonIndexingListTable,win=$win,disable= d endif End Function IndexButtonProc(ctrlName) : ButtonControl String ctrlName if (stringmatch(ctrlName,"buttonLoadSPE")) Wave image = $LoadWinViewFile("") if (WaveExists(image)) String wnote=note(image), bkgFile=StringByKey("bkgFile",wnote,"=") Variable xdim=NumberByKey("xdim",wnote,"="), ydim=NumberByKey("ydim",wnote,"=") SVAR S_fileName=S_fileName printf "for file '"+S_fileName+"'" if (strlen(bkgFile)>0) printf ", background file = '%s'", bkgFile endif printf "\r" printf "total length = %d x %d = %d points\r", xdim,ydim,xdim*ydim print "number type is '"+WinViewFileTypeString(NumberByKey("numType", wnote,"="))+"'" print "Created a 2-d wave '"+GetWavesDataFolder(image,2)+"'" DoAlert 1, "Display this image" if (V_Flag==1) Graph_imageMake(image,1) endif endif elseif (stringmatch(ctrlName,"buttonViewSPE") && strlen(WaveListClass("spe*","*","DIMS:2"))) Graph_imageMake($"",1) elseif (stringmatch(ctrlName,"buttonBkgRemove") && strlen(WaveListClass("speImage","*","DIMS:2"))) RemoveBackgroundImage($"",NaN) elseif (stringmatch(ctrlName,"buttonFitPeaks") && strlen(WaveListClass("speImage*","*","DIMS:2"))) // FitPeaks($"",NaN,NaN) // FunctionList("FitPeak*",";" , "WIN:[Indexing]") String fitPeakFunc="FitPeaksWithSeedFill" // "FitPeaksStepWise" prompt fitPeakFunc,"peak fitting method",popup,"FitPeaksWithSeedFill;FitPeaks;FitPeaksNew;FitPeaksStepWise" DoPrompt "Peak Fit",fitPeakFunc if (!V_flag) if (stringmatch(fitPeakFunc,"FitPeaks")) FitPeaks($"",NaN,NaN) elseif (stringmatch(fitPeakFunc,"FitPeaksNew")) FitPeaksNew($"",NaN,NaN) elseif (stringmatch(fitPeakFunc,"FitPeaksStepWise")) FitPeaksStepWise($"",NaN,NaN,NaN,NaN) elseif (stringmatch(fitPeakFunc,"FitPeaksWithSeedFill")) FitPeaksWithSeedFill($"",NaN,NaN,NaN,NaN) endif endif elseif (stringmatch(ctrlName,"buttonPeaksFromBoxes") && strlen(StrVarOrDefault("pkList",""))) SVAR pkList=pkList setFittedPeaksFromList($"",NaN,pkList) elseif (stringmatch(ctrlName,"buttonIndex") && strlen(WaveListClass("FittedPeakList","*","DIMS:2,MAXCOLS:11,MINCOLS:11"))) IndexAndDisplay($"",NaN,NaN,NaN,NaN,NaN,NaN,NaN) elseif (stringmatch(ctrlName,"buttonStrainRefine")) DeviatoricStrainRefine(NaN) elseif (stringmatch(ctrlName,"buttonReportIndex")) MakeIndexingReportSheet() elseif (stringmatch(ctrlName,"buttonCalcEnergyIndex")) NVAR h=root:Packages:micro:Index:h_e NVAR k=root:Packages:micro:Index:k_e NVAR l=root:Packages:micro:Index:l_e EnergyOfhkl($"",NaN,h,k,l) #if (Exists("IndexLots")==6) elseif (stringmatch(ctrlName,"buttonIndexLots") ) IndexLots("","","","",NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN) elseif (stringmatch(ctrlName,"buttonWrite3dFile") && strlen(WaveListClass("indexationResultList","*","TEXT:1"))) Write3dOrientsFile($"",NaN) elseif (stringmatch(ctrlName,"buttonFindClosestPoint") && strlen(WaveListClass("OrientationSliceWave*","*",""))) findClosestPoint(NaN,NaN) elseif (stringmatch(ctrlName,"buttonIndexingListTable") && strlen(WaveListClass("indexationResultList*","*","TEXT:1"))) TableOfIndexingList($"") #endif endif EnableDisableIndexControls(GetUserData("microPanel","","IndexPanelName")) End //Function IndexButtonProc(ctrlName) : ButtonControl // String ctrlName // // if (stringmatch(ctrlName,"buttonLoadSPE")) // Wave image = $LoadWinViewFile("") // if (WaveExists(image)) // String wnote=note(image), bkgFile=StringByKey("bkgFile",wnote,"=") // Variable xdim=NumberByKey("xdim",wnote,"="), ydim=NumberByKey("ydim",wnote,"=") // SVAR S_fileName=S_fileName // printf "for file '"+S_fileName+"'" // if (strlen(bkgFile)>0) // printf ", background file = '%s'", bkgFile // endif // printf "\r" // printf "total length = %d x %d = %d points\r", xdim,ydim,xdim*ydim // print "number type is '"+WinViewFileTypeString(NumberByKey("numType", wnote,"="))+"'" // print "Created a 2-d wave '"+GetWavesDataFolder(image,2)+"'" // DoAlert 1, "Display this image" // if (V_Flag==1) // Graph_imageMake(image,1) // endif // endif // elseif (stringmatch(ctrlName,"buttonViewSPE") && strlen(WaveListClass("spe*","*","DIMS:2"))) // Graph_imageMake($"",1) // elseif (stringmatch(ctrlName,"buttonBkgRemove") && strlen(WaveListClass("speImage","*","DIMS:2"))) // RemoveBackgroundImage($"",NaN) // elseif (stringmatch(ctrlName,"buttonFitPeaks") && strlen(WaveListClass("speImage*","*","DIMS:2"))) // FitPeaks($"",NaN,NaN) // elseif (stringmatch(ctrlName,"buttonPeaksFromBoxes") && strlen(StrVarOrDefault("pkList",""))) // SVAR pkList=pkList // setFittedPeaksFromList($"",NaN,pkList) // elseif (stringmatch(ctrlName,"buttonIndex") && strlen(WaveListClass("FittedPeakList","*","DIMS:2,MAXCOLS:11,MINCOLS:11"))) // IndexAndDisplay($"",NaN,NaN,NaN,NaN,NaN,NaN,NaN) // elseif (stringmatch(ctrlName,"buttonReportIndex")) // MakeIndexingReportSheet() // elseif (stringmatch(ctrlName,"buttonCalcEnergyIndex")) // NVAR h=root:Packages:micro:Index:h_e // NVAR k=root:Packages:micro:Index:k_e // NVAR l=root:Packages:micro:Index:l_e // EnergyOfhkl($"",NaN,h,k,l) // endif // EnableDisableIndexControls(GetUserData("microPanel","","IndexPanelName")) //End // Function hklTagsPopMenuProc(ctrlName,popNum,popStr) : PopupMenuControl String ctrlName Variable popNum String popStr if (strlen(WaveListClass("IndexedPeakList","*",""))<1) return 1 endif if (stringmatch(popStr,"Re-Draw hkl tags")) DisplayResultOfIndexing($"",NaN) elseif (stringmatch(popStr,"Clear hkl tags off Graph")) ClearhklOffGraph("") endif EnableDisableIndexControls(GetUserData("microPanel","","IndexPanelName")) End // Function CalcE_SetVarProc(ctrlName,varNum,varStr,varName) : SetVariableControl String ctrlName Variable varNum String varStr String varName if (strlen(WaveListClass("IndexedPeakList","*",""))<1) return 1 endif NVAR h=root:Packages:micro:Index:h_e NVAR k=root:Packages:micro:Index:k_e NVAR l=root:Packages:micro:Index:l_e EnergyOfhkl($"",NaN,h,k,l) EnableDisableIndexControls(GetUserData("microPanel","","IndexPanelName")) End // Function TablesPopMenuProc(ctrlName,popNum,popStr) : PopupMenuControl String ctrlName Variable popNum String popStr if (strlen(WaveListClass("FittedPeakList;IndexedPeakList","*",""))<1) return 1 endif if (stringmatch(popStr,"Fitted Peaks")) TableFullPeakList($"") elseif (stringmatch(popStr,"Indexed Peaks")) TableFullPeakIndexed($"") elseif (stringmatch(popStr,"Strain Peaks")) TableFullPeakStrain($"") endif End // End of Index set panel // ========================================================================= // ========================================================================= Function InitIndexingPackage() // used to initialize this package InitLatticeSymPackage() // init Lattice Sym package NewDataFolder/O root:Packages:geometry End