#pragma rtGlobals=1 // Use modern global access method. #pragma IgorVersion=6.1 // These procedures and calculations duplicate the work of K. Krycka and WC Chen // in calculating the state of the He cell and subsequent correction of scattering data // // // SRK May 2011 // // // // there is a particular sequence of things that need to be calculated // lots of constants, and lots of confusing, similar notation. // // // for this implementation, I'll follow what is described in the "PASANS" // writeup by K. Krycka, and I'll try to follow the equations as numbered there // and keep the notation as close as possible. // // error propagation is written up elsewhere // I'll need space for 4 input files in, say SAM // - load in all of the UU files, adding together // - rename the UU data, error // // - repeat for the other three cross sections, in the SAM folder, there will be // scattering data for all four cross sections present. // // then add together the values for the coefficient matrix. // -- this can be tricky with rescaling for time, and adding to the proper row of the // coefficient matrix. I'll need to re-read either the monitor or the time from the header // of each file that was added so that the contributions are added to the matrix in correct proportion // // Then everything is set to do the inversion. // -- the result of the inversion is 4 corrected data sets, with no polarization effects. "_pc" // // Now I can one-by-one, copy the correct UU, UD, etc. into "data" and "linear_data" (and the Reals, etc) // and run through the corrections as if it was normal SANS data // // this whole procedure is going to be essentially a big script of existing procedures // // // **** search for TODO to find items still to be fixed in other procedures ********** // // // TODO: // // X- mathod to save and restore the panel state - especially the popup selections // // X- should I force the Polarization correction to be re-done just before the protocol is // executed? Then I'm sure that the PC is done. Must do for each tab (only if part of the protocol) // Except that the procedures work on the "active" tab... (YES, and this has been done) // // -- When multiple files are added together, there are changes made to the RealsRead (monCts, etc.). Are these // properly made, and then properly copied to the "_UU", and then properly copied back to the untagged waves // for use in the reduction? (now at this later date, I don't understand this question...) // // -- still not sure what is needed for absolute scaling // // -- what is the sample transmission, and exactly what +/- states are the proper measurements to use for transmission? // // -- generate some sort of report of what was set up, and what was used in the calculation // // // main entry to the PolCor Panel Proc ShowPolCorSetup() Variable restore=0 DoWindow/F PolCor_Panel if(V_flag==0) InitProtocolPanel() //this will reset the strings. restore=Initialize_PolCorPanel() PolCor_Panel() // be sure that the panel is onscreen DoIgorMenu "Control","Retrieve Window" SetWindow PolCor_Panel hook(kill)=PolCorPanelHook //to save the state when panel is killed //disable the controls on other tabs ToggleSelControls("_1_",1) ToggleSelControls("_2_",1) //restore the entries if(restore) RestorePolCorPanel() endif endif End Function RestorePolCorPanel() //restore the popup state Wave/T/Z w=root:Packages:NIST:Polarization:PolCor_popState Variable ii,num String name,popStr,list list = P_GetConditionNameList() //list of conditions if(WaveExists(w)) num = DimSize(w,0) for(ii=0;ii 0) listWave[lba.row][lba.col] = S_Selection endif endif break case 3: // double click break case 4: // cell selection case 5: // cell selection plus shift key break case 6: // begin edit break case 7: // finish edit break case 13: // checkbox clicked (Igor 6.2 or later) break endswitch return 0 End // This hook is activated when the whole window is killed. It saves the state of the popups and list boxes. // -- the protocol is not saved since it can be recalled // Function PolCorPanelHook(s) STRUCT WMWinHookStruct &s Variable hookResult = 0 switch(s.eventCode) // case 0: // Activate // // Handle activate // break // // case 1: // Deactivate // // Handle deactivate // break case 2: // kill // Handle kill // the variables with the run numbers are automatically saved and restored if not re-initialized // get a list of all of the popups String popList="",item Variable num,ii // -- old way, with popups for the conditions // popList=ControlNameList("PolCor_Panel",";","popup_*") // -- new way - list boxes automatically saved, condition popup needs to be saved popList=ControlNameList("PolCor_Panel",";","popup*") num=ItemsInList(popList,";") Make/O/T/N=(num,2) root:Packages:NIST:Polarization:PolCor_popState Wave/T w=root:Packages:NIST:Polarization:PolCor_popState for(ii=0;ii 0 && strlen(cellStr) > 0) //non-null entries, go on runList += runStr+"," // this is a comma-delimited list else if(strlen(runStr) == 0 && strlen(cellStr) == 0) // not a problem, don't bother reporting else //report the error and stop DoAlert 0,"run number or cell is not set in row "+num2str(row)+" for type "+pType SetDataFolder root: return(0) endif endif endfor Print runList // check for errors parsedRuns =ParseRunNumberList(runlist) if(strlen(parsedRuns) == 0) Print "enter a valid file number before proceeding" SetDataFolder root: return(0) endif SetDataFolder root: // find time midpoint for the files to load Variable tMid tMid = getTimeMidpoint(runList) Print/D "time midpoint",tmid // this adds multiple raw data files, as specified by the list err = AddFilesInList(type,parsedRuns) // adds to a work file = type, not RAW UpdateDisplayInformation(type) TagLoadedData(type,pType) //see also DisplayTaggedData() // now add the appropriate bits to the matrix if(!WaveExists($("root:Packages:NIST:"+type+":PolMatrix"))) Make/O/D/N=(4,4) $("root:Packages:NIST:"+type+":PolMatrix") Make/O/D/N=(4,4) $("root:Packages:NIST:"+type+":PolMatrix_err") endif WAVE matA = $("root:Packages:NIST:"+type+":PolMatrix") WAVE matA_err = $("root:Packages:NIST:"+type+":PolMatrix_err") // listStr = ControlNameList("PolCor_Panel",";","*"+pType+"*") //This loops over all of the files and adds the coefficients to the PolMatrix // the PolMatrix rows are cleared on pass 0 as each pType data is loaded. // this way repeated loading will always result in the correct fill // returns the error matrix as the squared error (take sqrt in calling function) AddToPolMatrix(matA,matA_err,pType,tMid) SetDataFolder root: return(0) End // by definition-- the rows are: // // UU = 0 // DU = 1 // DD = 2 // UD = 3 // // // TODO: // -- check all of the math // -- not yet using the midpoint time, even though it is passed in (?) // exactly where in the math would I use the time midpoint? The midpoint passed in is the // midpoint of all of the files in the list. Individual contributions to the matrix are here // calculated at the (start) time of each file. So is a midpoint really necessary? // // -- the PolMatrix_err returned from here is the squared error! // Function AddToPolMatrix(matA,matA_err,pType,tMid) Wave matA,matA_err String pType Variable tMid Variable row,Psm, PsmPf, PCell,err_Psm, err_PsmPf, err_PCell Variable ii,jj,muPo,err_muPo,gam,err_gam,monCts,t1,num,fileCount Variable Po,err_Po,Pt,err_Pt,Tmaj,Tmin,err_Tmaj,err_Tmin,Te,err_Te,mu,err_mu,summedMonCts Variable ea_uu, ea_ud, ea_dd, ea_du Variable ec_uu, ec_ud, ec_dd, ec_du String listStr,fname="",condStr,condNote,decayNote,cellStr,t0Str,t1Str,runStr // get the current tab String type Variable tabNum ControlInfo/W=PolCor_Panel PolCorTab type = S_value Print "selected data type = ",type tabNum = V_Value SetDataFolder root:Packages:NIST:Polarization // listStr = StringList("gStr_PolCor_"+num2str(tabNum)+"_*"+pType+"*", ";" ) //////////// if(tabNum == 2) //BGD data, read from UU every time, but don't change the pType tag Wave/T lb=$("ListWave_"+num2str(tabNum)+"_"+"UU") else Wave/T lb=$("ListWave_"+num2str(tabNum)+"_"+pType) endif num = DimSize(lb,0) //should be 10, as initialized // if the condition (for all of the sets) is "none", get out if(tabNum==0 || tabNum==1) ControlInfo/W=PolCor_Panel $("popup_"+num2str(tabNum)+"_1") else ControlInfo/W=PolCor_Panel $("popup_"+num2str(1)+"_1") //use the condition of the empty tab endif condStr = S_Value // Print "Using condition ",condStr," for ",type if(cmpstr(condStr, "none" ) == 0) DoAlert 0,"Condition is not set." SetDataFolder root: return(0) endif Wave condition = $("root:Packages:NIST:Polarization:Cells:"+condStr) // get wave note from condition condNote = note(condition) // get P's from note Psm = NumberByKey("P_sm", condNote, "=", ",", 0) PsmPf = NumberByKey("P_sm_f", condNote, "=", ",", 0) err_Psm = NumberByKey("err_P_sm", condNote, "=", ",", 0) err_PsmPf = NumberByKey("err_P_sm_f", condNote, "=", ",", 0) // // // find the proper propotions to add the matrix contributions // if only one file, this = 1, otherwise it should sum to one // Make/O/D/N=10 proportion proportion = 0 summedMonCts = 0 // loop over the (10) rows in the listWave for(ii=0;ii t_last) t_last = t1 runt_last = getCountTime(fname) //seconds endif endfor // print/D t_last // Print/D runt_last // print/D t_first elap = (t_last + runt_last) - t_first // from start of first file, to end of last tMid = t_first + elap/2 return(tMid) End // options to reduce one or all types, in the same manner as the load. // // largely copied from ReduceAFile() // // // // Function ReducePolCorDataButton(ctrlName) : ButtonControl String ctrlName String pType // Prompt pType,"Pol Type",popup,"UU;DU;DD;UD;All;" // DoPrompt "Type to load",pType // if (V_Flag) // return 0 // user canceled // endif // Print pType pType = "All" // get the protocol to use // this is pulled from ReduceAFile() Variable err String waveStr //pick a protocol wave from the Protocols folder //must switch to protocols folder to get wavelist (missing parameter) SetDataFolder root:myGlobals:Protocols Execute "PickAProtocol()" //get the selected protocol wave choice through a global string variable SVAR protocolName = root:myGlobals:Protocols:gProtoStr //If "CreateNew" was selected, go to the questionnare, to make a new set //and put the name of the new Protocol wave in gProtoStr if(cmpstr("CreateNew",protocolName) == 0) return(0) Endif //give the full path:name to the executeProtocol function waveStr = "root:myGlobals:Protocols:"+protocolName //samStr is set at top to "ask", since this is the action always desired from "ReduceAFile" //return data folder to root before Macro is done SetDataFolder root: if(cmpstr(pType,"All") == 0) ExecutePolarizedProtocol(waveStr,"UU") ExecutePolarizedProtocol(waveStr,"DU") ExecutePolarizedProtocol(waveStr,"DD") ExecutePolarizedProtocol(waveStr,"UD") else ExecutePolarizedProtocol(waveStr,pType) endif return(0) End // very similar to ExecuteProtocol // // // OCT 2012 - changed this to force a re-load of all of the data, and a re-calculation // of the Pol-corrected data, so that all of the "_pc" waves that are present are the // correct, and current values. Only re-loads the data that is used for the particular protocol, // just like a normal reduction. This is, somewhat redundant, since the data is re-loaded 4x, when // it really only needs to be re-loaded 1x, but this is only a minor speed hit. // // -- the "extensions" now all are "_UU_pc" and similar, to use the polarization corrected data and errors // Function ExecutePolarizedProtocol(protStr,pType) String protStr,pType //protStr is the full path to the selected protocol wave WAVE/T prot = $protStr SetDataFolder root:myGlobals:Protocols Variable filesOK,err,notDone String activeType, msgStr, junkStr, pathStr="", samStr="" PathInfo catPathName //this is where the files are pathStr=S_path NVAR useXMLOutput = root:Packages:NIST:gXML_Write //Parse the instructions in the prot wave //0 - bkg //1 - emp //2 - div //3 - mask //4 - abs params c2-c5 //5 - average params //6 = DRK file (**out of sequence) // For each of the tabs (SAM, EMP, BGD) // -- reload the data // -- re-do the polarization correction // then, and only then, after we're sure that all of the data is correct and current, then proceed with the // correction of the data with the selected protocol String dataType,str STRUCT WMButtonAction ba ba.eventCode = 2 // mouse up // Now ensure that the proper SAM data is loaded, then re-tag it // the Polarization corrected data is UU_pc, DU_pc, etc. // this tags it for display, and puts it in the correctly named waves ChangeDataTab(0) //SAM LoadRawPolarizedButton(ba) PolCorButton(ba) dataType="SAM" sprintf str,"DisplayTaggedData(\"%s\",\"%s\")",dataType,pType+"_pc" Execute str // force a re-load of BGD data, then re-tag it if(cmpstr(prot[0],"none") != 0) //if BGD is used, protStr[0] = "" ChangeDataTab(2) //BGD LoadRawPolarizedButton(ba) PolCorButton(ba) dataType="BGD" sprintf str,"DisplayTaggedData(\"%s\",\"%s\")",dataType,pType+"_pc" Execute str endif // force a re-load the EMP data, then re-tag it if(cmpstr(prot[1],"none") != 0) //if EMP is used, protStr[1] = "" ChangeDataTab(1) //EMP LoadRawPolarizedButton(ba) PolCorButton(ba) dataType="EMP" sprintf str,"DisplayTaggedData(\"%s\",\"%s\")",dataType,pType+"_pc" Execute str endif // // from here down, the steps are identical // // - with the exceptions of: // - file naming. Names are additionally tagged with pType // - if the protocol[0] or [1] are "" , then the step will be used // the step is only skipped if the protocol is "none" // //do the CORRECT step based on the answers to emp and bkg subtraction //by setting the proper"mode" //1 = both emp and bgd subtraction //2 = only bgd subtraction //3 = only emp subtraction //4 = no subtraction //additional modes 091301 // ------currently, for polarized reduction, DRK mode is not allowed or recognized at all... //11 = emp, bgd, drk //12 = bgd and drk //13 = emp and drk //14 = no subtractions //work.drk is from proto[6] // //subtracting just the DRK data is NOT an option - it doesnt' really make any physical sense // - in this case, DRK is skipped (equivalent to mode==4) // automatically accounts for attenuators given the lookup tables and the //desired subtractions //Attenuator lookup tables are alredy implemented (NG1 = NG7) // //dispatch to the proper "mode" of Correct() Variable mode=4,val do if( (cmpstr("none",prot[0]) == 0) && (cmpstr("none",prot[1]) == 0) ) //no subtraction (mode = 4), mode = 4 Endif If((cmpstr(prot[0],"none") != 0) && (cmpstr(prot[1],"none") == 0)) //subtract BGD only mode=2 Endif If((cmpstr(prot[0],"none") == 0) && (cmpstr(prot[1],"none") != 0)) //subtract EMP only mode=3 Endif If((cmpstr(prot[0],"none") != 0) && (cmpstr(prot[1],"none") != 0)) // bkg and emp subtraction are to be done (BOTH not "none") mode=1 Endif activeType = "COR" // //add in DRK mode (0= no used, 10 = used) // val = NumberByKey("DRKMODE",prot[6],"=","," ) // mode += val // print "Correct mode = ",mode err = Correct(mode) if(err) SetDataFolder root: Abort "error in Correct, called from executeprotocol, normal cor" endif TagLoadedData(activeType,pType+"_pc") UpdateDisplayInformation(ActiveType) //update before breaking from loop While(0) //check for work.div file (prot[2]) //add if needed // can't properly check the filename - so for now add and divide, if anything other than "none" //do/skip divide step based on div answer If(cmpstr("none",prot[2])!=0) // if !0, then there's a file requested If(cmpstr("ask",prot[2]) == 0) //ask user for file junkStr = PromptForPath("Select the detector sensitivity file") If(strlen(junkStr)==0) SetDataFolder root: Abort "No file selected, data reduction aborted" Endif ReadHeaderAndWork("DIV", junkStr) else //assume it's a path, and that the first (and only) item is the path:file //list processing is necessary to remove any final comma junkStr = pathStr + StringFromList(0, prot[2],"," ) ReadHeaderAndWork("DIV",junkStr) Endif //got a DIV file, select the proper type of work data to DIV (= activeType) err = Divide_work(activeType) //returns err = 1 if data doesn't exist in specified folders If(err) SetDataFolder root: Abort "data missing in DIV step, call from executeProtocol" Endif activeType = "CAL" TagLoadedData(activeType,pType+"_pc") UpdateDisplayInformation(ActiveType) //update before breaking from loop Endif Variable c2,c3,c4,c5,kappa_err //do absolute scaling if desired if(cmpstr("none",prot[4])!=0) if(cmpstr("ask",prot[4])==0) //get the params from the user Execute "AskForAbsoluteParams_Quest()" //then from the list SVAR junkAbsStr = root:myGlobals:Protocols:gAbsStr c2 = NumberByKey("TSTAND", junkAbsStr, "=", ";") //parse the list of values c3 = NumberByKey("DSTAND", junkAbsStr, "=", ";") c4 = NumberByKey("IZERO", junkAbsStr, "=", ";") c5 = NumberByKey("XSECT", junkAbsStr, "=", ";") kappa_err = NumberByKey("SDEV", junkAbsStr, "=", ";") else //get the parames from the list c2 = NumberByKey("TSTAND", prot[4], "=", ";") //parse the list of values c3 = NumberByKey("DSTAND", prot[4], "=", ";") c4 = NumberByKey("IZERO", prot[4], "=", ";") c5 = NumberByKey("XSECT", prot[4], "=", ";") kappa_err = NumberByKey("SDEV", prot[4], "=", ";") Endif //get the sample trans and thickness from the activeType folder String destStr = "root:Packages:NIST:"+activeType+":realsread" Wave dest = $destStr Variable c0 = dest[4] //sample transmission Variable c1 = dest[5] //sample thickness err = Absolute_Scale(activeType,c0,c1,c2,c3,c4,c5,kappa_err) if(err) SetDataFolder root: Abort "Error in Absolute_Scale(), called from executeProtocol" endif activeType = "ABS" TagLoadedData(activeType,pType+"_pc") UpdateDisplayInformation(ActiveType) //update before breaking from loop Endif //check for mask //add mask if needed // can't properly check the filename - so for now always add //doesn't change the activeType if(cmpstr("none",prot[3])!=0) If(cmpstr("ask",prot[3])==0) //get file from user junkStr = PromptForPath("Select Mask file") If(strlen(junkStr)==0) //no selection of mask file is not a fatal error, keep going, and let cirave() //make a "null" mask //if none desired, make sure that the old mask is deleted //junkStr = GetDataFolder(1) //SetDataFolder root:Packages:NIST:MSK KillWaves/Z root:Packages:NIST:MSK:data //SetDataFolder junkStr DoAlert 0,"No Mask file selected, data not masked" else //read in the file from the dialog ReadMCID_MASK(junkStr) Endif else //just read it in from the protocol //list processing is necessary to remove any final comma junkStr = pathStr + StringFromList(0, prot[3],"," ) ReadMCID_MASK(junkStr) Endif else //if none desired, make sure that the old mask is deleted //junkStr = GetDataFolder(1) //SetDataFolder root:Packages:NIST:MSK KillWaves/Z root:Packages:NIST:MSK:data //SetDataFolder junkStr Endif //mask data if desired (this is done automatically in the average step) and is //not done explicitly here (if no mask in MSK folder, a null mask is created and "used") // average/save data as specified //Parse the keyword= string as needed, based on AVTYPE //average/plot first String av_type = StringByKey("AVTYPE",prot[5],"=",";") If(cmpstr(av_type,"none") != 0) If (cmpstr(av_type,"")==0) //if the key could not be found... (if "ask" the string) //get the averaging parameters from the user, as if the set button was hit //in the panel SetAverageParamsButtonProc("dummy") //from "ProtocolAsPanel" SVAR tempAveStr = root:myGlobals:Protocols:gAvgInfoStr av_type = StringByKey("AVTYPE",tempAveStr,"=",";") else //there is info in the string, use the protocol //set the global keyword-string to prot[5] String/G root:myGlobals:Protocols:gAvgInfoStr = prot[5] Endif Endif //convert the folder to linear scale before averaging, then revert by calling the window hook ConvertFolderToLinearScale(activeType) strswitch(av_type) //dispatch to the proper routine to average to 1D data case "none": //still do nothing break case "2D_ASCII": //do nothing break case "QxQy_ASCII": //do nothing break case "PNG_Graphic": //do nothing break case "Rectangular": RectangularAverageTo1D(activeType) break case "Annular": AnnularAverageTo1D(activeType) break case "Circular": CircularAverageTo1D(activeType) break case "Sector": CircularAverageTo1D(activeType) break case "Sector_PlusMinus": Sector_PlusMinus1D(activeType) break default: //do nothing endswitch ///// end of averaging dispatch // put data back on log or lin scale as set by default fRawWindowHook() //save data if desired String fullpath = "", newfileName="" String item = StringByKey("SAVE",prot[5],"=",";") //does user want to save data? If( (cmpstr(item,"Yes")==0) && (cmpstr(av_type,"none") != 0) ) //then save //get name from textwave of the activeType dataset String textStr = "root:Packages:NIST:"+activeType+":textread" Wave/T textPath = $textStr String tempFilename = samStr If(WaveExists(textPath) == 1) #if (exists("QUOKKA")==6) newFileName = ReplaceString(".nx.hdf", tempFilename, "") #elif (exists("HFIR")==6) // newFileName = ReplaceString(".xml",textPath[0],"") //removes 4 chars // newFileName = ReplaceString("SANS",newFileName,"") //removes 4 more chars = 8 // newFileName = ReplaceString("exp",newFileName,"") //removes 3 more chars = 11 // newFileName = ReplaceString("scan",newFileName,"") //removes 4 more chars = 15, should be enough? newFileName = GetPrefixStrFromFile(textPath[0])+GetRunNumStrFromFile(textPath[0]) #else newFileName = UpperStr(GetNameFromHeader(textPath[0])) //NCNR data drops here, trims to 8 chars #endif else newFileName = "" //if the header is missing? //Print "can't read the header - newfilename is null" Endif //pick ABS or AVE extension String exten = activeType if(cmpstr(exten,"ABS") != 0) exten = "AVE" endif if(cmpstr(av_type,"2D_ASCII") == 0) exten = "ASC" endif if(cmpstr(av_type,"QxQy_ASCII") == 0) exten = "DAT" endif // add an "x" to the file extension if the output is XML // currently (2010), only for ABS and AVE (1D) output if( cmpstr(exten,"ABS") == 0 || cmpstr(exten,"AVE") == 0 ) if(useXMLOutput == 1) exten += "x" endif endif //Path is catPathName, symbolic path //if this doesn't exist, a dialog will be presented by setting dialog = 1 // // -- add in pType tag to the name for the polarization "type" // Variable dialog = 0 PathInfo/S catPathName item = StringByKey("NAME",prot[5],"=",";") //Auto or Manual naming String autoname = StringByKey("AUTONAME",prot[5],"=",";") //autoname - will get empty string if not present If((cmpstr(item,"Manual")==0) || (cmpstr(newFileName,"") == 0)) //manual name if requested or if no name can be derived from header fullPath = newfileName + pType + "."+ exten //puts possible new name or null string in dialog dialog = 1 //force dialog for user to enter name else //auto-generate name and prepend path - won't put up any dialogs since it has all it needs //use autoname if present if (cmpstr(autoname,"") != 0) fullPath = S_Path + autoname + pType + "." +exten else fullPath = S_Path + newFileName + pType + "." + exten endif Endif // strswitch(av_type) case "Annular": WritePhiave_W_Protocol(activeType,fullPath,dialog) break case "2D_ASCII": Fast2DExport(activeType,fullPath,dialog) break case "QxQy_ASCII": QxQy_Export(activeType,fullPath,dialog) break case "PNG_Graphic": SaveAsPNG(activeType,fullpath,dialog) break default: if (useXMLOutput == 1) WriteXMLWaves_W_Protocol(activeType,fullPath,dialog) else WriteWaves_W_Protocol(activeType,fullpath,dialog) endif endswitch //Print "data written to: "+ fullpath Endif //done with everything in protocol list return(0) End // just like the RecallProtocolButton // - the reset function is different // Function RecallPolCorProtocolButton(ctrlName) : ButtonControl String ctrlName //will reset panel values based on a previously saved protocol //pick a protocol wave from the Protocols folder //MUST move to Protocols folder to get wavelist SetDataFolder root:myGlobals:Protocols Execute "PickAProtocol()" //get the selected protocol wave choice through a global string variable SVAR protocolName = root:myGlobals:Protocols:gProtoStr //If "CreateNew" was selected, ask user to try again if(cmpstr("CreateNew",protocolName) == 0) Abort "CreateNew is for making a new Protocol. Select a previously saved Protocol" Endif //reset the panel based on the protocol textwave (currently a string) ResetToSavedPolProtocol(protocolName) SetDataFolder root: return(0) end //function that actually parses the protocol specified by nameStr //which is just the name of the wave, without a datafolder path // Function ResetToSavedPolProtocol(nameStr) String nameStr //allow special cases of Base and DoAll Protocols to be recalled to panel - since they "ask" //and don't need paths String catPathStr PathInfo catPathName catPathStr=S_path //SetDataFolder root:myGlobals:Protocols //on windows, data folder seems to get reset (erratically) to root: Wave/T w=$("root:myGlobals:Protocols:" + nameStr) String fullPath="",comma=",",list="",nameList="",PathStr="",item="" Variable ii=0,numItems,checked,specialProtocol=0 if((cmpstr(nameStr,"Base")==0) || (cmpstr(nameStr,"DoAll")==0)) return(0) //don't allow these Endif //background = check5 checked = 1 nameList = w[0] If(cmpstr(nameList,"none") ==0) checked = 0 Endif //set the global string to display and checkbox CheckBox check5 win=PolCor_Panel,value=checked //EMP = check4 checked = 1 nameList = w[1] If(cmpstr(nameList,"none") ==0) checked = 0 Endif //set the global string to display and checkbox CheckBox check4 win=PolCor_Panel,value=checked //DIV file checked = 1 nameList = w[2] If(cmpstr(nameList,"none") ==0) checked = 0 Endif //set the global string to display and checkbox String/G root:myGlobals:Protocols:gDIV = nameList CheckBox check0 win=PolCor_Panel,value=checked //Mask file checked = 1 nameList = w[3] If(cmpstr(nameList,"none") ==0) checked = 0 Endif //set the global string to display and checkbox String/G root:myGlobals:Protocols:gMASK = nameList CheckBox check1 win=PolCor_Panel,value=checked //4 = abs parameters list = w[4] numItems = ItemsInList(list,";") checked = 1 if(numitems == 4 || numitems == 5) //allow for protocols with no SDEV list item //correct number of parameters, assume ok String/G root:myGlobals:Protocols:gAbsStr = list CheckBox check2 win=PolCor_Panel,value=checked else item = StringFromList(0,list,";") if(cmpstr(item,"none")==0) checked = 0 list = "none" String/G root:myGlobals:Protocols:gAbsStr = list CheckBox check2 win=PolCor_Panel,value=checked else //force to "ask" checked = 1 String/G root:myGlobals:Protocols:gAbsStr = "ask" CheckBox check2 win=PolCor_Panel,value=checked Endif Endif //5 = averaging choices list = w[5] item = StringByKey("AVTYPE",list,"=",";") if(cmpstr(item,"none") == 0) checked = 0 String/G root:myGlobals:Protocols:gAVE = "none" CheckBox check3 win=PolCor_Panel,value=checked else checked = 1 String/G root:myGlobals:Protocols:gAVE = list CheckBox check3 win=PolCor_Panel,value=checked Endif //6 = DRK choice //7 = unused //all has been reset, get out Return (0) End Function ExportPolCorProtocolButton(ctrlName) : ButtonControl String ctrlName ExportProtocol(ctrlName) return(0) End Function ImportPolCorProtocolButton(ctrlName) : ButtonControl String ctrlName ImportProtocol(ctrlName) return(0) End // at a first pass, uses the regular reduction protocol SaveProtocolButton(ctrlName) // // TODO // X- won't work, as it uses the MakeProtocolFromPanel function... so replace this // Function SavePolCorProtocolButton(ctrlName) : ButtonControl String ctrlName Variable notDone=1, newProto=1 //will prompt for protocol name, and save the protocol as a text wave //prompt for name of new protocol wave to save do Execute "AskForName()" SVAR newProtocol = root:myGlobals:Protocols:gNewStr //make sure it's a valid IGOR name newProtocol = CleanupName(newProtocol,0) //strict naming convention String/G root:myGlobals:Protocols:gNewStr=newProtocol //reassign, if changed Print "newProtocol = ",newProtocol SetDataFolder root:myGlobals:Protocols if(WaveExists( $("root:myGlobals:Protocols:" + newProtocol) ) == 1) //wave already exists DoAlert 1,"That name is already in use. Do you wish to overwrite the existing protocol?" if(V_Flag==1) notDone = 0 newProto = 0 else notDone = 1 endif else //name is good notDone = 0 Endif while(notDone) //current data folder is root:myGlobals:Protocols if(newProto) Make/O/T/N=8 $("root:myGlobals:Protocols:" + newProtocol) Endif // MakeProtocolFromPanel( $("root:myGlobals:Protocols:" + newProtocol) ) MakePolProtocolFromPanel( $("root:myGlobals:Protocols:" + newProtocol) ) String/G root:myGlobals:Protocols:gProtoStr = newProtocol //the data folder WAS changed above, this must be reset to root: SetDatafolder root: return(0) End //function that does the guts of reading the panel controls and globals //to create the necessary text fields for a protocol //Wave/T w (input) is an empty text wave of 8 elements for the protocol //on output, w[] is filled with the protocol strings as needed from the panel // // -- For polarized beam protocols, don't fill in EMP or BGD, as these are handled differently, since 4 XS // Function MakePolProtocolFromPanel(w) Wave/T w //construct the protocol text wave form the panel //it is to be parsed by ExecuteProtocol() for the actual data reduction PathInfo catPathName //this is where the files came from String pathstr=S_path,tempStr,curList Variable checked,ii,numItems //look for checkboxes, then take each item in list and prepend the path //w[0] = background ControlInfo/W=PolCor_Panel check5 checked = V_Value if(checked) w[0] = "" // BKG will be used else w[0] = "none" // BKG will not be used endif //w[1] = empty ControlInfo/W=PolCor_Panel check4 checked = V_Value if(checked) w[1] = "" // EMP will be used else w[1] = "none" // EMP will not be used endif //w[2] = div file ControlInfo/W=PolCor_Panel check0 checked = V_value if(checked) //build the list //just read the global SVAR str=root:myGlobals:Protocols:gDIV if(cmpstr(str,"ask")==0) w[2] = str else tempStr = ParseRunNumberList(str) if(strlen(tempStr)==0) return(1) else w[2] = tempstr str=tempstr endif endif else //none used - set textwave (and global?) w[2] = "none" String/G root:myGlobals:Protocols:gDIV = "none" endif //w[3] = mask file ControlInfo/W=PolCor_Panel check1 checked = V_value if(checked) //build the list //just read the global SVAR str=root:myGlobals:Protocols:gMASK if(cmpstr(str,"ask")==0) w[3] = str else tempstr = ParseRunNumberList(str) if(strlen(tempstr)==0) return(1) else w[3] = tempstr str = tempstr endif endif else //none used - set textwave (and global?) w[3] = "none" String/G root:myGlobals:Protocols:gMASK = "none" endif //w[4] = abs parameters ControlInfo/W=PolCor_Panel check2 checked = V_value if(checked) //build the list //just read the global SVAR str=root:myGlobals:Protocols:gAbsStr w[4] = str else //none used - set textwave (and global?) w[4] = "none" String/G root:myGlobals:Protocols:gAbsStr = "none" endif //w[5] = averaging choices ControlInfo/W=PolCor_Panel check3 checked = V_value if(checked) //just read the global SVAR avestr=root:myGlobals:Protocols:gAVE w[5] = avestr else //none used - set textwave w[5] = "AVTYPE=none;" endif //w[6] //work.DRK information SVAR drkStr=root:myGlobals:Protocols:gDRK w[6] = "" //w[7] //currently unused w[7] = "" return(0) End // the data in the SAM, EMP, BKG folders will be either _UU or _UU_pc, depending if the data // is as-loaded, or if it's been polarization corrected. This is to display the polarization-corrected "_pc" // data sets ONLY. If you want to see the individual data sets, well that's just the SAM, EMP, BGD files. // look at thum one-by-one... // // -- data in subsequent correction step folders do have the _pc extensions, the _pc data is // used for each step, so the _pc is redundant, but consistent // Function Display_4(type,scaling) String type,scaling String dest = "root:Packages:NIST:"+type NVAR isLogscale = $(dest + ":gIsLogScale") SetDataFolder $("root:Packages:NIST:"+type) wave uu = linear_data_uu_pc wave d_uu = data_uu_pc wave du = linear_data_du_pc wave d_du = data_du_pc wave dd = linear_data_dd_pc wave d_dd = data_dd_pc wave ud = linear_data_ud_pc wave d_ud = data_ud_pc if(cmpstr(scaling,"log") == 0) d_uu = log(uu) d_du = log(du) d_dd = log(dd) d_ud = log(ud) isLogScale = 1 else d_uu = uu d_du = du d_dd = dd d_ud = ud isLogScale = 0 endif DoWindow/F SANS_X4 if(V_flag==0) Display /W=(811,44,1479,758)/K=1 ControlBar 100 DoWindow/C SANS_X4 DoWindow/T SANS_X4,type+"_pc" Button button0 pos={130,65},size={50,20},title="Do It",proc=Change4xsButtonProc PopupMenu popup0 pos={20,35},title="Data Type",value="SAM;EMP;BGD;COR;CAL;ABS;" //RAW, SAS, DIV, etc, won't have _pc data and are not valid PopupMenu popup1 pos={190,35},title="Scaling",value="log;linear;" TitleBox title0 title="Only Polarization-corrected sets are displayed",pos={5,5} else RemoveImage/Z data_uu_pc //remove the old images (different data folder) RemoveImage/Z data_du_pc RemoveImage/Z data_dd_pc RemoveImage/Z data_ud_pc DoWindow/T SANS_X4,type+"_pc" endif AppendImage/B=bot_uu/L=left_uu data_UU_pc ModifyImage data_UU_pc ctab= {*,*,YellowHot,0} AppendImage/B=bot_dd/L=left_dd data_DD_pc ModifyImage data_DD_pc ctab= {*,*,YellowHot,0} AppendImage/B=bot_du/L=left_du data_DU_pc ModifyImage data_DU_pc ctab= {*,*,YellowHot,0} AppendImage/B=bot_ud/L=left_ud data_UD_pc ModifyImage data_UD_pc ctab= {*,*,YellowHot,0} DoUpdate ModifyGraph freePos(left_uu)={0,kwFraction},freePos(bot_uu)={0.6,kwFraction} ModifyGraph freePos(left_dd)={0,kwFraction},freePos(bot_dd)={0,kwFraction} ModifyGraph freePos(left_du)={0.6,kwFraction},freePos(bot_du)={0.6,kwFraction} ModifyGraph freePos(left_ud)={0.6,kwFraction},freePos(bot_ud)={0,kwFraction} ModifyGraph axisEnab(left_uu)={0.6,1},axisEnab(bot_uu)={0,0.4} ModifyGraph axisEnab(left_dd)={0,0.4},axisEnab(bot_dd)={0,0.4} ModifyGraph axisEnab(left_du)={0.6,1},axisEnab(bot_du)={0.6,1} ModifyGraph axisEnab(left_ud)={0,0.4},axisEnab(bot_ud)={0.6,1} ModifyGraph standoff=0 ModifyGraph lblPosMode(left_uu)=4,lblPosMode(left_dd)=4,lblPosMode(left_du)=4,lblPosMode(left_ud)=4 ModifyGraph lblPos(left_uu)=40,lblPos(left_dd)=40,lblPos(left_du)=40,lblPos(left_ud)=40 Label left_uu "UU" Label left_dd "DD" Label left_du "DU" Label left_ud "UD" ModifyGraph fSize=16 // force a redraw to get the axes in the right spot DoUpdate SetDataFolder root: return(0) End Function Change4xsButtonProc(ba) : ButtonControl STRUCT WMButtonAction &ba String dataType,scaling switch( ba.eventCode ) case 2: // mouse up // click code here ControlInfo popup0 dataType = S_Value ControlInfo popup1 scaling = S_Value Display_4(dataType,scaling) break case -1: // control being killed break endswitch return 0 End // clear the entries for all 4 XS for the currently selected Tab only // clears both the run numbers and the cell assignments // Function ClearPolCorEntries(ba) : ButtonControl STRUCT WMButtonAction &ba switch( ba.eventCode ) case 2: // mouse up // click code here // // String type Variable tabNum ControlInfo/W=PolCor_Panel PolCorTab // type = S_value // Print "selected data type = ",type,V_Value tabNum = V_Value WAVE/T twDD = $("root:Packages:NIST:Polarization:ListWave_"+num2str(tabNum)+"_DD") WAVE/T twUU = $("root:Packages:NIST:Polarization:ListWave_"+num2str(tabNum)+"_UU") WAVE/T twUD = $("root:Packages:NIST:Polarization:ListWave_"+num2str(tabNum)+"_UD") WAVE/T twDU = $("root:Packages:NIST:Polarization:ListWave_"+num2str(tabNum)+"_DU") twDD = "" twUU = "" twUD = "" twDU = "" break case -1: // control being killed break endswitch return 0 End ////////////////////////////////////////////////////////////// // /////////// all of the functions below are unused. See the procedures for the //// panels for the functions that interact with the input and calculated matrices // // // // // //// //// (/S) FindFileFromRunNumber(num) gets fname //// [4] is trans, [41] is trans error, [40] is Twhole //// // // // //Constant kTe = 0.87 // transmission of the unfilled cell // // // //// calculation of mu //// //// Known: Te ===> Global constant currently, may change later //// //// Input: T He (unpolarized), using unpolarized beam //// T He cell out, using unpolarized beam //// T background, using unpolarized beam //// //// Equation 7 //// //Function opacity_mu(T_he,T_out,T_bk) // Variable T_he,T_out,T_bk // // Variable mu // //// using the global constant! // // mu = (1/kTe)*(T_he - T_bk)/(T_out - t_bk) // mu = -1*ln(mu) // // return(mu) //End // // // //Proc calc_muP(mu, runT_he, runT_out, runT_bk) // Variable mu=3.108, runT_he, runT_out, runT_bk // // Variable muP,T_he, T_out, T_bk // String fname // // fname = FindFileFromRunNumber(runT_he) // T_he = getDetCount(fname)/getMonitorCount(fname)/getCountTime(fname) //use CR, not trans (since no real empty condition) // // fname = FindFileFromRunNumber(runT_out) // T_out = getDetCount(fname)/getMonitorCount(fname)/getCountTime(fname) // // fname = FindFileFromRunNumber(runT_bk) // T_bk = getDetCount(fname)/getMonitorCount(fname)/getCountTime(fname) // // muP = Cell_muP(mu, T_he, T_out, T_bk) // // Print "Count rates T_he, T_out, T_bk = ",T_he, T_out, T_bk // Print "Mu*P = ",muP // Print "Time = ",getFileCreationDate(fname) // //end // // //// ???? is this correct ???? //// -- check the form of the equation. It's not the same in some documents //// //// calculation of mu.P(t) from exerimental measurements //// //// Known: Te and mu //// Input: T He cell (polarized cell), using unpolarized beam //// T He cell OUT, using unpolarized beam //// T background, using unpolarized beam //// //// Equation 9, modified by multiplying the result by mu + moving tmp inside the acosh() //// //Function Cell_muP(mu, T_he, T_out, T_bk) // Variable mu, T_he, T_out, T_bk // //// using the global constant! // // Variable muP,tmp // // tmp = kTe*exp(-mu) //note mu has been moved // muP = acosh( (T_he - T_bk)/(T_out - T_bk) * (1/tmp)) // // return(muP) //End // // //// //// calculation of mu.P(t) from Gamma and t=0 value //// //// Known: Gamma, muP_t0, t0, tn //// //// times are in hours, Gamma [=] hours //// tn is later than t0, so t0-tn is negative //// //// Equation 11 //// //Function muP_at_t(Gam_He, muP_t0, t0, tn) // Variable Gam_He, muP_t0, t0, tn // // Variable muP // // muP = muP_t0 * exp( (t0 - tn)/Gam_He ) // // return(muP) //End // //// Calculation of Pcell(t) //// note that this is a time dependent quantity //// //// Known: muP(t) //// Input: nothing additional //// //// Equation 10 //// //Function PCell(muP) // Variable muP // // Variable PCell // PCell = tanh(muP) // // return(PCell) //End // // //// calculation of Pf (flipper) //// //// Known: nothing //// Input: Tuu, Tdu, and Tdd, Tud //// (but exactly what measurement conditions?) //// ( are these T's also calculated quantities???? -- Equation(s) 12--) //// //// Equation 14 //// //// (implementation of equation 13 is more complicated, and not implemented yet) //// //Function Flipper_Pf(Tuu, Tdu, Tdd, Tud) // Variable Tuu, Tdu, Tdd, Tud // // Variable pf // // pf = (Tdd - Tdu)/(Tuu - Tud) // // return(pf) //End // // // //// (this is only one of 4 methods, simply the first one listed) //// ???? this equation doesn't match up with the equation in the SS handout //// //// calculation of P'sm (supermirror) //// //// Known: Pcell(t1), Pcell(t2) (some implementations need Pf ) //// Input: Tuu(t1), Tud(t2) //// //// Equation 15?? //// //Function SupMir_Psm(Pcell1,Pcell2,Tuu,Tud) // Variable Pcell1,Pcell2,Tuu,Tud // // Variable Psm // // Psm = (Tuu - Tud)/(PCell1 + PCell2) // // return(Psm) //End