#pragma rtGlobals=1 // Use modern global access method. #pragma version=5.0 #pragma IgorVersion=6.1 //******************* // Vers 1.2 100901 // //******************* // Utility procedures for handling of workfiles (each is housed in a separate datafolder) // // - adding data to a workfile // - copying workfiles to another folder // // - absolute scaling // - DIV detector sensitivity corrections // // - the WorkFile Math panel for simple image math // - // - adding work.drk data without normalizing to monitor counts //*************************** //testing procedure, not called anymore Proc Add_to_Workfile(type, add) String type,add Prompt type,"WORK data type",popup,"SAM;EMP;BGD" Prompt add,"Add to current WORK contents?",popup,"No;Yes" //macro will take whatever is in RAW folder and "ADD" it to the folder specified //in the popup menu //"add" = yes/no, don't add to previous runs //switch here - two separate functions to avoid (my) confusion Variable err if(cmpstr(add,"No")==0) //don't add to prev work contents, copy RAW contents to work and convert err = Raw_to_work(type) else //yes, add RAW to the current work folder contents err = Add_raw_to_work(type) endif String newTitle = "WORK_"+type DoWindow/F SANS_Data DoWindow/T SANS_Data, newTitle KillStrings/Z newTitle //need to update the display with "data" from the correct dataFolder fRawWindowHook() End //will "ADD" the current contents of the RAW folder to the newType work folder //and will ADD the RAW contents to the existing content of the newType folder // - used when adding multiple runs together //(the function Raw_to_work(type) makes a fresh workfile) // //the current display type is updated to newType (global) Function Add_raw_to_work(newType) String newType String destPath="" // if the desired workfile doesn't exist, let the user know, and just make a new one destPath = "root:Packages:NIST:"+newType + ":data" if(WaveExists($destpath) == 0) Print "There is no old work file to add to - a new one will be created" //call Raw_to_work(), then return from this function Raw_to_Work(newType) Return(0) //does not generate an error - a single file was converted to work.newtype Endif //now make references to data in newType folder DestPath="root:Packages:NIST:"+newType WAVE data=$(destPath +":data") // these wave references point to the EXISTING work data WAVE/T textread=$(destPath + ":textread") WAVE integersread=$(destPath + ":integersread") WAVE realsread=$(destPath + ":realsread") Variable deadTime,defmon,total_mon,total_det,total_trn,total_numruns,total_rtime Variable ii,jj,itim,cntrate,dscale,scale,uscale,wrk_beamx,wrk_beamy,xshift,yshift // 08/01 detector constants are now returned from a function, based on the detector type and beamline // dt_ornl = 3.4e-6 //deadtime of Ordella detectors as of 30-AUG-99 // dt_ill=3.0e-6 //Cerca detector deadtime constant as of 30-AUG-99 defmon=1e8 //default monitor counts //Yes, add to previous run(s) in work, that does exist //use the actual monitor count run.savmon rather than the normalized monitor count //in run.moncnt and unscale the work data total_mon = realsread[1] //saved monitor count uscale = total_mon/defmon //unscaling factor total_det = uscale*realsread[2] //unscaled detector count total_trn = uscale*realsread[39] //unscaled trans det count total_numruns = integersread[3] //number of runs in workfile total_rtime = integersread[2] //total counting time in workfile //retrieve workfile beamcenter wrk_beamx = realsread[16] wrk_beamy = realsread[17] //unscale the workfile data in "newType" // //check for log-scaling and adjust if necessary ConvertFolderToLinearScale(newType) // //then unscale the data array data *= uscale //DetCorr() has not been applied to the data in RAW , do it now in a local reference to the raw data WAVE raw_data = $"root:Packages:NIST:RAW:data" WAVE raw_reals = $"root:Packages:NIST:RAW:realsread" WAVE/T raw_text = $"root:Packages:NIST:RAW:textread" WAVE raw_ints = $"root:Packages:NIST:RAW:integersread" //check for log-scaling of the raw data - make sure it's linear ConvertFolderToLinearScale("RAW") // switches to control what is done, don't do the transmission correction for the BGD measurement NVAR doEfficiency = root:myGlobals:gDoDetectorEffCorr NVAR gDoTrans = root:myGlobals:gDoTransmissionCorr Variable doTrans = gDoTrans if(cmpstr("BGD",newtype) == 0) doTrans = 0 //skip the trans correction for the BGD file but don't change the value of the global endif DetCorr(raw_data,raw_reals,doEfficiency,doTrans) //applies correction to raw_data, and overwrites it //if RAW data is ILL type detector, correct raw_data for same counts being written to 4 pixels if(cmpstr(raw_text[9], "ILL ") == 0 ) //text field in header is 6 characters "ILL---" raw_data /= 4 endif //deadtime corrections to raw data deadTime = DetectorDeadtime(raw_text[3],raw_text[9]) //pick the correct detector deadtime itim = raw_ints[2] cntrate = sum(raw_data,-inf,inf)/itim //080802 use data sum, rather than scaler value dscale = 1/(1-deadTime*cntrate) //update totals by adding RAW values to the local ones (write to work header at end of function) total_mon += raw_reals[0] total_det += dscale*raw_reals[2] total_trn += raw_reals[39] total_rtime += raw_ints[2] total_numruns +=1 //do the beamcenter shifting if there is a mismatch //and then add the two data sets together, changing "data" since it is the workfile data xshift = raw_reals[16] - wrk_beamx yshift = raw_reals[17] - wrk_beamy If((xshift != 0) || (yshift != 0)) DoAlert 1,"Do you want to ignore the beam center mismatch?" if(V_flag==1) xshift=0 yshift=0 endif endif NVAR pixelsX = root:myGlobals:gNPixelsX NVAR pixelsY = root:myGlobals:gNPixelsY If((xshift == 0) && (yshift == 0)) //no shift, just add them data += dscale*raw_data //do the deadtime correction on RAW here else //shift the beamcenter, then add Make/O/N=1 $(destPath + ":noadd") //needed to get noadd condition back from ShiftSum() WAVE noadd = $(destPath + ":noadd") Variable sh_sum //returned value Print "BEAM CENTER MISMATCH - - BEAM CENTER WILL BE SHIFTED TO THIS FILE'S VALUE" //ii,jj are just indices here, not physical locations - so [0,127] is fine ii=0 do jj=0 do //get the contribution of shifted data sh_sum = ShiftSum(data,ii,jj,xshift,yshift,noadd) if(noadd[0]) //don't do anything to data[][] else //add the raw_data + shifted sum (and do the deadtime correction on both) data[ii][jj] += dscale*(raw_data[ii][jj]+sh_sum) //do the deadtime correction on RAW here Endif jj+=1 while(jj= 1 and will "bump up" the highest angles // so divide here to get the correct answer (5/22/08 SRK) if(doEfficiency) data[ii][jj] /= DetEffCorr(lambda,dtdist,xd,yd) // solidAngle[ii][jj] = DetEffCorr(lambda,dtdist,xd,yd) //testing only endif // large angle transmission correction is <= 1 and will "bump up" the highest angles if(doTrans) if(trans<0.1 && ii==0 && jj==0) Print "***transmission is less than 0.1*** and is a significant correction" endif if(trans==0) if(ii==0 && jj==0) Print "***transmission is ZERO*** and has been reset to 1.0 for the averaging calculation" endif trans = 1 endif data[ii][jj] /= LargeAngleTransmissionCorr(trans,dtdist,xd,yd) //moved from 1D avg SRK 11/2007 solidAngle[ii][jj] = LargeAngleTransmissionCorr(trans,dtdist,xd,yd) //testing only endif jj+=1 while(jj0.99)) //OR //small arg, approx correction correction= 1-0.5*uval*arg else //large arg, exact correction correction = (1-exp(-uval*arg))/(uval*arg) endif //end of transmission/pathlength correction return(correction) end //****************** //direct port of the FORTRAN code for calculating the weighted //shifted element to add when beam centers in data headers do not match //(indices updated to [0,n-1] indexing rather than (1,n) of fortran // // as of IGOR 4.0, could be rewritten to pass-by-reference noadd, rather than wave, but the function // is so little used, it's not worth the time Function ShiftSum(DATA,ip,jp,XSHIFT,YSHIFT,noadd) Wave data Variable ip,jp,xshift,yshift Wave noadd // // COMPUTE WEIGHTED OFFSET ELEMENT SUM FOR USE IN SANS DATA // ANALYSIS MODULES. // // "data" wave passed in is the current contents of the work file // sum_val is the return value of the function // "noadd" is passed back to the calling function as a one-point wave Variable XDELTA,YDELTA,kk,II,JJ,ISHIFT,JSHIFT,sum_val Make/O/N=4 iii,jjj,a // ----------------------------------------------------------------- ISHIFT = trunc(XSHIFT) // INTEGER PART, trunc gives int closest in dierction of zero XDELTA = XSHIFT - ISHIFT //FRACTIONAL PART. JSHIFT = trunc(YSHIFT) YDELTA = YSHIFT - JSHIFT II = ip + ISHIFT JJ = jp + JSHIFT // SHIFT IS DEFINED AS A VECTOR ANCHORED AT THE STATIONARY CENTER // AND POINTING TO THE MOVABLE CENTER. THE MOVABLE FIELD IS THUS // ACTUALLY MOVED BY -SHIFT. // IF ((XDELTA>= 0) && (YDELTA >= 0)) // CASE I ---- "%&" is "and" III[0] = II JJJ[0] = JJ III[1] = II + 1 JJJ[1] = JJ III[2] = II + 1 JJJ[2] = JJ + 1 III[3] = II JJJ[3] = JJ + 1 A[0] = (1. - XDELTA)*(1. - YDELTA) A[1] = XDELTA*(1. - YDELTA) A[2] = XDELTA*YDELTA A[3] = (1. - XDELTA)*YDELTA Endif IF ((XDELTA >= 0) && (YDELTA < 0)) // CASE II. III[0] = II JJJ[0] = JJ III[1] = II JJJ[1] = JJ - 1 III[2] = II + 1 JJJ[2] = JJ - 1 III[3] = II + 1 JJJ[3] = JJ A[0] = (1. - XDELTA)*(1. + YDELTA) A[1] = (1. - XDELTA)*(-YDELTA) A[2] = XDELTA*(-YDELTA) A[3] = XDELTA*(1. + YDELTA) Endif IF ((XDELTA < 0) && (YDELTA >= 0)) // CASE III. III[0] = II JJJ[0] = JJ III[1] = II JJJ[1] = JJ + 1 III[2] = II - 1 JJJ[2] = JJ + 1 III[3] = II - 1 JJJ[3] = JJ A[0] = (1. + XDELTA)*(1 - YDELTA) A[1] = (1. + XDELTA)*YDELTA A[2] = -XDELTA*YDELTA A[3] = -XDELTA*(1. - YDELTA) Endif IF ((XDELTA < 0) && (YDELTA < 0)) //CASE IV. III[0] = II JJJ[0] = JJ III[1] = II - 1 JJJ[1] = JJ III[2] = II - 1 JJJ[2] = JJ - 1 III[3] = II JJJ[3] = JJ - 1 A[0] = (1. + XDELTA)*(1. + YDELTA) A[1] = -XDELTA*(1. + YDELTA) A[2] = (-XDELTA)*(-YDELTA) A[3] = (1. + XDELTA)*(-YDELTA) Endif NVAR pixelsX = root:myGlobals:gNPixelsX NVAR pixelsY = root:myGlobals:gNPixelsY //check to see if iii[0],jjj[0] are valid detector elements, in [0,127] //if not set noadd[0] to 1, to let calling routine know NOT to add // CALL TESTIJ(III(1),JJJ(1),OKIJ) NOADD[0] = 0 if( (iii[0]<0) || (iii[0]>(pixelsX-1)) ) noadd[0] = 1 endif if((jjj[0]<0) || (jjj[0]>(pixelsY-1)) ) noadd[0] = 1 endif sum_val = 0. kk = 0 Do IF(JJJ[kk] == pixelsX) //do nothing else sum_val += A[kk]*DATA[III[kk]][JJJ[kk]] endif kk+=1 while(kk<4) //clean up waves KillWaves/z iii,jjj,a RETURN (sum_val) End //function ShiftSum //************************ //unused testing procedure, may not be up-to-date with other procedures //check before re-implementing // Proc DIV_a_Workfile(type) String type Prompt type,"WORK data type",popup,"COR;SAM;EMP;BGD" //macro will take whatever is in SELECTED folder and DIVide it by the current //contents of the DIV folder - the function will check for existence //before proceeding Variable err err = Divide_work(type) //returns err = 1 if data doesn't exist in specified folders if(err) Abort "error in Divide_work" endif //contents are always dumped to CAL type = "CAL" String newTitle = "WORK_"+type DoWindow/F SANS_Data DoWindow/T SANS_Data, newTitle KillStrings/Z newTitle //need to update the display with "data" from the correct dataFolder //reset the current displaytype to "type" String/G root:myGlobals:gDataDisplayType=Type fRawWindowHook() End //function will divide the contents of "type" folder with the contents of //the DIV folder // all data is converted to linear scale for the calculation // Function Divide_work(type) String type //check for existence of data in type and DIV // if the desired workfile doesn't exist, let the user know, and abort String destPath="" destPath = "root:Packages:NIST:"+Type + ":data" if(WaveExists($destpath) == 0) Print "There is no work file in "+type+"--Aborting" Return(1) //error condition Endif //check for DIV // if the DIV workfile doesn't exist, let the user know,and abort destPath = "root:Packages:NIST:DIV:data" if(WaveExists($destpath) == 0) Print "There is no work file in DIV --Aborting" Return(1) //error condition Endif //files exist, proceed //check for log-scaling of the "DIV" data and adjust if necessary ConvertFolderToLinearScale("DIV") //copy type information to CAL, wiping out the old contents of the CAL folder first //destPath = "root:Packages:NIST:CAL" //SetDataFolder destPath //KillWaves/A/Z //get rid of the old data in CAL folder //check for log-scaling of the "type" data and adjust if necessary ConvertFolderToLinearScale(type) //then continue //copy from current dir (type)=destPath to CAL, overwriting CAL contents destPath = "root:Packages:NIST:" + type Duplicate/O $(destPath + ":data"),$"root:Packages:NIST:CAL:data" // Duplicate/O $(destPath + ":vlegend"),$"root:Packages:NIST:CAL:vlegend" Duplicate/O $(destPath + ":textread"),$"root:Packages:NIST:CAL:textread" Duplicate/O $(destPath + ":integersread"),$"root:Packages:NIST:CAL:integersread" Duplicate/O $(destPath + ":realsread"),$"root:Packages:NIST:CAL:realsread" //need to save a copy of filelist string too (from the current type folder) SVAR oldFileList = $(destPath + ":fileList") //now switch to reference waves in CAL folder destPath = "root:Packages:NIST:CAL" //make appropriate wave references Wave data=$(destPath + ":data") // these wave references point to the data in CAL Wave/t textread=$(destPath + ":textread") //that are to be directly operated on Wave integersread=$(destPath + ":integersread") Wave realsread=$(destPath + ":realsread") Variable/G $(destPath + ":gIsLogScale")=0 //make new flag in CAL folder, data is linear scale //need to copy filelist string too String/G $(destPath + ":fileList") = oldFileList Wave div_data = $"root:Packages:NIST:DIV:data" //hard-wired in.... //do the division, changing data in CAL data /= div_data //update CAL header textread[1] = date() + " " + time() //date + time stamp Return(0) End //test procedure, not called anymore Proc AbsoluteScaling(type,c0,c1,c2,c3,c4,c5) String type Variable c0=1,c1=0.1,c2=0.95,c3=0.1,c4=1,c5=32.0 Prompt type,"WORK data type",popup,"CAL;COR;SAM" Prompt c0, "Sample Transmission" Prompt c1, "Sample Thickness (cm)" Prompt c2, "Standard Transmission" Prompt c3, "Standard Thickness (cm)" Prompt c4, "I(0) from standard fit (normalized to 1E8 monitor cts)" Prompt c5, "Standard Cross-Section (cm-1)" Variable err //call the function to do the math //data from "type" will be scaled and deposited in ABS err = Absolute_Scale(type,c0,c1,c2,c3,c4,c5) if(err) Abort "Error in Absolute_Scale()" endif //contents are always dumped to ABS type = "ABS" String newTitle = "WORK_"+type DoWindow/F SANS_Data DoWindow/T SANS_Data, newTitle KillStrings/Z newTitle //need to update the display with "data" from the correct dataFolder //reset the current displaytype to "type" String/G root:myGlobals:gDataDisplayType=Type fRawWindowHook() End //s_ is the standard //w_ is the "work" file //both are work files and should already be normalized to 10^8 monitor counts Function Absolute_Scale(type,w_trans,w_thick,s_trans,s_thick,s_izero,s_cross) String type Variable w_trans,w_thick,s_trans,s_thick,s_izero,s_cross //convert the "type" data to absolute scale using the given standard information //copying the "type" waves to ABS //check for existence of data, rescale to linear if needed String destPath //check for "type" destPath = "root:Packages:NIST:"+Type + ":data" if(WaveExists($destpath) == 0) Print "There is no work file in "+type+"--Aborting" Return(1) //error condition Endif //check for log-scaling of the "type" data and adjust if necessary destPath = "root:Packages:NIST:"+Type NVAR gIsLogScale = $(destPath + ":gIsLogScale") if(gIsLogScale) Duplicate/O $(destPath + ":linear_data") $(destPath + ":data")//back to linear scale Variable/G $(destPath + ":gIsLogScale")=0 //the "type" data is not logscale anymore endif //copy "oldtype" information to ABS //overwriting out the old contents of the ABS folder (/O option in Duplicate) //copy over the waves data,vlegend,text,integers,reals(read) String oldType= "root:Packages:NIST:"+type //this is where the data to be absoluted is //copy from current dir (type) to ABS, defined by destPath Duplicate/O $(oldType + ":data"),$"root:Packages:NIST:ABS:data" // Duplicate/O $(oldType + ":vlegend"),$"root:Packages:NIST:ABS:vlegend" Duplicate/O $(oldType + ":textread"),$"root:Packages:NIST:ABS:textread" Duplicate/O $(oldType + ":integersread"),$"root:Packages:NIST:ABS:integersread" Duplicate/O $(oldType + ":realsread"),$"root:Packages:NIST:ABS:realsread" //need to save a copy of filelist string too (from the current type folder) SVAR oldFileList = $(oldType + ":fileList") //need to copy filelist string too String/G $"root:Packages:NIST:ABS:fileList" = oldFileList //now switch to ABS folder //make appropriate wave references WAVE data=$"root:Packages:NIST:ABS:data" // these wave references point to the "type" data in ABS WAVE/T textread=$"root:Packages:NIST:ABS:textread" //that are to be directly operated on WAVE integersread=$"root:Packages:NIST:ABS:integersread" WAVE realsread=$"root:Packages:NIST:ABS:realsread" Variable/G $"root:Packages:NIST:ABS:gIsLogscale"=0 //make new flag in ABS folder, data is linear scale //do the actual absolute scaling here, modifying the data in ABS Variable defmon = 1e8,w_moncount,s1,s2,s3,s4 w_moncount = realsread[0] //monitor count in "type" if(w_moncount == 0) //zero monitor counts will give divide by zero --- DoAlert 0,"Total monitor count in data file is zero. No rescaling of data" Return(1) //report error Endif //calculate scale factor s1 = defmon/realsread[0] //[0] is monitor count (s1 should be 1) s2 = s_thick/w_thick s3 = s_trans/w_trans s4 = s_cross/s_izero data *= s1*s2*s3*s4 //********* 15APR02 // DO NOt correct for atenuators here - the COR step already does this, putting all of the data one equal // footing (zero atten) before doing the subtraction. // //Print "ABS data multiplied by ",s1*s2*s3*s4/attenFactor //update the ABS header information textread[1] = date() + " " + time() //date + time stamp Return (0) //no error End //************* // start of section of functions used for workfile math panel //************* //function will copy the contents of oldtype folder to newtype folder //converted to linear scale before copying //******data in newtype is overwritten******** // Function CopyWorkContents(oldtype,newtype) String oldtype,newtype //check for existence of data in oldtype // if the desired workfile doesn't exist, let the user know, and abort String destPath="" destPath = "root:Packages:NIST:"+oldType + ":data" if(WaveExists($destpath) == 0) Print "There is no work file in "+oldtype+"--Aborting" Return(1) //error condition Endif //check for log-scaling of the "type" data and adjust if necessary ConvertFolderToLinearScale(oldtype) Fix_LogLinButtonState(0) //make sure the button reflects the new linear scaling //then continue //copy from current dir (type)=destPath to newtype, overwriting newtype contents destPath = "root:Packages:NIST:" + oldtype Duplicate/O $(destPath + ":data"),$("root:Packages:NIST:"+newtype+":data") Duplicate/O $(destPath + ":textread"),$("root:Packages:NIST:"+newtype+":textread") Duplicate/O $(destPath + ":integersread"),$("root:Packages:NIST:"+newtype+":integersread") Duplicate/O $(destPath + ":realsread"),$("root:Packages:NIST:"+newtype+":realsread") //need to save a copy of filelist string too (from the current type folder) SVAR oldFileList = $(destPath + ":fileList") //now switch to reference waves in newtype folder destPath = "root:Packages:NIST:"+newtype Variable/G $(destPath + ":gIsLogScale")=0 //make new flag in newtype folder, data is linear scale //need to copy filelist string too String/G $(destPath + ":fileList") = oldFileList Return(0) End //Entry procedure from main panel // Proc CopyWorkFolder(oldType,newType) String oldType,newType Prompt oldType,"Source WORK data type",popup,"SAM;EMP;BGD;DIV;COR;CAL;RAW;ABS;STO;SUB;DRK;" Prompt newType,"Destination WORK data type",popup,"SAM;EMP;BGD;DIV;COR;CAL;RAW;ABS;STO;SUB;DRK;" // Prompt oldType,"Source WORK data type",popup,"AAA;BBB;CCC;DDD;EEE;FFF;GGG;" // Prompt newType,"Destination WORK data type",popup,"AAA;BBB;CCC;DDD;EEE;FFF;GGG;" // data folder "old" will be copied to "new" (and will overwrite) CopyWorkContents(oldtype,newtype) End //initializes datafolder and constants necessary for the workfilemath panel // Proc Init_WorkMath() //create the data folder //String str = "AAA;BBB;CCC;DDD;EEE;FFF;GGG;" String str = "File_1;File_2;Result;" NewDataFolder/O/S root:Packages:NIST:WorkMath String/G gFolderList=str Variable ii=0,num=itemsinlist(str) do Execute "NewDataFolder/O "+StringFromList(ii, str ,";") ii+=1 while(ii