#pragma rtGlobals=1 // Use modern global access method. #pragma version = 1.4 #include "inelasticUtility 1.3", version>=1.3 #include "specMore" #include "JZT-analysis" #include "Elements", version>=1.0 //#include "JelliumResponse" Menu "dataFiles" "Update A Range of Scans", UpdateRangeOfScans("") "Combine spec scans", CombineSpecScans("") "Load a Range of Scans", LoadRangeOfSpecScans("","","") "Show Avaiable Q's",MakeAvailableQs(1) "Draw all Q Graphs", DrawAll_Q_Graphs("",1) "Display a Combined Plot",DisplayCombinedPlot($"") "Reset Graph LIst", ResetGraphLIst(NaN) "Choose new name of data file", ReTargetDataFile("") "FTP data", FTPdata("") "Init new Igor File", InitInelasticIgorFile() End Menu "Macros" "Renormalize All or One", ReNormAll("",NaN) // "Renormalize One", ReNormOne("",NaN) "Read Many Overnite Scans", ReadInManyOverniteScans(NaN,NaN,NaN) "Elapsed time for scans", ElapsedTimeForScans("") "Apply CaF2 Bkg", ApplyCaF2Bkg($"",NaN) "Apply Flipped Bkg", ApplyFlippedBkg($"",0) "Correction Factor Compute",CorrectionFactorElement("",NaN,NaN) "Find Elastic Center Peak", FindElasticCenterPeak("") "Moment Of Aluminum", MomentOfAluminum($"",NaN) End Proc Examples() graphList = "Ni_13F" „FindElasticCenterPeak("root:scan_126_131,root:scan_132_137,root:scan_138_143,root:scan_144_149,root:scan_150_155,root:scan_156_161") „graphList = "135kF;15kF;16kF;2kF;21kF;23kF;25kF;1kF;12kF;15AkF;05kF;071kF 135AkF;12AkF;16AkF;23AkF;21AkF;2AkF;013_2kF;013_16kF;" „graphList = "135kF;15kF;16kF;2kF;21kF;23kF;25kF;1kF;12kF;15AkF;15AkF_avg;" „graphList += "05kF;071kF;135AkF;12AkF;16AkF;23AkF;21AkF;2AkF;" „graphList += "013_2kF;013_16kF;013_2AkF;013_2kFavg;013_16AkF;013_16kFavg;" „graphList += "013_135kF;013_21kF;013_21AkF;013_135AkF;013_12kF;013_12AkF" „ReadInRangeOfScans("181-195",2) ; CombineSpecScans("181-195") FTP download: url="ftp://ord.uni.aps.anl.gov/home/tischler/data/al3"; path="Macintosh HD:home:tischler:inelastic:Al-UNICAT:raw:al3" #191 dE_eV;Energy;DCM_theta;DCM_enc;ID33_E;Epoch_;Det_top;pin;I0;I00;harmonic;seconds;Det_bot; 13 columns 7 points #192 dE_eV;Energy;DCM_theta;DCM_enc;ID33_E;Epoch_;Det_top;pin;I0;I00;harmonic;seconds;Det_bot; 13 columns 11 points #193 dE_eV;Energy;DCM_theta;DCM_enc;ID33_E;Epoch_;Det_top;pin;I0;I00;harmonic;seconds;Det_bot; 13 columns 59 points #194 dE_eV;Energy;DCM_theta;DCM_enc;ID33_E;Epoch_;Det_top;pin;I0;I00;harmonic;seconds;Det_bot; 13 columns 41 points #195 dE_eV;Energy;DCM_theta;DCM_enc;ID33_E;Epoch_;Det_top;pin;I0;I00;harmonic;seconds;Det_bot; 13 columns 4 points „DrawAll_QkF_Graphs("15AkF_avg",1) EndMacro Window Layout_top() : Layout PauseUpdate; Silent 1 String gname=StringFromList(0, WinList("*",";", "WIN:")) String command="Layout/C=1/W=(5,42,506,526) "+gname+"(72,72,387,292)/O=1" Execute command TextBox/N=text0/O=90/F=0/S=3/A=LB/X=8.00/Y=72.18 "\\Z16 Arbitrary Units " EndMacro Function ReadInManyOverniteScans(firstScan,NumOfQs,step) Variable firstScan=19 // first scan Variable NumOfQs=8 // number of Q scans to process Variable step=4 // number of scans per Q firstScan = (numtype(firstScan) || firstScan<0) ? 1 : firstScan NumOfQs = (numtype(NumOfQs) || NumOfQs<1) ? 1 : NumOfQs step = (numtype(step) || step<1) ? 5 : step Variable doFTP = NumVarOrDefault("root:Packages:inelasticUtility:doFTP",0)+1 Prompt firstScan, "first scan number" Prompt NumOfQs, "number of Q's measured" Prompt step, "number of eVscans per Q" Prompt doFTP, "use FTP to get new data",popup,"No;Yes" DoPrompt "Process Group of Scans", firstScan, NumOfQs, step, doFTP if (V_Flag) return 0 endif doFTP = (doFTP==2) Variable j=0 SVAR specDefaultFile=root:Packages:spec:specDefaultFile if (doFTP) FTPdata(specDefaultFile) endif String range do sprintf range, "%d-%d", firstScan, firstScan+step-1 ReadInRangeOfScans(range,1) CombineSpecScans(range) firstScan += step j += 1 while (j2 || strlen(range)<1) if (WhichListItem(range,list)<0 && strlen(range)) list = list+";"+range endif aluminum_special = (numtype(aluminum_special) || aluminum_special<0) ? 0 : aluminum_special+1 if (strlen(list)>4) Prompt range, "scan range for combining", popup, list else Prompt range, "scan range for combining, no combine list found" endif Prompt aluminum_special, "for Al remove bkg and compute 1st moment",popup,"No 1st moments;all Al;Al only on al# sub-folders" DoPrompt "scan?",range, aluminum_special if(V_Flag) return 1 endif aluminum_special -= 1 endif if (strlen(range)<1) DoAlert 0,"no range of scans given" return 1 endif Variable irange = WhichListItem(range,list) // index to list when only one range is chosen // irange ² -1 --> range entered by hand, irange = 0 --> do all in list, irange ³ 1 --> do item one-1 in list String fldrSav= GetDataFolder(1) SetDataFolder root: SVAR specDataFolder= root:Packages:spec:specDataFolder String specDataFolderSAVE=specDataFolder // save original value NVAR scaleFactor=root:Packages:inelasticUtility:scaleFactor Variable scaleFactorSAVE=scaleFactor String subFldr String scaleFactorList = StrVarOrDefault("root:Packages:inelasticUtility:scaleFactorList","") Variable i=irange String wName, eName do if (irange>=0) range = StringFromList(i,list) if (strlen(range)<1) break endif if (i>0) print "" endif endif // printf "calling ReNormOne(%s,%d)\r", range,aluminum_special ReNormOne(range,aluminum_special) i += 1 while (irange==0) // keep looping on all SetDataFolder fldrSav specDataFolder = specDataFolderSAVE scaleFactor = scaleFactorSAVE End Function ReNormOne(range,aluminum_special) String range Variable aluminum_special // 0=no, 1=yes, 2=conditional on folder name if (numtype(aluminum_special) || aluminum_special<0 || strlen(range)<1) String list = StrVarOrDefault("root:Packages:inelasticUtility:combineScanList", "") if (strlen(list)>1) Prompt range, "scan range for combining", popup, list else Prompt range, "scan range for combining" endif aluminum_special = (numtype(aluminum_special) || aluminum_special<0) ? 0 : aluminum_special+1 Prompt aluminum_special, "for Al remove bkg and compute 1st moment",popup,"No 1st moments;all Al;Al only on al# sub-folders" DoPrompt "scan?",range, aluminum_special if(V_Flag) return 1 endif aluminum_special -= 1 endif if (strlen(range)<1) DoAlert 0,"no scan range given" return 1 endif String fldrSav= GetDataFolder(1) SetDataFolder root: SVAR specDataFolder= root:Packages:spec:specDataFolder String specDataFolderSAVE=specDataFolder // save original value NVAR scaleFactor=root:Packages:inelasticUtility:scaleFactor Variable scaleFactorSAVE=scaleFactor String subFldr, wName, eName String scaleFactorList = StrVarOrDefault("root:Packages:inelasticUtility:scaleFactorList","") subFldr = StringFromList(1,range,":") range = StringFromList(0,range,":") if (strlen(subFldr)>0) // a sub folder is specified specDataFolder = "root:raw:"+subFldr+":" endif scaleFactor = NumberByKey(subFldr,scaleFactorList) scaleFactor = numtype(scaleFactor) ? scaleFactorSAVE : scaleFactor if (strlen(scaleFactorList)>1) printf "re-processing range='%s', in sub folder '%s', with scale factor = %g\r",range,subFldr,scaleFactor endif scaleFactor *= NumVarOrDefault(specDataFolder+"spec"+num2istr(str2num(range))+":slitFactor",1) wName = CombineSpecScans(range) // returns the full pathname to the data folder eName = wName +"dE" wName += "DetScaled" if (WaveExists($wName) && WaveExists($eName)) Wave dE=$eName if (dE[0] < -2) // only subtract bkg if dE goes beyond -2eV ApplyCaF2Bkg($wName,0.3) wName += "B" endif // if (dE[0] < -8) // only subtract bkg if dE goes beyond -8eV // ApplyFlippedBkg($wName,0) // wName += "B" // endif endif if (aluminum_special==1 || (aluminum_special==2 && stringmatch(subFldr,"al*"))) MomentOfAluminum($wName,2) // 2 --> use power law tail endif SetDataFolder fldrSav specDataFolder = specDataFolderSAVE scaleFactor = scaleFactorSAVE return 0 End Function ReNormAll_OLD(aluminum_special) Variable aluminum_special // 0=no, 1=yes, 2=conditional on folder name if (numtype(aluminum_special) || aluminum_special<0 ) aluminum_special = (numtype(aluminum_special) || aluminum_special<0) ? 0 : aluminum_special Prompt aluminum_special, "for Al remove bkg and compute 1st moment",popup,"No 1st moments;all Al;Al only on al# sub-folders" DoPrompt "bkg and moment?", aluminum_special if(V_Flag) return 1 endif aluminum_special -= 1 endif String fldrSav= GetDataFolder(1) SetDataFolder root: SVAR list = root:Packages:inelasticUtility:combineScanList // this string must be present SVAR specDataFolder= root:Packages:spec:specDataFolder String specDataFolderSAVE=specDataFolder // save original value NVAR scaleFactor=root:Packages:inelasticUtility:scaleFactor Variable scaleFactorSAVE=scaleFactor String subFldr String scaleFactorList = StrVarOrDefault("root:Packages:inelasticUtility:scaleFactorList","") Variable i=0 String id, wName, eName do id = StringFromList(i,list) if (strlen(id)<1) break endif if (i>0) print "" endif subFldr = StringFromList(1,id,":") id = StringFromList(0,id,":") if (strlen(subFldr)>0) // a sub folder is specified specDataFolder = "root:raw:"+subFldr+":" endif scaleFactor = NumberByKey(subFldr,scaleFactorList) scaleFactor = numtype(scaleFactor) ? scaleFactorSAVE : scaleFactor if (strlen(scaleFactorList)>1) printf "re-processing range='%s', in sub folder '%s', with scale factor = %g\r",id,subFldr,scaleFactor endif scaleFactor *= NumVarOrDefault(specDataFolder+"spec"+num2istr(str2num(id))+":slitFactor",1) wName = CombineSpecScans(id) // returns the full pathname to the data folder eName = wName +"dE" wName += "DetScaled" if (WaveExists($wName) && WaveExists($eName)) Wave dE=$eName if (dE[0] < -2) // only subtract bkg if dE goes beyond -2eV ApplyCaF2Bkg($wName,0.3) wName += "B" endif // if (dE[0] < -8) // only subtract bkg if dE goes beyond -8eV // ApplyFlippedBkg($wName,0) // wName += "B" // endif endif if (aluminum_special==1 || (aluminum_special==2 && stringmatch(subFldr,"al*"))) MomentOfAluminum($wName,2) // 2 --> use power law tail endif i += 1 while (1) SetDataFolder fldrSav specDataFolder = specDataFolderSAVE scaleFactor = scaleFactorSAVE End Function ApplyCaF2Bkg(wav,halfWidth) Wave wav // wave to remove bkg from, usually Det or DetScaled Variable halfWidth // halfWidth to use for finding the peak center String fldrSav= GetDataFolder(1) Variable addToPlot=NumVarOrDefault("root:Packages:inelasticUtility:doPlotting",0) String swav Prompt halfWidth, "width of peak to use for centering (eV)" if (WaveExists(wav) && numtype(halfWidth)) // wav exists, only need halfWidth halfWidth = numtype(halfWidth) ? 0.3 : halfWidth DoPrompt "half width", halfWidth if (V_Flag) return NaN endif elseif (!WaveExists(wav) || numtype(halfWidth)) // if wav was entered as $"", then we get here halfWidth = numtype(halfWidth) ? 0.3 : halfWidth swav="DetScaled" String flist = listFoldersStartingWith("scan_") if (strlen(flist)>1) // I see scans folders, look in there // first try to set id to go with the top graph Wave ywav = TraceNameToWaveRef("","DetScaled") String id if (WaveExists(ywav)) id = GetWavesDataFolder(ywav,0) else id = StringFromList(ItemsInList(flist)-1,flist) // folder id, something like "43_47" endif Prompt id, "id of data folder (e.g. \"62_66\")", popup, flist Prompt swav, "Wave to remove background from", popup, "Det;DetScaled" DoPrompt "pick wave for background removal", id, swav,halfWidth swav = ":"+id+":"+swav else // probably in the folder already, look here Prompt swav, "Wave to remove background from", popup, WaveList("D*",";","DIMS:1") DoPrompt "pick wave for background removal", swav,halfWidth endif if (V_Flag) return NaN endif addToPlot=1 Wave wav=$swav endif swav=GetWavesDataFolder(wav,2) // swav is the full path name to wave if (!WaveExists(wav)) print "could not find '"+swav+"'" Abort "'"+swav+"'"+" does not exist" endif String fldr = GetWavesDataFolder(wav,1) // get name of folder (full path) to wav SetDataFolder $fldr String strB, strBkg strB = swav+"B" strBkg = swav+"Bkg" Duplicate/O $swav $strB, $strBkg Wave wavB = $strB Wave wavBkg = $strBkg Variable BonGraph = isWaveOnGraph("",wavB) // flags that wave is on the top graph Variable BkgOnGraph = isWaveOnGraph("",wavBkg) addToPlot = (BonGraph && BkgOnGraph) ? 0 : addToPlot // do not add wave to plot if both are already there if (addToPlot) DoAlert 1, "Append Missing Waves to top graph when done" addToPlot = (V_Flag==1) endif // This section finds the shift that aligns peaks of background and data Wave dE=dE WaveStats/Q $strB Variable dEo = dE[V_maxloc] Variable ilo = floor(BinarySearchInterp(dE,dEo-halfWidth)) Variable ihi = ceil(BinarySearchInterp(dE,dEo+halfWidth)) String err = swav+"_err" Make/O/D W_coef={.0001,1} if (exists(err)==1) FuncFit /Q CaF2_fit, W_coef, $strB[ilo,ihi] /X=dE /W=$err /I=1 else FuncFit /Q CaF2_fit, W_coef, $strB[ilo,ihi] /X=dE endif String noteStr=note($strB) // This section provides the minimum background. // if (NumVarOrDefault("root:useMinBkg",0)) // use a minimum bkg, use min between [60,80eV] // Variable minBkg // String printMore="" // if (exists("minBkg")==2) // use the specified minBkg in local data folder // NVAR GlobalminBkg = minBkg // minBkg = max(GlobalminBkg,0) // sprintf printMore, ", and a minimum background of %g",minBkg // else // ilo = BinarySearch(dE,60) // ihi = BinarySearch(dE,80) // ilo = (ilo<0) ? dE[inf] : ilo // ihi = (ihi<0) ? dE[inf] : ihi // WaveStats /Q/R=[ilo,ihi] $swav // get V_min // minBkg = max(V_min,0) // sprintf printMore, ", and a minimum background of %g in %s[0,%d]",minBkg,strBkg,ihi // endif // Wave wBkg=$strBkg // ilo = BinarySearch(dEneg,0) // ihi = numpnts(wBkg) - 1 // wBkg[0,ihi] = max(minBkg,wBkg[p]) // noteStr = ReplaceNumberByKey("minBkg",noteStr,minBkg,"=") // print printMore // endif // This section subtracts background from data Note $strBkg noteStr Note/K $strB Note $strB noteStr Variable i, N=numpnts(wav) for (i=0;i=CaF_dE[Inf]) yval = CaF[Inf] else yval = interp(x,CaF_dE,CaF) endif return w[1] * yval End Function ApplyFlippedBkg(wav,deV) Variable deV Wave wav // wave to remove bkg from, usually Det or DetScaled String fldrSav= GetDataFolder(1) Variable addToPlot=NumVarOrDefault("root:Packages:inelasticUtility:doPlotting",0) String swav if (WaveExists(wav) && numtype(deV)) // wav exists, only need deV Prompt deV, "peak shift (eV)" DoPrompt "give offset energy of background peak (eV)", deV if (V_Flag) return NaN endif elseif (!WaveExists(wav) || numtype(deV)) // if wav was entered as $"", then we get here deV = numtype(deV) ? 0 : deV Prompt deV, "peak shift (eV)" swav="Det" String flist = listFoldersStartingWith("scan_") if (strlen(flist)>1) // I see scans folders, look in there String id = StringFromList(ItemsInList(flist)-1,flist) // folder id, something like "43_47" Prompt id, "id of data folder (e.g. \"62_66\")", popup, flist Prompt swav, "Wave to remove background from", popup, "Det;DetScaled" DoPrompt "pick wave for background removal", id, swav,deV swav = ":"+id+":"+swav else // probably in the folder already, look here Prompt swav, "Wave to remove background from", popup, WaveList("D*",";","DIMS:1") DoPrompt "pick wave for background removal", swav,deV endif if (V_Flag) return NaN endif addToPlot=1 Wave wav=$swav endif swav=GetWavesDataFolder(wav,2) // swav is the full path name to wave if (!WaveExists(wav)) print "could not find '"+swav+"'" Abort "'"+swav+"'"+" does not exist" endif String fldr = GetWavesDataFolder(wav,1) // get name of folder (full path) to wav SetDataFolder $fldr String strB, strBkg strB = swav+"B" strBkg = swav+"Bkg" Duplicate/O $swav $strB, $strBkg Wave dE=dE Variable ilo = floor(BinarySearchInterp(dE,-2.5)) Variable ihi = ceil(BinarySearchInterp(dE,2.5)) String err = swav+"_err" if (exists(err)==1) CurveFit/Q gauss $strB[ilo,ihi] /X=dE /W=$err /I=1 else CurveFit/Q gauss $strB[ilo,ihi] /X=dE endif Wave W_coef=W_coef printf "center at %g",W_coef[2] // used 1eV steps everywhere and use 0.2 eV in [-2,2] Variable N = (dE[inf]-dE[0])+1 + (2*9) Make/N=(N)/O dEneg dEneg=0 Variable i for (i=0;i<((dE[inf]-dE[0])+1);i+=1) dEneg[i] = dE[0]+i endfor for (i=101;i<110;i+=1) dEneg[i] = -0.9 + (i-101)/10 endfor for (i=110;i<119;i+=1) dEneg[i] = 0.1 + (i-110)/10 endfor Sort dEneg,dEneg String cmd sprintf cmd "Interpolate/T=3/I=3/F=0/S=%s/Y=%s/X=dEneg %s /X=dE", err,strBkg,swav Execute cmd String printMore="", noteStr=note($strB) if (NumVarOrDefault("root:useMinBkg",0)) // use a minimum bkg, use min between [60,80eV] Variable minBkg if (exists("minBkg")==2) // use the specified minBkg in local data folder NVAR GlobalminBkg = minBkg minBkg = max(GlobalminBkg,0) sprintf printMore, ", and a minimum background of %g",minBkg else ilo = BinarySearch(dE,60) ihi = BinarySearch(dE,80) ilo = (ilo<0) ? dE[inf] : ilo ihi = (ihi<0) ? dE[inf] : ihi WaveStats /Q/R=[ilo,ihi] $swav // get V_min minBkg = max(V_min,0) sprintf printMore, ", and a minimum background of %g in %s[0,%d]",minBkg,strBkg,ihi endif Wave wBkg=$strBkg ilo = BinarySearch(dEneg,0) ihi = numpnts(wBkg) - 1 wBkg[0,ihi] = max(minBkg,wBkg[p]) noteStr = ReplaceNumberByKey("minBkg",noteStr,minBkg,"=") endif Note $strBkg noteStr Note/K $strB Note $strB noteStr print printMore Wave wB = $strB dEneg = -dEneg[p] + 2*W_coef[2]+deV wB = wav[p] - interpBkg(dE[p],deNeg,$strBkg) if (addToPlot) DoAlert 1, "Append Waves to top graph" if (V_Flag==1) AppendToGraph $strBkg vs dEneg AppendToGraph $strB vs dE String str = NameOfWave($strBkg) ModifyGraph lsize($str)=2,rgb($str)=(19675,39321,1) str = NameOfWave($strB) ModifyGraph opaque($str)=1,lstyle($str)=1 ModifyGraph mode($str)=4,marker($str)=8,msize($str)=2 endif endif SetDataFolder fldrSav return 0 End Static Function interpBkg(xx,wx,wy) Variable xx Wave wx,wy if (xx > wx[0]) return wy[0] else return interp(xx,wx,wy) endif End Static Function/T listFoldersStartingWith(start) String start="scan_*" start += "*" string str, list="" Variable ii=0 do str = GetIndexedObjName(":",4,ii) if (stringmatch(str, start)) list += str+";" endif ii += 1 while(strlen(str)>0) return list End Function CorrectionFactorElement(symb,DataAlMoment,keV) // Multiply other elements data by fhis // if DataAlMoment ==NaN, then the user is prompted from root:AlMomentList // example of root:AlMomentList = "2.34362 at 7.586 after TiO2 at 7.586 after TiO2;7.08226 at 9.49 old value" String symb // atomic symbol, or material name in corresponding .mtl file Variable DataAlMoment // first moment of the aluminum data,1kF=1.75 (1/) Variable keV // incident energy (keV) Variable symbOK=0 if (!numtype(element2Z(symb))) symbOK = 1 else Variable refNum=0 PathInfo home String fileName=S_Path+symb+".mtl" Open /R/Z refNum fileName if (!V_Flag) Close refNum symbOK = 1 symb = S_Path+symb endif endif Variable iprint=0 if (!symbOK || numtype(DataAlMoment) || DataAlMoment<=0 || numtype(keV) || keV<=0) symb = SelectString(numtype(Z),symb,"Cr") SVAR symbols=root:Packages:Elements:symbols String symSelect symSelect = "TiO2;NiO;"+symbols Prompt symb, "atomic symbol", popup, symSelect if ((numtype(DataAlMoment) || DataAlMoment<=0)&&exists("root:AlMomentList")==2) // use AlMomentList for DataAlMoment & keV SVAR AlMomentList=root:AlMomentList String AlData="" Prompt AlData, "Measured 1st moment of Al, units of (I/Io * eV)", popup, AlMomentList DoPrompt "values", symb,AlData DataAlMoment=str2num(StringFromList(0,AlData,"a")) keV = str2num(StringFromList(1,AlData,"t")) else // ask for all three separately keV = numtype(keV) ? 7.5882 : keV Prompt keV, "energy (kev)," Prompt DataAlMoment, "Measured 1st moment of Al, units of (I/Io * eV)" DoPrompt "values", symb,keV,DataAlMoment endif if (V_Flag) return NaN endif iprint = 1 endif if (numtype(keV)||numtype(DataAlMoment) || DataAlMoment<=0) Abort "invalid DataAlMoment or energy, check AlMomentList" endif if (numtype(element2Z(symb))) PathInfo home if (strlen(symb)<20) symb = S_Path+symb endif endif Variable fsumAluminum = f_sumRule(1.75) // f_sum rule for aluminum (1.75 1/) Variable muAl = abs_absorb_OSX("Al", keV*1000) // 1/abs_length (1/µm) Variable muZ = abs_absorb_OSX(symb, keV*1000) muZ = (muZ==0) ? NaN : muZ Variable factor = fsumAluminum/DataAlMoment * muZ / muAl if (iprint) if (numtype(factor)) printf "cannot compute correction factor for '%s' at %g keV\r",symb,keV else printf "for '%s' at %g keV, using ŗ E*Al dE = %g, correction factor is %g\r",symb,keV,DataAlMoment,factor endif endif return factor End // This routine needed under OSX only (use Guy Jenings stuff for OS9) Function abs_absorb_OSX(symb,eV) // returns mu (1/micron) String symb // atomic symbol Variable eV // energy in eV String lenList="" if (exists("abs_absorb")==3) // abs_absorb exists String funcName="abs_absorb" FUNCREF abs_absorb_OSX refabs_absorb = $funcName return refabs_absorb(symb,ev) endif Variable i=0 // remove any leading path part from symb do if (strsearch(symb,":",i)>=0) i = strsearch(symb,":",i)+1 endif while(strsearch(symb,":",i)>=0) symb = symb[i,inf] if(abs(ev-9500)<100) // try to use little table // absorption lengths (µm) at 9.5 keV // lenList="Al:124;O:1.12e6;Si:112;Sc:29.4;Cr:8.76;Ni:4.70;Cu:4.55;In:9.14;Ti:17.4;TiO2:22.7;NiO:6.7" lenList="Al:124;O:1.12e6;Si:112;Sc:29.4;Cr:8.76;Ni:4.70;Cu:4.55;In:9.14;Ti:17.4;TiO2:29.8149;NiO:7.89921" return 1/NumberByKey(symb, lenList) elseif(abs(ev-7594.2)<100) // absorption lengths (µm) at 7.5942 keV // lenList="Al:64.7;O:6.576e5;Si:58.4;Sc:16.0;Cr:4.86;Ni:20.3;Cu:18.9;In:5.03;Ti:9.51;TiO2:12.4;NiO:28.5" lenList="Al:64.7;O:6.576e5;Si:58.4;Sc:16.0;Cr:4.86;Ni:20.3;Cu:18.9;In:5.03;Ti:9.51;TiO2:16.3339;NiO:32.5514" return 1/NumberByKey(symb, lenList) else Abort "this only knows about 9.5 and 7.594 keV" endif return NaN End // This routine needed under OSX only (use Guy Jenings stuff for OS9) //Function abs_absorbProtoFunc(symb,eV) // returns mu (1/micron) // String symb // atomic symbol // Variable eV // energy in eV // // String lenList = "" // if (abs(eV-9500)<0.1) // lenList="Al:124;Si:112;Sc:29.4;Cr:8.76;Ni:4.70;Cu:4.55;In:9.14" // absorption lengths (µm) at 9.5 keV // elseif(abs(ev-7594.2)<0.1) // lenList="Al:64.7;Si:58.4;Sc:16.0;Cr:4.86;Ni:20.3;Cu:18.9;In:5.03" // absorption lengths (µm) at 7.5924 keV // else // Abort "this only knows about 9.5 and 7.5924 keV" // endif // // Variable len = NumberByKey(symb, lenList) // return 1/len //End Function UpdateRangeOfScans(range) String range if (strlen(range)<1) Prompt range, "range of scan numbers to use" DoPrompt "scans to combine", range if (V_Flag) return 0 endif endif String fldrSav= GetDataFolder(1) String range0=range range = ExpandRange(range,";") Variable N=ItemsInList(range) Variable i1,i2 i1 = str2num(StringFromList(0, range)) i2 = str2num(StringFromList(N-1, range)) String fldr="root:scan_"+num2istr(i1)+"_"+num2istr(i2) if (DataFolderExists(fldr )) KillDataFolder $fldr endif Variable i,j=0 do i = str2num(StringFromList(j, range)) fldr="root:raw:spec"+num2istr(i) if (DataFolderExists(fldr )) KillDataFolder $fldr endif j += 1 while (j3 || numtype(tail)) // if wav was entered as $"", then we get here, or invalid tail showPlot = 1 // show the plot is user input needed tail = (numtype(tail) || tail<1 || tail>3) ? 1 : tail Prompt tail,"type of tail to use",popup,"exponential;power law;fixed fraction" String swav="DetB" String flist = listFoldersStartingWith("scan_") if (WaveExists(wav)) // then only pick tail DoPrompt "type of analytic", tail elseif (strlen(flist)>1) // I see scans folders, look in there String id = StringFromList(ItemsInList(flist)-1,flist) // folder id, something like "43_47" Prompt id, "id of data folder (e.g. \"62_66\")", popup, flist Prompt swav, "Wave to take 1st moment of", popup, "DetB;DetScaledB" DoPrompt "pick input wave", id, swav,tail swav = ":"+id+":"+swav Wave wav=$swav else // probably in the folder already, look here Prompt swav, "Wave to take 1st moment of", popup, WaveList("D*",";","DIMS:1") DoPrompt "pick a wave", swav,tail Wave wav=$swav endif if (V_Flag) return NaN endif endif if (!WaveExists(wav)) print "could not find '"+swav+"'" Abort "'"+swav+"'"+" does not exist" endif if (tail<1 || tail>3 || numtype(tail)) Abort "tail has illegal value of "+num2str(tail) endif String fldr = GetWavesDataFolder(wav,1) // get name of folder (full path) to wav // try to determine Q (without prompting) Variable QkF, Q_Angstrom Q_Angstrom = str2num(StringByKey("Q_Angstrom",note(wav),"=")) QkF = numtype(Q_Angstrom) ? NaN : abs(Q_Angstrom)/1.75 if (numtype(QkF)) Variable i = strsearch(fldr,"_",0)+1 if (i) QkF = QkF_of_scan(str2num(fldr[i,inf])) endif endif if (numtype(QkF) || QkF<=0) Abort "bad QkF" endif Wave dE=$(fldr+"dE") printf "processing first moment of '%s' at Q = %g kF\r",GetWavesDataFolder(wav,2), QkF String smoment=fldr+"moment" Duplicate/O wav $smoment Wave moment=$smoment moment *= dE[p] moment[0,ceil(BinarySearchInterp(dE,0))]=0 // for all x<0, moment is 0 String cmd sprintf cmd "Interpolate/T=2/N=500/E=2/Y=%smoment_CS %s /X=%sdE", fldr,smoment,fldr Execute cmd Wave moment_CS=$(fldr+"moment_CS") SetScale/P x DimOffset(moment_CS,0),DimDelta(moment_CS,0),"eV", moment_CS Integrate/T moment_CS moment_CS /= QkF^2 Variable Etail = 64 // energy where we switch from data to analytic tail if (showPlot) Display moment_CS SetAxis bottom 0,100 Execute "JonsStyle_()" Label bottom "ĘE (\\U)" Label left "1\\Sst\\M moment" Cursor A moment_CS Etail ShowInfo endif printf "at %g eV, 1st moment = %g, note this is already divided by QkF^2\r", Etail,moment_CS(Etail) Variable extraMoment,Ae if (tail==1) // use exponenetial tails not power law Variable act = 20 // activation energy for exponential, exp(-ene/20) // get Ae such that intensity(de) = A * exp(-de/act), and choose to match at dE=Etail (thus the Ae) Ae = faverageXY(dE,wav,62.9,65.1) * exp(Etail/act) // this makes wav(Etail) == Ae*exp(-Etail/act) extraMoment = (act^2) * Ae * exp(-Etail/act) * (1+ Etail/act) elseif (tail==2) // get Ae such that intensity(de) = A * de^power, and choose to match at dE=Etail (thus the Ae) Variable power=-3 // was power=-3.4 power = NumVarOrDefault("root:Packages:inelasticUtility:tailPower",-3) if (power>=-2) Abort "The first moment will diverge, must choose power < -2" endif Variable p2 = power+2 Ae = faverageXY(dE,wav,62.9,65.1) / Etail^power // this makes wav(Etail) == Ae*Etail^power extraMoment = -Ae / p2 * (Etail^p2) // extra moment from Etail to infinity elseif (tail==3) // assume a fixed fraction passed Eo Variable fraction = NumVarOrDefault("root:tailFraction",0.06) // default is 6% after 64 eV Variable loPart = moment_CS(Etail) * QkF^2 // extra moment from Etail to infinity extraMoment = loPart/(1/fraction-1) // extra moment from Etail to infinity else Abort "tail has illegal value" endif extraMoment /= QkF^2 // need this here too Variable mtoInfinity = extraMoment + moment_CS(Etail) Variable correc = extraMoment/mtoInfinity if (tail==1) printf " extrapolating to Infinity, 1st moment = %g, a %.2g %% correction (using exponential activation of %g)\r",mtoInfinity,correc*100,act elseif (tail==2) printf " extrapolating to Infinity, 1st moment = %g, a %.2g %% correction (using power of %g)\r",mtoInfinity,correc*100,power elseif (tail==3) printf " extrapolating to Infinity, 1st moment = %g, a %.2g %% correction (using fixed fraction)\r",mtoInfinity,correc*100 endif Variable/G momentAtInfinity = mtoInfinity Variable/G V_QkF = QkF Killwaves/Z moment_CS, moment return mtoInfinity End Function/T MakeAvailableQs(printIt) Variable printIt String fldrSav= GetDataFolder(1) Variable Qmax=10, stepSize=.05 Variable N=Qmax/stepSize Make/N=(N)/O/T availableQs availableQs = "" SetScale/P x stepSize,stepSize,"", availableQs SetDataFolder root:raw: String fldrList=StringByKey("FOLDERS",DataFolderDir(1)) // a list of all the folders names in raw String fldr Variable j,Q,i=0 do fldr = StringFromList(i,fldrList,",") if (strlen(fldr)<1) break endif sscanf fldr,"spec%d",j if (V_flag!=1) i += 1 continue endif Q = Q_of_scan(j) if (numtype(Q) || Q0) Q = pnt2x(availableQs,i) if (printIt) printf "Q=%.2f %s\r",Q,availableQs[i] endif sprintf str, "Q=%g:scan=%s", Q,oneQ list += str+";" endif endfor KillWaves/Z availableQs return list End Function DrawAll_Q_Graphs(graph,doLayout) String graph="all" Variable doLayout SVAR graphList=root:Packages:inelasticUtility:graphList if (!SVAR_Exists(graphList)) Abort "graphList does not exist" endif if (strlen(graph)<1) Prompt graph, "graph to draw",popup,"all;"+graphList Prompt doLayout, "put up Layouts", popup, "No;Yes" DoPrompt "Graphs to draw", graph,doLayout if (V_Flag || strlen(graph)<1) return 0 endif endif Variable N=ItemsInList(graphList) String gName Variable i if (cmpstr(graph,"all")) gName = "Graph_"+graph if (strlen(WinList(gName,";","WIN:1"))>0) // graph already exists, bring it to top DoWindow/F $gName else Execute gName+"()" endif else i = N-1 // put up graphs in reverse order (first one will be on top) do gName = "Graph_"+StringFromList(i, graphList) if (strlen(WinList(gName,";","WIN:1"))>0) // graph already exists, bring it to top DoWindow/F $gName else Execute gName+"()" endif i -= 1 while (i>=0) endif if (doLayout-1) if (cmpstr(graph,"all")) Execute "LayoutForGraph(\""+graph+"\")" DoAlert 1, "print the Layouts?" if (V_Flag==1) Execute "PrintLayout Layout_"+graph endif else i = 0 do Execute "LayoutForGraph(\""+StringFromList(i, graphList)+"\")" i += 1 while (i0) SetDataFolder fldrSav End Function/S CombineSpecScans(range) String range if (strlen(range)<1) Prompt range, "range of scan numbers to use" DoPrompt "scans to combine", range if (V_Flag) return "" endif endif Variable doPlotting = NumVarOrDefault("root:Packages:inelasticUtility:doPlotting",0) Variable useHarmonic=1 if (doPlotting) DoAlert 1, "use the harmonic to add dead-time correction" useHarmonic = (V_Flag==1) endif if (useHarmonic && doPlotting) DoAlert 0, "Note that the does not yet have the correct mathematical form" endif Variable darkIo = NumVarOrDefault("root:Packages:inelasticUtility:darkIo",0) // default to no dark current String range0=range range = ExpandRange(range,";") Variable N=ItemsInList(range) Variable i1,i2 i1 = str2num(StringFromList(0, range)) i2 = str2num(StringFromList(N-1, range)) String fldrSav= GetDataFolder(1) String newfldr=":scan_"+num2istr(i1)+"_"+num2istr(i2) NewDataFolder /O $newfldr String fldr,ywav,xwav, errwav ywav = newfldr + ":Det" errwav = newfldr + ":Det_err" xwav = newfldr + ":dE" // Variable filter // transmission of the PF4 filter (always, filter <=1) Variable dx_combine // two points get combined if their delta x is < dx_combine (was 0.05) SVAR specDataFolder= root:Packages:spec:specDataFolder if (rawScansExists(range)) // the raw data exists Make/N=2/O $ywav,$xwav, $errwav Wave wxwav=$xwav Wave wywav=$ywav Wave werrwav=$errwav String xx, yy, ii, sec, harm String noteStr = "" Variable i Variable j=0,len=0,len0 do i = str2num(StringFromList(j, range)) fldr = specDataFolder+"spec"+num2istr(i)+":" xx = fldr+"dE_eV" SVAR yName = $(fldr+"specYwave") yy = fldr+yName ii = fldr+"I0" ii = SelectString(exists(ii)-1,ii,fldr+"Ion0") sec = fldr+"seconds" harm = fldr+"harmonic" Wave wxx=$xx Wave wyy=$yy Wave wii=$ii Wave wsec=$sec Wave wharm=$harm if (j==0) noteStr = note(wxx) dx_combine = (wxx[1]-wxx[0])/5 endif len0=len len += numpnts($yy) Redimension/N=(len) $xwav,$ywav,$errwav wxwav[len0,len-1] = wxx[p-len0] // to compute the signal that goes into wywav, take: counts/(Io-dark) // filter = NumberByKey("PF4_trans", StrVarOrDefault(fldr+"EPICS_PVs","PF4_trans:1")) // defaults to 1, but is never >1 // do not use the filter, because it is located upstream of the ion chambers, so det/Io is still correct if (useHarmonic && WaveExists(wharm)) wywav[len0,len-1] = (wyy[p-len0]+2*wharm[p-len0]) / (wii[p-len0] - (darkIo*wsec[p-len0])) werrwav[len0,len-1] = sqrt(wyy[p-len0]+2*wharm[p-len0]) / (wii[p-len0] - (darkIo*wsec[p-len0])) else wywav[len0,len-1] = wyy[p-len0] / (wii[p-len0] - (darkIo*wsec[p-len0])) werrwav[len0,len-1] = sqrt(wyy[p-len0]) / (wii[p-len0] - (darkIo*wsec[p-len0])) endif werrwav[len0,len-1] = (werrwav[p]==0) ?1 / (wii[p-len0] - (darkIo*wsec[p-len0])) : werrwav[p] // special case for no counts j += 1 while (j0) // AppendText specInfoT(i1,"comment") // endif // str = StringByKey("DATAFILE",note(DetScaled),"=") // if (strlen(str)>1) // AppendText str // endif else SetDataFolder fldrSav endif return newfldr End Static Function rawScansExists(range) String range if (strlen(range)<1) return 0 endif range = ExpandRange(range,";") Variable j,i=0 do j = str2num(StringFromList(i,range)) if (numtype(j) && i>0) break endif if (strlen(specInfoT(j,"specCommand"))<1) // the raw data does not exists return 0 endif i += 1 while(1) return 1 End Function DisplayCombinedPlot(yWave) Wave yWave if (!WaveExists(yWave)) // no Y wave passed, querry for one String yName="DetScaled" String flist = listFoldersStartingWith("scan_") // list of possibilities String id = StringFromList(ItemsInList(flist)-1,flist) // folder id, something like "43_47" Prompt id, "id of data folder (e.g. \"62_66\")", popup, flist DoPrompt "pick wave folder", id if (V_Flag) return NaN endif String fldr = ":"+id+":" String fldrSav= GetDataFolder(1) SetDataFolder $fldr String wList = WaveList("Det*",";","") SetDataFolder $fldrSav Prompt yName, "Name of Y-wave", popup, wList DoPrompt "pick input wave", yName if (V_Flag) return NaN endif yName = fldr+yName Wave yWave=$yName endif if (!WaveExists(yWave)) print "could not find '"+yName+"'" Abort "'"+yName+"'"+" does not exist" endif // String fldr = GetWavesDataFolder(yWave,1) // get name of folder (full path) to wav fldr = GetWavesDataFolder(yWave,1) // get full path name to waves String dEname = fldr+"dE" // get name of delta-energy wave, x-axis dEname = SelectString(exists(dEname)-1,dEname,fldr+"dE_eV") if (exists(dEname)!=1) Abort "cannot x-axis wave" endif Wave dE = $dEname String noteStr = note(yWave) Variable scalefactor = NumberByKey("scaleFactor",noteStr,"=") String range = StringByKey("range",noteStr,"=") Display yWave vs dE ModifyGraph gfSize=12, tick=2, minor=1, standoff=0, lowTrip=0.001, mirror=1 ModifyGraph axOffset(left)=-1.8,axOffset(bottom)=-0.8 String errName = GetWavesDataFolder(yWave,2)+"_err" // get full path name to err wave waves if (exists(errName)==1) Wave yErr=$errName ErrorBars $NameOfWave(yWave) Y,wave=(yErr,yErr) endif if (scaleFactor==1 || numtype(scaleFactor)) // if scaleFactor is 1, then the data is not yet scaled Label left "detector / I\\Bo\\M (\\E)" else Label left "s(\\f02q\\f00,\\F'Symbol'\\f02w\\f00\\F]0) (\\u eV\\S -1 \\M\\S-3\\M)" // Label left "signal (\\E)" endif Label bottom "ĘE (\\U)" Textbox/F=0/S=3/A=RT/B=1 "Scans "+range ModifyGraph mode=4,marker=19,msize=2,lstyle=1,rgb=(0,0,65535) ModifyGraph zero(bottom)=2 SetAxis left NumVarOrDefault("root:Packages:inelasticUtility:defaultYlo",0),NumVarOrDefault("root:Packages:inelasticUtility:defaultYhi",.2) SetAxis bottom NumVarOrDefault("root:Packages:inelasticUtility:defaultXlo",-10),NumVarOrDefault("root:Packages:inelasticUtility:defaultXhi",60) Variable Q = NumberByKey("Q_Angstrom",noteStr,"=") // Q (1/) String str sprintf str, "Q = %.3f (\\S-1\\M)",Q AppendText str // sprintf str "\\F'Symbol'Dc\\F]0 = %g”",90-specInfo(i1,"chi") // AppendText str str = specInfoT(str2num(range),"comment") if (strlen(str)>0) AppendText str endif str = StringByKey("DATAFILE",noteStr,"=") if (strlen(str)>1) AppendText str endif DoWindow /C $MakeCombinedGraphName(fldr,Q) End Function/T MakeCombinedGraphName(fldr,Q) // make a graph name based on the full folder name and Q String fldr Variable Q String gname Variable i=strsearch(fldr,"scan_",1)+5 fldr = fldr[i,Inf] i = strlen(fldr)-1 if (char2num(fldr[i])==58) // 58 is ':' fldr = fldr[0,i-1] // strip off trailing ':' endif sprintf gName,"Graph_%s_%02dAng",fldr,round(Q*10) gname = UniqueName(gname,6,99) // catch presence of bad characters gname = gname[0,strlen(gname)-3] return gname End Function ReadInRangeOfScans(range,ftp) String range Variable ftp ftp = min(2,max(ftp,1)) if (strlen(range)<1) Prompt range, "range of scan numbers to read" Prompt ftp, "first ftp the data", popup, "No;Yes" DoPrompt "Read range of scans", range, ftp if (V_Flag) return 0 endif endif if (strlen(range)<1) Abort "nothing to read in" endif range = ExpandRange(range,";") SVAR rawDataFolder=root:Packages:spec:specDataFolder if (!DataFolderExists(rawDataFolder)) NewDataFolder $rawDataFolder endif SVAR specDefaultFile=root:Packages:spec:specDefaultFile if (strlen(specDefaultFile)<1) ReTargetDataFile("") endif if (ftp==2) FTPdata(specDefaultFile) endif String fldrSav= GetDataFolder(1) SetDataFolder root:raw: String str Variable N=ItemsInList(range) Variable i=0 do str = StringFromList(i, range) if (DataFolderExists("root:raw:spec"+str)) DoAlert 1, "The data for spec"+str+" already exists, delete and re-read?" if (V_Flag==1) KillDataFolder $("root:raw:spec"+str) endif endif specRead(specDefaultFile,str2num(str),"raw") i += 1 while (i2) sortType = 1 Prompt sortType, "sort graphList?",popup,"none;by index;by Q" DoPrompt "sort", sortType if (V_Flag) return "" endif sortType -= 1 endif String win, mList = MacroList("Graph_*",";","KIND:4;SUBTYPE:Graph;NPARAMS:0") Variable i,N = ItemsInList(mList) graphList = "" for (i=0;i