\subsection{Scan} The first version of the scan command was implemented in Tcl. This prooved to be inefficient. Therefore scan was reimplemented in C. Scanning seems to be simple but is not because of the many special cases involved: \begin{itemize} \item Scans must be interruptable and continuable \item Data files need to be written in different formats \item Different output has to be generated at various steps \item In polarization measurements, several points with different magnetic field orientations need to be measured at the same instrument position. \item Users might want to be specify complex scan paths or scan on logarithmic axis. \end{itemize} I order to cope with all this, the scan module is modifiable in two ways: For each step of the scanning process there is an overloadable function in the scan data structure. The first way to modify scan behavious thus is to write new functions in C and to assign them to the scan module. In order to support scriptable scans another system is in place: Stored in a string dictioanary there are the names of SICS functions which will be called at each scan operation. The scan functions then invoke the functions specified. In order for this to work, the scan must be configured "newscan". These two schemes exits because the scan module is in transition to a refactoring towards the second scheme. The principal setup thus is a central scan object which deals with all the scan management: storing variables, positions, counting results etc. and the configuration of the scan. This is augmented by libraries of scan functions which get invoked at the various steps. There is a standard scan library which is doumented here as well. \subsubsection{Scan Variables} Scan variables are held in this data structure: @d scanvar @{ typedef struct { char Name[132]; pIDrivable pInter; pDummy pObject; float fStart; float fStep; float *fData; int dataList; int logVar; }VarEntry, *pVarEntry; @} The VarEntry structure holds the data for each single scan variable. These are its name, its object data structures, the start and step values for the scan and in dataList the positions actually reached during the scan. Scan variables have an interface: @d scanvarint @{ /** * MakeScanVar creates a scan variable. All the necessary checks are * performed * @@param pSics The interpreter in order to locate the variable. * @@param pCon A connection object for error reporting * @@param name The name of the variable to scan * @@param start The start position from which to scan * @@param step The step width with which to scan. * @@return A pointer to a new scan variable object on success, NULL * else */ pVarEntry MakeScanVar(SicsInterp *pSics, SConnection *pCon, char *name, float start, float step); /** * make a variable which is logged during the scan but not driven. * @@param pSics The interpreter in order to locate the variable. * @@param pCon A connection object for error reporting * @@param name The name of the variable to log */ pVarEntry MakeLogVar(SicsInterp *pSics, SConnection *pCon, char *name); /** * InitScanVar clears the list of scan points * @@param pvar The scna variable to clear */ void InitScanVar(pVarEntry pVar); /** * DeleteVarEntry deletes a scan variable. * @@param pData The scan variable entry to delete. */ void DeleteVarEntry(void *pData); /** * ScanVarName returns the name of the scan variable * @@param pVar The scan variable to query. * @@return The name of the scan variable. Do not delete pointer. */ char *ScanVarName(pVarEntry pVar); /** * ScanVarStart returns the start value for the scan * @@param pVar The scan variable to query. * @@return The start point for the scan. */ float ScanVarStart(pVarEntry pVar); /** * ScanVarStep returns the start value for the scan * @@param pVar The scan variable to query. * @@return The step width for the scan. */ float ScanVarStep(pVarEntry pVar); /** * StartScanVar starts the scan variable to drive to the next * position. * @@param pVar The scan variable to start. * @@param pCon The connection to report errors to. * @@param i The position number to drive to * @@return 1 on success, 0 on failure */ int StartScanVar(pVarEntry pVar, SConnection *pCon, int i); /** * AppendScanVar appends a position to the list of positions * reached while scanning this variable. * @@param pVar The scan variable to append to. * @@param pos The position to append. */ void AppendScanVar(pVarEntry pVar, float pos); /** * GetScanVarPos returns a position for an index. * @@param pVar The scan variable to append to. * @@param i The position number to retrieve * @@return The positiopn or -99999.99 for an error */ float GetScanVarPos(pVarEntry pVar, int i); /** * CopyScanVar copies the scan positions to the array given. * @@param pVar The scan variable to copy from * @@param fData The array to copy to. * @@param np The number of slots in fData. */ void CopyScanVar(pVarEntry pVar, float *fData, int np); /** * CheckScanVar checks if the scan variable can be driven through the * whole range. * @@param pVar The scan variable to check * @@param pCon The connection object to which to report errors. * @@param np The number of points to check for. * @@return 0 on failuyre, 1 on success */ int CheckScanVar(pVarEntry pVar, SConnection *pCon, int np); /** * queries if the variable is alogged variable or a drive one. * @@param pVar The variable to query. * @@return 1 if log var, 0 else */ int isLogVar(pVarEntry pVar); @} \subsubsection{The Scan Object} @d scandata @{ /*--------------------------------------------------------------------------*/ typedef struct { int i; long lCount; long Monitors[10]; float fTime; } CountEntry, *pCountEntry; /*---------------------------------------------------------------------------*/ typedef struct __ScanData { pObjectDescriptor pDes; pICallBack pCall; pDynar pScanVar; char objectName[132]; int iScanVar; int iNP; int iMode; float fPreset; char pFile[1024]; FILE *fd; SicsInterp *pSics; SConnection *pCon; char pRecover[1024]; char pHeaderFile[1024]; int (*PrepareScan)(pScanData self); int (*WriteHeader)(pScanData self); int (*WriteScanPoints) (pScanData self, int iPoint); int (*ScanDrive)(pScanData self, int i); int (*ScanCount)(pScanData self, int i); int (*CollectScanData) (pScanData self, int iP); pStringDict scanFunctions; long lPos; void *pCounterData; char pCounterName[512]; int iChannel; pDynar pCounts; int iCounts; int iActive; int iWindow; char *pCommand; void *pSpecial; } ScanData; @} The CountEntry structure holds the entries for one counting operations. These are the lCounts collected, up to 10 monitors and the time needed for counting. This is the time read from the counter box. The ScanData datastructure contains the following fields: \begin{description} \item[pDes] The standard SICS object descriptor. \item[pCall] A pointer to the standard SICS callback interface. Scan support the SCANPOINT message which will be executed after each scan point. \item[pScanVar, iScanVar] A dynamic array of VarEntry structures which define the variables to drive in the scan. iScanVar is the total number of scan variables. A scan might drive more then one motor or variable. \item[iNP] is the number of scan points. \item[iMode] is the counter mode to use. \item[fPreset] is the preset value for the counter at each scan point. The exponents set for the counter apply. \item[pFile] is the name of the data file to write. This will be created automatically from SICS variables at the start of a scan. \item[fd] is the file descriptor for the open file when writing. fd will be opened by WriteHeader and closed again after WriteScanPoints. \item[pRecover] is the name of the recover file. After each scan point scan writes some data to file which allows to restart an aborted scan. \item[pHeaderFile] is the name of a template file which will be used for generating the scan file header. Its format is simple: Everything except a few keywords will be copied verbatim. The keywords will be replaced by their apropriate values. Valid keywords are: !!DATE!! for the current date, !!VAR(name)!! for the value of a simple Sics variable, !!DRIV(name)!! for a Sics scan variable. The name of the variable is given in parenthesis. !!VAR!! and !!DRIV!! can be distinguished easily: Try a run or drive command on the variable in question. If it works and does not complain, it is the second sort. The second sort are mostly motors or collective variables such as lambda etc. Only one value of such a type per line is permitted. \item[pSics] a pointer to a SICS interpreter to use while running for finding data. \item[pCon] The connection object to use for error reporting during scan execution. \item[PrepareScan] checks limits of scan variables and memorizes important scan information. Sometimes this is not wanted, that is why it is parametrized here. \item[WriteHeader] is a pointer to a function which writes the header part of the scan file. Replace this function if another data format is needed. \item[WriteScanPoints] is a pointer to a function which will be called after each scan point to write the scan data to the data file. Replace this function when another data format is needed. \item[ScanDrive] is executed when the next point of a scan has to be reached. i is the point of the scan. \item[ScanCount] is executed when a scan point had been reached and a counting operation has to be performed. i is the scan point where we are. This function together with ScanDrive and the data writing functions allow for customized scans. \item[CollectScanData] reads all the scan data into the scan's data structures after any scan point. Overload this if a different storage scheme is required especiallay for polarising scans. \item[scanFunctions] A string dictionary holding the names of the configured functions for the various steps of the scan. \item[posSoft] is a flag which is true if scan variable are stored with soft position, i.e. with zeropoints applied. \item[pCounterData] is a pointer to a counter structure. This defines the counter to use and is initialized at creation of the scan data structure. \item[pCountername] is the name of the counter used. \item[iChannel] is the channel to use for counting. 0 is the main counter, everything above one of the monitors. \item[pCount, iCounts] is a dynamic array containing iCounts sets of counting infomation. For each scan point this array holds the counts measured. iCounts is also the current scan position. \item[iWindow] the width of the window used for peak integration. See integrate.w,c for more details. \item[pCommand] It turned out that a way is needed to define user defined speciality scans, especially for those magnetic polarized guys. The way it is done is that scan has to be configured user. In this mode, ScanCount will call a script which does everything necessary at the scan point, including adding data to the data file. pCommand now holds the name of the script to invoke. \item[pSpecial] Usually NULL. A entry which allows customized scans to keep some additional data in the scan data structure. \end{description} The functional interface to the scan module includes the following functions: @d scaninter @{ /*------------------------- live & death ----------------------------------*/ pScanData CreateScanObject(char *pRecover, char *pHeader, pCounter pCount, char *objName); void DeleteScanObject(void *self); /*-------------------------------------------------------------------------*/ int AddScanVar(pScanData self, SicsInterp *pSics, SConnection *pCon, char *name, float fStart, float fStep); int ClearScanVar(pScanData self); int DoScan(pScanData self, int iNP, int iMode, float fPreset, SicsInterp *pSics, SConnection *pCon); int SilentScan(pScanData self, int iNP, int iMode, float fPreset, SicsInterp *pSics, SConnection *pCon); int RecoverScan(pScanData self, SicsInterp *pSics, SConnection *pCon); int GetScanCounts(pScanData self, long *lData, int iDataLen); int GetScanVar(pScanData self, int iWhich, float *fData, int iDataLen); int GetSoftScanVar(pScanData self, int iWhich, float *fData, int iDataLen); int GetScanVarName(pScanData self, int iWhich, char *pName, int iLength); int GetScanVarStep(pScanData self, int iWhich, float *fStep); int GetScanMonitor(pScanData self, int iWhich, long *lData, int iDataLen); int GetScanNP(pScanData self); float GetScanPreset(pScanData self); int ScanIntegrate(pScanData self, float *fSum, float *fVariance); int SimScan(pScanData self, float fPos, float FHWM, float fHeight); /* creates a simulated gaussian shaped peak with the parameters given. */ int ResetScanFunctions(pScanData self); /* resets the configurable scan functions to their default values. */ int NonCheckPrepare(pScanData self); /* a function for the PrepareScan field in the scan data structure which does not check the boundaries of the scan as the default PrepareScan does. */ int AppendScanLine(pScanData self, char *line); /* AppendScanLine appends a line to the scan data file. When finished it updates the position pointer in the file to point behind the added line. */ int StoreScanCounts(pScanData self, char *data); /* parses the numbers in data and stores them as the count and monitor data for the current scan point. */ /*------------------------ Interpreter Interface --------------------------*/ int ScanFactory(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); int ScanWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); @} All functions take a pointer to a ScanData structure as their first parameter. The functions: \begin{description} \item[CreateScanObject] creates a scan object. The parameters are the path to a recovery file, the path to a template file for file generation and a pointer to a counter object. \item[DeleteScanObject] removes the ScanData structure from memory properly. \item[AddScanVar] adds a variable to be scanned. Parameters are the name of the scan variable, the start and step values for the scan and a connection object to which errors shall be printed. \item[ClearScanVar] clears all scan variables. \item[DoScan] performs the actual scan. Parameters are the number of points, the counter mode and preset, the connection object for which the scan is done and the SICS interpreter executing the scan command. \item[SilentScan] does the same as DoScan but suppresses all output to data files. This is good for internal scans as in the optimize or mesure modules. \item[RecoverScan] loads the data about an aborted scan from the recovery file and continues to execute it. This most certainly will not work with custom scans. But is known to work with SICS TOPSI like standard scans. \item[GetScanCounts] allows to retrieve the counts collected in the scan. Max iDatLen entries will be copied into lData. \item[GetScanVar] retrieves the scan positions for the scan variable number i. Max iDatLen entries get copied into fData. \item[GetSoftScanVar] retrieves the scan positions for the scan variable number i. The soft positions are retrieved, not the hard position stored during the scan. \item[GetScanVarName] retrieves the name of scan variable i. \item[GetScanVarStep] gets the step of the scan variable i. \item[GetScanMonitor] allows to retrieve the monitor counts collected in monitor i during the scan. Max iDatLen entries will be copied into lData. \item[GetScanNP] returns the number of points in the scan. \item[GetScanPreset] returns the counter preset value for the scan. \item[ScanIntegrate] integrates the peak after a scan. Returns the summed counts and the variance. See the section on integrate for more details. \item[ResetScanFunctions] reinstalls the default functions for scan processing into the ScanData structure. \item[NonCheckPrepare] Before a scan is started, various data structures in the scan object are initialized. Thereby the scan boundaries are checked against the motor limits. For some scans this is not feasible. This version omits this check and must be entered as the PrepareScan function field in the scan data structure by code using the scan module. \item[AppendScanLine] appends a line to the scan file. This is useful for user configured scans, for instance in polarisation mode. \item[StoreScanCounts] parses the data given in data and stores the numbers as count values as the count data for the current scan point. Another feature for supporting user configurable scans. \item[SimScan] creates a simulated gaussian peak with the given parameters. Used for debugging several things. \item[ScanFactory] is the SICS interpreter object creation function for the scan object. \item[ScanWrapper] is the SICS interpreter object function for interacting with the scan module. \end{description} \subsubsection{The Standard Scan Library} The following functions constitute the standard scan library. Please note that the scan file data format is driven by a template. The format of this template is documented in the SICS managers documentation. @d stdscan @{ /** * make a filename according to SICS rules for this scan */ char *ScanMakeFileName(SicsInterp *pSics, SConnection *pCon); /* * write the header bits from the template */ void WriteTemplate(FILE *fd, FILE *temp, char *filename, pScanData pScan, SConnection *pCon, SicsInterp *pSics); /** * write the header of the scan file */ int WriteHeader(pScanData self); /** * WriteScanPoints is called for each point to write the scan data * to screen and to file. */ int WriteScanPoints(pScanData self, int iPoint); /** * Called before the scan to prepare. The default implementation * checks if all scan positions are available and configures the * counter. */ int PrepareScan(pScanData self); /** * allocate a new data file */ int prepareDataFile(pScanData self); /** * second version of PrepareScan which does not check scan limits */ int NonCheckPrepare(pScanData self); /** * prepare for a scan without complaining... */ int SilentPrepare(pScanData self); /** * ScanDrive handles driving to the scan point iPoint. */ int ScanDrive(pScanData self, int iPoint); /** * ScanFastDrive starts driving to the scan point iPoint, but * does not wait. Use this for implementing slightly faster * scans. */ int ScanFastDrive(pScanData self, int iPoint); /** * ScanCount is called at each scan step to do the counting. */ int ScanCount(pScanData self, int iPoint); /** * CollectScanData stores the scans count results into * the scan data structure and prints the information about the * scan progress. */ int CollectScanData(pScanData self, int iPoint); int CollectScanDataJochen(pScanData self, int iPoint); int CollectSilent(pScanData self, int iPoint); /*===================================================================*/ /** * Script invocation for writing the scan header. */ int ScriptWriteHeader(pScanData self); /** * Script writing each scan point */ int ScriptWriteScanPoints(pScanData self, int iPoint); /** * Script preparation of the scan. */ int ScriptPrepareScan(pScanData self); /** * Script driving to a scan point */ int ScriptScanDrive(pScanData self, int iPoint); /** * Script counting a scan point */ int ScriptScanCount(pScanData self, int iPoint); /** * Script collecting scan data for each scan point */ int ScriptScanCollect(pScanData self, int iPoint); /** * ScriptScanFinish invokes a script after the scan has finished */ int ScriptScanFinish(pScanData self); /** * ConfigureScript assigns the script invocation functions for * scan */ void ConfigureScript(pScanData self); /*=====================================================================*/ int StandardScanWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); @} @o scanvar.h @{ /*----------------------------------------------------------------------- Header file for the SICS ScanVariable. This is a support module for the SICS scan system. Evolved during refactoring scan in November 2004 copyright: see file COPYRIGHT Mark Koennecke, November 2004 -------------------------------------------------------------------------*/ #ifndef SICSSCANVAR #define SICSSCANVAR #include "sics.h" @ /*---------------------------------------------------------------------*/ @ #endif @} @o scan.h @{ /*--------------------------------------------------------------------------- S C A N Header file for the SICS scan object. Mark Koennecke, October 1997 Extracted scan variable: Mark Koennecke, November 2004 copyright: see copyright.h -----------------------------------------------------------------------------*/ #ifndef SICSSCAN1 #define SICSSCAN1 typedef struct __ScanData *pScanData; /*--------------------------------------------------------------------------*/ #include "counter.h" @ #endif @} @o scan.i @{ /*-------------------------------------------------------------------------- Internal header file holding the definition of the scan objects data structure. Mark Koennecke, October 1997 ----------------------------------------------------------------------------*/ #include "sdynar.h" #include "scanvar.h" #include "stringdict.h" @ /* internal helper functions for scan implementations */ /* CollectCounterData collects all the data from the configured counter ans stows it away */ CountEntry CollectCounterData(pScanData self); void InitCountEntry(pCountEntry pCount); @} @o stdscan.h @{ /*-------------------------------------------------------------------------- S T A N D A R D S C A N This is a library of scan functions for the SICS standard scan. copyright: see copyright.h Extracted from scan.c: Mark Koennecke, November 2004 ----------------------------------------------------------------------------*/ #ifndef SICSSTDSCAN #define SICSSTDSCAN @ #endif @}