/*---------------------------------------------------------------------- SICS interface to the triple axis spectrometer calculation module. copyright: see file COPYRIGHT Mark Koennecke, April-May 2005 Reworked to support an updater script for Integration into Hipadaba Mark Koennecke, July 2009 Modified to use drivables rather then motors Mark Koennecke, September 2011 ----------------------------------------------------------------------*/ #include #include #include "sics.h" #include "lld.h" #include "SCinter.h" #include "trigd.h" #include "tasub.h" #include "tasdrive.h" #include "vector.h" #include "tasmono.h" /*------------------- motor indexes in motor data structure ---------*/ #define A1 0 #define A2 1 #define MCV 2 #define MCH 3 #define A3 4 #define A4 5 #define SGU 6 #define SGL 7 #define A5 8 #define A6 9 #define ACV 10 #define ACH 11 /*----------------- data structure management code -------------------*/ static void invokeUpdate(ptasUB self, SConnection *pCon, char *key) { char buffer[1024]; if(self->updater != NULL){ snprintf(buffer,1024,"%s %s", self->updater, key); InterpExecute(pServ->pSics,pCon,buffer); } } /*--------------------------------------------------------------------*/ static void saveCrystal(char *objName, char *name, pmaCrystal crystal, FILE * fd) { fprintf(fd, "%s %s dd %f\n", objName, name, crystal->dd); fprintf(fd, "%s %s hb1 %f\n", objName, name, crystal->HB1); fprintf(fd, "%s %s hb2 %f\n", objName, name, crystal->HB2); fprintf(fd, "%s %s vb1 %f\n", objName, name, crystal->VB1); fprintf(fd, "%s %s vb2 %f\n", objName, name, crystal->VB2); fprintf(fd, "%s %s ss %d\n", objName, name, crystal->ss); } /*------------------------------------------------------------------*/ static void saveReflections(ptasUB self, char *name, FILE * fd) { tasReflection r; int status; status = LLDnodePtr2First(self->reflectionList); fprintf(fd, "%s clear\n", name); while (status == 1) { LLDnodeDataTo(self->reflectionList, &r); fprintf(fd, "%s addref %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)); status = LLDnodePtr2Next(self->reflectionList); } } /*-------------------------------------------------------------------*/ static int tasUBSave(void *pData, char *name, FILE * fd) { ptasUB self = (ptasUB) pData; tasReflection r; if (self == NULL) { return 0; } fprintf(fd, "#---- tasUB module %s\n", name); saveCrystal(name, "mono", &self->machine.monochromator, fd); saveCrystal(name, "ana", &self->machine.analyzer, fd); fprintf(fd, "%s cell %f %f %f %f %f %f\n", name, self->cell.a, self->cell.b, self->cell.c, self->cell.alpha, self->cell.beta, self->cell.gamma); saveReflections(self, name, fd); fprintf(fd, "%s outofplane %d\n", name, self->outOfPlaneAllowed); if (self->tasMode == KICONST) { fprintf(fd, "%s const ki\n", name); } else if (self->tasMode == ELASTIC) { fprintf(fd, "%s const elastic\n", name); } else { fprintf(fd, "%s const kf\n", name); } fprintf(fd, "%s ss %d\n", name, self->machine.ss_sample); fprintf(fd, " %s setub %f %f %f %f %f %f %f %f %f\n", name, self->machine.UB[0][0], self->machine.UB[0][1], self->machine.UB[0][2], self->machine.UB[1][0], self->machine.UB[1][1], self->machine.UB[1][2], self->machine.UB[2][0], self->machine.UB[2][1], self->machine.UB[2][2]); fprintf(fd, " %s setnormal %f %f %f\n", name, self->machine.planeNormal[0][0], self->machine.planeNormal[1][0], self->machine.planeNormal[2][0]); fprintf(fd, "%s settarget %f %f %f %f %f %f\n", name, self->target.qh, self->target.qk, self->target.ql, self->target.qm, self->target.ki, self->target.kf); 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; } /*------------------------------------------------------------------*/ static void defaultMonochromator(pmaCrystal mono) { mono->dd = 3.35; mono->ss = 1; mono->HB1 = 1.; mono->HB2 = 1.; mono->VB1 = 1.; mono->VB2 = 1.; } /*--------------------------------------------------------------------*/ static ptasUB MakeTasUB() { ptasUB pNew = NULL; pNew = (ptasUB) malloc(sizeof(tasUB)); if (pNew == NULL) { return NULL; } memset(pNew, 0, sizeof(tasUB)); pNew->pDes = CreateDescriptor("TAS-UB"); pNew->machine.UB = mat_creat(3, 3, UNIT_MATRIX); pNew->machine.planeNormal = mat_creat(3, 1, ZERO_MATRIX); pNew->machine.planeNormal[2][0] = 1.; pNew->reflectionList = LLDcreate(sizeof(tasReflection)); if (!pNew->pDes || !pNew->machine.UB || pNew->reflectionList < 0 || pNew->machine.planeNormal == NULL) { free(pNew); return NULL; } pNew->pDes->SaveStatus = tasUBSave; pNew->machine.ss_sample = 1; defaultMonochromator(&pNew->machine.monochromator); defaultMonochromator(&pNew->machine.analyzer); defaultCell(&pNew->cell); pNew->tasMode = KICONST; pNew->targetEn = .0; pNew->actualEn = .0; pNew->outOfPlaneAllowed = 1; pNew->mustRecalculate = 1; pNew->mono = MakeTasMono(); pNew->monoData = pNew; return pNew; } /*-------------------------------------------------------------------*/ static void KillTasUB(void *pData) { ptasUB self = (ptasUB) pData; if (self == NULL) { return; } LLDdelete(self->reflectionList); if (self->pDes != NULL) { DeleteDescriptor(self->pDes); } if (self->machine.UB != NULL) { mat_free(self->machine.UB); } if (self->machine.planeNormal != NULL) { mat_free(self->machine.planeNormal); } if(self->updater != NULL){ free(self->updater); } if(self->mono != NULL){ free(self->mono); } free(self); } /*==================== interpreter interface section =================*/ static int testMotor(ptasUB pNew, SConnection * pCon, char *name, int idx) { char pBueffel[132]; if (pNew->motors[idx] == NULL) { snprintf(pBueffel, 131, "ERROR: required motor %s NOT found", name); SCWrite(pCon, pBueffel, eError); return 0; } else { return 1; } } /*-------------------------------------------------------------------*/ static void updateTargets(ptasUB pNew, SConnection * pCon) { tasAngles ang; readTASMotAngles(pNew, pCon, &ang); calcTasQEPosition(&pNew->machine, ang, &pNew->target); } /*--------------------------------------------------------------------*/ static pMotor TasFindMotor(SicsInterp *pSics, char *name) { pMotor mot = NULL; CommandList *pCom = NULL; mot = FindMotor(pSics,name); if(mot == NULL){ pCom = FindCommand(pSics,name); if(pCom != NULL && GetDrivableInterface(pCom->pData) != NULL){ mot = (pMotor)pCom->pData; } } return mot; } /*--------------------------------------------------------------------*/ int TasUBFactory(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { ptasUB pNew = NULL; int status = 0, i; char pBueffel[132]; char names[][3] = { "ei", "ki", "qh", "qk", "ql", "ef", "kf", "en" }; char *defltMot[] = {"a1", "a2", "mcv", "mch", "a3", "a4", "sgu", "sgl", "a5", "a6", "acv", "ach"}; if (argc < 2) { SCWrite(pCon, "ERROR: need name to install tasUB", eError); return 0; } if (argc > 2 && argc < 14) { SCWrite(pCon, "ERROR: not enough motor names specified for MakeTasUB", eError); return 0; } pNew = MakeTasUB(); if (pNew == NULL) { SCWrite(pCon, "ERROR: out of memory creating tasUB", eError); return 0; } /* assign motors */ if (argc < 14) { /* * default names and assignement */ pNew->motors[0] = TasFindMotor(pSics, "a1"); pNew->motors[1] = TasFindMotor(pSics, "a2"); pNew->motors[2] = TasFindMotor(pSics, "mcv"); pNew->motors[3] = TasFindMotor(pSics, "mch"); pNew->motors[4] = TasFindMotor(pSics, "a3"); pNew->motors[5] = TasFindMotor(pSics, "a4"); pNew->motors[6] = TasFindMotor(pSics, "sgu"); pNew->motors[7] = TasFindMotor(pSics, "sgl"); pNew->motors[8] = TasFindMotor(pSics, "a5"); pNew->motors[9] = TasFindMotor(pSics, "a6"); pNew->motors[10] = TasFindMotor(pSics, "acv"); pNew->motors[11] = TasFindMotor(pSics, "ach"); for (i=0; i < 12; i++) { strcpy(pNew->motname[i], defltMot[i]); } } else { /* * user defined names */ pNew->motors[0] = TasFindMotor(pSics, argv[2]); pNew->motors[1] = TasFindMotor(pSics, argv[3]); pNew->motors[2] = TasFindMotor(pSics, argv[4]); pNew->motors[3] = TasFindMotor(pSics, argv[5]); pNew->motors[4] = TasFindMotor(pSics, argv[6]); pNew->motors[5] = TasFindMotor(pSics, argv[7]); pNew->motors[6] = TasFindMotor(pSics, argv[8]); pNew->motors[7] = TasFindMotor(pSics, argv[9]); pNew->motors[8] = TasFindMotor(pSics, argv[10]); pNew->motors[9] = TasFindMotor(pSics, argv[11]); pNew->motors[10] = TasFindMotor(pSics, argv[12]); pNew->motors[11] = TasFindMotor(pSics, argv[13]); for (i=0; i < 12; i++) { strcpy(pNew->motname[i], argv[i+2]); } } /* curvature motors may be missing, anything else is a serious problem */ status += testMotor(pNew, pCon, pNew->motname[A1], A1); status += testMotor(pNew, pCon, pNew->motname[A2], A2); status += testMotor(pNew, pCon, pNew->motname[A3], A3); status += testMotor(pNew, pCon, pNew->motname[A4], A4); status += testMotor(pNew, pCon, pNew->motname[SGU], SGU); status += testMotor(pNew, pCon, pNew->motname[SGL], SGL); status += testMotor(pNew, pCon, pNew->motname[A5], A5); status += testMotor(pNew, pCon, pNew->motname[A6], A6); if (status != 8) { SCWrite(pCon, "ERROR: a required motor is missing, tasub NOT installed", eError); return 0; } status = AddCommand(pSics, argv[1], TasUBWrapper, KillTasUB, pNew); if (status != 1) { SCWrite(pCon, "ERROR: duplicate tasUB command not created", eError); return 0; } /* install virtual motors */ for (i = 0; i < 8; i++) { status = InstallTasMotor(pSics, pNew, i + 1, names[i]); if (status != 1) { snprintf(pBueffel, 131, "ERROR: failed to create TAS motor %s", names[i]); SCWrite(pCon, pBueffel, eError); } } status = InstallTasQMMotor(pSics, pNew); if (status != 1) { snprintf(pBueffel, 131, "ERROR: failed to create TAS motor qm"); SCWrite(pCon, pBueffel, eError); } return 1; } /*-----------------------------------------------------------------*/ static int setCrystalParameters(pmaCrystal crystal, SConnection * pCon, int argc, char *argv[]) { int status; double d; char pBueffel[132]; status = Tcl_GetDouble(InterpGetTcl(pServ->pSics), argv[3], &d); if (status != TCL_OK) { snprintf(pBueffel, 131, "ERROR: failed to convert %s to number", argv[3]); SCWrite(pCon, pBueffel, eError); return 1; } if (!SCMatchRights(pCon, usMugger)) { return 0; } strtolower(argv[2]); if (strcmp(argv[2], "dd") == 0) { crystal->dd = d; SCSendOK(pCon); SCparChange(pCon); return 1; } else if (strcmp(argv[2], "ss") == 0) { status = (int)d; if (status == 1) { crystal->ss = 1; } else if(status == -1) { crystal->ss = -1; } else { SCPrintf(pCon,eError, "ERROR: %f not allowed for scattering sense, only 1,-1", d); return 0; } SCSendOK(pCon); SCparChange(pCon); return 1; } else if (strcmp(argv[2], "hb1") == 0) { crystal->HB1 = d; SCSendOK(pCon); SCparChange(pCon); return 1; } else if (strcmp(argv[2], "hb2") == 0) { crystal->HB2 = d; SCSendOK(pCon); SCparChange(pCon); return 1; } else if (strcmp(argv[2], "vb1") == 0) { crystal->VB1 = d; SCSendOK(pCon); SCparChange(pCon); return 1; } else if (strcmp(argv[2], "vb2") == 0) { crystal->VB2 = d; SCSendOK(pCon); SCparChange(pCon); return 1; } else { snprintf(pBueffel, 131, "ERROR: crystal parameter %s not known", argv[2]); SCWrite(pCon, pBueffel, eError); return 0; } } /*-----------------------------------------------------------------*/ static int getCrystalParameters(pmaCrystal crystal, SConnection * pCon, int argc, char *argv[]) { char pBueffel[132]; strtolower(argv[2]); if (strcmp(argv[2], "dd") == 0) { snprintf(pBueffel, 131, "%s.%s.dd = %f", argv[0], argv[1], crystal->dd); SCWrite(pCon, pBueffel, eValue); return 1; } else if (strcmp(argv[2], "hb1") == 0) { snprintf(pBueffel, 131, "%s.%s.hb1 = %f", argv[0], argv[1], crystal->HB1); SCWrite(pCon, pBueffel, eValue); return 1; } else if (strcmp(argv[2], "hb2") == 0) { snprintf(pBueffel, 131, "%s.%s.hb2 = %f", argv[0], argv[1], crystal->HB2); SCWrite(pCon, pBueffel, eValue); return 1; } else if (strcmp(argv[2], "vb1") == 0) { snprintf(pBueffel, 131, "%s.%s.vb1 = %f", argv[0], argv[1], crystal->VB1); SCWrite(pCon, pBueffel, eValue); return 1; } else if (strcmp(argv[2], "vb2") == 0) { snprintf(pBueffel, 131, "%s.%s.vb2 = %f", argv[0], argv[1], crystal->VB2); SCWrite(pCon, pBueffel, eValue); return 1; } else if (strcmp(argv[2], "ss") == 0) { snprintf(pBueffel, 131, "%s.%s.ss = %d", argv[0], argv[1], crystal->ss); SCWrite(pCon, pBueffel, eValue); return 1; } else { snprintf(pBueffel, 131, "ERROR: crystal parameter %s not known", argv[2]); SCWrite(pCon, pBueffel, eError); return 0; } } /*------------------------------------------------------------------*/ static int handleCrystalCommands(pmaCrystal crystal, SConnection * pCon, int argc, char *argv[]) { char pBueffel[132]; if (argc < 3) { snprintf(pBueffel, 131, "ERROR: insufficent number of arguments to %s %s", argv[0], argv[1]); SCWrite(pCon, pBueffel, eError); return 0; } if (argc > 3) { return setCrystalParameters(crystal, pCon, argc, argv); } else { return getCrystalParameters(crystal, pCon, argc, argv); } } /*---------------------------------------------------------------------*/ static int tasReadCell(SConnection * pCon, ptasUB self, int argc, char *argv[]) { int status; Tcl_Interp *pTcl = InterpGetTcl(pServ->pSics); char pBueffel[256]; if (argc < 8) { SCWrite(pCon, "ERROR: insufficient number of arguments to tasub cell", eError); return 0; } if (!SCMatchRights(pCon, usUser)) { return 0; } status = Tcl_GetDouble(pTcl, argv[2], &self->cell.a); 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(pTcl, argv[3], &self->cell.b); 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(pTcl, argv[4], &self->cell.c); 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(pTcl, argv[5], &self->cell.alpha); 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(pTcl, argv[6], &self->cell.beta); 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(pTcl, argv[7], &self->cell.gamma); if (status != TCL_OK) { snprintf(pBueffel, 255, "ERROR: failed to convert %s to number", argv[7]); SCWrite(pCon, pBueffel, eError); return 0; } self->ubValid = 0; SCWrite(pCon, "WARNING: UB is now invalid", eWarning); SCparChange(pCon); SCSendOK(pCon); return 1; } /*---------------------------------------------------------------------*/ static void tasListCell(SConnection * pCon, char *name, lattice direct) { char pBueffel[255]; snprintf(pBueffel, 255, "%s.cell = %f %f %f %f %f %f", name, direct.a, direct.b, direct.c, direct.alpha, direct.beta, direct.gamma); SCWrite(pCon, pBueffel, eValue); } /*--------------------------------------------------------------------*/ static void clearReflections(ptasUB self) { LLDdelete(self->reflectionList); self->reflectionList = LLDcreate(sizeof(tasReflection)); self->ubValid = 0; } /*------------------------------------------------------------------*/ static void listReflections(ptasUB self, SConnection * pCon) { tasReflection r; int status; int count = 0; char line[256]; Tcl_DString list; Tcl_DStringInit(&list); snprintf(line, 255, " NO QH QK QL %s %s %s %s EI EF\n", self->motname[A3], self->motname[A4], self->motname[SGU], self->motname[SGL]); Tcl_DStringAppend(&list, line, -1); status = LLDnodePtr2First(self->reflectionList); while (status == 1) { count++; LLDnodeDataTo(self->reflectionList, &r); snprintf(line, 255, "%3d %6.2f %6.2f %6.2f %7.2f %7.2f %6.2f %6.2f %6.2f %6.2f\n", count, 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, line, -1); status = LLDnodePtr2Next(self->reflectionList); } if (count == 0) { SCWrite(pCon, "Reflection list is empty", eValue); } else { SCWrite(pCon, Tcl_DStringValue(&list), eValue); } Tcl_DStringFree(&list); } /*-------------------------------------------------------------------*/ #define ABS(x) (x < 0 ? -(x) : (x)) /*-------------------------------------------------------------------*/ static int addReflection(ptasUB self, SicsInterp * pSics, SConnection * pCon, int argc, char *argv[]) { tasReflection r; int status, count = 11; char pBueffel[256]; tasAngles angles; Tcl_DString list; if (argc < 5) { SCWrite(pCon, "ERROR: need at least miller indices to add reflection", eError); return 0; } if (!SCMatchRights(pCon, usUser)) { 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; } if (self->tasMode == ELASTIC) { count = 10; } if (argc >= count) { 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); if (self->tasMode != ELASTIC) { 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); } else { r.qe.kf = r.qe.ki; } } else { if (argc > 5) { SCWrite(pCon, "WARNING: not all angles given on command line, using positions instead", eWarning); } status = readTASMotAngles(self, pCon, &r.angles); if (status != 1) { return status; } r.qe.ki = maCalcK(self->machine.monochromator, r.angles.monochromator_two_theta); r.qe.kf = maCalcK(self->machine.analyzer, r.angles.analyzer_two_theta); } if (self->tasMode == ELASTIC) { r.qe.kf = r.qe.ki; } if (ABS(r.qe.ki - r.qe.kf) > .01) { SCWrite(pCon, "WARNING: KI != KF!", eWarning); } LLDnodeAppend(self->reflectionList, &r); Tcl_DStringInit(&list); snprintf(pBueffel, 255, " QH QK QL %s %s %s %s EI EF\n", self->motname[A3], self->motname[A4], self->motname[SGU], self->motname[SGL]); Tcl_DStringAppend(&list, pBueffel, -1); snprintf(pBueffel, 255, " %6.2f %6.2f %6.2f %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); SCWrite(pCon, Tcl_DStringValue(&list), eValue); Tcl_DStringFree(&list); 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; int status; status = LLDnodePtr2First(list); while (status == 1) { if (count == idx) { LLDnodeDataTo(list, r); return 1; } status = LLDnodePtr2Next(list); count++; } return 0; } /*-----------------------------------------------------------------*/ void setStopFixed(ptasUB self, int val) { if(val == 0 || val ==1) { self->stopFixed = val; } } /*------------------------------------------------------------------*/ 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) { Tcl_DStringAppend(&list, "NO UB", -1); } else { Tcl_DStringAppend(&list, "UB = ", -1); snprintf(pBueffel, 255, "%f %f %f\n", self->machine.UB[0][0], self->machine.UB[0][1], self->machine.UB[0][2]); Tcl_DStringAppend(&list, pBueffel, -1); for (i = 1; i < 3; i++) { snprintf(pBueffel, 255, " %f %f %f\n", self->machine.UB[i][0], self->machine.UB[i][1], self->machine.UB[i][2]); Tcl_DStringAppend(&list, pBueffel, -1); } } snprintf(pBueffel, 255, "UB generated from reflections:\n"); Tcl_DStringAppend(&list, pBueffel, -1); snprintf(pBueffel, 255, " QH QK QL %s %s %s %s EI EF\n", self->motname[A3], self->motname[A4], self->motname[SGU], self->motname[SGL]); 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); } /*-----------------------------------------------------------------*/ static void printReflectionDiagnostik(ptasUB self, SConnection * pCon, tasReflection r) { tasReflection r2; Tcl_DString list; char line[256]; tasQEPosition qe; tasAngles angles; Tcl_DStringInit(&list); snprintf(line, 255, "METHOD QH QK QL %s %s %s %s EI EF\n", self->motname[A3], self->motname[A4], self->motname[SGU], self->motname[SGL]); Tcl_DStringAppend(&list, line, -1); snprintf(line, 255, "INPUT %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, line, -1); qe.ki = r.qe.ki; qe.kf = r.qe.kf; qe.qh = r.qe.qh; qe.qk = r.qe.qk; qe.ql = r.qe.ql; calcAllTasAngles(&self->machine, qe, &angles); snprintf(line, 255, "QE->ANG %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, angles.a3, angles.sample_two_theta, angles.sgu, angles.sgl, KtoEnergy(r.qe.ki), KtoEnergy(r.qe.kf)); Tcl_DStringAppend(&list, line, -1); angles.a3 = r.angles.a3; angles.sample_two_theta = r.angles.sample_two_theta; angles.sgu = r.angles.sgu; angles.sgl = r.angles.sgl; calcTasQEPosition(&self->machine, angles, &qe); snprintf(line, 255, "ANG->QE %8.4f %8.4f %8.4f %7.2f %7.2f %6.2f %6.2f %6.2f %6.2f\n", qe.qh, qe.qk, qe.ql, angles.a3, angles.sample_two_theta, angles.sgu, angles.sgl, KtoEnergy(qe.ki), KtoEnergy(qe.kf)); Tcl_DStringAppend(&list, line, -1); SCWrite(pCon, Tcl_DStringValue(&list), eWarning); Tcl_DStringFree(&list); } /*------------------------------------------------------------------*/ static void listDiagnostik(ptasUB self, SConnection * pCon) { tasReflection r; int status; status = LLDnodePtr2First(self->reflectionList); while (status == 1) { LLDnodeDataTo(self->reflectionList, &r); printReflectionDiagnostik(self, pCon, r); status = LLDnodePtr2Next(self->reflectionList); } } /*-----------------------------------------------------------------*/ static int addAuxReflection(ptasUB self, SConnection * pCon, SicsInterp * pSics, int argc, char *argv[]) { int status, ss; tasReflection r1, r2; float value = -999.99; char pBueffel[256]; MATRIX UB = NULL, B = NULL; if (argc < 5) { SCWrite(pCon, "ERROR: not enough arguments auxiliary reflection, need HKL", eError); return 0; } if (!SCMatchRights(pCon, usUser)) { return 0; } status = Tcl_GetDouble(InterpGetTcl(pSics), argv[2], &r2.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], &r2.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], &r2.qe.ql); if (status != TCL_OK) { snprintf(pBueffel, 255, "ERROR: failed to convert %s to number", argv[4]); SCWrite(pCon, pBueffel, eError); return 0; } B = mat_creat(3, 3, ZERO_MATRIX); if (B == NULL) { SCWrite(pCon, "ERROR: out of memory creating B matrix", eError); return 0; } status = calculateBMatrix(self->cell, B); if (status < 0) { SCWrite(pCon, "ERROR: bad cell constants, no volume", eError); mat_free(B); return 0; } status = findReflection(self->reflectionList, 0, &r1); if (status != 1) { r2.qe.kf = self->current.kf; r2.qe.ki = self->current.ki; GetDrivablePosition(self->motors[A3], pCon, &value); ss = self->machine.ss_sample; r2.angles.a3 = fmod(value + ss*180.,360.) - ss*180.; r2.angles.sgu = .0; r2.angles.sgl = .0; calcTwoTheta(B, r2.qe, self->machine.ss_sample, &r2.angles.sample_two_theta); r1 = r2; } status = makeAuxReflection(B, r1, &r2, self->machine.ss_sample); mat_free(B); if (status < 0) { SCWrite(pCon, "ERROR: out of memory in makeAuxUB or scattering angle not closed", eError); return 0; } LLDnodeAppend(self->reflectionList, &r2); SCSendOK(pCon); invokeUpdate(self,pCon,"ref"); return 1; } /*------------------------------------------------------------------*/ static int calcAuxUB(ptasUB self, SConnection * pCon, SicsInterp * pSics, int argc, char *argv[]) { int status; tasReflection r1, r2; char pBueffel[256]; MATRIX UB = NULL, B = NULL; if (argc < 5) { SCWrite(pCon, "ERROR: not enough arguments for UB calculation, need HKL of second plane vector", eError); return 0; } if (!SCMatchRights(pCon, usUser)) { return 0; } status = Tcl_GetDouble(InterpGetTcl(pSics), argv[2], &r2.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], &r2.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], &r2.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 = findReflection(self->reflectionList, 0, &r1); if (status != 1) { snprintf(pBueffel, 255, "ERROR: cannot find first reflection"); SCWrite(pCon, pBueffel, eError); return 0; } B = mat_creat(3, 3, ZERO_MATRIX); if (B == NULL) { SCWrite(pCon, "ERROR: out of memory creating B matrix", eError); return 0; } status = calculateBMatrix(self->cell, B); if (status < 0) { SCWrite(pCon, "ERROR: bad cell constants, no volume", eError); mat_free(B); return 0; } status = makeAuxReflection(B, r1, &r2, self->machine.ss_sample); mat_free(B); if (status < 0) { SCWrite(pCon, "ERROR: out of memory in makeAuxUB", eError); return 0; } UB = calcTasUBFromTwoReflections(self->cell, r1, r2, &status); if (UB == NULL) { switch (status) { case UBNOMEMORY: SCWrite(pCon, "ERROR: out of memory calculating UB matrix", eError); break; case REC_NO_VOLUME: SCWrite(pCon, "ERROR: bad cell constants, no volume", eError); break; } 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); } if (self->machine.planeNormal != NULL) { mat_free(self->machine.planeNormal); } self->machine.UB = UB; self->machine.planeNormal = makeVector(); self->machine.planeNormal[2][0] = 1.; /* self->machine.planeNormal = calcPlaneNormal(r1, r2); */ self->ubValid = 1; SCparChange(pCon); SCSendOK(pCon); return 1; } /*------------------------------------------------------------------*/ static int calcUB(ptasUB self, SConnection * pCon, SicsInterp * pSics, int argc, char *argv[]) { int idx1, idx2, status; tasReflection r1, r2; char pBueffel[256]; MATRIX UB = NULL; if (argc < 4) { SCWrite(pCon, "ERROR: not enough arguments for UB calculation, need index of two reflections", eError); return 0; } if (!SCMatchRights(pCon, usUser)) { return 0; } 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; } idx1--; status = findReflection(self->reflectionList, idx1, &r1); if (status != 1) { snprintf(pBueffel, 255, "ERROR: cannot find reflection with index %d", idx1 + 1); SCWrite(pCon, pBueffel, eError); return 0; } 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; } idx2--; status = findReflection(self->reflectionList, idx2, &r2); if (status != 1) { snprintf(pBueffel, 255, "ERROR: cannot find reflection with index %d", idx2 + 1); SCWrite(pCon, pBueffel, eError); return 0; } if(!self->outOfPlaneAllowed){ r1.angles.sgu = .0; r1.angles.sgl = .0; r2.angles.sgu = .0; r2.angles.sgl = .0; } UB = calcTasUBFromTwoReflections(self->cell, r1, r2, &status); if (UB == NULL) { switch (status) { case UBNOMEMORY: SCWrite(pCon, "ERROR: out of memory calculating UB matrix", eError); break; case REC_NO_VOLUME: SCWrite(pCon, "ERROR: bad cell constants, no volume", eError); break; } 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); } if (self->machine.planeNormal != NULL) { mat_free(self->machine.planeNormal); } self->machine.UB = UB; /* self->machine.planeNormal = calcPlaneNormalQ(UB,r1, r2);*/ self->machine.planeNormal = makeVector(); self->machine.planeNormal[2][0] = 1.; self->r1 = r1; self->r2 = r2; self->ubValid = 1; listUB(self, pCon); listDiagnostik(self, pCon); invokeUpdate(self,pCon,"main"); SCparChange(pCon); return 1; } /*-----------------------------------------------------------------*/ static int calcUBFromCell(ptasUB self, SConnection * pCon) { MATRIX B, U, UB; tasReflection r1; int status; B = mat_creat(3, 3, UNIT_MATRIX); U = mat_creat(3, 3, UNIT_MATRIX); status = findReflection(self->reflectionList, 0, &r1); if (status == 1) { /* U[0][0] = Cosd(r1.angles.a3); U[0][1] = -Sind(r1.angles.a3); U[1][0] = Sind(r1.angles.a3); U[1][1] = Cosd(r1.angles.a3); */ } if (B == NULL || U == NULL) { SCWrite(pCon, "ERROR: out of memory in calcUBFromCell", eError); return 0; } status = calculateBMatrix(self->cell, B); if (status == REC_NO_VOLUME) { SCWrite(pCon, "ERROR: cell has no volume", eError); return 0; } UB = mat_mul(U, B); if (UB == NULL) { SCWrite(pCon, "ERROR: matrix multiplication failed", eError); return 0; } if (mat_det(UB) < .000001) { SCWrite(pCon, "ERROR: invalid UB matrix, check cell", eError); return 0; } if (self->machine.UB != NULL) { mat_free(self->machine.UB); } self->machine.UB = UB; self->machine.planeNormal[0][0] = .0; self->machine.planeNormal[1][0] = .0; self->machine.planeNormal[2][0] = 1.; self->ubValid = 1; SCparChange(pCon); invokeUpdate(self,pCon,"main"); mat_free(U); mat_free(B); return 1; } /*-----------------------------------------------------------------*/ static int calcTestUBWrap(ptasUB self, SConnection *pCon, int argc, char *argv[]) { MATRIX UB; double om, sgu, sgl; tasReflection r1, r2; if(argc < 5) { SCWrite(pCon,"ERROR: not enough arguments to test UB", eError); return 0; } om = atof(argv[2]); sgu = atof(argv[3]); sgl = atof(argv[4]); UB = calcTestUB(self->cell, om, sgu, sgl); if(UB == NULL){ SCWrite(pCon,"ERROR: out of memory or invalid cell in test UB", eError); return 0; } mat_free(self->machine.UB); self->machine.UB = UB; /* r1.qe.qh = 1.0; r1.qe.qk = .0; r1.qe.ql = .0; r2.qe.qh = .0; r2.qe.qk = 1.0; r2.qe.ql = .0; self->machine.planeNormal = calcPlaneNormalQ(UB,r1,r2); self->machine.planeNormal[0][0] = -Sind(sgl); self->machine.planeNormal[1][0] = Cosd(sgl)*Sind(sgu); self->machine.planeNormal[2][0] = Cosd(sgl)*Cosd(sgu); SCPrintf(pCon,eValue,"Normal = %f,%f,%f\n", self->machine.planeNormal[0][0], self->machine.planeNormal[1][0], self->machine.planeNormal[2][0]); self->machine.planeNormal = calcTestNormal(sgu,sgl); SCPrintf(pCon,eValue,"Alternative normal = %f,%f,%f\n", self->machine.planeNormal[0][0], self->machine.planeNormal[1][0], self->machine.planeNormal[2][0]); */ self->machine.planeNormal[0][0] = .0; self->machine.planeNormal[1][0] = .0; self->machine.planeNormal[2][0] = 1.0; SCSendOK(pCon); return 1; } /*------------------------------------------------------------------*/ static int calcRefAngles(ptasUB self, SConnection * pCon, SicsInterp * pSics, int argc, char *argv[]) { tasQEPosition q; tasAngles angles; char pBueffel[256]; int status; if (self->tasMode == ELASTIC) { if (argc < 6) { SCWrite(pCon, "ERROR: need Qh, Qk, Ql, EI for calculation", eError); return 0; } } else { if (argc < 7) { SCWrite(pCon, "ERROR: need Qh, Qk, Ql, EI, EF for calculation", eError); return 0; } } status = Tcl_GetDouble(InterpGetTcl(pSics), argv[2], &q.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], &q.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], &q.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], &q.ki); if (status != TCL_OK) { snprintf(pBueffel, 255, "ERROR: failed to convert %s to number", argv[5]); SCWrite(pCon, pBueffel, eError); return 0; } if (self->tasMode != ELASTIC) { status = Tcl_GetDouble(InterpGetTcl(pSics), argv[6], &q.kf); if (status != TCL_OK) { snprintf(pBueffel, 255, "ERROR: failed to convert %s to number", argv[6]); SCWrite(pCon, pBueffel, eError); return 0; } } else { q.kf = q.ki; } q.ki = energyToK(q.ki); q.kf = energyToK(q.kf); status = calcAllTasAngles(&self->machine, q, &angles); switch (status) { case ENERGYTOBIG: SCWrite(pCon, "ERROR: energy to big", eError); return 0; break; case UBNOMEMORY: SCWrite(pCon, "ERROR: Out of memory calculating angles", eError); return 0; break; case BADRMATRIX: SCWrite(pCon, "ERROR: bad crystallographic parameters or bad UB", eError); return 0; break; case TRIANGLENOTCLOSED: SCWrite(pCon, "ERROR: scattering triangle not closed", eError); return 0; break; } if (self->tasMode != ELASTIC) { snprintf(pBueffel, 255, " %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f", angles.monochromator_two_theta, angles.a3, angles.sample_two_theta, angles.sgu, angles.sgl, angles.analyzer_two_theta); } else { snprintf(pBueffel, 255, " %8.2f %8.2f %8.2f %8.2f %8.2f", angles.monochromator_two_theta, angles.a3, angles.sample_two_theta, angles.sgl, angles.sgu); } SCWrite(pCon, pBueffel, eValue); 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 (self->tasMode != ELASTIC) { if (argc < 8) { SCWrite(pCon, "ERROR: need a2, a3, a4, sgu, sgl, a6 for calculation", eError); return 0; } } else { if (argc < 7) { SCWrite(pCon, "ERROR: need a2, a3, a4, sgu, sgl 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; } if (self->tasMode != ELASTIC) { 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; } } else { angles.analyzer_two_theta = angles.monochromator_two_theta; } status = calcTasQEPosition(&self->machine, angles, &q); switch (status) { case UBNOMEMORY: SCWrite(pCon, "ERROR: Out of memory calculating angles", eError); return 0; break; } if (self->tasMode == ELASTIC) { q.kf = q.ki; } 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; char pBueffel[256]; int status; if (argc < 11) { SCWrite(pCon, "ERROR: not enough arguments for setting UB", eError); return 0; } if (!SCMatchRights(pCon, usUser)) { return 0; } status = Tcl_GetDouble(InterpGetTcl(pSics), argv[2], &value); if (status != TCL_OK) { snprintf(pBueffel, 255, "ERROR: failed to convert %s to number", argv[2]); SCWrite(pCon, pBueffel, eError); return 0; } self->machine.UB[0][0] = value; status = Tcl_GetDouble(InterpGetTcl(pSics), argv[3], &value); if (status != TCL_OK) { snprintf(pBueffel, 255, "ERROR: failed to convert %s to number", argv[3]); SCWrite(pCon, pBueffel, eError); return 0; } self->machine.UB[0][1] = value; status = Tcl_GetDouble(InterpGetTcl(pSics), argv[4], &value); if (status != TCL_OK) { snprintf(pBueffel, 255, "ERROR: failed to convert %s to number", argv[4]); SCWrite(pCon, pBueffel, eError); return 0; } self->machine.UB[0][2] = value; status = Tcl_GetDouble(InterpGetTcl(pSics), argv[5], &value); if (status != TCL_OK) { snprintf(pBueffel, 255, "ERROR: failed to convert %s to number", argv[5]); SCWrite(pCon, pBueffel, eError); return 0; } self->machine.UB[1][0] = value; status = Tcl_GetDouble(InterpGetTcl(pSics), argv[6], &value); if (status != TCL_OK) { snprintf(pBueffel, 255, "ERROR: failed to convert %s to number", argv[6]); SCWrite(pCon, pBueffel, eError); return 0; } self->machine.UB[1][1] = value; status = Tcl_GetDouble(InterpGetTcl(pSics), argv[7], &value); if (status != TCL_OK) { snprintf(pBueffel, 255, "ERROR: failed to convert %s to number", argv[7]); SCWrite(pCon, pBueffel, eError); return 0; } self->machine.UB[1][2] = value; status = Tcl_GetDouble(InterpGetTcl(pSics), argv[8], &value); if (status != TCL_OK) { snprintf(pBueffel, 255, "ERROR: failed to convert %s to number", argv[8]); SCWrite(pCon, pBueffel, eError); return 0; } self->machine.UB[2][0] = value; status = Tcl_GetDouble(InterpGetTcl(pSics), argv[9], &value); if (status != TCL_OK) { snprintf(pBueffel, 255, "ERROR: failed to convert %s to number", argv[9]); SCWrite(pCon, pBueffel, eError); return 0; } self->machine.UB[2][1] = value; status = Tcl_GetDouble(InterpGetTcl(pSics), argv[10], &value); if (status != TCL_OK) { snprintf(pBueffel, 255, "ERROR: failed to convert %s to number", argv[10]); SCWrite(pCon, pBueffel, eError); return 0; } self->machine.UB[2][2] = value; self->ubValid = 1; SCSendOK(pCon); SCparChange(pCon); invokeUpdate(self,pCon,"main"); return 1; } /*------------------------------------------------------------------*/ static int getUB(SConnection * pCon, SicsInterp * pSics, ptasUB self, int argc, char *argv[]) { double value; char pBueffel[512]; int status; snprintf(pBueffel, 511, "tasub.ub = %f %f %f %f %f %f %f %f %f", self->machine.UB[0][0], self->machine.UB[0][1], self->machine.UB[0][2], self->machine.UB[1][0], self->machine.UB[1][1], self->machine.UB[1][2], self->machine.UB[2][0], self->machine.UB[2][1], self->machine.UB[2][2]); SCWrite(pCon, pBueffel, eValue); return 1; } /*------------------------------------------------------------------*/ static int setNormal(SConnection * pCon, SicsInterp * pSics, ptasUB self, int argc, char *argv[]) { double value; char pBueffel[256]; int status; if (argc < 5) { SCWrite(pCon, "ERROR: not enough arguments for setting plane normal", eError); return 0; } if (!SCMatchRights(pCon, usUser)) { return 0; } status = Tcl_GetDouble(InterpGetTcl(pSics), argv[2], &value); if (status != TCL_OK) { snprintf(pBueffel, 255, "ERROR: failed to convert %s to number", argv[2]); SCWrite(pCon, pBueffel, eError); return 0; } self->machine.planeNormal[0][0] = value; status = Tcl_GetDouble(InterpGetTcl(pSics), argv[3], &value); if (status != TCL_OK) { snprintf(pBueffel, 255, "ERROR: failed to convert %s to number", argv[3]); SCWrite(pCon, pBueffel, eError); return 0; } self->machine.planeNormal[1][0] = value; status = Tcl_GetDouble(InterpGetTcl(pSics), argv[4], &value); if (status != TCL_OK) { snprintf(pBueffel, 255, "ERROR: failed to convert %s to number", argv[4]); SCWrite(pCon, pBueffel, eError); return 0; } self->machine.planeNormal[2][0] = value; SCSendOK(pCon); SCparChange(pCon); return 1; } /*------------------------------------------------------------------*/ static int getNormal(SConnection * pCon, SicsInterp * pSics, ptasUB self, int argc, char *argv[]) { double value; char pBueffel[512]; int status; snprintf(pBueffel, 511, "tasub.normal = %f %f %f", self->machine.planeNormal[0][0], self->machine.planeNormal[1][0], self->machine.planeNormal[2][0]); SCWrite(pCon, pBueffel, eValue); return 1; } /*------------------------------------------------------------------*/ static int setTarget(SConnection * pCon, SicsInterp * pSics, ptasUB self, int argc, char *argv[]) { double value; char pBueffel[256]; int status; if (argc < 8) { SCWrite(pCon, "ERROR: not enough arguments for setting qe target", eError); return 0; } if (!SCMatchRights(pCon, usUser)) { return 0; } status = Tcl_GetDouble(InterpGetTcl(pSics), argv[2], &self->target.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], &self->target.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], &self->target.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], &self->target.qm); 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], &self->target.ki); 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], &self->target.kf); if (status != TCL_OK) { snprintf(pBueffel, 255, "ERROR: failed to convert %s to number", argv[7]); SCWrite(pCon, pBueffel, eError); return 0; } SCSendOK(pCon); return 1; } /*------------------------------------------------------------------*/ int tasUpdate(SConnection * pCon, ptasUB self) { int status; tasAngles angles; status = readTASMotAngles(self, pCon, &angles); if (status != 1) { return status; } status = calcTasQEPosition(&self->machine, angles, &self->current); if (status < 0) { SCWrite(pCon, "ERROR: out of memory calculating Q-E variables", eError); return 0; } if (self->tasMode == ELASTIC) { self->current.kf = self->current.ki; } self->mustRecalculate = 0; SCSendOK(pCon); return 1; } /*------------------------------------------------------------------*/ static int deleteReflection(SConnection * pCon, SicsInterp * pSics, ptasUB self, int argc, char *argv[]) { int idx, count = 0, status; char pBueffel[256]; if (argc < 3) { SCWrite(pCon, "ERROR: need number of reflection to delete", eError); return 0; } status = Tcl_GetInt(InterpGetTcl(pSics), argv[2], &idx); if (status != TCL_OK) { snprintf(pBueffel, 255, "ERROR: failed to convert %s to number", argv[2]); SCWrite(pCon, pBueffel, eError); return 0; } idx--; status = LLDnodePtr2First(self->reflectionList); while (status == 1) { if (count == idx) { LLDnodeDelete(self->reflectionList); break; } status = LLDnodePtr2Next(self->reflectionList); count++; } SCSendOK(pCon); invokeUpdate(self,pCon,"ref"); return 1; } /*------------------------------------------------------------------*/ static int replaceReflection(SConnection * pCon, SicsInterp * pSics, ptasUB self, int argc, char *argv[]) { int idx, count = 0, status; char pBueffel[256]; tasReflection r; if (argc < 12) { SCWrite(pCon, "ERROR: need id and new values to replace", eError); return 0; } status = Tcl_GetInt(InterpGetTcl(pSics), argv[2], &idx); if (status != TCL_OK) { snprintf(pBueffel, 255, "ERROR: failed to convert %s to number", argv[2]); SCWrite(pCon, pBueffel, eError); return 0; } idx--; status = LLDnodePtr2First(self->reflectionList); while (status == 1) { if (count == idx) { LLDnodeDataTo(self->reflectionList,&r); r.qe.qh = atof(argv[3]); r.qe.qk = atof(argv[4]); r.qe.ql = atof(argv[5]); r.angles.a3 = atof(argv[6]); r.angles.sample_two_theta = atof(argv[7]); r.angles.sgu = atof(argv[8]); r.angles.sgl = atof(argv[9]); r.qe.ki = energyToK(atof(argv[10])); r.qe.kf = energyToK(atof(argv[11])); LLDnodeDataFrom(self->reflectionList,&r); break; } status = LLDnodePtr2Next(self->reflectionList); count++; } SCSendOK(pCon); invokeUpdate(self,pCon,"ref"); return 1; } /*-------------------------------------------------------------------*/ int TasUBWrapper(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { ptasUB self = NULL; char pBueffel[131]; int status, newSS; double misalign = .0, a3offset; self = (ptasUB) pData; assert(self != NULL); if (argc < 2) { SCWrite(pCon, "ERROR: insufficient arguments to tasUB", eError); return 0; } strtolower(argv[1]); if (strcmp(argv[1], "mono") == 0) { status = handleCrystalCommands(&self->machine.monochromator, pCon, argc, argv); if(argc > 3){ invokeUpdate(self,pCon,"mono"); } self->mustRecalculate = 1; return status; } else if (strcmp(argv[1], "ana") == 0) { status = handleCrystalCommands(&self->machine.analyzer, pCon, argc, argv); self->mustRecalculate = 1; if(argc > 3){ invokeUpdate(self,pCon,"ana"); } return status; } else if (strcmp(argv[1], "cell") == 0) { if (argc > 2) { status = tasReadCell(pCon, self, argc, argv); invokeUpdate(self,pCon,"main"); return status; } else { tasListCell(pCon, argv[0], self->cell); return 1; } } else if (strcmp(argv[1], "clear") == 0) { clearReflections(self); clearReflections(self); SCWrite(pCon, "WARNING: UB is now invalid", eWarning); invokeUpdate(self,pCon,"ref"); SCSendOK(pCon); return 1; } else if (strcmp(argv[1], "listref") == 0) { listReflections(self, pCon); return 1; } else if (strcmp(argv[1], "addref") == 0) { status = addReflection(self, pSics, pCon, argc, argv); invokeUpdate(self, pCon,"ref"); return status; } else if (strcmp(argv[1], "repref") == 0) { status = replaceReflection(pCon, pSics, self, argc, argv); return status; } else if (strcmp(argv[1], "listub") == 0) { listUB(self, pCon); return 1; } else if (strcmp(argv[1], "makeub") == 0) { return calcUB(self, pCon, pSics, argc, argv); } else if (strcmp(argv[1], "makeauxub") == 0) { return calcAuxUB(self, pCon, pSics, argc, argv); } else if (strcmp(argv[1], "addauxref") == 0) { return addAuxReflection(self, pCon, pSics, argc, argv); } else if (strcmp(argv[1], "makeubfromcell") == 0) { return calcUBFromCell(self, pCon); } else if (strcmp(argv[1], "maketestub") == 0) { return calcTestUBWrap(self, pCon, argc, argv); } 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], "getub") == 0) { return getUB(pCon, pSics, self, argc, argv); } else if (strcmp(argv[1], "setnormal") == 0) { return setNormal(pCon, pSics, self, argc, argv); } else if (strcmp(argv[1], "getnormal") == 0) { return getNormal(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], "updatetargets") == 0) { updateTargets(self, pCon); SCSendOK(pCon); return 1; } else if (strcmp(argv[1], "const") == 0) { if (argc > 2) { strtolower(argv[2]); if (!SCMatchRights(pCon, usUser)) { return 0; } if (strcmp(argv[2], "ki") == 0) { self->tasMode = KICONST; } else if (strcmp(argv[2], "kf") == 0) { self->tasMode = KFCONST; } else if (strcmp(argv[2], "elastic") == 0) { self->tasMode = ELASTIC; } else { SCWrite(pCon, "ERROR: unknown triple axis mode, accepted are ki, kf, elastic", eError); return 0; } invokeUpdate(self,pCon,"main"); SCSendOK(pCon); return 1; } else { if (self->tasMode == KICONST) { snprintf(pBueffel, 131, "%s.const = ki", argv[0]); } else if (self->tasMode == ELASTIC) { snprintf(pBueffel, 131, "%s.const = elastic", argv[0]); } else { snprintf(pBueffel, 131, "%s.const = kf", argv[0]); } SCWrite(pCon, pBueffel, eValue); return 1; } } else if (strcmp(argv[1], "ss") == 0) { if (argc > 2) { strtolower(argv[2]); if (!SCMatchRights(pCon, usUser)) { return 0; } status = Tcl_GetInt(InterpGetTcl(pSics), argv[2], &newSS); if (status != TCL_OK) { SCWrite(pCon, "ERROR: failed to convert argument to number", eError); return 0; } if (newSS != 1 && newSS != -1) { SCWrite(pCon, "ERROR: invalid value for scattering sense, only 1, -1 allowed", eError); return 0; } self->machine.ss_sample = newSS; tasUpdate(pCon, self); invokeUpdate(self,pCon,"main"); SCSendOK(pCon); return 1; } else { snprintf(pBueffel, 131, "%s.ss = %d", argv[0], self->machine.ss_sample); SCWrite(pCon, pBueffel, eValue); return 1; } } else if(strcmp(argv[1],"misalign") == 0){ status = calcTasMisalignment(&self->machine, self->current,&misalign); if(status != 1){ SCWrite(pCon,"ERROR: failed to calculate misalignment, fix UB", eError); return 0; } SCPrintf(pCon,eValue,"tasub.misalign = %f", misalign ); return 1; } else if (strcmp(argv[1], "outofplane") == 0) { if (argc > 2) { strtolower(argv[2]); if (!SCMatchRights(pCon, usUser)) { return 0; } status = Tcl_GetInt(InterpGetTcl(pSics), argv[2], &newSS); if (status != TCL_OK) { SCWrite(pCon, "ERROR: failed to convert argument to number", eError); return 0; } self->outOfPlaneAllowed = newSS; invokeUpdate(self,pCon,"main"); SCWrite(pCon,"WARNING: You have to recalculate the UB matrix after swapping outofplane mode", eWarning); SCSendOK(pCon); return 1; } else { snprintf(pBueffel, 131, "%s.outofplane = %d", argv[0], self->outOfPlaneAllowed); SCWrite(pCon, pBueffel, eValue); return 1; } } else if (strcmp(argv[1], "a3offset") == 0) { if (argc > 2) { strtolower(argv[2]); if (!SCMatchRights(pCon, usMugger)) { return 0; } status = Tcl_GetDouble(InterpGetTcl(pSics), argv[2], &a3offset); if (status != TCL_OK) { SCWrite(pCon, "ERROR: failed to convert argument to number", eError); return 0; } self->machine.a3offset = a3offset; invokeUpdate(self,pCon,"main"); SCSendOK(pCon); return 1; } else { snprintf(pBueffel, 131, "%s.a3offset = %lf", argv[0], self->machine.a3offset); SCWrite(pCon, pBueffel, eValue); return 1; } } else if (strcmp(argv[1], "silent") == 0) { if (argc > 2) { strtolower(argv[2]); if (!SCMatchRights(pCon, usUser)) { return 0; } status = Tcl_GetInt(InterpGetTcl(pSics), argv[2], &newSS); if (status != TCL_OK) { SCWrite(pCon, "ERROR: failed to convert argument to number", eError); return 0; } self->silent = newSS; SCSendOK(pCon); return 1; } else { snprintf(pBueffel, 131, "%s.silent = %d", argv[0], self->silent); SCWrite(pCon, pBueffel, eValue); return 1; } } else if (strcmp(argv[1], "updater") == 0) { if (argc > 2) { if (!SCMatchRights(pCon, usMugger)) { return 0; } self->updater = strdup(argv[2]); SCSendOK(pCon); return 1; } else { snprintf(pBueffel, 131, "%s.updater = %s", argv[0], self->updater); SCWrite(pCon, pBueffel, eValue); return 1; } } else { snprintf(pBueffel, 131, "ERROR: subcommand %s to %s not defined", argv[1], argv[0]); SCWrite(pCon, pBueffel, eError); return 0; } return 1; }