diff --git a/conman.c b/conman.c index 222a07e3..5b379708 100644 --- a/conman.c +++ b/conman.c @@ -652,7 +652,7 @@ static void writeToLogFiles(SConnection *self, char *buffer) SICSLogWrite(buffer,iOut); /* write to commandlog if user or manager privilege */ - if(SCGetRights(self) <= usUser) + if(SCGetRights(self) <= usUser && self->iMacro != 1) { sprintf(pBueffel,"To sock %d :",iRet); WriteToCommandLog(pBueffel,buffer); diff --git a/devexec.c b/devexec.c index 9c5718e9..bf333406 100644 --- a/devexec.c +++ b/devexec.c @@ -419,7 +419,10 @@ case HWFault: /* real HW error: burning, no net etc.. */ ExeInterest(self, pDev, "finished with problem"); DeleteDevEntry(pDev); + pDev = NULL; + LLDnodeDataTo(self->iList,&pDev); LLDnodeDelete(self->iList); + iRet = LLDnodePtr2Prev(self->iList); self->iStatus = DEVERROR; if(pDrivInt) { diff --git a/exebuf.c b/exebuf.c index b693d36a..b38dfd7a 100644 --- a/exebuf.c +++ b/exebuf.c @@ -129,7 +129,7 @@ static pDynString findBlockEnd(pExeBuf self){ return NULL; } buffer = GetCharArray(self->bufferContent); - if(self->end != 0){ + if(self->end != -1){ self->start = self->end + 1; } for(i = self->start; i < strlen(buffer); i++){ @@ -162,7 +162,7 @@ int exeBufProcess(pExeBuf self, SicsInterp *pSics, assert(pSics); self->start = 0; - self->end = 0; + self->end = -1; self->lineno = 0; pTcl = InterpGetTcl(pSics); diff --git a/histmem.c b/histmem.c index 250c5b47..db0d79ef 100644 --- a/histmem.c +++ b/histmem.c @@ -629,7 +629,7 @@ if(isInTOFMode(self->pDriv->data)) { iDim[*nDim] = getNoOfTimebins(self->pDriv->data); - *nDim ++; + *nDim = *nDim + 1; } return 1; } diff --git a/hkl.c b/hkl.c index c7ac0dee..34df8d0f 100644 --- a/hkl.c +++ b/hkl.c @@ -887,6 +887,30 @@ static int calculateNormalBeamOmega(MATRIX z1, pHKL self, return 0; } +/*------------------------------------------------------------------------*/ +static void stopHKLMotors(pHKL self) +{ + if(self->pTheta != NULL) + { + self->pTheta->pDrivInt->Halt(self->pTheta); + } + if(self->pOmega != NULL) + { + self->pOmega->pDrivInt->Halt(self->pOmega); + } + if(self->pChi != NULL) + { + self->pChi->pDrivInt->Halt(self->pChi); + } + if(self->pPhi != NULL) + { + self->pPhi->pDrivInt->Halt(self->pPhi); + } + if(self->pNu != NULL) + { + self->pNu->pDrivInt->Halt(self->pNu); + } +} /*-------------------------------------------------------------------------*/ int RunHKL(pHKL self, float fHKL[3], float fPsi, int iHamil, SConnection *pCon) @@ -911,7 +935,7 @@ static int calculateNormalBeamOmega(MATRIX z1, pHKL self, if(!iRet) { SCWrite(pCon,"ERROR: cannot start two theta motor",eError); - StopExe(pServ->pExecutor,"all"); + stopHKLMotors(self); return 0; } @@ -921,7 +945,7 @@ static int calculateNormalBeamOmega(MATRIX z1, pHKL self, if(!iRet) { SCWrite(pCon,"ERROR: cannot start omega motor",eError); - StopExe(pServ->pExecutor,"all"); + stopHKLMotors(self); return 0; } @@ -933,7 +957,6 @@ static int calculateNormalBeamOmega(MATRIX z1, pHKL self, pDum->pDescriptor, pDum, pCon,fSet[2]); if(!iRet) { - StopExe(pServ->pExecutor,"all"); SCWrite(pCon,"ERROR: cannot start nu motor",eError); return 0; } @@ -953,7 +976,7 @@ static int calculateNormalBeamOmega(MATRIX z1, pHKL self, if(!iRet) { SCWrite(pCon,"ERROR: cannot start chi motor",eError); - StopExe(pServ->pExecutor,"all"); + stopHKLMotors(self); return 0; } pDum = (pDummy)self->pPhi; @@ -962,7 +985,7 @@ static int calculateNormalBeamOmega(MATRIX z1, pHKL self, if(!iRet) { SCWrite(pCon,"ERROR: cannot start phi",eError); - StopExe(pServ->pExecutor,"all"); + stopHKLMotors(self); return 0; } for(i = 0; i < 3; i++) diff --git a/hklmot.c b/hklmot.c index aeece55f..6f7c66cb 100644 --- a/hklmot.c +++ b/hklmot.c @@ -107,10 +107,10 @@ static int HKLCheckStatus(void *pData, SConnection *pCon){ assert(self != NULL); if(self->pHkl->targetDirty == 1){ status = RunHKL(self->pHkl,self->pHkl->targetHKL,.0,0,pCon); + self->pHkl->targetDirty = 0; if(status != 1){ return HWFault; } - self->pHkl->targetDirty = 0; return HWBusy; } else { return checkMotors(self,pCon); diff --git a/mesure.c b/mesure.c index ce68d1c8..dc182539 100644 --- a/mesure.c +++ b/mesure.c @@ -633,6 +633,8 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) ClearScanVar(self->pScanner); AddScanVar(self->pScanner, pServ->pSics,pCon,self->pCOmega, fStart, stepWidth); + snprintf(pBueffel,131,"Scanning om from %f with step %f", fStart, stepWidth); + SCWrite(pCon,pBueffel,eValue); /* Oksana does not want o2t scans to be tightly coupled, this is why we cannot use the normal o2t scan variable. Instead we calculate new limits and @@ -648,6 +650,8 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) fStart -= (np/2.)*stepWidth; AddScanVar(self->pScanner, pServ->pSics,pCon,self->pC2Theta, fStart, stepWidth); + snprintf(pBueffel,131,"Scanning 2theta from %f with step %f", fStart, stepWidth); + SCWrite(pCon,pBueffel,eValue); } /* @@ -665,10 +669,7 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) } /* do the scan */ - snprintf(pBueffel,131,"Scanning %s, step %f, np = %d",scanVar, stepWidth, np); - SCWrite(pCon,pBueffel,eWarning); free(scanVar); - if(self->iCompact) { self->pScanner->CollectScanData = CompactScanData; diff --git a/network.c b/network.c index b6bfb62b..d2ec21bb 100644 --- a/network.c +++ b/network.c @@ -154,8 +154,8 @@ CreateSocketAdress( i = sizeof(struct linger); lili.l_onoff = 1; lili.l_linger = 1; -/* setsockopt(pRes->sockid,SOL_SOCKET,SO_LINGER,&lili,i); -*/ + setsockopt(pRes->sockid,SOL_SOCKET,SO_LINGER,&lili,i); + pRes->iType = PORT; pRes->lMagic = NETMAGIC; return pRes; diff --git a/nxxml.c b/nxxml.c new file mode 100644 index 00000000..3b0c01ec --- /dev/null +++ b/nxxml.c @@ -0,0 +1,1443 @@ +/* + * This is the implementation file for the XML file driver + * for NeXus + * + * Copyright (C) 2004 Mark Koennecke + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For further information, see + */ +#include +#include +#include +#include +#include +#include "nxio.h" +#include "nxdataset.h" + + +extern void *NXpData; +extern char *NXIformatNeXusTime(); + + +/*----------------------- our data structures -------------------------- + One might wonder why a node stack is still needed even if this API + operates on top of a tree API. The reason for this are the links. + Following a link on any NXopenpath, data means a jump through the + whole tree. In order to correctly return from such adventures, + a stack is needed. Moreover we need it in order to keep track of the + state of search operations. + + The true NXroot node is always at stack[0]. The root in the data + structure is the ?xml element. The latter one is needed to store + the tree. +-----------------------------------------------------------------------*/ +typedef struct { + mxml_node_t *current; + mxml_node_t *currentChild; + int currentAttribute; +}xmlStack; +/*---------------------------------------------------------------------*/ +typedef struct { + mxml_node_t *root; /* root node */ + int readOnly; /* read only flag */ + int stackPointer; /* stack pointer */ + char filename[1024]; /* file name, for NXflush, NXclose */ + xmlStack stack[NXMAXSTACK]; /* stack */ +}XMLNexus, *pXMLNexus; +/*===================== support functions ===============================*/ +static int isDataNode(mxml_node_t *node){ + if(mxmlElementGetAttr(node,"name") != NULL){ + return 0; + } + if(strcmp(node->value.element.name,"NXroot") == 0){ + return 0; + } + if(strcmp(node->value.element.name,"NAPIlink") == 0){ + return 0; + } + return 1; +} +/*----------------------------------------------------------------------*/ +extern char *stptok(char *s, char *tok, size_t toklen, char *brk); + +static mxml_node_t *getLinkTarget(pXMLNexus xmlHandle, const char *target){ + mxml_node_t *node = NULL; + mxml_node_t *testNode = NULL; + char path[132], *pPtr; + + pPtr = (char *)target + 1; + node = xmlHandle->stack[0].current; + while((pPtr = stptok(pPtr,path,131,"/")) != NULL){ + /* + search for group node + */ + testNode = mxmlFindElement(node,node,NULL,"name",path,MXML_DESCEND_FIRST); + if(testNode == NULL){ + /* + it can still be a data node + */ + testNode = mxmlFindElement(node,node,path,NULL,NULL,MXML_DESCEND_FIRST); + } + if(testNode == NULL){ + NXIReportError(NXpData,"Cannot follow broken link"); + return NULL; + } else { + node = testNode; + } + } + return node; +} +/*==================== file functions ===================================*/ +static void errorCallbackForMxml(const char *txt){ + NXIReportError(NXpData,(char *)txt); +} +/*-----------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXopen(CONSTCHAR *filename, NXaccess am, + NXhandle* pHandle) { + pXMLNexus xmlHandle = NULL; + FILE *fp = NULL; + char *time_buffer = NULL; + mxml_node_t *current; + + /* + allocate data + */ + xmlHandle = (pXMLNexus)malloc(sizeof(XMLNexus)); + if(!xmlHandle){ + NXIReportError(NXpData, "Out of memory allocating XML file handle"); + return NX_ERROR; + } + memset(xmlHandle,0,sizeof(XMLNexus)); + + /* + initialize mxml XML parser + */ + mxmlSetCustomHandlers(nexusLoadCallback, nexusWriteCallback); + initializeNumberFormats(); + mxmlSetErrorCallback(errorCallbackForMxml); + + /* + open file + */ + strncpy(xmlHandle->filename,filename,1023); + switch(am){ + case NXACC_READ: + xmlHandle->readOnly = 1; + case NXACC_RDWR: + fp = fopen(filename,"r"); + if(fp == NULL){ + NXIReportError(NXpData,"Failed to open file:"); + NXIReportError(NXpData,(char *)filename); + free(xmlHandle); + return NX_ERROR; + } + xmlHandle->root = mxmlLoadFile(NULL,fp,nexusTypeCallback); + xmlHandle->stack[0].current = mxmlFindElement(xmlHandle->root, + xmlHandle->root, + "NXroot", + NULL,NULL, + MXML_DESCEND); + xmlHandle->stack[0].currentChild = NULL; + xmlHandle->stack[0].currentAttribute = 0; + fclose(fp); + break; + case NXACC_CREATEXML: + xmlHandle->root = mxmlNewElement(NULL, + "?xml version=\"1.0\" encoding=\"UTF-8\"?"); + current = mxmlNewElement(xmlHandle->root,"NXroot"); + mxmlElementSetAttr(current,"NeXus_version",NEXUS_VERSION); + mxmlElementSetAttr(current,"XML_version","mxml-2.0"); + mxmlElementSetAttr(current,"file_name",filename); + time_buffer = NXIformatNeXusTime(); + if(time_buffer != NULL){ + mxmlElementSetAttr(current,"file_time",time_buffer); + free(time_buffer); + } + xmlHandle->stack[0].current = current; + xmlHandle->stack[0].currentChild = NULL; + xmlHandle->stack[0].currentAttribute = 0; + break; + default: + NXIReportError(NXpData,"Bad access parameter specified in NXXopen"); + return NX_ERROR; + } + if(xmlHandle->stack[0].current == NULL){ + NXIReportError(NXpData, + "No NXroot element in XML-file, no NeXus-XML file"); + return NX_ERROR; + } + + *pHandle = xmlHandle; + return NX_OK; +} +/*----------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXclose (NXhandle* fid){ + pXMLNexus xmlHandle = NULL; + FILE *fp = NULL; + + xmlHandle = (pXMLNexus)*fid; + assert(xmlHandle); + + if(xmlHandle->readOnly == 0) { + fp = fopen(xmlHandle->filename,"w"); + if(fp == NULL){ + NXIReportError(NXpData,"Failed to open NeXus XML file for writing"); + return NX_ERROR; + } + mxmlSaveFile(xmlHandle->root,fp,NXwhitespaceCallback); + fclose(fp); + } + mxmlDelete(xmlHandle->root); + free(xmlHandle); + *fid = NULL; + return NX_OK; +} +/*----------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXflush(NXhandle *fid){ + pXMLNexus xmlHandle = NULL; + FILE *fp = NULL; + + xmlHandle = (pXMLNexus)*fid; + assert(xmlHandle); + + if(xmlHandle->readOnly == 0) { + fp = fopen(xmlHandle->filename,"w"); + if(fp == NULL){ + NXIReportError(NXpData,"Failed to open NeXus XML file for writing"); + return NX_ERROR; + } + mxmlSaveFile(xmlHandle->root,fp,NXwhitespaceCallback); + fclose(fp); + } + return NX_OK; +} +/*======================================================================= + Group functions +=========================================================================*/ +NXstatus CALLING_STYLE NXXmakegroup (NXhandle fid, CONSTCHAR *name, + CONSTCHAR *nxclass){ + pXMLNexus xmlHandle = NULL; + mxml_node_t *newGroup = NULL; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + NXIReportError(NXpData,"Close dataset before trying to create a group"); + return NX_ERROR; + } + + newGroup = mxmlNewElement(xmlHandle->stack[xmlHandle->stackPointer].current, + nxclass); + if(!newGroup){ + NXIReportError(NXpData,"failed to allocate new group"); + return NX_ERROR; + } + mxmlElementSetAttr(newGroup,"name",name); + return NX_OK; +} +/*----------------------------------------------------------------------*/ +static mxml_node_t *searchGroupLinks(pXMLNexus xmlHandle, CONSTCHAR *name, + CONSTCHAR *nxclass){ + mxml_node_t *linkNode = NULL; + mxml_node_t *current; + mxml_node_t *test = NULL; + const char *linkTarget; + + current = xmlHandle->stack[xmlHandle->stackPointer].current; + linkNode = current; + while((linkNode = mxmlFindElement(linkNode,current,"NAPIlink",NULL,NULL, + MXML_DESCEND_FIRST)) != NULL){ + linkTarget = mxmlElementGetAttr(linkNode,"target"); + test = getLinkTarget(xmlHandle,linkTarget); + if(test != NULL){ + if(strcmp(test->value.element.name,nxclass) == 0){ + if(strcmp(mxmlElementGetAttr(test,"name"),name) == 0){ + return test; + } + } + } + } + return NULL; +} +/*------------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXopengroup (NXhandle fid, CONSTCHAR *name, + CONSTCHAR *nxclass){ + pXMLNexus xmlHandle = NULL; + mxml_node_t *newGroup = NULL; + char error[1024]; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + NXIReportError(NXpData,"Close dataset before trying to open a group"); + return NX_ERROR; + } + newGroup = mxmlFindElement(xmlHandle->stack[xmlHandle->stackPointer].current, + xmlHandle->stack[xmlHandle->stackPointer].current, + nxclass, + "name", + name, + MXML_DESCEND_FIRST); + if(newGroup == NULL){ + newGroup = searchGroupLinks(xmlHandle,name,nxclass); + } + if(!newGroup){ + snprintf(error,1023,"Failed to open %s, %s",name,nxclass); + NXIReportError(NXpData,error); + return NX_ERROR; + } + xmlHandle->stackPointer++; + xmlHandle->stack[xmlHandle->stackPointer].current = newGroup; + xmlHandle->stack[xmlHandle->stackPointer].currentChild = NULL; + xmlHandle->stack[xmlHandle->stackPointer].currentAttribute = 0; + return NX_OK; +} +/*----------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXclosegroup (NXhandle fid){ + pXMLNexus xmlHandle = NULL; + mxml_node_t *newGroup = NULL; + char error[1024]; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + /* + silently fix this + */ + NXXclosedata(fid); + } + if(xmlHandle->stackPointer > 0){ + xmlHandle->stackPointer--; + } + return NX_OK; +} +/*========================================================================= + dataset functions +=========================================================================*/ +NXstatus CALLING_STYLE NXXcompmakedata (NXhandle fid, CONSTCHAR *name, + int datatype, + int rank, + int dimensions[], + int compress_type, int chunk_size[]){ + /* + compression does not relly make sense with XML + */ + return NXXmakedata(fid,name,datatype,rank,dimensions); +} +/*-----------------------------------------------------------------------*/ +static char *buildTypeString(int datatype, int rank, int dimensions[]){ + char *typestring = NULL; + char pNumber[20]; + int i; + + /* + allocate data + */ + typestring = (char *)malloc(132*sizeof(char)); + if(!typestring){ + NXIReportError(NXpData,"Failed to allocate typestring"); + return NULL; + } + memset(typestring,0,132*sizeof(char)); + + getNumberText(datatype,typestring,130); + if(rank > 1 || dimensions[0] > 1) { + strcat(typestring,"["); + snprintf(pNumber,19,"%d",dimensions[0]); + strncat(typestring,pNumber,130-strlen(typestring)); + for(i = 1; i < rank; i++){ + snprintf(pNumber,19,",%d",dimensions[i]); + strncat(typestring,pNumber,130-strlen(typestring)); + } + strcat(typestring,"]"); + } + return typestring; +} +/*------------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXmakedata (NXhandle fid, + CONSTCHAR *name, int datatype, + int rank, int dimensions[]){ + pXMLNexus xmlHandle = NULL; + mxml_node_t *dataNode = NULL; + mxml_node_t *newData = NULL; + mxml_node_t *current; + char *typestring; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + NXIReportError(NXpData,"Close dataset before trying to create a dataset"); + return NX_ERROR; + } + if(dimensions[0] < 0){ + NXIReportError(NXpData, + "NeXus XML-API does not support unlimited dimensions"); + return NX_ERROR; + } + + current = xmlHandle->stack[xmlHandle->stackPointer].current; + /* + NX_CHAR maps to MXML_OPAQUE datasets + */ + dataNode = mxmlNewElement(current,name); + if(datatype == NX_CHAR){ + newData = mxmlNewOpaque(dataNode,""); + return NX_OK; + } else { + typestring = buildTypeString(datatype,rank,dimensions); + if(typestring != NULL){ + mxmlElementSetAttr(dataNode,TYPENAME,typestring); + free(typestring); + } else { + NXIReportError(NXpData,"Failed to allocate typestring"); + return NX_ERROR; + } + newData = (mxml_node_t *)malloc(sizeof(mxml_node_t)); + if(!newData){ + NXIReportError(NXpData,"Failed to allocate space for dataset"); + return NX_ERROR; + } + memset(newData,0,sizeof(mxml_node_t)); + mxmlAdd(dataNode, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, newData); + newData->type = MXML_CUSTOM; + newData->value.custom.data = createNXDataset(rank,datatype,dimensions); + if(!newData->value.custom.data){ + NXIReportError(NXpData,"Failed to allocate space for dataset"); + return NX_ERROR; + } + newData->value.custom.destroy = destroyDataset; + } + return NX_OK; +} +/*----------------------------------------------------------------------*/ +static mxml_node_t *searchSDSLinks(pXMLNexus xmlHandle, CONSTCHAR *name){ + mxml_node_t *linkNode = NULL; + mxml_node_t *current; + mxml_node_t *test = NULL; + const char *linkTarget; + + current = xmlHandle->stack[xmlHandle->stackPointer].current; + linkNode = current; + while((linkNode = mxmlFindElement(linkNode,current,"NAPIlink",NULL,NULL, + MXML_DESCEND_FIRST)) != NULL){ + linkTarget = mxmlElementGetAttr(linkNode,"target"); + test = getLinkTarget(xmlHandle,linkTarget); + if(test != NULL){ + if(strcmp(test->value.element.name,name) == 0){ + return test; + } + } + } + return NULL; +} +/*-----------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXopendata (NXhandle fid, CONSTCHAR *name){ + pXMLNexus xmlHandle = NULL; + mxml_node_t *dataNode = NULL; + char error[1024]; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + /* + silently fix this + */ + xmlHandle->stackPointer--; + if(xmlHandle->stackPointer < 0){ + xmlHandle->stackPointer = 0; + } + } + + dataNode = mxmlFindElement(xmlHandle->stack[xmlHandle->stackPointer].current, + xmlHandle->stack[xmlHandle->stackPointer].current, + name, + NULL, + NULL, + MXML_DESCEND_FIRST); + if(dataNode == NULL){ + dataNode = searchSDSLinks(xmlHandle,name); + } + if(!dataNode){ + snprintf(error,1023,"Failed to open dataset %s",name); + NXIReportError(NXpData,error); + return NX_ERROR; + } + xmlHandle->stackPointer++; + xmlHandle->stack[xmlHandle->stackPointer].current = dataNode; + xmlHandle->stack[xmlHandle->stackPointer].currentChild = NULL; + xmlHandle->stack[xmlHandle->stackPointer].currentAttribute = 0; + return NX_OK; +} +/*----------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXclosedata (NXhandle fid){ + pXMLNexus xmlHandle = NULL; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + if(xmlHandle->stackPointer > 0){ + xmlHandle->stackPointer--; + } + return NX_OK; + } + return NX_OK; +} +/*----------------------------------------------------------------------*/ +static mxml_node_t *findData(mxml_node_t *node){ + mxml_node_t *baby = node; + + while( (baby = mxmlWalkNext(baby,node,MXML_DESCEND_FIRST)) != NULL){ + if(baby->type == MXML_OPAQUE || baby->type == MXML_CUSTOM){ + return baby; + } + } + return NULL; +} +/*------------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXputdata (NXhandle fid, void *data){ + pXMLNexus xmlHandle = NULL; + mxml_node_t *userData = NULL; + mxml_node_t *current = NULL; + pNXDS dataset; + int length; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + NXIReportError(NXpData,"No dataset open"); + return NX_ERROR; + } + + current = xmlHandle->stack[xmlHandle->stackPointer].current; + userData = findData(current); + assert(userData != NULL); + if(userData->type == MXML_OPAQUE){ + /* + text data + */ + mxmlSetOpaque(userData,(const char *)data); + } else { + dataset = (pNXDS)userData->value.custom.data; + assert(dataset); + length = getNXDatasetByteLength(dataset); + memcpy(dataset->u.ptr,data,length); + } + return NX_OK; +} +/*------------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXgetdata (NXhandle fid, void *data){ + pXMLNexus xmlHandle = NULL; + mxml_node_t *userData = NULL; + mxml_node_t *current = NULL; + pNXDS dataset; + int length; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + NXIReportError(NXpData,"No dataset open"); + return NX_ERROR; + } + + current = xmlHandle->stack[xmlHandle->stackPointer].current; + userData = findData(current); + assert(userData != NULL); + if(userData->type == MXML_OPAQUE){ + /* + text data + */ + strcpy((char *)data,userData->value.opaque); + } else { + dataset = (pNXDS)userData->value.custom.data; + assert(dataset); + length = getNXDatasetByteLength(dataset); + memcpy(data,dataset->u.ptr,length); + } + return NX_OK; +} +/*------------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXgetinfo (NXhandle fid, int *rank, + int dimension[], int *iType){ + pXMLNexus xmlHandle = NULL; + mxml_node_t *userData = NULL; + mxml_node_t *current = NULL; + pNXDS dataset; + int myRank, i; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + NXIReportError(NXpData,"No dataset open"); + return NX_ERROR; + } + + current = xmlHandle->stack[xmlHandle->stackPointer].current; + userData = findData(current); + assert(userData != NULL); + if(userData->type == MXML_OPAQUE){ + /* + text data + */ + *rank = 1; + *iType = NX_CHAR; + dimension[0]= strlen(userData->value.opaque) +1; + } else { + dataset = (pNXDS)userData->value.custom.data; + assert(dataset); + myRank = getNXDatasetRank(dataset); + *rank = myRank; + *iType = getNXDatasetType(dataset); + for(i = 0; i < myRank; i++){ + dimension[i] = getNXDatasetDim(dataset,i); + } + } + return NX_OK; +} +/*--------------------------------------------------------------------- + clone the dataset and set the data pointer. This in order to use + the addressing and type conversion implemented in nxdataset +---------------------------------------------------------------------*/ +static pNXDS makeSlabData(pNXDS dataset, void *data, int size[]){ + pNXDS slabData = NULL; + int rank, i; + + slabData = (pNXDS)malloc(sizeof(NXDS)); + if(slabData == NULL){ + return NULL; + } + + rank = getNXDatasetRank(dataset); + slabData->rank = rank; + slabData->dim = (int *)malloc(rank*sizeof(int)); + for(i = 0; i < rank; i++){ + slabData->dim[i] = size[i]; + } + slabData->type = getNXDatasetType(dataset); + slabData->u.ptr = data; + slabData->magic = dataset->magic; + return slabData; +} +/*-------------------------------------------------------------------- + This goes by recursion +----------------------------------------------------------------------*/ +static void putSlabData(pNXDS dataset, pNXDS slabData, int dim, + int start[], + int sourcePos[],int targetPos[]){ + int i, rank, length; + + rank = getNXDatasetRank(slabData); + length = getNXDatasetDim(slabData,dim); + if(dim != rank-1){ + for(i = 0; i < length; i++){ + targetPos[dim] = start[dim] +i; + sourcePos[dim] = i; + putSlabData(dataset,slabData, dim+1,start, + sourcePos,targetPos); + } + } else { + for(i = 0; i < length; i++){ + targetPos[dim] = start[dim] +i; + sourcePos[dim] = i; + putNXDatasetValue(dataset,targetPos, + getNXDatasetValue(slabData,sourcePos)); + } + } +} +/*----------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXputslab (NXhandle fid, void *data, + int iStart[], int iSize[]){ + + pXMLNexus xmlHandle = NULL; + mxml_node_t *userData = NULL; + mxml_node_t *current = NULL; + pNXDS dataset, slabData; + int sourcePos[NX_MAXRANK], targetPos[NX_MAXRANK]; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + NXIReportError(NXpData,"No dataset open"); + return NX_ERROR; + } + + current = xmlHandle->stack[xmlHandle->stackPointer].current; + userData = findData(current); + assert(userData != NULL); + if(userData->type == MXML_OPAQUE){ + NXIReportError(NXpData,"This API does not support slabs on text data"); + return NX_ERROR; + } + dataset = (pNXDS)userData->value.custom.data; + assert(dataset); + slabData = makeSlabData(dataset, data, iSize); + if(slabData == NULL){ + NXIReportError(NXpData,"Failed to allocate slab data"); + return NX_ERROR; + } + putSlabData(dataset,slabData,0,iStart,sourcePos,targetPos); + free(slabData->dim); + free(slabData); + + return NX_OK; +} +/*-------------------------------------------------------------------- + This goes by recursion +----------------------------------------------------------------------*/ +static void getSlabData(pNXDS dataset, pNXDS slabData, int dim, + int start[], + int sourcePos[],int targetPos[]){ + int i, rank, length; + + rank = getNXDatasetRank(slabData); + length = getNXDatasetDim(slabData,dim); + if(dim != rank-1){ + for(i = 0; i < length; i++){ + sourcePos[dim] = start[dim] +i; + targetPos[dim] = i; + getSlabData(dataset,slabData, dim+1,start, + sourcePos,targetPos); + } + } else { + for(i = 0; i < length; i++){ + sourcePos[dim] = start[dim] +i; + targetPos[dim] = i; + putNXDatasetValue(slabData,targetPos, + getNXDatasetValue(dataset,sourcePos)); + } + } +} +/*----------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXgetslab (NXhandle fid, void *data, + int iStart[], int iSize[]){ + pXMLNexus xmlHandle = NULL; + mxml_node_t *userData = NULL; + mxml_node_t *current = NULL; + pNXDS dataset, slabData; + int sourcePos[NX_MAXRANK], targetPos[NX_MAXRANK]; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + NXIReportError(NXpData,"No dataset open"); + return NX_ERROR; + } + + current = xmlHandle->stack[xmlHandle->stackPointer].current; + userData = findData(current); + assert(userData != NULL); + if(userData->type == MXML_OPAQUE){ + NXIReportError(NXpData,"This API does not support slabs on text data"); + return NX_ERROR; + } + dataset = (pNXDS)userData->value.custom.data; + assert(dataset); + slabData = makeSlabData(dataset, data, iSize); + if(slabData == NULL){ + NXIReportError(NXpData,"Failed to allocate slab data"); + return NX_ERROR; + } + getSlabData(dataset,slabData,0,iStart,sourcePos,targetPos); + free(slabData->dim); + free(slabData); + + return NX_OK; +} +/*----------------------------------------------------------------------*/ +static NXstatus CALLING_STYLE NXXsetnumberformat(NXhandle fid, + int type, char *format){ + pXMLNexus xmlHandle = NULL; + mxml_node_t *current = NULL; + mxml_node_t *userData = NULL; + pNXDS dataset; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + current = xmlHandle->stack[xmlHandle->stackPointer].current; + userData = findData(current); + assert(userData != NULL); + if(userData->type == MXML_OPAQUE){ + return NX_OK; + } + dataset = (pNXDS)userData->value.custom.data; + assert(dataset); + if(dataset->format != NULL){ + free(dataset->format); + } + dataset->format = strdup(format); + } else { + setNumberFormat(type, format); + } + return NX_OK; +} +/*============================ Attributes ============================*/ +static char *formatAttributeData(void *data, int datalen, int iType){ + int intData = 0; + long iValue; + double dValue; + char type[20]; + char *number; + + + if(iType == NX_CHAR){ + return strdup((char *)data); + } + + number = (char *)malloc(132*sizeof(char)); + if(!number){ + NXIReportError(NXpData,"Failed to allocate attribute number buffer"); + return NULL; + } + + if(datalen > 1){ + return NULL; + } + type[0] = '\0'; + switch(iType){ + case NX_INT32: + iValue = ((int *)data)[0]; + intData = 1; + strcpy(type,"NX_INT32:"); + break; + case NX_UINT32: + iValue = ((unsigned int *)data)[0]; + intData = 1; + strcpy(type,"NX_UINT32:"); + break; + case NX_INT16: + iValue = ((short *)data)[0]; + intData = 1; + strcpy(type,"NX_INT16:"); + break; + case NX_UINT16: + iValue = ((unsigned short *)data)[0]; + intData = 1; + strcpy(type,"NX_UINT16:"); + break; + case NX_INT8: + iValue = (int)((char *)data)[0]; + intData = 1; + strcpy(type,"NX_INT8:"); + break; + case NX_UINT8: + intData = 1; + iValue = (int)((unsigned char *)data)[0]; + strcpy(type,"NX_UINT8:"); + break; + case NX_FLOAT32: + dValue = ((float *)data)[0]; + strcpy(type,"NX_FLOAT32:"); + intData = 0; + break; + case NX_FLOAT64: + dValue = ((double *)data)[0]; + strcpy(type,"NX_FLOAT64:"); + intData = 0; + break; + } + if(intData){ + snprintf(number,79,"%s%d",type,iValue); + } else { + snprintf(number,79,"%s%f",type,dValue); + } + return number; +} +/*---------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXputattr (NXhandle fid, CONSTCHAR *name, void *data, + int datalen, int iType){ + pXMLNexus xmlHandle = NULL; + mxml_node_t *current = NULL; + char *numberData = NULL; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + /* + global attribute + */ + current = xmlHandle->stack[0].current; + } else { + /* + dataset attribute + */ + current = xmlHandle->stack[xmlHandle->stackPointer].current; + if(strcmp(name,TYPENAME) == 0){ + NXIReportError(NXpData,"type is a reserved attribute name, rejected"); + return NX_ERROR; + } + } + + numberData = formatAttributeData(data,datalen,iType); + if(numberData == NULL){ + NXIReportError(NXpData,"This API does not support non number arrays"); + return NX_ERROR; + } else { + mxmlElementSetAttr(current,name,numberData); + free(numberData); + } + return NX_OK; +} +/*--------------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXgetattr (NXhandle fid, char *name, + void *data, int* datalen, int* iType){ + pXMLNexus xmlHandle = NULL; + mxml_node_t *current = NULL; + const char *attribute = NULL; + char error[1024]; + char *attData = NULL; + int iValue, nx_type; + float fValue; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + /* + global attribute + */ + current = xmlHandle->stack[0].current; + } else { + /* + dataset attribute + */ + current = xmlHandle->stack[xmlHandle->stackPointer].current; + } + + attribute = mxmlElementGetAttr(current,name); + if(!attribute){ + snprintf(error,1023,"Attribute %s not found", name); + NXIReportError(NXpData,error); + return NX_ERROR; + } + nx_type = translateTypeCode((char *)attribute); + if(nx_type < 0) { + /* + no type code == text attribute + */ + nx_type = NX_CHAR; + } else { + /* + We need to find the number after the type code. However, there is + the complication of the datatype type attribute ... + */ + if(strcmp(name,TYPENAME) == 0){ + nx_type = NX_CHAR; + } else { + attData = strchr(attribute,(int)':'); + if(attData == NULL){ + NXIReportError(NXpData,"ERROR: bad attribute string, : missing"); + return NX_ERROR; + } + attData++; + } + } + *iType = nx_type; + switch(nx_type){ + case NX_CHAR: + strncpy((char *)data, attribute, *datalen); + *datalen = strlen(attribute); + *iType = NX_CHAR; + break; + case NX_INT32: + ((int *)data)[0] = atoi(attData); + *datalen = 1; + break; + case NX_UINT32: + ((unsigned int *)data)[0] = atoi(attData); + *datalen = 1; + break; + case NX_INT16: + ((short *)data)[0] = atoi(attData); + *datalen = 1; + break; + case NX_UINT16: + ((unsigned short *)data)[0] = atoi(attData); + *datalen = 1; + break; + case NX_INT8: + ((char *)data)[0] = atoi(attData); + *datalen = 1; + break; + case NX_UINT8: + ((unsigned char *)data)[0] = atoi(attData); + *datalen = 1; + break; + case NX_FLOAT32: + ((float *)data)[0] = atof(attData); + *datalen = 1; + break; + case NX_FLOAT64: + ((double *)data)[0] = atof(attData); + *datalen = 1; + break; + } + + return NX_OK; +} +/*====================== search functions =================================*/ +NXstatus CALLING_STYLE NXXgetnextentry (NXhandle fid,NXname name, + NXname nxclass, int *datatype){ + pXMLNexus xmlHandle = NULL; + mxml_node_t *next = NULL, *userData; + int stackPtr; + const char *target = NULL, *attname = NULL; + pNXDS dataset; + char pBueffel[256]; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + NXIReportError(NXpData,"Cannot search datasets"); + return NX_ERROR; + } + + stackPtr = xmlHandle->stackPointer; + if(xmlHandle->stack[stackPtr].currentChild == NULL){ + /* + initialization of search + */ + xmlHandle->stack[stackPtr].currentChild = + xmlHandle->stack[stackPtr].current->child; + } else { + /* + proceed + */ + xmlHandle->stack[stackPtr].currentChild = + xmlHandle->stack[stackPtr].currentChild->next; + } + next = xmlHandle->stack[stackPtr].currentChild; + if(next == NULL){ + return NX_EOD; + } + if(strcmp(next->value.element.name,"NAPIlink") == 0){ + target = mxmlElementGetAttr(next,"target"); + if(target == NULL){ + NXIReportError(NXpData,"Corrupted file, NAPIlink without target"); + return NX_ERROR; + } + next = getLinkTarget(xmlHandle,target); + if(next == NULL){ + NXIReportError(NXpData,"Corrupted file, broken link"); + return NX_ERROR; + } + } + + if(isDataNode(next)){ + strcpy(name,next->value.element.name); + strcpy(nxclass,"SDS"); + userData = findData(next); + if(userData == NULL){ + snprintf(pBueffel,255,"Corrupted file, userData for %s not found", + name); + NXIReportError(NXpData,pBueffel); + return NX_ERROR; + } + if(userData->type == MXML_OPAQUE){ + *datatype = NX_CHAR; + } else { + dataset = (pNXDS)userData->value.custom.data; + assert(dataset); + *datatype = getNXDatasetType(dataset); + } + } else { + strcpy(nxclass,next->value.element.name); + attname = mxmlElementGetAttr(next,"name"); + strcpy(name,attname); + } + return NX_OK; +} +/*----------------------------------------------------------------------*/ +NX_EXTERNAL NXstatus CALLING_STYLE NXXinitgroupdir(NXhandle fid){ + pXMLNexus xmlHandle = NULL; + int stackPtr; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + NXIReportError(NXpData,"Cannot search datasets"); + return NX_ERROR; + } + + stackPtr = xmlHandle->stackPointer; + xmlHandle->stack[stackPtr].currentChild = NULL; + return NX_OK; +} +/*-------------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXgetnextattr (NXhandle fid, NXname pName, + int *iLength, int *iType){ + pXMLNexus xmlHandle = NULL; + mxml_node_t *current = NULL; + int stackPtr, currentAtt, nx_type; + char *attVal; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + /* + dataset attribute + */ + stackPtr = xmlHandle->stackPointer; + } else { + /* + global attribute + */ + stackPtr = 0; + } + + current = xmlHandle->stack[stackPtr].current; + currentAtt = xmlHandle->stack[stackPtr].currentAttribute; + if(currentAtt >= + current->value.element.num_attrs ){ + xmlHandle->stack[stackPtr].currentAttribute = 0; + return NX_EOD; + } + + /* + hide type attribute + */ + if(strcmp(current->value.element.attrs[currentAtt].name,TYPENAME) == 0){ + xmlHandle->stack[stackPtr].currentAttribute++; + return NXXgetnextattr(fid,pName,iLength,iType); + } + + strcpy(pName,current->value.element.attrs[currentAtt].name); + attVal = current->value.element.attrs[currentAtt].value; + nx_type = translateTypeCode((char *)attVal); + if(nx_type < 0 || strcmp(pName,TYPENAME) == 0){ + /* + no type == NX_CHAR + */ + *iLength = strlen(attVal); + *iType = NX_CHAR; + } else { + *iLength = 1; + *iType = nx_type; + } + + xmlHandle->stack[stackPtr].currentAttribute++; + return NX_OK; +} +/*-------------------------------------------------------------------------*/ +NX_EXTERNAL NXstatus CALLING_STYLE NXXinitattrdir(NXhandle fid){ + pXMLNexus xmlHandle = NULL; + int stackPtr; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + /* + dataset attribute + */ + stackPtr = xmlHandle->stackPointer; + } else { + /* + global attribute + */ + stackPtr = 0; + } + + xmlHandle->stack[stackPtr].currentAttribute = 0; + return NX_OK; +} +/*-------------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXgetgroupinfo (NXhandle fid, int *iN, + NXname pName, NXname pClass){ + pXMLNexus xmlHandle = NULL; + mxml_node_t *child = NULL; + mxml_node_t *current = NULL; + const char *nameAtt = NULL; + int childCount; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + NXIReportError(NXpData,"No group open"); + return NX_ERROR; + } + current = xmlHandle->stack[xmlHandle->stackPointer].current; + + nameAtt = mxmlElementGetAttr(current,"name"); + if(nameAtt != NULL){ + strcpy(pName,nameAtt); + } + strcpy(pClass,current->value.element.name); + + childCount = 0; + child = current->child; + while(child != NULL){ + childCount++; + child = child->next; + } + *iN = childCount; + return NX_OK; +} +/*----------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXgetattrinfo (NXhandle fid, int *iN){ + pXMLNexus xmlHandle = NULL; + mxml_node_t *current = NULL; + int stackPtr, currentAtt; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + /* + dataset attribute + */ + stackPtr = xmlHandle->stackPointer; + } else { + /* + global attribute + */ + stackPtr = 0; + } + + current = xmlHandle->stack[stackPtr].current; + /* + hide type attribute + */ + if(mxmlElementGetAttr(current,TYPENAME) != NULL){ + *iN = current->value.element.num_attrs -1; + } else { + *iN = current->value.element.num_attrs; + } + return NX_OK; +} +/*================= Linking functions =================================*/ +static int countPathChars(mxml_node_t *path[], int stackPtr){ + int count = 1; + const char *name = NULL; + + while(stackPtr >= 0) { + if(isDataNode(path[stackPtr])){ + count += strlen(path[stackPtr]->value.element.name); + } else { + name = mxmlElementGetAttr(path[stackPtr],"name"); + if(name != NULL){ + count += strlen(name); + } + } + stackPtr--; + count += 1; + } + return count; +} +/*-------------------------------------------------------------------*/ +static char *buildPathString(mxml_node_t *path[], int stackPtr){ + int count = 0; + const char *name = NULL; + char *pathString = NULL; + + count = countPathChars(path,stackPtr); + pathString = (char *)malloc((count+10)*sizeof(char)); + if(pathString == NULL){ + return NULL; + } + memset(pathString,0,(count+10)*sizeof(char)); + + while(stackPtr >= 0) { + if(isDataNode(path[stackPtr])){ + strcat(pathString,"/"); + strcat(pathString,path[stackPtr]->value.element.name); + } else { + name = mxmlElementGetAttr(path[stackPtr],"name"); + if(name != NULL){ + strcat(pathString,"/"); + strcat(pathString,name); + } + } + stackPtr--; + } + return pathString; +} +/*--------------------------------------------------------------------*/ +static char *findLinkPath(mxml_node_t *node){ + mxml_node_t **path = NULL; + int stackPtr; + mxml_node_t *current = NULL; + char *pathString = NULL, *result = NULL; + int count; + + path = (mxml_node_t **)malloc(NXMAXSTACK*sizeof(mxml_node_t *)); + if(path == NULL){ + NXIReportError(NXpData,"ERROR: out of memory follwoing link path"); + return NULL; + } + memset(path,0,NXMAXSTACK*sizeof(mxml_node_t *)); + + /* + first path: walk up the tree untill NXroot is found + */ + current = node; + stackPtr = 0; + while(current != NULL && + strcmp(current->value.element.name,"NXroot") != 0){ + path[stackPtr] = current; + stackPtr++; + current = current->parent; + } + stackPtr--; + + /* + path now contains the nodes to the root node in reverse order. + From this build the path string + */ + result = buildPathString(path,stackPtr); + free(path); + return result; +} +/*--------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXgetdataID (NXhandle fid, NXlink* sRes){ + pXMLNexus xmlHandle = NULL; + mxml_node_t *current = NULL; + char *linkPath = NULL; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + return NX_ERROR; + } + current = xmlHandle->stack[xmlHandle->stackPointer].current; + + linkPath = findLinkPath(current); + if(!linkPath){ + NXIReportError(NXpData,"Failed to allocate link path string"); + return NX_ERROR; + } + strncpy(sRes->targetPath,linkPath,1023); + free(linkPath); + return NX_OK; +} +/*--------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXgetgroupID (NXhandle fid, NXlink* sRes){ + pXMLNexus xmlHandle = NULL; + mxml_node_t *current = NULL; + char *linkPath = NULL; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + NXIReportError(NXpData,"No group open"); + return NX_ERROR; + } + current = xmlHandle->stack[xmlHandle->stackPointer].current; + + if(xmlHandle->stackPointer == 0){ + return NX_ERROR; + } + + linkPath = findLinkPath(current); + if(!linkPath){ + NXIReportError(NXpData,"Failed to allocate link path string"); + return NX_ERROR; + } + strncpy(sRes->targetPath,linkPath,1023); + free(linkPath); + return NX_OK; +} +/*-----------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXmakelink (NXhandle fid, NXlink* sLink){ + pXMLNexus xmlHandle = NULL; + mxml_node_t *current = NULL, *linkNode = NULL; + mxml_node_t *linkedNode = NULL; + + xmlHandle = (pXMLNexus)fid; + assert(xmlHandle); + + if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){ + NXIReportError(NXpData,"No group to link to open"); + return NX_ERROR; + } + current = xmlHandle->stack[xmlHandle->stackPointer].current; + linkNode = mxmlNewElement(current,"NAPIlink"); + if(!linkNode){ + NXIReportError(NXpData,"Failed to allocate new link element"); + return NX_ERROR; + } + mxmlElementSetAttr(linkNode,"target",sLink->targetPath); + linkedNode = getLinkTarget(xmlHandle,sLink->targetPath); + if(linkedNode != NULL){ + mxmlElementSetAttr(linkedNode,"target",sLink->targetPath); + } + return NX_OK; +} +/*----------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXXsameID (NXhandle fileid, NXlink* pFirstID, + NXlink* pSecondID){ + if(strcmp(pFirstID->targetPath,pSecondID->targetPath) == 0) { + return NX_OK; + } else { + return NX_ERROR; + } +} +/*--------------------------------------------------------------------*/ +int NXXcompress(NXhandle fid, int comp){ + NXIReportError(NXpData,"NXcompress is deprecated, IGNORED"); + return NX_OK; +} +/*----------------------------------------------------------------------*/ +void NXXassignFunctions(pNexusFunction fHandle){ + fHandle->nxclose=NXXclose; + fHandle->nxflush=NXXflush; + fHandle->nxmakegroup=NXXmakegroup; + fHandle->nxopengroup=NXXopengroup; + fHandle->nxclosegroup=NXXclosegroup; + fHandle->nxmakedata=NXXmakedata; + fHandle->nxcompmakedata=NXXcompmakedata; + fHandle->nxcompress=NXXcompress; + fHandle->nxopendata=NXXopendata; + fHandle->nxclosedata=NXXclosedata; + fHandle->nxputdata=NXXputdata; + fHandle->nxputattr=NXXputattr; + fHandle->nxputslab=NXXputslab; + fHandle->nxgetdataID=NXXgetdataID; + fHandle->nxmakelink=NXXmakelink; + fHandle->nxgetdata=NXXgetdata; + fHandle->nxgetinfo=NXXgetinfo; + fHandle->nxgetnextentry=NXXgetnextentry; + fHandle->nxgetslab=NXXgetslab; + fHandle->nxgetnextattr=NXXgetnextattr; + fHandle->nxgetattr=NXXgetattr; + fHandle->nxgetattrinfo=NXXgetattrinfo; + fHandle->nxgetgroupID=NXXgetgroupID; + fHandle->nxgetgroupinfo=NXXgetgroupinfo; + fHandle->nxsameID=NXXsameID; + fHandle->nxinitgroupdir=NXXinitgroupdir; + fHandle->nxinitattrdir=NXXinitattrdir; + fHandle->nxsetnumberformat=NXXsetnumberformat; +} + diff --git a/tasdrive.c b/tasdrive.c index 4a230630..27a44723 100644 --- a/tasdrive.c +++ b/tasdrive.c @@ -29,7 +29,7 @@ #define ACH 11 /*============== Drivable Interface functions =====================*/ -static int TASSetValue(void *pData, SConnection *pCon, +static long TASSetValue(void *pData, SConnection *pCon, float value){ ptasMot self = (ptasMot)pData; assert(self); @@ -142,7 +142,8 @@ static float TASQMGetValue(void *pData, SConnection *pCon){ if(status != 1){ return -999.99; } - status = calcTasPowderPosition(&self->math->machine, angles, &self->math->current); + status = calcTasPowderPosition(&self->math->machine, + angles, &self->math->current); if(status < 0){ SCWrite(pCon,"ERROR: out of memory calculating Q-E variables",eError); return -999.99; @@ -176,7 +177,7 @@ static int TASHalt(void *pData){ } /*---------------------------------------------------------------------------*/ static int startMotors(ptasMot self, tasAngles angles, - SConnection *pCon){ + SConnection *pCon, int driveQ){ float val; double curve; int status; @@ -276,6 +277,9 @@ static int startMotors(ptasMot self, tasAngles angles, } } } + if(driveQ == 0){ + return OKOK; + } /* crystal @@ -319,39 +323,95 @@ static int startMotors(ptasMot self, tasAngles angles, self->math->mustDrive = 0; return OKOK; } +/*---------------------------------------------------------------------------*/ +static int checkQMotorLimits(ptasMot self, SConnection *pCon, + tasAngles angles){ + int status, retVal = 1; + char error[131]; + char pBueffel[256]; + + status = self->math->motors[A3]->pDrivInt->CheckLimits(self->math->motors[A3], + angles.a3, + error, + 131); + if(status != 1) { + retVal = 0; + snprintf(pBueffel,256,"ERROR: limit violation an a3: %s", error); + SCWrite(pCon,pBueffel,eError); + } + + status = self->math->motors[A4]->pDrivInt->CheckLimits(self->math->motors[A4], + angles.sample_two_theta, + error, + 131); + if(status != 1) { + retVal = 0; + snprintf(pBueffel,256,"ERROR: limit violation an a4: %s", error); + SCWrite(pCon,pBueffel,eError); + } + + status = self->math->motors[A3]->pDrivInt->CheckLimits(self->math->motors[SGU], + angles.sgu, + error, + 131); + if(status != 1) { + retVal = 0; + snprintf(pBueffel,256,"ERROR: limit violation an SGU: %s", error); + SCWrite(pCon,pBueffel,eError); + } + + status = self->math->motors[SGL]->pDrivInt->CheckLimits(self->math->motors[SGL], + angles.sgl, + error, + 131); + if(status != 1) { + retVal = 0; + snprintf(pBueffel,256,"ERROR: limit violation an SGL: %s", error); + SCWrite(pCon,pBueffel,eError); + } + return retVal; +} /*-----------------------------------------------------------------------------*/ static int calculateAndDrive(ptasMot self, SConnection *pCon){ tasAngles angles; - int status; + int status, driveQ = 1; + if(self->math->ubValid == 0){ + SCWrite(pCon,"WARNING: UB matrix invalid",eWarning); + } status = calcAllTasAngles(&self->math->machine, self->math->target, &angles); + self->math->mustDrive = 0; switch(status){ case ENERGYTOBIG: SCWrite(pCon,"ERROR: desired energy to big",eError); - self->math->mustDrive = 0; return HWFault; break; - case UBNOMEMORY: SCWrite(pCon,"ERROR: out of memory calculating angles",eError); - self->math->mustDrive = 0; - return HWFault; + driveQ = 0; break; case BADRMATRIX: SCWrite(pCon,"ERROR: bad crystallographic parameters or bad UB",eError); - self->math->mustDrive = 0; - return HWFault; + driveQ = 0; + break; + case BADUBORQ: + SCWrite(pCon,"ERROR: bad UB matrix or bad Q-vector",eError); + driveQ = 0; break; case TRIANGLENOTCLOSED: SCWrite(pCon,"ERROR: cannot close scattering triangle",eError); - self->math->mustDrive = 0; - return HWFault; + driveQ = 0; break; - default: - return startMotors(self,angles,pCon); } - return HWFault; + if(!checkQMotorLimits(self,pCon,angles)){ + driveQ = 0; + } + + if(driveQ == 0){ + SCWrite(pCon,"WARNING: NOT driving Q-vector because of errors",eError); + } + return startMotors(self,angles,pCon, driveQ); } /*-----------------------------------------------------------------------------*/ static int checkMotors(ptasMot self, SConnection *pCon){ diff --git a/tasub.c b/tasub.c index b54f0079..a1419396 100644 --- a/tasub.c +++ b/tasub.c @@ -53,6 +53,7 @@ static void saveReflections(ptasUB self, char *name, FILE *fd){ /*-------------------------------------------------------------------*/ static int tasUBSave(void *pData, char *name, FILE *fd){ ptasUB self = (ptasUB)pData; + tasReflection r; if(self == NULL){ return 0; @@ -83,8 +84,16 @@ static int tasUBSave(void *pData, char *name, FILE *fd){ name, self->target.qh, self->target.qk, self->target.ql, self->target.qm, self->target.ki, self->target.kf); - fprintf(fd,"%s setidx %d %d\n", - name, self->r1, self->r2); + r = self->r1; + fprintf(fd,"%s r1 %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f\n", + name, r.qe.qh, r.qe.qk, r.qe.ql, r.angles.a3, r.angles.sample_two_theta, + r.angles.sgu, r.angles.sgl, + KtoEnergy(r.qe.ki), KtoEnergy(r.qe.kf)); + r = self->r2; + fprintf(fd,"%s r2 %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f\n", + name, r.qe.qh, r.qe.qk, r.qe.ql, r.angles.a3, r.angles.sample_two_theta, + r.angles.sgu, r.angles.sgl, + KtoEnergy(r.qe.ki), KtoEnergy(r.qe.kf)); fprintf(fd,"%s update\n", name); return 1; } @@ -455,6 +464,8 @@ static int tasReadCell(SConnection *pCon, ptasUB self, int argc, char *argv[]){ SCWrite(pCon,pBueffel,eError); return 0; } + self->ubValid = 0; + SCWrite(pCon,"WARNING: UB is now invalid",eWarning); SCparChange(pCon); SCSendOK(pCon); return 1; @@ -477,8 +488,7 @@ static void clearReflections(ptasUB self){ LLDnodeDelete(self->reflectionList); status = LLDnodePtr2Next(self->reflectionList); } - self->r1 = -1; - self->r2 = -1; + self->ubValid = 0; } /*------------------------------------------------------------------*/ static void listReflections(ptasUB self, SConnection *pCon){ @@ -621,6 +631,84 @@ static int addReflection(ptasUB self, SicsInterp *pSics, SCparChange(pCon); return 1; } +/*------------------------------------------------------------------------------*/ +static int readReflection(SConnection *pCon, SicsInterp *pSics, + ptasReflection res, + int argc, char *argv[]){ + tasReflection r; + int status; + char pBueffel[256]; + + if(!SCMatchRights(pCon,usUser)){ + return 0; + } + + if(argc < 11){ + SCWrite(pCon,"ERROR: not enough parameters to read reflection",eError); + return 0; + } + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[2],&r.qe.qh); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[2]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[3],&r.qe.qk); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[3]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[4],&r.qe.ql); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[4]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[5],&r.angles.a3); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[5]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[6],&r.angles.sample_two_theta); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[6]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[7],&r.angles.sgu); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[7]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[8],&r.angles.sgl); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[8]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[9],&r.qe.ki); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[9]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + r.qe.ki = energyToK(r.qe.ki); + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[10],&r.qe.kf); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[10]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + r.qe.kf = energyToK(r.qe.kf); + if(ABS(r.qe.ki - r.qe.kf) > .01) { + SCWrite(pCon,"WARNING: KI != KF!",eWarning); + } + *res = r; + return 1; +} /*-----------------------------------------------------------------*/ int findReflection(int list, int idx, ptasReflection r){ int count = 0; @@ -642,7 +730,7 @@ static void listUB(ptasUB self , SConnection *pCon){ Tcl_DString list; char pBueffel[255]; int i; - + tasReflection r; Tcl_DStringInit(&list); if(self->machine.UB == NULL){ @@ -658,9 +746,32 @@ static void listUB(ptasUB self , SConnection *pCon){ Tcl_DStringAppend(&list,pBueffel,-1); } } - snprintf(pBueffel,255,"UB generated from reflections %d and %d in list\n", - self->r1, self->r2); + snprintf(pBueffel,255,"UB generated from reflections:\n"); Tcl_DStringAppend(&list,pBueffel,-1); + snprintf(pBueffel,255, + " QH QK QL A3 A4 SGU SGL EI EF\n"); + Tcl_DStringAppend(&list,pBueffel,-1); + r = self->r1; + snprintf(pBueffel,255, + " %8.4f %8.4f %8.4f %7.2f %7.2f %6.2f %6.2f %6.2f %6.2f\n", + r.qe.qh, r.qe.qk, r.qe.ql, r.angles.a3, + r.angles.sample_two_theta, r.angles.sgu, r.angles.sgl, + KtoEnergy(r.qe.ki), KtoEnergy(r.qe.kf)); + Tcl_DStringAppend(&list,pBueffel,-1); + r = self->r2; + snprintf(pBueffel,255, + " %8.4f %8.4f %8.4f %7.2f %7.2f %6.2f %6.2f %6.2f %6.2f\n", + r.qe.qh, r.qe.qk, r.qe.ql, r.angles.a3, + r.angles.sample_two_theta, r.angles.sgu, r.angles.sgl, + KtoEnergy(r.qe.ki), KtoEnergy(r.qe.kf)); + Tcl_DStringAppend(&list,pBueffel,-1); + snprintf(pBueffel,255,"Plane Normal: %8.4f %8.4f %8.4f\n", + self->machine.planeNormal[0][0], self->machine.planeNormal[1][0], + self->machine.planeNormal[2][0]); + Tcl_DStringAppend(&list,pBueffel,-1); + if(self->ubValid == 0){ + Tcl_DStringAppend(&list,"WARNING: UB matrix is invalid\n",-1); + } SCWrite(pCon,Tcl_DStringValue(&list),eValue); Tcl_DStringFree(&list); } @@ -723,7 +834,7 @@ static void listDiagnostik(ptasUB self, SConnection *pCon){ /*------------------------------------------------------------------*/ static int calcUB(ptasUB self, SConnection *pCon, SicsInterp *pSics, int argc, char *argv[]){ - int idx, status; + int idx1, idx2, status; tasReflection r1, r2; char pBueffel[256]; MATRIX UB = NULL; @@ -739,32 +850,32 @@ static int calcUB(ptasUB self, SConnection *pCon, SicsInterp *pSics, return 0; } - status = Tcl_GetInt(InterpGetTcl(pSics),argv[2],&idx); + status = Tcl_GetInt(InterpGetTcl(pSics),argv[2],&idx1); if(status != TCL_OK){ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[2]); SCWrite(pCon,pBueffel,eError); return 0; } - status = findReflection(self->reflectionList, idx-1,&r1); + idx1--; + status = findReflection(self->reflectionList, idx1,&r1); if(status != 1){ - snprintf(pBueffel,255,"ERROR: cannot find reflection with index %d",idx); + snprintf(pBueffel,255,"ERROR: cannot find reflection with index %d",idx1+1); SCWrite(pCon,pBueffel,eError); return 0; } - self->r1 = idx; - status = Tcl_GetInt(InterpGetTcl(pSics),argv[3],&idx); + status = Tcl_GetInt(InterpGetTcl(pSics),argv[3],&idx2); if(status != TCL_OK){ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[3]); SCWrite(pCon,pBueffel,eError); return 0; } - status = findReflection(self->reflectionList, idx-1,&r2); + idx2--; + status = findReflection(self->reflectionList, idx2,&r2); if(status != 1){ - snprintf(pBueffel,255,"ERROR: cannot find reflection with index %d",idx); + snprintf(pBueffel,255,"ERROR: cannot find reflection with index %d",idx2+1); SCWrite(pCon,pBueffel,eError); return 0; } - self->r2 = idx; UB = calcTasUBFromTwoReflections(self->cell,r1,r2,&status); if(UB == NULL){ @@ -778,6 +889,10 @@ static int calcUB(ptasUB self, SConnection *pCon, SicsInterp *pSics, } return 0; } + if(mat_det(UB) < .000001){ + SCWrite(pCon,"ERROR: invalid UB matrix, check reflections",eError); + return 0; + } if(self->machine.UB != NULL){ mat_free(self->machine.UB); } @@ -786,6 +901,9 @@ static int calcUB(ptasUB self, SConnection *pCon, SicsInterp *pSics, } self->machine.UB = UB; self->machine.planeNormal = calcPlaneNormal(r1,r2); + self->r1 = r1; + self->r2 = r2; + self->ubValid = 1; listUB(self,pCon); listDiagnostik(self,pCon); SCparChange(pCon); @@ -866,6 +984,74 @@ static int calcRefAngles(ptasUB self, SConnection *pCon, return 1; } /*------------------------------------------------------------------*/ +static int calcQFromAngles(ptasUB self, SConnection *pCon, + SicsInterp *pSics, + int argc, char *argv[]){ + tasQEPosition q; + tasAngles angles; + char pBueffel[256]; + int status; + + if(argc < 8){ + SCWrite(pCon,"ERROR: need a2, a3, a4, sgu, sgl, a6 for calculation", + eError); + return 0; + } + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[2], + &angles.monochromator_two_theta); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[2]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[3],&angles.a3); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[3]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[4],&angles.sample_two_theta); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[4]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[5],&angles.sgu); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[5]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[6],&angles.sgl); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[6]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[7],&angles.analyzer_two_theta); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[7]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + status = calcTasQEPosition(&self->machine,angles,&q); + switch(status){ + case UBNOMEMORY: + SCWrite(pCon,"ERROR: Out of memory calculating angles",eError); + return 0; + break; + } + + snprintf(pBueffel,255,"%8.4f %8.4f %8.4f %8.4f %8.4f", + q.qh, + q.qk, + q.ql, + KtoEnergy(q.ki), + KtoEnergy(q.kf)); + SCWrite(pCon,pBueffel,eValue); + return 1; +} +/*------------------------------------------------------------------*/ static int setUB(SConnection *pCon, SicsInterp *pSics, ptasUB self, int argc, char *argv[]){ double value; @@ -953,28 +1139,13 @@ static int setUB(SConnection *pCon, SicsInterp *pSics, ptasUB self, return 0; } self->machine.UB[2][2] = value; + self->ubValid = 1; SCSendOK(pCon); SCparChange(pCon); return 1; } /*------------------------------------------------------------------*/ -static int setIDX(SConnection *pCon, SicsInterp *pSics, ptasUB self, - int argc, char *argv[]){ - if(argc < 4) { - SCWrite(pCon,"ERROR: not enough arguments to setidx", eError); - return 0; - } - - if(!SCMatchRights(pCon,usMugger)){ - return 0; - } - self->r1 = atoi(argv[2]); - self->r2 = atoi(argv[3]); - SCSendOK(pCon); - return 1; -} -/*------------------------------------------------------------------*/ static int setNormal(SConnection *pCon, SicsInterp *pSics, ptasUB self, int argc, char *argv[]){ double value; @@ -1114,11 +1285,6 @@ static int deleteReflection(SConnection *pCon, SicsInterp *pSics, SCWrite(pCon,pBueffel,eError); return 0; } - if(idx == self->r1 || idx == self->r2) { - SCWrite(pCon,"ERROR: I refuse to delete reflections used for current UB", - eError); - return 0; - } idx--; status = LLDnodePtr2First(self->reflectionList); while(status == 1){ @@ -1162,6 +1328,7 @@ int TasUBWrapper(SConnection *pCon,SicsInterp *pSics, void *pData, } else if(strcmp(argv[1],"clear") == 0){ clearReflections(self); clearReflections(self); + SCWrite(pCon,"WARNING: UB is now invalid",eWarning); SCSendOK(pCon); return 1; } else if(strcmp(argv[1],"listref") == 0){ @@ -1174,20 +1341,24 @@ int TasUBWrapper(SConnection *pCon,SicsInterp *pSics, void *pData, return 1; } else if(strcmp(argv[1],"makeub") == 0){ return calcUB(self,pCon,pSics,argc,argv); - } else if(strcmp(argv[1],"calcref") == 0){ + } else if(strcmp(argv[1],"calcang") == 0){ return calcRefAngles(self,pCon,pSics,argc,argv); + } else if(strcmp(argv[1],"calcqe") == 0){ + return calcQFromAngles(self,pCon,pSics,argc,argv); } else if(strcmp(argv[1],"setub") == 0){ return setUB(pCon,pSics,self,argc,argv); } else if(strcmp(argv[1],"setnormal") == 0){ return setNormal(pCon,pSics,self,argc,argv); - } else if(strcmp(argv[1],"setidx") == 0){ - return setIDX(pCon,pSics,self,argc,argv); } else if(strcmp(argv[1],"settarget") == 0){ return setTarget(pCon,pSics,self,argc,argv); } else if(strcmp(argv[1],"update") == 0){ return tasUpdate(pCon,self); } else if(strcmp(argv[1],"del") == 0){ return deleteReflection(pCon,pSics,self,argc,argv); + } else if(strcmp(argv[1],"r1") == 0){ + return readReflection(pCon,pSics,&self->r1,argc,argv); + } else if(strcmp(argv[1],"r2") == 0){ + return readReflection(pCon,pSics,&self->r2,argc,argv); } else if(strcmp(argv[1],"const") == 0){ if(argc > 2){ strtolower(argv[2]); diff --git a/tasub.h b/tasub.h index b703e863..f713db56 100644 --- a/tasub.h +++ b/tasub.h @@ -27,7 +27,8 @@ int mustRecalculate; int mustDrive; pMotor motors[12]; - int r1, r2; + tasReflection r1, r2; + int ubValid; }tasUB, *ptasUB; diff --git a/tasublib.c b/tasublib.c index d311fb35..20efc6f0 100644 --- a/tasublib.c +++ b/tasublib.c @@ -18,6 +18,8 @@ #define PI 3.141592653589793 #define ECONST 2.072 #define DEGREE_RAD (PI/180.0) /* Radians per degree */ +#define VERT 0 +#define HOR 1 /*============== monochromator/analyzer stuff =========================*/ double energyToK(double energy){ double K; @@ -33,8 +35,14 @@ double KtoEnergy(double k){ return energy; } /*-------------------------------------------------------------------*/ -static double calcCurvature(double B1, double B2, double theta){ - return B1 + B2/Sind(ABS(theta)); +static double calcCurvature(double B1, double B2, double theta, + int ori){ + assert(ori == VERT || ori == HOR); + if(ori == VERT){ + return B1 + B2/Sind(ABS(theta)); + } else { + return B1 + B2*Sind(ABS(theta)); + } } /*--------------------------------------------------------------------*/ int maCalcTwoTheta(maCrystal data, double k, double *two_theta){ @@ -51,11 +59,11 @@ int maCalcTwoTheta(maCrystal data, double k, double *two_theta){ } /*--------------------------------------------------------------------*/ double maCalcVerticalCurvature(maCrystal data, double two_theta){ - return calcCurvature(data.VB1,data.VB2, two_theta/2.); + return calcCurvature(data.VB1,data.VB2, two_theta/2.,VERT); } /*-------------------------------------------------------------------*/ double maCalcHorizontalCurvature(maCrystal data, double two_theta){ - return calcCurvature(data.HB1,data.HB2, two_theta/2.); + return calcCurvature(data.HB1,data.HB2, two_theta/2.,HOR); } /*--------------------------------------------------------------------*/ double maCalcK(maCrystal data, double two_theta){ @@ -155,11 +163,22 @@ static MATRIX calcTasUVectorFromAngles(tasReflection r){ /*-------------------------------------------------------------------*/ MATRIX calcPlaneNormal(tasReflection r1, tasReflection r2){ MATRIX u1 = NULL, u2 = NULL, planeNormal = NULL; + int i; u1 = calcTasUVectorFromAngles(r1); u2 = calcTasUVectorFromAngles(r2); if(u1 != NULL && u2 != NULL){ - return vectorCrossProduct(u1,u2); + planeNormal = vectorCrossProduct(u1,u2); + /* + The plane normal has to point to the stars and not to the earth + core in order for the algorithm to work. + */ + if(planeNormal[2][0] < .0){ + for(i = 0; i < 3; i++){ + planeNormal[i][0] = -1.*planeNormal[i][0]; + } + } + return planeNormal; } else { return NULL; } @@ -187,11 +206,15 @@ MATRIX calcTasUBFromTwoReflections(lattice cell, tasReflection r1, h2 = tasReflectionToHC(r2.qe,B); if(h1 == NULL || h2 == NULL){ *errorCode = UBNOMEMORY; + mat_free(B); return NULL; } HT = matFromTwoVectors(h1,h2); if(HT == NULL){ *errorCode = UBNOMEMORY; + mat_free(B); + mat_free(h1); + mat_free(h2); return NULL; } @@ -202,39 +225,59 @@ MATRIX calcTasUBFromTwoReflections(lattice cell, tasReflection r1, u2 = calcTasUVectorFromAngles(r2); if(u1 == NULL || u2 == NULL){ *errorCode = UBNOMEMORY; + mat_free(B); + mat_free(h1); + mat_free(h2); return NULL; } UT = matFromTwoVectors(u1,u2); if(UT == NULL){ *errorCode = UBNOMEMORY; + mat_free(B); + mat_free(h1); + mat_free(h2); + mat_free(u1); + mat_free(u2); + mat_free(HT); return NULL; } - /* - debugging output - printf("B-matrix\n"); - mat_dump(B); - printf("HT-matrix\n"); - mat_dump(HT); - printf("UT-matrix\n"); - mat_dump(UT); - */ - /* UT = U * HT */ HTT = mat_tran(HT); if(HTT == NULL){ *errorCode = UBNOMEMORY; + mat_free(B); + mat_free(h1); + mat_free(h2); + mat_free(u1); + mat_free(u2); + mat_free(HT); return NULL; } U = mat_mul(UT,HTT); if(U == NULL){ *errorCode = UBNOMEMORY; + mat_free(B); + mat_free(h1); + mat_free(h2); + mat_free(u1); + mat_free(u2); + mat_free(HT); + mat_free(HTT); return NULL; } UB = mat_mul(U,B); if(UB == NULL){ + mat_free(B); + mat_free(h1); + mat_free(h2); + mat_free(u1); + mat_free(u2); + mat_free(HT); + mat_free(HTT); + mat_free(U); *errorCode = UBNOMEMORY; } @@ -296,12 +339,14 @@ static MATRIX tasReflectionToQC(tasQEPosition r, MATRIX UB){ } /*----------------------------------------------------------------------------*/ static MATRIX buildRMatrix(MATRIX UB, MATRIX planeNormal, - tasQEPosition qe){ + tasQEPosition qe, int *errorCode){ MATRIX U1V, U2V, TV, TVINV, M; - + + *errorCode = 1; U1V = tasReflectionToQC(qe,UB); if(U1V == NULL){ + *errorCode = UBNOMEMORY; return NULL; } normalizeVector(U1V); @@ -309,6 +354,13 @@ static MATRIX buildRMatrix(MATRIX UB, MATRIX planeNormal, U2V = vectorCrossProduct(planeNormal,U1V); if(U2V == NULL){ killVector(U1V); + *errorCode = UBNOMEMORY; + return NULL; + } + if(vectorLength(U2V) < .0001){ + *errorCode = BADUBORQ; + killVector(U1V); + killVector(U2V); return NULL; } @@ -316,9 +368,14 @@ static MATRIX buildRMatrix(MATRIX UB, MATRIX planeNormal, if(TV == NULL){ killVector(U1V); killVector(U2V); + *errorCode = UBNOMEMORY; return NULL; } + TVINV = mat_inv(TV); + if(TVINV == NULL){ + *errorCode = BADUBORQ; + } killVector(U1V); killVector(U2V); @@ -329,30 +386,36 @@ static MATRIX buildRMatrix(MATRIX UB, MATRIX planeNormal, int calcTasQAngles(MATRIX UB, MATRIX planeNormal, int ss, tasQEPosition qe, ptasAngles angles){ MATRIX R, QC; - double om, q, theta, cos2t, tmp, sq; + double om, q, theta, cos2t; + int errorCode = 1; - R = buildRMatrix(UB, planeNormal, qe); + R = buildRMatrix(UB, planeNormal, qe, &errorCode); if(R == NULL){ - return UBNOMEMORY; + return errorCode; } + - sq = sqrt(R[0][0]*R[0][0] + R[1][0]*R[1][0]); - if(ABS(sq) < .00001){ - return BADRMATRIX; + angles->sgl = Asind(-R[2][0]); + if(ABS(angles->sgl -90.) < .5){ + return BADUBORQ; } - om = Acosd(R[0][0]/sq); - om -= 180.; - tmp = Asind(R[1][0]/sqrt(R[0][0]*R[0][0] + R[1][0]*R[1][0])); + /* + Now, this is slightly different then in the publication by M. Lumsden. + The reason is that the atan2 helps to determine the sign of om + whereas the sin, cos formula given by M. Lumsden yield ambiguous signs + especially for om. + sgu = atan(R[2][1],R[2][2]) where: + R[2][1] = cos(sgl)sin(sgu) + R[2][2] = cos(sgu)cos(sgl) + om = atan(R[1][0],R[0][0]) where: + R[1][0] = sin(om)cos(sgl) + R[0][0] = cos(om)cos(sgl) + The definitions of th R components are taken from M. Lumsden + R-matrix definition. + */ - tmp = Acosd(sqrt(R[0][0]*R[0][0] + R[1][0]*R[1][0])); - angles->sgl = Asind(-R[2][0]); - - sq = sqrt(R[0][0]*R[0][0] + R[1][0]*R[1][0]); - if(ABS(sq) < .00001){ - return BADRMATRIX; - } - angles->sgu = Asind(R[2][1]/sq); - tmp = Acosd(R[2][2]/sqrt(R[0][0]*R[0][0]+R[1][0]*R[1][0])); + om = Atan2d(R[1][0],R[0][0]); + angles->sgu = Atan2d(R[2][1],R[2][2]); QC = tasReflectionToQC(qe,UB); if(QC == NULL){ @@ -370,6 +433,15 @@ int calcTasQAngles(MATRIX UB, MATRIX planeNormal, int ss, tasQEPosition qe, theta = calcTheta(qe.ki, qe.kf,angles->sample_two_theta); angles->a3 = om + theta; + /* + put a3 into -180, 180 properly. We cal always turn by 180 because the + scattering geometry is symmetric in this respect. It is like looking at + the scattering plane from the other side + */ + angles->a3 -= 180.; + if(angles->a3 < -180.){ + angles->a3 += 360.; + } killVector(QC); mat_free(R); @@ -395,9 +467,10 @@ int calcTasQH(MATRIX UB, tasAngles angles, ptasQEPosition qe){ Thereby take into account the physicists magic fudge 2PI factor */ - q = sqrt(qe->ki*qe->ki + qe->kf*qe->kf - 2.*qe->ki*qe->kf*Cosd(angles.sample_two_theta)); - q /= 2. * PI; + q = sqrt(qe->ki*qe->ki + qe->kf*qe->kf - + 2.*qe->ki*qe->kf*Cosd(angles.sample_two_theta)); qe->qm = q; + q /= 2. * PI; for(i = 0; i < 3; i++){ QV[i][0] *= q; @@ -431,14 +504,14 @@ int calcAllTasAngles(ptasMachine machine, tasQEPosition qe, return status; } - status = calcTasQAngles(machine->UB, machine->planeNormal, - machine->ss_sample, qe,angles); + status = maCalcTwoTheta(machine->analyzer,qe.kf,& + angles->analyzer_two_theta); if(status != 1){ return status; } - status = maCalcTwoTheta(machine->analyzer,qe.kf,& - angles->analyzer_two_theta); + status = calcTasQAngles(machine->UB, machine->planeNormal, + machine->ss_sample, qe,angles); if(status != 1){ return status; } @@ -498,7 +571,6 @@ int calcTasPowderPosition(ptasMachine machine, tasAngles angles, qe->qm = sqrt(qe->ki*qe->ki + qe->kf*qe->kf - 2.*qe->ki*qe->kf*Cosd(angles.sample_two_theta)); - return 1; } /*====================== Logic implementation =========================*/ @@ -582,6 +654,3 @@ double getTasPar(tasQEPosition qe, int tasVar){ assert(0); } } - - - diff --git a/tasublib.h b/tasublib.h index 8a4ab20c..4fad553a 100644 --- a/tasublib.h +++ b/tasublib.h @@ -17,6 +17,7 @@ #define UBNOMEMORY -702 #define TRIANGLENOTCLOSED -703 #define BADRMATRIX -704 +#define BADUBORQ -705 /*========================== defines for tasMode ====================*/ #define KICONST 1 #define KFCONST 2 diff --git a/trigd.c b/trigd.c index b3cb8953..807087ba 100644 --- a/trigd.c +++ b/trigd.c @@ -53,6 +53,16 @@ extern double Atand (double x) return (data); } /******************************************************************************* +* Atan of angle in degrees. +*******************************************************************************/ +extern double Atan2d (double x, double y) +{ + double data; + + data = (atan2(x,y)/DEGREE_RAD); + return (data); +} +/******************************************************************************* * Atan2 of angle in degrees. *******************************************************************************/ extern double Atand2 (double x) diff --git a/trigd.h b/trigd.h index bf3c6c47..9aa7697f 100644 --- a/trigd.h +++ b/trigd.h @@ -14,4 +14,5 @@ double Atand2 (double x); double Acosd (double x); double Asind (double x); + double Atan2d(double x, double y); #endif