Files
sics/scan.w
Ferdi Franceschini 6921d0426c PSI UPDATE
r1724 | ffr | 2007-03-27 07:56:13 +1000 (Tue, 27 Mar 2007) | 2 lines
2012-11-15 13:10:21 +11:00

603 lines
24 KiB
OpenEdge ABL

\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"
@<scanvar@>
/*---------------------------------------------------------------------*/
@<scanvarint@>
#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"
@<scaninter@>
#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"
@<scandata@>
/*
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
@<stdscan@>
#endif
@}