#pragma rtGlobals=1 // Use modern global access method. #pragma ModuleName=InelasticGen #pragma version = 2.51 #include "inelasticUtility", version>=1.4 #include "specMore" #include "JZT-analysis" #include "Xray", version>=2.1 #include "Utility_JZT", version>=2.51 #include "epics" //#include "JelliumResponse" // // with version 2.0, use s(q,w) in eV^-1 nm^-3 (was using eV^-1 ^-3) // // version 2.3 (October 9, 2005) added correction for position of elastic line in 1st moment calculation // // version 2.4 (April 2, 2006) changed graph names from 1/ to 1/nm. Then now end in nm, not Ang // // version 2.5 (Dec 17, 2006) added a filter correction to CombineSpecScans(), the filters are now after the Io due to removal of USAXS // also removed the annoying alerts about harmonic and dead time correct when using UpdateListOfScans() Menu "dataFiles" "Update A Range of Scans", UpdateListOfScans("") " ReadIn a RangeOf Scans",ReadInRangeOfScans("",0) "Renormalize All or One", ReNormAll("",NaN,"") "Dump All Combined Scans",DumpAllCombinedScans() "-" "Read Many Overnite Scans", ReadInManyOverniteScans(NaN,NaN,NaN) "Elapsed time for scans", ElapsedTimeForScans("") // "Apply CaF2 Bkg", ApplyCaF2Bkg($"","") // "Apply Flipped Bkg", ApplyFlippedBkg($"",0) "Correction Factor Compute",CorrectionFactorElement("",NaN,NaN) // "Find Elastic Center Peak", FindElasticCenterPeak("") "Moment Of Aluminum", MomentOfAluminum($"",NaN) "-" "Re-Set CombineScanList",ReSet_combineScanList() "Combine spec scans", CombineSpecScans("") // "Load a Range of Scans", LoadRangeOfSpecScansLocal("","","") "Display a Combined Plot",DisplayCombinedPlot($"") "Draw all Q Graphs", DrawAll_Q_Graphs("",1) " Reset Graph LIst", ResetGraphLIst(NaN) "Center All Elastic Lines on Graph",CenterPlotsOnGraph() "Show Avaiable Q's",ListAvailableQs() "Choose new name of data file", ReTargetDataFile("") // " FTP data [use NFS]", FTPdata("") // "Check For Double Notes in Bkg",CheckDoubleNoteInBkg(0) "Init new Igor File", InitInelasticIgorFile(0) End Menu "Macros" // "Renormalize All or One", ReNormAll("",NaN,"") "Center All plots on Elastic Line",MakeCenteredEnergies() // "Read Many Overnite Scans", ReadInManyOverniteScans(NaN,NaN,NaN) // "Elapsed time for scans", ElapsedTimeForScans("") // "Apply CaF2 Bkg", ApplyCaF2Bkg($"","") // "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",1) ; 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 // this routine checks for double notes that occured in DetScaledBkg (due to a bug), if called with doIt==4, this also fixes them Function CheckDoubleNoteInBkg(doIt) Variable doIt // doit==4 does it, otherwise just test for doubles String combineScanList = StrVarOrDefault("root:Packages:inelasticUtility:combineScanList","") if (strlen(combineScanList)<1) Abort "CheckDoubleNoteInBkg() only works when 'combineScanList' has been defined" endif String range, fldr, swav, noteStr Variable i=0,j do range = StringFromList(i,combineScanList) if (strlen(range)<1) break // done, checked all elements in combineScanList endif sprintf swav, "root:scan_%d_%d:DetScaledBkg",str2num(range),lastInRange(range) if (exists(swav)!=1) DoAlert 0, "'"+swav+"' does not exist" i += 1 continue endif Wave wav=$swav noteStr = note(wav) j = strsearch(noteStr,"\r",0) if (j>0 && doit==4) print "fixing double note string in ",swav Note/K wav Note wav, noteStr[0,j-1] elseif (j>0) DoAlert 0, "found a double note in DetScaledBkg" print "found a double note in ",swav print " so run CheckDoubleNoteInBkg(4) to fix these up" return 1 endif i += 1 while(1) if (doit!=4) print "no double notes found" endif End Function DumpAllCombinedScans() String range, fldr String combineScanList = StrVarOrDefault("root:Packages:inelasticUtility:combineScanList","") if (strlen(combineScanList)<1) Abort "DumpCombinedScans() only works when 'combineScanList' has been defined" endif String fname=IgorInfo(1)+"_dump.txt" Variable refNum Open /C="R*ch"/P=home/T="TEXT" refNum as fname fprintf refNum,"From Igor Experiment '%s', dumped %s, %s\r\r\r\r",IgorInfo(1),date(),time() String str,sdE, sy, notestr="" Variable i1,i2, i=0,j, chi do range = StringFromList(i,combineScanList) i += 1 if (strlen(range)<1) break // done, checked all elements in combineScanList endif i1 = str2num(range) i2 = lastInRange(range) sprintf fldr, "root:scan_%d_%d:",i1,i2 if (!DataFolderExists(fldr)) DoAlert 0, "Folder '"+fldr+"' does not exist" continue endif sdE = fldr+"dE" sy = fldr+"DetScaledB" if (exists(sy)!=1) sy = fldr+"DetScaled" endif if (exists(sy)!=1 || exists(sdE)!=1) DoAlert 0, "for folder '"+fldr+"' DetScaled or dE does not exist" continue endif Wave dE = $sdE Wave yy = $sy noteStr = note(yy) str = StringByKey("DATAFILE", noteStr,"=") if (strlen(str)>1) fprintf refNum,"DATAFILE=%s;",str endif str = StringByKey("DATE", noteStr,"=") if (strlen(str)>1) fprintf refNum,"DATE=%s;",str endif str = StringByKey("range", noteStr,"=") if (strlen(str)>0) fprintf refNum,"range=%s;",str chi = specInfo(str2num(str),"chi") if (abs(90-chi)>.3) fprintf refNum,"chi=%.2f;",chi endif endif str = StringByKey("Q_nm", noteStr,"=") // try for Q in (1/nm) if (strlen(str)>0) fprintf refNum,"Q_nm=%s;",str else str = StringByKey("Q_Angstrom", noteStr,"=") // if (Q not in (1/nm), try for (1/) if (strlen(str)>0) fprintf refNum,"Q_nm=%g;",str2num(str)*10 // but save Q in (1/nm) endif endif str=directionOfScan(NumberByKey("SCAN_N", noteStr,"=")) if (strlen(str)>0) fprintf refNum,"Q_direction=(%s);",str endif if (SealedIonChamber(NumberByKey("EPOCH",noteStr,"="))!=1) fprintf refNum,"ionChamber=UNsealed;" endif str = StringByKey("COMMENT", noteStr,"=") if (strlen(str)>1) fprintf refNum,"COMMENT=%s;",str endif fprintf refNum,"\r" Variable scale = NumberByKey("scaleFactor", noteStr) if (scale==1 || numtype(scale)) fprintf refNum,"dE[eV] I/Io\r" else // fprintf refNum,"dE[eV] S(q,w)[eV^-1 Angstrom^-3]\r" fprintf refNum,"dE[eV] S(q,w)[eV^-1 nm^-3]\r" endif Variable N=numpnts(dE) for (j=0;j=changeTime) return 1 else return NaN endif End Function MakeCenteredEnergies() String range, fldr, fldrSav= GetDataFolder(1) String combineScanList = StrVarOrDefault("root:Packages:inelasticUtility:combineScanList","") if (strlen(combineScanList)<1) Abort "MakeCenteredEnergies() only works when 'combineScanList' has been defined" endif String sdE,sdE0 Variable i1,i2, i=0 do range = StringFromList(i,combineScanList) if (strlen(range)<1) break // done, checked all elements in combineScanList endif i1 = str2num(range) i2 = lastInRange(range) sprintf fldr, "root:scan_%d_%d",i1,i2 if (!DataFolderExists(fldr)) DoAlert 0, "Folder '"+fldr+"' does not exist" i += 1 continue endif SetDataFolder $fldr sdE = fldr+":dE" sdE0 = fldr+":dE0" Wave dE = $sdE if (dE[0]>-1 || dE[Inf]<2) i += 1 continue // this scan does not include the elastic line endif if (exists("dE0")!=1) // make dE0 ONLY if it does not already exist Duplicate $sdE $sdE0 endif Wave dE0 = $sdE0 PlainFWHMofWave("DetScaled","dE0") NVAR center = V_center print GetDataFolder(1)," ",center dE = dE0[p] - center // dE gets changed, dE0 holds the original energy i += 1 while(1) SetDataFolder fldrSav End Function ReSet_combineScanList() String/G root:Packages:inelasticUtility:combineScanList SVAR combineScanList = root:Packages:inelasticUtility:combineScanList String fldrList = StringByKey("FOLDERS",DataFolderDir(1)) String range,fldr,wName, noteStr Variable i=0 do fldr = StringFromList(i,fldrList,",") i += 1 if (strlen(fldr)<1) break endif wName = ":"+fldr+":dE" if (!stringmatch(fldr,"scan_*") || exists(wName)!=1) continue endif Wave wav=$wName range = StringByKey("range",note(wav),"=") if (strlen(range)<1) continue endif if (WhichListItem(range,combineScanList)>=0) // range is already there continue endif printf "adding '%s' range = '%s'\r",wName,range combineScanList = AddListItem(range,combineScanList,";",Inf) // add range to end of combineScanList while(1) End //Function LoadRangeOfSpecScansLocal(range,fileName,path) // // load a range of spec scans // // it returns number of scans processed, or 0 if failed // String range // range of spec scans, ie "3-7,11,13,17-20" // String fileName // String path // // String fldrSav= GetDataFolder(1) // String fldr = StrVarOrDefault("root:Packages:spec:specDataFolder", ":" ) // if (!stringmatch(fldr,fldrSav)) // DoAlert 1, "Put raw spec data into '"+fldr+"'" // if (V_flag==1) // SetDataFolder $fldr // endif // endif // Variable n = LoadRangeOfSpecScans(range,fileName,path) // SetDataFolder fldrSav // return n //End Function ReadInManyOverniteScans(firstScan,NumOfQs,step) Variable firstScan // first scan Variable NumOfQs // number of Q scans to process Variable step // number of scans per Q // Variable doFTP = NumVarOrDefault("root:Packages:inelasticUtility:doFTP",0) if (firstScan<1 || NumOfQs<1 || step<1 || numtype(firstScan+NumOfQs+step)) firstScan = (numtype(firstScan) || firstScan<0) ? 1 : firstScan NumOfQs = (numtype(NumOfQs) || NumOfQs<1) ? 1 : NumOfQs step = (numtype(step) || step<1) ? 5 : step Prompt firstScan, "first scan number" Prompt NumOfQs, "number of Q's measured" Prompt step, "number of eVscans per Q" // doFTP += 1 // Prompt doFTP, "use FTP to get new data",popup,"No;Yes" // DoPrompt "Process Group of Scans", firstScan, NumOfQs, step, doFTP DoPrompt "Process Group of Scans", firstScan, NumOfQs, step if (V_Flag) return 0 endif // doFTP = (doFTP==2) endif printf " ReadInManyOverniteScans(%d,%d,%d)\r",firstScan,NumOfQs,step Variable j=0 String fldrSav SVAR specDefaultFile=root:Packages:spec:specDefaultFile // if (doFTP) // FTPdata(specDefaultFile) // endif String range do sprintf range, "%d-%d", firstScan, firstScan+step-1 ReadInRangeOfScans(range,0) fldrSav= GetDataFolder(1) CombineSpecScans(range) SetDataFolder fldrSav firstScan += step j += 1 while (j2 || strlen(rangeList)<1) aluminum_special = (numtype(aluminum_special) || aluminum_special<0) ? 0 : aluminum_special+1 if (strlen(scanList)) Prompt rangeList, "scan range ist for combining", popup, "all;"+scanList else Prompt rangeList, "scan range list 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?",rangeList, aluminum_special if(V_Flag) return 1 endif aluminum_special -= 1 printIt = 1 endif if (strlen(rangeList)<1) DoAlert 0,"no range of scans given" return 1 endif printIt = strlen(bkgFldr) ? printIt : 1 bkgFldr = ChooseNewBkgFolder(bkgFldr) // this also sets the global lastBkg if (strlen(bkgFldr)<1) DoAlert 0,"no background folder chosen" return 1 endif if (printIt) printf "ReNormAll(\"%s\",%d,\"%s\")\r",rangeList,aluminum_special,bkgFldr endif scanList = SelectString(stringmatch(rangeList,"all"),rangeList,scanList) 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","") String wName, eName Variable i for (i=0;i2 || 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 // printIt = 1 // endif // if (strlen(range)<1) // DoAlert 0,"no range of scans given" // return 1 // endif // printIt = strlen(bkgFldr) ? printIt : 1 // bkgFldr = ChooseNewBkgFolder(bkgFldr) // this also sets the global lastBkg // if (strlen(bkgFldr)<1) // DoAlert 0,"no background folder chosen" // return 1 // endif // if (printIt) // printf "ReNormAll(\"%s\",%d,\"%s\")\r",range,aluminum_special,bkgFldr // 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==0) ? 1 : irange // for irange==0, i starts with 1 // String wName, eName // do // if (irange>=0) // if irange ² -1, then do not chage range // 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,bkgFldr) // i += 1 // while (irange==0) // keep looping on all, only go thru once on the others // SetDataFolder fldrSav // specDataFolder = specDataFolderSAVE // scaleFactor = scaleFactorSAVE //End Function ReNormOne(range,aluminum_special,bkgFldr) String range Variable aluminum_special // 0=no, 1=yes, 2=conditional on folder name String bkgFldr // folder with background waves 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 bkgFldr = ChooseNewBkgFolder(bkgFldr) // this also sets the global lastBkg if (strlen(bkgFldr)<1) DoAlert 0,"no background folder chosen" 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] < -1.9) // only subtract bkg if dE goes beyond -2eV Variable epoch = NumberByKey("EPOCH",note(dE),"=")+Epoch_spec_Igor Variable lowEnd = (date2secs(2004,7,1) use power law tail endif SetDataFolder fldrSav specDataFolder = specDataFolderSAVE scaleFactor = scaleFactorSAVE return 0 End // using the standard CaF2 elastic peak, remove bkg from wave 'wav'. // creates the waves wavB and wavBkg, which may be added to the top plot Function ApplyCaF2Bkg(wav,bkgFldr) Wave wav // wave to remove bkg from, usually Det or DetScaled String bkgFldr // folder with background waves String fldrSav= GetDataFolder(1) Variable addToPlot=NumVarOrDefault("root:Packages:inelasticUtility:doPlotting",0) String swav if (!WaveExists(wav)) // if wav was entered as $"", then we get here 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 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 endif if (V_Flag) return NaN endif addToPlot=1 Wave wav=$swav endif bkgFldr = ChooseNewBkgFolder(bkgFldr) // this also sets the global lastBkg // done with user input if (!DataFolderExists(bkgFldr) && !DataFolderExists("root:Packages:inelasticUtility:"+bkgFldr) || !strlen(bkgFldr)) print "could not find background folder: '"+bkgFldr+"'" Abort "could not find background folder: '"+bkgFldr+"'" 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 && cmpstr(StringFromList(0,GetRTStackInfo(0)),"ReNormAll")) 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 WaveStats/Q wav Variable ilo, ihi, dEmax, level = V_max*0.25 // fit the elastic peak at only up to 25% of max. // change made Dec 04, things seem to fit better level = V_max*0.95 Wave dE=dE dEmax = dE[V_maxloc] // dE at the max, a rough approximation of the energy offset Make/O/D W_coef={dEmax,V_max} if (abs(dEmax)<.005) W_coef[0] = 0.01 endif // In this section, add a mask so that we are not fitting the peak, but the tails on the -energy side mostly // what we used to do is to fit the center of the peak between the half heights. But this does not work // properly when there is a big dead-time correction at the peak // // Ignore the peak part, and use the left side from 25% of the peak max out to -4 eV, // and on the right side go from 25% down out to +1.25 eV. String maskName = UniqueName("mask",1,0) Make/N=(numpnts(wavB)) $maskName Wave mask = $maskName mask = 0 // mask off everything ilo = BinarySearch(dE,-4+dEmax) FindLevel /P/Q/R=[ilo,V_maxloc] wav, level ihi = floor(V_LevelX) mask[ilo,ihi] = 1 // turn on from -4eV to 25% of peak if (ihi-ilo<=0) return NaN endif FindLevel /P/Q/R=[V_maxloc,Inf] wav, level ilo = ceil(V_LevelX) ihi = BinarySearch(dE,1.25+dEmax) ilo = (ilo==ihi) ? ilo-1 : ilo // if ilo==ihi, move ilo one lower mask[ilo,ihi] = 1 // turn on from 25% of peak to 1.25eV if (ihi-ilo<=0) return NaN endif String errTail = UniqueName("errTail",1,0) // make the tails carry more weight if (exists(swav+"_err")==1) Wave errw = $(swav+"_err") Duplicate $(swav+"_err") $errTail Wave errT = $errTail // change made Dec 04, things seem to fit better // errT = errw[p]^2 // what I had needed to make the tails fit errT = errw[p]^(1.15) // now a much smaller correction is needed, things work better errT = numtype(errT[p]) ? Inf : errT[p] endif if (exists(errTail)==1) FuncFit /Q CaF2_fit, W_coef, $strB /X=dE /M=mask /W=$errTail /I=1 else FuncFit /Q CaF2_fit, W_coef, $strB /X=dE /M=mask endif KillWaves/Z $maskName, $errTail String noteStr=note($strB) // This section actually subtracts background from data Note/K $strBkg Note $strBkg, noteStr Note/K $strB Note $strB, noteStr Variable i,N=numpnts(wav) for (i=0;i1) // 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[N-1]) yval = CaF[N-1] 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/K $strBkg 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 symbOK = strlen(LookUpMaterial(symb)) > 2 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 if (symbOK) Prompt symb, "atomic symbol" else Prompt symb, "atomic symbol", popup, "TiO2;NiO;CoO;LiF;CuO;MnO;FeO;CaF2;"+symbols endif 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)" DataAlMoment = numtype(DataAlMoment) ? NumVarOrDefault("momentAtInfinity",0) : DataAlMoment keV = numtype(keV) ? NaN : specinfo(NumVarOrDefault("root:Packages:spec:lastScan",0),"Eo") DoPrompt "values", symb,DataAlMoment,keV endif if (V_Flag) return NaN endif iprint = 1 endif // iprint = ( iprint || ItemsInList(GetRTStackInfo(0))<2 ) // force printing if called from command line iprint = ( iprint || topOfStack() ) // force printing if called from command line if (numtype(keV)||numtype(DataAlMoment) || DataAlMoment<=0) Abort "invalid DataAlMoment or energy, check AlMomentList" endif Variable fsumAluminum = f_sumRule(1.75) // f_sum rule for aluminum (@ 1.75 1/) Variable muAl = Get_MuFormula("Al",keV) // 1/abs_length (1/µm) Variable muZ = Get_MuFormula(symb, keV) 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 Function UpdateListOfScans(rangeList) String rangeList if (ItemsInList(GetRTStackInfo(0))<2 && numtype(str2num(rangeList))>0) Prompt rangeList, "list of range of scan ranges to combine, e.g. 1-5;7,8,9;22" DoPrompt "list of scans ranges", rangeList if (V_Flag) return 0 endif printf "UpdateListOfScans(\"%s\")\r",rangeList endif if (numtype(str2num(rangeList))) return 1 endif String range Variable i for (i=0;i0) Prompt range, "range of scan numbers to use" DoPrompt "scans to combine", range if (V_Flag) return 0 endif endif if (numtype(str2num(range))) return 1 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 String dataFolder=StrVarOrDefault("root:Packages:spec:specDataFolder","root:raw:"), fldr Variable i,j=0 // kill all existing data (this way we will force an update) do i = str2num(StringFromList(j, range)) fldr=dataFolder+"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) ? 2 : 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, i Q_Angstrom = str2num(StringByKey("Q_Angstrom",note(wav),"=")) QkF = numtype(Q_Angstrom) ? NaN : abs(Q_Angstrom)/1.75 if (numtype(QkF)) 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 // make a correction if the elastic line is not exactly at zero energy String sPeak=NameOfWave(wav) i = strlen(sPeak)-1 if (strsearch(sPeak,"B",Inf,1)==i) // check if name of wav ends in "B" sPeak = fldr+sPeak[0,i-1] // trim off trailing "B" else sPeak = GetWavesDataFolder(wav,2) // not a background removed wave, so center on the peak endif if (exists(sPeak)!=1) Abort "unable to find peak wave for setting Eo" endif PlainFWHMofWave(sPeak,fldr+"dE") NVAR Eo=V_center // center of elastic line Wave dE=$(fldr+"dE") printf "processing first moment of '%s' at Q = %g kF, elastic line at %.3f eV\r",GetWavesDataFolder(wav,2), QkF,Eo String smoment=fldr+"moment" Duplicate/O wav $smoment Wave moment=$smoment moment *= (dE[p]-Eo) // first moment corrected for shift in elastic line moment[0,ceil(BinarySearchInterp(dE,Eo))]=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+Eo,65.1+Eo) * 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+Eo,65.1+Eo) / 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 ListAvailableQs() Variable printIt = (ItemsInList(GetRTStackInfo(0))<2) 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)/10 // convert from (1/nm) to (1/) 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 && doPlotting && cmpstr(StringFromList(0,GetRTStackInfo(0)),"ReNormAll")) if (!stringmatch(StringFromList(0,GetRTStackInfo(0)),"UpdateListOfScans")) DoAlert 1, "use the harmonic to add dead-time correction" useHarmonic = (V_Flag==1) endif endif if (useHarmonic && doPlotting && cmpstr(StringFromList(0,GetRTStackInfo(0)),"ReNormAll")) if (!stringmatch(StringFromList(0,GetRTStackInfo(0)),"UpdateListOfScans")) DoAlert 0, "Note that the dead time does not yet have the correct mathematical form" endif endif Variable darkIo = NumVarOrDefault("root:Packages:inelasticUtility:darkIo",0) // default to no dark current if (darkIo<=0) // check the spec dark_Io_Name // SVAR dark_Io_Name=root:Packages:spec:dark_Io_Name // darkIo = specInfo(str2num(range),dark_Io_Name) darkIo = specInfo(str2num(range),StrVarOrDefault("root:Packages:spec:dark_Io_Name","")) endif darkIo = (darkIo>0) ? darkIo : 0 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") String yName = StrVarOrDefault(fldr+"yAxisName","") if (strlen(yName)<1) yName = StrVarOrDefault(fldr+"specYwave","") endif // 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 Wave filter = $(fldr+"filter") if (j==0) noteStr = note(wxx) // dx_combine = (wxx[1]-wxx[0])/25 // dx_combine = max(NumVarOrDefault("root:Packages:inelasticUtility:dx_combine_min",0),dx_combine) dx_combine = max(NumVarOrDefault("root:Packages:inelasticUtility:dx_combine_min",0),dx_combine) dx_combine = (dx_combine<=0)? (wxx[1]-wxx[0])/25 : dx_combine dx_combine = dx_combine<=0 ? 1 : 0.01 // this line only needed if there is only one point // print "dx_combine=",dx_combine 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])) Duplicate/O wharm wharmTemp_ wharmTemp_ = (wyy[p]<200 && wharm[p]<10) ? 0 : wharm[p] // harmonic not 2 photons if very small wywav[len0,len-1] = (wyy[p-len0]+2*wharmTemp_[p-len0]) / (wii[p-len0] - (darkIo*wsec[p-len0])) werrwav[len0,len-1] = sqrt(wyy[p-len0]+2*wharmTemp_[p-len0]) / (wii[p-len0] - (darkIo*wsec[p-len0])) KillWaves wharmTemp_ 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 // add the filter correction here. Only correct with filter if after Dec 1, 2006. if (NumberByKey("EPOCH",noteStr,"=")+Epoch_spec_Igor > date2secs(2006, 12,1)) // new data consider filter correction if (WaveExists(filter)) wywav[len0,len-1] /=filter werrwav[len0,len-1] /=filter endif endif j += 1 while (j0) 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 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 find x-axis wave" endif Wave dE = $dEname String noteStr = note(yWave) Variable scalefactor = NumberByKey("scaleFactor",noteStr) String range = StringByKey("range",noteStr,"=") Variable Q = NumberByKey("Q_nm",noteStr,"=") // Q (1/nm) if (numtype(Q)) Q = NumberByKey("Q_Angstrom",noteStr,"=")*10 // Q (1/) endif String graphWin = MakeCombinedGraphName(fldr,Q) // name of graph window Variable gExists = (strlen(WinList(graphWin, ";","WIN:1"))>0) // grah window already exists if (gExists) DoWindow /F $graphWin return 0 endif // Display yWave vs dE STRUCT boxStructure box nextWinPosition(box) Display/W=(box.l,box.t,box.r,box.b) yWave vs dE ModifyGraph tick=2, minor=1, standoff=0, lowTrip=0.001, mirror=1, gfMult=125 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(\\[1\\f02q\\f00\\X1\\S\\F'Symbol'®\\F]0,\\F'Symbol'\\M\\f02w\\f00\\F]0) (\\u eV\\S -1 \\Mnm\\S-3\\M)" endif Label bottom "ÆE (\\U)" Textbox/F=0/S=3/A=RT/B=1 SelectString(ItemsInRange(range)-1,"Scan ","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) String str // sprintf str, "Q = %.3f (\\S-1\\M)",Q // AppendText str sprintf str, "Q = %.2f (nm\\S-1\\M)",Q AppendText str sprintf str, "\\Zr070Q = %.3f (\\S-1\\M)",Q/10 AppendText str Variable dchi = 90-specInfo(str2num(range),"chi") String direction=directionOfScan(NumberByKey("SCAN_N", noteStr,"=")) if (strlen(direction)>0) AppendText "along ("+direction+")" endif if (abs(dchi)>2) // this was 0.5, not 2.0 AppendText "\\F'Symbol'Dc\\F]0 = "+num2str(dchi)+"¡" endif str = specInfoT(str2num(range),"comment") if (strlen(str)>0) AppendText str endif str = StringByKey("DATAFILE",noteStr,"=") if (strlen(str)>1) AppendText "\\Zr070"+str+"\\M" // was \Z09 endif DoWindow /C $graphWin End Static Structure boxStructure uint32 l,r,t,b EndStructure Static Function/S nextWinPosition(box) STRUCT boxStructure &box String list // fix Ang, nm here list = MacroList("Graph_*Ang",";","KIND:4;SUBTYPE:Graph") list += MacroList("Graph_*nm",";","KIND:4;SUBTYPE:Graph") list = RemoveFromList(WinList("Graph_*",";","WIN:1"),list) Variable order = ItemsInList(list) String str = StringByKey("SCREEN1",IgorInfo(0)) // get screen width Variable i=strsearch(str, "RECT=",0) Variable width = str2num(StringFromList(2,str[i+5,Inf],","))/2 - 6 // screen height Variable scrHeight = str2num(StringFromList(3,str[i+5,Inf],",")) Variable aspect=1.9 Variable height = width/aspect Variable nVert = ceil((scrHeight-height-44) / (22+height)) // number to stack vertically Variable left,top,right,bottom // window size left = round(2+mod(order,2)*(width+4)) order = mod(floor(order/2),nVert) top = round(44+order*(22+height)) bottom = floor(top+height) right = floor(left + width) box.l = left box.r = right box.t = top box.b = bottom sprintf str,"%d,%d,%d,%d",left,top,right,bottom return str End Function/T MakeCombinedGraphName(fldr,Q) // make a graph name based on the full folder name and Q String fldr Variable Q // Q in (1/nm) 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 String Qstr sprintf Qstr, "%03.0f",abs(Q)*10 // Graph name us 1/nm for Q sprintf gName,"Graph_%s_%snm",fldr,Qstr gname = UniqueName(gname,6,99) // catch presence of bad characters gname = gname[0,strlen(gname)-3] return gname End //Function/T MakeCombinedGraphName(fldr,Q) // make a graph name based on the full folder name and Q // String fldr // Variable Q // Q in (1/) // 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/T directionOfScan(scanNum) Variable scanNum String wName = UniqueName("hkl",1,0) Make/N=3/O/D $wName Wave h = $wName h[0] = specInfo(scanNum,"H") h[1] = specInfo(scanNum,"K") h[2] = specInfo(scanNum,"L") integerDirectionApprox(h,12) String str, fmt fmt = SelectString(h[0]>=0 && h[1]>=0 && h[2]>=0 && h[0]<10 && h[1]<10 && h[2]<10, "%d %d %d","%d%d%d") sprintf str, fmt,h[0],h[1],h[2] KillWaves/Z h return str End Function integerDirectionExact(hkl,maxInt) // changes vector hkl to be an approxiamtely integer vector, like integerDirectionApprox(), but exact Wave hkl Variable maxInt String wName = UniqueName("hkl",1,0) Make/N=(numpnts(hkl))/O/D $wName Wave hkli = $wName WaveStats/Q/M=1 hkl Variable biggest = max(abs(V_max),abs(V_min)) hkli = round(hkl[p]*maxInt/biggest) Variable factor = gcf(GetWavesDataFolder(hkli,2)) hkl /= factor KillWaves/Z hkli End // Function integerDirectionApprox(hkl,maxInt) // changes vector hkl to be an integer vector, approximately in same direction Wave hkl Variable maxInt WaveStats/Q/M=1 hkl Variable biggest = max(abs(V_max),abs(V_min)) hkl = round(hkl[p]*maxInt/biggest) Variable factor = gcf(GetWavesDataFolder(hkl,2)) hkl /= factor End // this revision of gcf uses the the "PrimeFactors" command available with Igor 5 Static Function gcf(factors) // find greatest common factor of a wave whose values are all integers String factors // either a list of factors or the name of a wave containing the factors String tempName="" Variable N,i if (exists(factors)==1 && strsearch(factors,";",0)<0) // passed a wave name Wave wav=$factors else N = ItemsInList(factors) // a list was passed if (N<1) return NaN endif tempName = UniqueName("tempPrimes",1,0) Make/N=(N) $tempName Wave wav=$tempName for (i=0;i=0) primeLists[i] = RemoveListItem(m,primeLists[i]) elseif (cmpstr(primeLists[i],"0;")) found=0 endif endfor if (found) gcf *= str2num(item) endif endfor KillWaves/Z primeLists,W_PrimeFactors, $tempName return gcf End Function ReadInRangeOfScans(range,ftp) String range Variable ftp // 0=no, 1=yes ftp = (ftp==1) if (strlen(range)<1) Prompt range, "range of scan numbers to read" ftp += 1 Prompt ftp, "first ftp the data", popup, "No;Yes" DoPrompt "Read range of scans", range, ftp if (V_Flag) return 0 endif ftp -= 1 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) FTPdata(specDefaultFile) endif String fldrSav= GetDataFolder(1) // SetDataFolder root:raw: SetDataFolder $rawDataFolder 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-hw || xWave[Inf]=hw) // uses internal wave scaling that spans zero PlainFWHMofWave(GetWavesDataFolder(yWave,2),"") NVAR center=V_Center ModifyGraph offset($trace)={-center,yoff} endif endfor End Function ElapsedTimeForScans(range) String range if (strlen(range)<1) Prompt range, "range of scan numbers to use" DoPrompt "Time for Scans", range if (V_Flag) return 0 endif endif range = ExpandRange(range,";") Variable N=ItemsInList(range) String wav Variable s=0, i=0 do wav = "root:raw:spec"+StringFromList(i, range)+":seconds" s += sum($wav) i += 1 while (i