
by length limited versions wherever appropriate. SKIPPED: psi/el755driv.c psi/faverage.c psi/frame.c psi/lmd200.c psi/polterwrite.c psi/psi.c psi/sanswave.c psi/sinqhmdriv.c psi/termprot.c
983 lines
25 KiB
C
983 lines
25 KiB
C
/*-------------------------------------------------------------------------
|
|
O P T I M I S E
|
|
|
|
This module optimises a peak with respect to various parameters.
|
|
The working of this is described in more detail in optimise.w
|
|
|
|
copyright: see copyright.h
|
|
|
|
Mark Koennecke, March 1998
|
|
--------------------------------------------------------------------------*/
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <tcl.h>
|
|
#include <assert.h>
|
|
#include "fortify.h"
|
|
#include "sdynar.h"
|
|
#include "sics.h"
|
|
#include "counter.h"
|
|
#include "motor.h"
|
|
#include "drive.h"
|
|
#include "scan.h"
|
|
#include "scan.i"
|
|
#include "fitcenter.h"
|
|
#include "optimise.h"
|
|
#include "stdscan.h"
|
|
|
|
#ifdef CYGNUS
|
|
#define MAXFLOAT 9999999.99
|
|
#endif
|
|
|
|
#define ABS(x) (x < 0 ? -(x) : (x))
|
|
|
|
/*----------------- local variable structure -----------------------------*/
|
|
|
|
typedef struct {
|
|
char *pName;
|
|
float fStep;
|
|
int iStep;
|
|
float fPrecision;
|
|
float fCenter;
|
|
float fShift;
|
|
pIDrivable pDriv;
|
|
void *pData;
|
|
int iLost;
|
|
} OVarEntry, *pOVarEntry;
|
|
/*-------------------------------------------------------------------------*/
|
|
static void FreeOVar(void *pData)
|
|
{
|
|
pOVarEntry self = NULL;
|
|
|
|
self = (pOVarEntry) pData;
|
|
if (!self)
|
|
return;
|
|
|
|
if (self->pName) {
|
|
free(self->pName);
|
|
}
|
|
free(self);
|
|
}
|
|
|
|
/*-------------------- the optimise structure -----------------------------*/
|
|
|
|
typedef struct __OptimiseStruct {
|
|
pObjectDescriptor pDes;
|
|
int iMaxCycles;
|
|
CounterMode eCount;
|
|
float fPreset;
|
|
int iChannel;
|
|
float fThreshold;
|
|
int iVar;
|
|
pDynar pVariables;
|
|
pScanData pScanner;
|
|
pFit pPeakFitter;
|
|
} Optimiser;
|
|
|
|
/*--- dummy functions to stop scan from writing scan files --------------*/
|
|
|
|
static int DummyHeader(pScanData self)
|
|
{
|
|
return 1;
|
|
}
|
|
static int DummyHeader2(pScanData self, int iPoint)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
pOptimise CreateOptimiser(pCounter pCount)
|
|
{
|
|
pOptimise pNew = NULL;
|
|
|
|
assert(pCount);
|
|
|
|
/* get some memory */
|
|
pNew = (pOptimise) malloc(sizeof(Optimiser));
|
|
if (!pNew) {
|
|
return NULL;
|
|
}
|
|
memset(pNew, 0, sizeof(Optimiser));
|
|
|
|
/* initialise a few defaults */
|
|
pNew->fThreshold = 100;
|
|
pNew->iMaxCycles = 7;
|
|
pNew->iChannel = 0;
|
|
pNew->eCount = eTimer;
|
|
pNew->iVar = 0;
|
|
pNew->fPreset = 10000.;
|
|
|
|
pNew->pDes = CreateDescriptor("PeakOptimiser");
|
|
if (!pNew->pDes) {
|
|
free(pNew);
|
|
return NULL;
|
|
}
|
|
|
|
pNew->pScanner = CreateScanObject(NULL, NULL, pCount, "optiscan");
|
|
if (!pNew->pScanner) {
|
|
DeleteDescriptor(pNew->pDes);
|
|
free(pNew);
|
|
return NULL;
|
|
|
|
}
|
|
pNew->pScanner->WriteHeader = DummyHeader;
|
|
pNew->pScanner->WriteScanPoints = DummyHeader2;
|
|
|
|
pNew->pPeakFitter = CreateFitCenter(pNew->pScanner);
|
|
if (!pNew->pPeakFitter) {
|
|
DeleteDescriptor(pNew->pDes);
|
|
DeleteScanObject(pNew->pScanner);
|
|
free(pNew);
|
|
return NULL;
|
|
}
|
|
|
|
pNew->iVar = 0;
|
|
pNew->pVariables = CreateDynar(0, 10, 10, FreeOVar);
|
|
if (!pNew->pVariables) {
|
|
DeleteFitCenter(pNew->pPeakFitter);
|
|
DeleteDescriptor(pNew->pDes);
|
|
DeleteScanObject(pNew->pScanner);
|
|
free(pNew);
|
|
return NULL;
|
|
}
|
|
|
|
return pNew;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
void DeleteOptimiser(void *pData)
|
|
{
|
|
pOptimise self = NULL;
|
|
|
|
self = (pOptimise) pData;
|
|
if (!self)
|
|
return;
|
|
|
|
if (self->pVariables) {
|
|
DeleteDynar(self->pVariables);
|
|
}
|
|
|
|
if (self->pPeakFitter) {
|
|
DeleteFitCenter(self->pPeakFitter);
|
|
}
|
|
if (self->pDes) {
|
|
DeleteDescriptor(self->pDes);
|
|
}
|
|
if (self->pScanner) {
|
|
DeleteScanObject(self->pScanner);
|
|
}
|
|
|
|
free(self);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
void OptimiserClear(pOptimise self)
|
|
{
|
|
assert(self);
|
|
self->iVar = 0;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int OptimiserAdd(pOptimise self,
|
|
char *pName, float fStep, int nStep, float fPrecision)
|
|
{
|
|
OVarEntry sNeu;
|
|
CommandList *pCom = NULL;
|
|
|
|
/* find and check our object */
|
|
pCom = FindCommand(pServ->pSics, pName);
|
|
if (!pCom) {
|
|
return 0;
|
|
}
|
|
sNeu.pData = pCom->pData;
|
|
sNeu.pDriv = GetDrivableInterface(sNeu.pData);
|
|
if (!sNeu.pDriv) {
|
|
return 0;
|
|
}
|
|
sNeu.fStep = fStep;
|
|
sNeu.iStep = nStep;
|
|
sNeu.fPrecision = fPrecision;
|
|
sNeu.pName = strdup(pName);
|
|
sNeu.iLost = 0;
|
|
|
|
DynarPutCopy(self->pVariables, self->iVar, &sNeu, sizeof(OVarEntry));
|
|
self->iVar++;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int OptimiserSetPar(pOptimise self, char *name, float fVal)
|
|
{
|
|
if (strcmp(name, "maxcycles") == 0) {
|
|
self->iMaxCycles = (int) fVal;
|
|
return 1;
|
|
} else if (strcmp(name, "threshold") == 0) {
|
|
self->fThreshold = fVal;
|
|
return 1;
|
|
} else if (strcmp(name, "channel") == 0) {
|
|
self->iChannel = (int) fVal;
|
|
return 1;
|
|
} else if (strcmp(name, "preset") == 0) {
|
|
self->fPreset = fVal;
|
|
return 1;
|
|
} else if (strcmp(name, "countmode") == 0) {
|
|
if (fVal < 0.05) {
|
|
self->eCount = eTimer;
|
|
} else {
|
|
self->eCount = ePreset;
|
|
}
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int OptimiserGetPar(pOptimise self, char *name, float *fVal)
|
|
{
|
|
if (strcmp(name, "maxcycles") == 0) {
|
|
*fVal = self->iMaxCycles;
|
|
return 1;
|
|
} else if (strcmp(name, "threshold") == 0) {
|
|
*fVal = self->fThreshold;
|
|
return 1;
|
|
} else if (strcmp(name, "channel") == 0) {
|
|
*fVal = self->iChannel;
|
|
return 1;
|
|
} else if (strcmp(name, "preset") == 0) {
|
|
*fVal = self->fPreset;
|
|
return 1;
|
|
} else if (strcmp(name, "countmode") == 0) {
|
|
if (self->eCount == eTimer) {
|
|
*fVal = 0.;
|
|
} else {
|
|
*fVal = 1.0;
|
|
}
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static int OptimiserInit(pOptimise self, SConnection * pCon)
|
|
{
|
|
int i, iRet;
|
|
void *pData;
|
|
pOVarEntry pOVar;
|
|
float fVal;
|
|
|
|
/* initialise each variable entry with the current position and
|
|
set the shift to something senseless.
|
|
*/
|
|
for (i = 0; i < self->iVar; i++) {
|
|
DynarGet(self->pVariables, i, &pData);
|
|
pOVar = (pOVarEntry) pData;
|
|
pOVar->fCenter = pOVar->pDriv->GetValue(pOVar->pData, pCon);
|
|
if (pOVar->fCenter < -900.) {
|
|
return SCANERROR;
|
|
}
|
|
pOVar->fShift = MAXFLOAT;
|
|
pOVar->iLost = 0;
|
|
}
|
|
self->pScanner->iChannel = self->iChannel;
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int CenterVariable(pOptimise self, SConnection * pCon, int i)
|
|
{
|
|
pOVarEntry pOvar;
|
|
void *pData;
|
|
int iRet, iReturn;
|
|
float fStart;
|
|
float fNewCenter, fStdDev, FWHM, fMax;
|
|
char pBueffel[512], cData[80];
|
|
|
|
assert(self);
|
|
assert((i >= 0) && (i < self->iVar));
|
|
assert(pCon);
|
|
|
|
/* get variable data */
|
|
DynarGet(self->pVariables, i, &pData);
|
|
pOvar = (pOVarEntry) pData;
|
|
|
|
/* do a scan first */
|
|
fStart = pOvar->fCenter - (pOvar->iStep / 2) * pOvar->fStep;
|
|
ClearScanVar(self->pScanner);
|
|
iRet = AddScanVar(self->pScanner, pServ->pSics, pCon,
|
|
pOvar->pName, fStart, pOvar->fStep);
|
|
if (!iRet) {
|
|
return 0;
|
|
}
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "Trying hard to optimise variable %s", pOvar->pName);
|
|
SCWrite(pCon, pBueffel, eLog);
|
|
iRet = SilentScan(self->pScanner, pOvar->iStep, self->eCount,
|
|
self->fPreset, pServ->pSics, pCon);
|
|
if (!iRet) {
|
|
return SCANABORT;
|
|
}
|
|
|
|
/* try to find a fit for this one */
|
|
iRet = CalculateFit(self->pPeakFitter);
|
|
if (iRet == 0) {
|
|
return SYSERROR;
|
|
}
|
|
GetFitResults(self->pPeakFitter, &fNewCenter, &fStdDev, &FWHM, &fMax);
|
|
|
|
/* write some diagnostic messages */
|
|
strcpy(pBueffel, "Peak Diagnosis: \n");
|
|
snprintf(cData,sizeof(cData)-1, "New %s position: %f \n", pOvar->pName, fNewCenter);
|
|
switch (iRet) {
|
|
case 1:
|
|
strcat(pBueffel, "Peak found in scan range \n");
|
|
strcat(pBueffel, cData);
|
|
iReturn = 1;
|
|
break;
|
|
case -1:
|
|
strcat(pBueffel, "Left half of peak missing \n");
|
|
strcat(pBueffel,
|
|
"Extending scan range and setting position to maximum \n");
|
|
strcat(pBueffel, cData);
|
|
iReturn = VARREDO;
|
|
break;
|
|
case -2:
|
|
strcat(pBueffel, "Right half of peak missing \n");
|
|
strcat(pBueffel,
|
|
"Extending scan range and setting position to maximum \n");
|
|
strcat(pBueffel, cData);
|
|
iReturn = 2;
|
|
break;
|
|
case -3:
|
|
case -4:
|
|
strcat(pBueffel, "No data in scan \n");
|
|
break;
|
|
default:
|
|
strcat(pBueffel, cData);
|
|
snprintf(pData,sizeof(pData)-1, "Fitting ended with error code %d \n", iRet);
|
|
strcat(pBueffel, cData);
|
|
break;
|
|
}
|
|
SCWrite(pCon, pBueffel, eLog);
|
|
|
|
if (fMax < self->fThreshold) {
|
|
SCWrite(pCon, "Peak may be lost, increasing scan range", eLog);
|
|
pOvar->iLost++;
|
|
if (pOvar->iLost > 2) {
|
|
return PEAKLOST;
|
|
}
|
|
} else {
|
|
pOvar->iLost = 0;
|
|
}
|
|
|
|
|
|
/* act upon the fits results */
|
|
if (iRet != 1) {
|
|
/* not enough scan data for a proper evaluation of the
|
|
peak. But the peak fitter has given us the maximum of
|
|
the counts. What we do is, we set the center to the
|
|
maximum, increase the scan width and mark the variable
|
|
for a redo in the next cycle by leaving the fShift
|
|
high. But we do this only if the maximum is above a threshold,
|
|
otherwise we just increase the scan range and leave the thing
|
|
where it is.
|
|
*/
|
|
if (fMax > self->fThreshold) {
|
|
pOvar->fCenter = fNewCenter;
|
|
}
|
|
pOvar->iStep += pOvar->iStep;
|
|
} else { /* the success case */
|
|
|
|
pOvar->fShift = ABS(pOvar->fCenter - fNewCenter);
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "%s shifted by %8.2f ", pOvar->pName, pOvar->fShift);
|
|
SCWrite(pCon, pBueffel, eLog);
|
|
pOvar->fPrecision = 3 * fStdDev;
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "%s precision set to 3*StdDev = %8.3f",
|
|
pOvar->pName, 3 * fStdDev);
|
|
SCWrite(pCon, pBueffel, eLog);
|
|
pOvar->fCenter = fNewCenter;
|
|
}
|
|
/* drive to the new center */
|
|
iRet = Drive(pCon, pServ->pSics, pOvar->pName, pOvar->fCenter);
|
|
if (!iRet) {
|
|
return DRIVEERROR;
|
|
}
|
|
|
|
return iReturn;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------
|
|
* We use the scan object here for counting. The reason is that this
|
|
* handles well in the common case of a single counter but also has
|
|
* provisions for other counting methods through the scan modules
|
|
* scripting mechanism
|
|
* ------------------------------------------------------------------------*/
|
|
static long ClimbCount(pOptimise self, SConnection * pCon)
|
|
{
|
|
int status;
|
|
long data[1];
|
|
int (*CollectFunc) (pScanData self, int iPoint) = NULL;
|
|
|
|
SilentPrepare(self->pScanner);
|
|
|
|
status = self->pScanner->ScanCount(self->pScanner, 0);
|
|
if (status != 1) {
|
|
return status;
|
|
}
|
|
if (self->pScanner->CollectScanData == CollectScanData) {
|
|
CollectFunc = self->pScanner->CollectScanData;
|
|
self->pScanner->CollectScanData = CollectSilent;
|
|
}
|
|
status = self->pScanner->CollectScanData(self->pScanner, 0);
|
|
if (CollectFunc != NULL) {
|
|
self->pScanner->CollectScanData = CollectFunc;
|
|
}
|
|
if (status != 1) {
|
|
return status;
|
|
}
|
|
GetScanCounts(self->pScanner, data, 1);
|
|
return data[0];
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static int ClimbDrive(SConnection * pCon, char *name, float value)
|
|
{
|
|
int status;
|
|
|
|
status = Start2Run(pCon, pServ->pSics, name, RUNDRIVE, value);
|
|
if (status != 1) {
|
|
return DRIVEERROR;
|
|
}
|
|
status = Wait4Success(GetExecutor());
|
|
if (status != DEVDONE) {
|
|
return DRIVEERROR;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static int findDirection(pOptimise self, pOVarEntry pOvar,
|
|
SConnection * pCon)
|
|
{
|
|
int status, direction;
|
|
float varValue;
|
|
long oneCount, twoCount;
|
|
|
|
varValue = pOvar->fCenter + pOvar->fStep;
|
|
status = ClimbDrive(pCon, pOvar->pName, varValue);
|
|
if (!status) {
|
|
return DRIVEERROR;
|
|
}
|
|
oneCount = ClimbCount(self, pCon);
|
|
if (oneCount < 0) {
|
|
return SCANERROR;
|
|
}
|
|
if (SCGetInterrupt(pCon) != eContinue) {
|
|
return SCANABORT;
|
|
}
|
|
varValue = pOvar->fCenter - pOvar->fStep;
|
|
status = ClimbDrive(pCon, pOvar->pName, varValue);
|
|
if (!status) {
|
|
return DRIVEERROR;
|
|
}
|
|
twoCount = ClimbCount(self, pCon);
|
|
if (SCGetInterrupt(pCon) != eContinue) {
|
|
return SCANABORT;
|
|
}
|
|
if (twoCount < 0) {
|
|
return SCANERROR;
|
|
}
|
|
if (oneCount > twoCount) {
|
|
direction = 1;
|
|
} else {
|
|
direction = -1;
|
|
}
|
|
return direction;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int ClimbVariable(pOptimise self, SConnection * pCon, int i)
|
|
{
|
|
pOVarEntry pOvar;
|
|
void *pData;
|
|
int status, direction = 1;
|
|
long oneCount, twoCount, lastCount, currentCount;
|
|
float varValue, startValue;
|
|
char buffer[256];
|
|
int (*CollectFunc) (pScanData self, int iPoint) = NULL;
|
|
|
|
assert(self);
|
|
assert((i >= 0) && (i < self->iVar));
|
|
assert(pCon);
|
|
|
|
/* get variable data */
|
|
DynarGet(self->pVariables, i, &pData);
|
|
pOvar = (pOVarEntry) pData;
|
|
startValue = pOvar->fCenter;
|
|
|
|
/*
|
|
* prepare scan object
|
|
*/
|
|
self->pScanner->pCon = pCon;
|
|
self->pScanner->pSics = pServ->pSics;
|
|
self->pScanner->iNP = 1;
|
|
self->pScanner->iMode = self->eCount;
|
|
self->pScanner->fPreset = self->fPreset;
|
|
|
|
direction = findDirection(self, pOvar, pCon);
|
|
if (direction < -1) {
|
|
return direction;
|
|
}
|
|
/*
|
|
* drive to the last best position
|
|
*/
|
|
varValue = pOvar->fCenter + direction * pOvar->fStep;
|
|
status = ClimbDrive(pCon, pOvar->pName, varValue);
|
|
if (!status) {
|
|
return DRIVEERROR;
|
|
}
|
|
lastCount = ClimbCount(self, pCon);
|
|
if (lastCount < 0) {
|
|
return SCANERROR;
|
|
}
|
|
currentCount = lastCount;
|
|
|
|
/*
|
|
* climb upwards as long as possible
|
|
*/
|
|
while (1) {
|
|
pOvar->fCenter = varValue;
|
|
varValue = pOvar->fCenter + direction * pOvar->fStep;
|
|
status = ClimbDrive(pCon, pOvar->pName, varValue);
|
|
if (!status) {
|
|
return DRIVEERROR;
|
|
}
|
|
if (SCGetInterrupt(pCon) != eContinue) {
|
|
return SCANABORT;
|
|
}
|
|
currentCount = ClimbCount(self, pCon);
|
|
if (currentCount < 0) {
|
|
return SCANERROR;
|
|
}
|
|
if (SCGetInterrupt(pCon) != eContinue) {
|
|
return SCANABORT;
|
|
}
|
|
snprintf(buffer, 255, "Climbing %s, value = %f, count = %ld",
|
|
pOvar->pName, varValue, currentCount);
|
|
SCWrite(pCon, buffer, eLog);
|
|
|
|
if (currentCount <= lastCount) {
|
|
/*
|
|
* we are finished. Drive to previous position and
|
|
* break
|
|
*/
|
|
status = ClimbDrive(pCon, pOvar->pName, pOvar->fCenter);
|
|
if (!status) {
|
|
return DRIVEERROR;
|
|
}
|
|
break;
|
|
} else {
|
|
/*
|
|
* go on, we are not over the top yet
|
|
*/
|
|
lastCount = currentCount;
|
|
}
|
|
}
|
|
pOvar->fShift = ABS(startValue - pOvar->fCenter);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static int CheckSuccess(pOptimise self)
|
|
{
|
|
int i, iTest;
|
|
pOVarEntry pOvar;
|
|
void *pData;
|
|
|
|
assert(self);
|
|
for (i = 0; i < self->iVar; i++) {
|
|
DynarGet(self->pVariables, i, &pData);
|
|
pOvar = (pOVarEntry) pData;
|
|
if (pOvar->fShift > pOvar->fPrecision) {
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
int OptimiserRun(pOptimise self, SConnection * pCon)
|
|
{
|
|
int i, iRet, iCycle, iRedoVar = 0;
|
|
char pBueffel[256];
|
|
|
|
assert(self);
|
|
|
|
if (self->iVar < 1) {
|
|
SCWrite(pCon, "ERROR: Nothing to optimise", eError);
|
|
return 0;
|
|
}
|
|
|
|
iRet = OptimiserInit(self, pCon);
|
|
if (!iRet) {
|
|
return iRet;
|
|
}
|
|
for (iCycle = 0; iCycle < self->iMaxCycles; iCycle++) {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "Optimiser cycle %d of %d started", iCycle,
|
|
self->iMaxCycles);
|
|
SCWrite(pCon, pBueffel, eLog);
|
|
for (i = iRedoVar; i < self->iVar; i++) {
|
|
iRet = CenterVariable(self, pCon, i);
|
|
if (iRet <= 0) {
|
|
return iRet;
|
|
}
|
|
if (iRet == VARREDO) {
|
|
iRedoVar = i;
|
|
break;
|
|
}
|
|
iRedoVar = 0;
|
|
}
|
|
iRet = CheckSuccess(self);
|
|
if (iRet) {
|
|
return 1;
|
|
}
|
|
}
|
|
return MAXCYCLE;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
int OptimiserClimb(pOptimise self, SConnection * pCon)
|
|
{
|
|
int i, iRet, iCycle, iRedoVar = 0;
|
|
char pBueffel[256];
|
|
|
|
assert(self);
|
|
|
|
if (self->iVar < 1) {
|
|
SCWrite(pCon, "ERROR: Nothing to optimise", eError);
|
|
return 0;
|
|
}
|
|
|
|
iRet = OptimiserInit(self, pCon);
|
|
if (!iRet) {
|
|
return iRet;
|
|
}
|
|
for (iCycle = 0; iCycle < self->iMaxCycles; iCycle++) {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "Optimiser cycle %d of %d started", iCycle,
|
|
self->iMaxCycles);
|
|
SCWrite(pCon, pBueffel, eLog);
|
|
for (i = iRedoVar; i < self->iVar; i++) {
|
|
iRet = ClimbVariable(self, pCon, i);
|
|
if (iRet <= 0) {
|
|
return iRet;
|
|
}
|
|
}
|
|
iRet = CheckSuccess(self);
|
|
if (iRet) {
|
|
return 1;
|
|
}
|
|
}
|
|
return MAXCYCLE;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int MakeOptimiser(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
CommandList *pCom;
|
|
pICountable pCt = NULL;
|
|
pCounter pCount;
|
|
pOptimise pNew = NULL;
|
|
char pBueffel[256];
|
|
int iRet;
|
|
|
|
/* check no of args */
|
|
if (argc < 3) {
|
|
SCWrite(pCon, "EEROR: Not enough arguments to create optimiser",
|
|
eError);
|
|
return 0;
|
|
}
|
|
|
|
/* 2 argument must be counter name */
|
|
pCom = FindCommand(pSics, argv[2]);
|
|
if (!pCom) {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: Expected counter name, cannot find %s",
|
|
argv[2]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
pCt = GetCountableInterface(pCom->pData);
|
|
if (!pCt) {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: Expected counter name, BUT %s is NO counter",
|
|
argv[2]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
pCount = (pCounter) pCom->pData;
|
|
|
|
pNew = CreateOptimiser(pCount);
|
|
if (!pNew) {
|
|
SCWrite(pCon, "ERROR: cannot create Optimiser", eError);
|
|
return 0;
|
|
}
|
|
|
|
iRet = AddCommand(pSics, argv[1], OptimiserAction,
|
|
DeleteOptimiser, pNew);
|
|
if (!iRet) {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: Duplicate Command %s NOT created", argv[1]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int OptimiserAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
pOptimise self = NULL;
|
|
char pBueffel[1024];
|
|
int iRet;
|
|
double d;
|
|
float fStep, fPrec, fVal;
|
|
int iStep;
|
|
|
|
self = (pOptimise) pData;
|
|
assert(self);
|
|
assert(pCon);
|
|
|
|
|
|
if (argc < 2) {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: Insufficient arguments to %s", argv[0]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
|
|
strtolower(argv[1]);
|
|
if (strcmp(argv[1], "addvar") == 0)
|
|
/*--------- addvar */
|
|
{
|
|
/* check rights */
|
|
if (!SCMatchRights(pCon, usUser)) {
|
|
SCWrite(pCon, "ERROR: You are not authorised to do this!", eError);
|
|
return 0;
|
|
}
|
|
/* check no of args */
|
|
if (argc < 6) {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: Insufficient arguments to %s addvar",
|
|
argv[0]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
/* convert arguments to types */
|
|
iRet = Tcl_GetDouble(pSics->pTcl, argv[3], &d);
|
|
if (iRet != TCL_OK) {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: expected float value for step but got %s",
|
|
argv[3]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
fStep = (float) d;
|
|
iRet = Tcl_GetInt(pSics->pTcl, argv[4], &iStep);
|
|
if (iRet != TCL_OK) {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1,
|
|
"ERROR: expected integer value for iStep but got %s",
|
|
argv[3]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
iRet = Tcl_GetDouble(pSics->pTcl, argv[5], &d);
|
|
if (iRet != TCL_OK) {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1,
|
|
"ERROR: expected float value for precision but got %s",
|
|
argv[3]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
fPrec = (float) d;
|
|
iRet = OptimiserAdd(self, argv[2], fStep, iStep, fPrec);
|
|
if (!iRet) {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1,
|
|
"ERROR: cannot optimise variable %s, mistyped?", argv[2]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
}
|
|
/*----- clear */
|
|
else if (strcmp(argv[1], "clear") == 0) {
|
|
/* check rights */
|
|
if (!SCMatchRights(pCon, usUser)) {
|
|
SCWrite(pCon, "ERROR: You are not aurhorised to do this!", eError);
|
|
return 0;
|
|
}
|
|
OptimiserClear(self);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
}
|
|
/*-------- run */
|
|
else if (strcmp(argv[1], "run") == 0) {
|
|
/* check rights */
|
|
if (!SCMatchRights(pCon, usUser)) {
|
|
SCWrite(pCon, "ERROR: You are not aurhorised to do this!", eError);
|
|
return 0;
|
|
}
|
|
iRet = OptimiserRun(self, pCon);
|
|
switch (iRet) {
|
|
case PEAKLOST:
|
|
SCWrite(pCon, "ERROR: lost the peak, sorry!", eError);
|
|
return 0;
|
|
break;
|
|
case MAXCYCLE:
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: could not optimise peak in %d cycles",
|
|
self->iMaxCycles);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
break;
|
|
case SCANERROR:
|
|
SCWrite(pCon, "ERROR: failed to scan the peak", eError);
|
|
return 0;
|
|
break;
|
|
case SCANABORT:
|
|
SCWrite(pCon, "ERROR: Scan was aborted, Optimiser follows", eError);
|
|
return 0;
|
|
break;
|
|
case DRIVEERROR:
|
|
SCWrite(pCon, "ERROR: Failure to drive variable to new position",
|
|
eError);
|
|
return 0;
|
|
break;
|
|
case 1:
|
|
SCWrite(pCon, "At long last, I finished optimising the peak",
|
|
eValue);
|
|
return 1;
|
|
break;
|
|
default:
|
|
SCWrite(pCon, "ERROR: Unidentified error krept into Optimiser",
|
|
eError);
|
|
return 0;
|
|
break;
|
|
}
|
|
}
|
|
/*-------- climb */
|
|
else if (strcmp(argv[1], "climb") == 0) {
|
|
/* check rights */
|
|
if (!SCMatchRights(pCon, usUser)) {
|
|
SCWrite(pCon, "ERROR: You are not aurhorised to do this!", eError);
|
|
return 0;
|
|
}
|
|
iRet = OptimiserClimb(self, pCon);
|
|
switch (iRet) {
|
|
case PEAKLOST:
|
|
SCWrite(pCon, "ERROR: lost the peak, sorry!", eError);
|
|
return 0;
|
|
break;
|
|
case MAXCYCLE:
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: could not optimise peak in %d cycles",
|
|
self->iMaxCycles);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
break;
|
|
case SCANERROR:
|
|
SCWrite(pCon, "ERROR: failed to scan the peak", eError);
|
|
return 0;
|
|
break;
|
|
case SCANABORT:
|
|
SCWrite(pCon, "ERROR: Scan was aborted, Optimiser follows", eError);
|
|
return 0;
|
|
break;
|
|
case DRIVEERROR:
|
|
SCWrite(pCon, "ERROR: Failure to drive variable to new position",
|
|
eError);
|
|
return 0;
|
|
break;
|
|
case 1:
|
|
SCWrite(pCon, "At long last, I finished optimising the peak",
|
|
eValue);
|
|
return 1;
|
|
break;
|
|
default:
|
|
SCWrite(pCon, "ERROR: Unidentified error krept into Optimiser",
|
|
eError);
|
|
return 0;
|
|
break;
|
|
}
|
|
SCWrite(pCon, "Optimiser climbed successfully", eValue);
|
|
return 1;
|
|
}
|
|
/* ------ count mode */
|
|
if (strcmp(argv[1], "countmode") == 0) {
|
|
if (argc > 2) { /* set case */
|
|
/* check rights */
|
|
if (!SCMatchRights(pCon, usUser)) {
|
|
SCWrite(pCon, "ERROR: You are not aurhorised to do this!", eError);
|
|
return 0;
|
|
}
|
|
if (strcmp(argv[2], "timer") == 0) {
|
|
fVal = 0.;
|
|
} else if (strcmp(argv[2], "monitor") == 0) {
|
|
fVal = 1.;
|
|
} else {
|
|
SCWrite(pCon, "ERROR: Invalid parameter for countmode", eError);
|
|
return 0;
|
|
}
|
|
OptimiserSetPar(self, "countmode", fVal);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else { /* get case */
|
|
|
|
OptimiserGetPar(self, "countmode", &fVal);
|
|
if (fVal < 0.05) {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "%s.countmode = timer", argv[0]);
|
|
} else {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "%s.countmode = monitor", argv[0]);
|
|
}
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
}
|
|
}
|
|
/*------ can be other pars */
|
|
else {
|
|
if (argc > 2) { /* set case */
|
|
/* check rights */
|
|
if (!SCMatchRights(pCon, usUser)) {
|
|
SCWrite(pCon, "ERROR: You are not aurhorised to do this!", eError);
|
|
return 0;
|
|
}
|
|
iRet = Tcl_GetDouble(pSics->pTcl, argv[2], &d);
|
|
if (iRet != TCL_OK) {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1,
|
|
"ERROR: expected numeric value for %s but got %s", argv[1],
|
|
argv[2]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
fVal = (float) d;
|
|
|
|
iRet = OptimiserSetPar(self, argv[1], fVal);
|
|
if (iRet) {
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: parameter %s not known", argv[1]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
} else { /* get case */
|
|
|
|
iRet = OptimiserGetPar(self, argv[1], &fVal);
|
|
if (!iRet) {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: parameter %s not known", argv[1]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "%s.%s = %f", argv[0], argv[1], fVal);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|