- Updated Makefiles
- Moved TAS code to psi - Updated programmers documentation SKIPPED: psi/make_gen psi/nextrics.c psi/t_conv.c psi/t_conv.f psi/t_rlp.c psi/t_rlp.f psi/t_update.c psi/t_update.f psi/hardsup/el734_utility.c psi/hardsup/makefile_alpha
This commit is contained in:
131
Makefile
131
Makefile
@ -1,131 +0,0 @@
|
|||||||
#----------------------------------------------------------------------------
|
|
||||||
# Makefile for SICS
|
|
||||||
#
|
|
||||||
# Mark Koennecke 1996-2001
|
|
||||||
# Markus Zolliker March 2000: add tecs
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
#------- comment or uncomment this if a fortified version is required.
|
|
||||||
# Note: A -DFORTIFY needs to be added to the CFLAGS as well.
|
|
||||||
#
|
|
||||||
#FORTIFYOBJ = fortify.o strdup.o
|
|
||||||
#----
|
|
||||||
FORTIFYOBJ =
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#==========================================================================
|
|
||||||
# assign if the National Instrument GPIB driver is available
|
|
||||||
#NI= -DHAVENI
|
|
||||||
#NIOBJ= nigpib.o
|
|
||||||
#NILIB=-lgpibenet
|
|
||||||
NI=
|
|
||||||
NIOBJ=
|
|
||||||
NILIB=
|
|
||||||
|
|
||||||
#----- comment or uncomment if a difrac version is required
|
|
||||||
# Do not forget to remove or add comments to ofac.c as well if changes
|
|
||||||
# were made here.
|
|
||||||
|
|
||||||
DIFOBJ=
|
|
||||||
DIFIL=
|
|
||||||
#DIFOBJ=difrac.o -Ldifrac -ldif -lfor
|
|
||||||
#----
|
|
||||||
#DIFOBJ=difrac.o -Ldifrac -ldif
|
|
||||||
#DIFIL= difrac.o
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
COBJ = Sclient.o network.o ifile.o intcli.o $(FORTIFYOBJ)
|
|
||||||
SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
|
|
||||||
servlog.o sicvar.o nserver.o SICSmain.o \
|
|
||||||
sicsexit.o costa.o task.o $(FORTIFYOBJ)\
|
|
||||||
macro.o ofac.o obpar.o obdes.o drive.o status.o intserv.o \
|
|
||||||
devexec.o mumo.o mumoconf.o selector.o selvar.o fupa.o lld.o \
|
|
||||||
lld_blob.o buffer.o strrepl.o ruli.o lin2ang.o fomerge.o\
|
|
||||||
script.o o2t.o alias.o napi45.o nxdata.o stringdict.o sdynar.o\
|
|
||||||
histmem.o histdriv.o histsim.o sinqhmdriv.o interface.o callback.o \
|
|
||||||
event.o emon.o evcontroller.o evdriver.o simev.o perfmon.o \
|
|
||||||
danu.o itc4driv.o itc4.o nxdict.o nxsans.o varlog.o stptok.o nread.o \
|
|
||||||
dilludriv.o scan.o fitcenter.o telnet.o token.o scontroller.o serial.o \
|
|
||||||
tclev.o hkl.o integrate.o optimise.o dynstring.o nextrics.o nxutil.o \
|
|
||||||
mesure.o uubuffer.o serialwait.o commandlog.o sps.o udpquieck.o \
|
|
||||||
sanswave.o faverage.o bruker.o rmtrail.o fowrite.o ltc11.o \
|
|
||||||
simchop.o choco.o chadapter.o docho.o trim.o eurodriv.o scaldate.o \
|
|
||||||
hklscan.o xytable.o amor2t.o nxamor.o amorscan.o amorstat.o \
|
|
||||||
circular.o el755driv.o maximize.o sicscron.o tecsdriv.o sanscook.o \
|
|
||||||
tasinit.o tasutil.o t_rlp.o t_conv.o d_sign.o d_mod.o \
|
|
||||||
tasdrive.o tasscan.o synchronize.o definealias.o swmotor.o t_update.o \
|
|
||||||
hmcontrol.o userscan.o slsmagnet.o rs232controller.o lomax.o \
|
|
||||||
polterwrite.o fourlib.o motreg.o motreglist.o anticollider.o \
|
|
||||||
s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) ecb.o ecbdriv.o \
|
|
||||||
ecbcounter.o hmdata.o tdchm.o nxscript.o A1931.o frame.o
|
|
||||||
|
|
||||||
MOTOROBJ = motor.o el734driv.o simdriv.o el734dc.o pipiezo.o pimotor.o
|
|
||||||
COUNTEROBJ = countdriv.o simcter.o counter.o
|
|
||||||
DMCOBJ = dmc.o
|
|
||||||
VELOOBJ = velo.o velosim.o velodorn.o velodornier.o
|
|
||||||
|
|
||||||
.SUFFIXES:
|
|
||||||
.SUFFIXES: .tcl .htm .c .o
|
|
||||||
|
|
||||||
#----- comment or uncomment the following according to operating system
|
|
||||||
|
|
||||||
#------------- for Digital Unix
|
|
||||||
BINTARGET = bin
|
|
||||||
HDFROOT=/data/lnslib
|
|
||||||
CC=cc
|
|
||||||
EXTRA=
|
|
||||||
CFLAGS = -I$(HDFROOT)/include -Ihardsup -DHDF4 -DHDF5 -I. -std1 \
|
|
||||||
-check_bounds -g -warnprotos -c
|
|
||||||
#CFLAGS = -I$(HDFROOT)/include -DFORTIFY -DHDF4 -DHDF5 -Ihardsup -g \
|
|
||||||
# -std1 -warnprotos -c
|
|
||||||
LIBS = -L$(HDFROOT)/lib -Lhardsup -lhlib -Lmatrix -lmatrix -Ltecs \
|
|
||||||
-ltecsl -ltcl8.0 -lfor $(HDFROOT)/lib/libhdf5.a \
|
|
||||||
$(HDFROOT)/lib/libLNSmfhdf.a $(HDFROOT)/lib/libLNSdf.a \
|
|
||||||
$(HDFROOT)/lib/libLNSjpeg.a -lLNSz -lm -ll -lc
|
|
||||||
|
|
||||||
#------- for cygnus
|
|
||||||
#HDFROOT=../HDF411
|
|
||||||
#CC=gcc
|
|
||||||
#EXTRA=
|
|
||||||
#CFLAGS = -I$(HDFROOT)/include -Ihardsup -DFORTIFY -DCYGNUS -g -c
|
|
||||||
#LIBS= -L$(HDFROOT)/lib -Lhardsup -lhlib -ltcl80 \
|
|
||||||
# -lmfhdf -ldf -ljpeg -lz -lm
|
|
||||||
|
|
||||||
#---------- for linux
|
|
||||||
#BINTARGET=../../bin
|
|
||||||
#HDFROOT=$(SINQDIR)/linux
|
|
||||||
#CC=gcc
|
|
||||||
#CFLAGS = -I$(HDFROOT)/include -DHDF4 -DHDF5 $(NI) -Ihardsup \
|
|
||||||
# -fwritable-strings -DCYGNUS -DNONINTF -g -c
|
|
||||||
#CFLAGS = -I$(HDFROOT)/include -DFORTIFY -DHDF4 -DHDF5 $(NI) -Ihardsup \
|
|
||||||
# -fwritable-strings -DCYGNUS -DNONINTF -g -c
|
|
||||||
#LIBS= -L$(HDFROOT)/lib -Lhardsup -Ltecs -ltecsl -Lmatrix -lmatrix -lhlib \
|
|
||||||
# $(NILIB) -ltcl -lhdf5 -lmfhdf -ldf -ljpeg -lz -lm -lg2c -ldl
|
|
||||||
#EXTRA=nintf.o
|
|
||||||
#---------------------------------
|
|
||||||
|
|
||||||
.c.o:
|
|
||||||
$(CC) $(CFLAGS) $*.c
|
|
||||||
|
|
||||||
all: $(BINTARGET)/SICServer
|
|
||||||
|
|
||||||
$(BINTARGET)/SICServer: $(SOBJ) $(MOTOROBJ) \
|
|
||||||
$(COUNTEROBJ) $(DMCOBJ) $(VELOOBJ) $(DIFIL) \
|
|
||||||
$(EXTRA) tecs/libtecsl.a hardsup/libhlib.a \
|
|
||||||
matrix/libmatrix.a
|
|
||||||
$(CC) -g -o SICServer \
|
|
||||||
$(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) $(DMCOBJ) \
|
|
||||||
$(VELOOBJ) $(DIFOBJ) $(EXTRA) $(LIBS)
|
|
||||||
cp SICServer $(BINTARGET)
|
|
||||||
|
|
||||||
clean:
|
|
||||||
- rm -f *.o
|
|
||||||
- rm -f $(BINTARGET)/SICServer
|
|
||||||
|
|
||||||
Dbg.o: Dbg.c
|
|
||||||
cc -g -I/data/koenneck/include -c Dbg.c
|
|
||||||
Dbg_cmd.o: Dbg_cmd.c
|
|
||||||
|
|
||||||
|
|
637
doc/programmer/command.tex
Normal file
637
doc/programmer/command.tex
Normal file
@ -0,0 +1,637 @@
|
|||||||
|
\chapter{Writing new SICS Commands}
|
||||||
|
If you wish to write a new command or add a completely new piece of hardware to
|
||||||
|
SICS, this is the chapter to study. There are two ways to implement
|
||||||
|
new commands into SICS: hrough the internal Tcl scripting language and
|
||||||
|
in ANSI--C. This section describes command writing in ANSI--C. You
|
||||||
|
should consider using Tcl when:
|
||||||
|
\begin{itemize}
|
||||||
|
\item The new command is very instrument specific. Rather extend a
|
||||||
|
SICS command in order to support your script.
|
||||||
|
\item The new command is a local syntax fudge.
|
||||||
|
\item The hardware device is an auxiliary, such a He level meter
|
||||||
|
etc.
|
||||||
|
\end{itemize}
|
||||||
|
On the other hand there are indications when to write in ANSI--C:
|
||||||
|
\begin{itemize}
|
||||||
|
\item Complex calculations need to be carried out.
|
||||||
|
\item Large amounts of data need to be handled.
|
||||||
|
\item The code requires extensive bit twiddling.
|
||||||
|
\item A new general SICS facility is provided.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
|
||||||
|
\section{Mapping Object Oriented Concepts into ANSI--C}
|
||||||
|
SICS is in principle an object oriented system. However, it is implemented
|
||||||
|
in ANSI--C. Therefore object oriented concepts must be mapped into C. The
|
||||||
|
three object oriented concepts which need to be mapped are:
|
||||||
|
\begin{itemize}
|
||||||
|
\item Data Encapsulation.
|
||||||
|
\item Polymorphism.
|
||||||
|
\item Inheritance.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
Of these, data encapsulation is by far the most important concept. Objects
|
||||||
|
in computer science can be understood as little boxes which contain some
|
||||||
|
data describing their state and which understand messages sent by other
|
||||||
|
objects. If such a message comes in, the object performs some action,
|
||||||
|
perhaps changes its internal state or sends new messages to other objects.
|
||||||
|
It is understood that changes to the internal data of the object can be
|
||||||
|
achieved only through messages to the object and not by directly manipulating
|
||||||
|
variables from the outside. In ANSI--C an object maps to a structure holding
|
||||||
|
the objects data and the messages map to functions which act upon the data
|
||||||
|
structure. In order to do this, the functions must take a pointer to the
|
||||||
|
objects data structure as first parameter. In order to prevent messing with
|
||||||
|
an objects data structure, only a pointer to a structure is declared in the
|
||||||
|
header file. The actual definition of the data structure happens only in
|
||||||
|
the implementation file. All functions belonging to an object are defined in that
|
||||||
|
implementation file and have full access to the data structure.
|
||||||
|
Users of the object see only the header file and thus only a pointer to the
|
||||||
|
objects data structure which prevents
|
||||||
|
them from messing with the objects data directly.
|
||||||
|
In order to illustrate the concepts lets look at
|
||||||
|
a primitive integer object defined in such a way.
|
||||||
|
\begin{verbatim}
|
||||||
|
/*-----------------------------------------------------------------------
|
||||||
|
ExampleInt.h
|
||||||
|
------------------------------------------------------------------------*/
|
||||||
|
typedef struct __ExampleInt *pExampleInt;
|
||||||
|
|
||||||
|
int GetInt(pExampleInt self);
|
||||||
|
void SetInt(pExampleInt self, int iNew);
|
||||||
|
/*------------------- EOF ExampleInt.h---------------------------------*/
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------
|
||||||
|
ExampleInt.c, Implementation file
|
||||||
|
-----------------------------------------------------------------------*/
|
||||||
|
typedef struct __ExampleInt {
|
||||||
|
int iExample;
|
||||||
|
} ExampleInt;
|
||||||
|
/*--------------------------------------------------------------------*/
|
||||||
|
int GetInt(pExampleInt self)
|
||||||
|
{
|
||||||
|
return self->iExample;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------*/
|
||||||
|
void SetInt(pExampleInt self, int iNew)
|
||||||
|
{
|
||||||
|
self->iExample = iNew;
|
||||||
|
}
|
||||||
|
\end{verbatim}
|
||||||
|
Using this scheme all code changing the internal state of an object lives
|
||||||
|
in one file. Changes to the objects data structure affect only the
|
||||||
|
implementation file and no other files.
|
||||||
|
This scheme is used for almost all SICS objects. A few system objects and
|
||||||
|
older SICS objects define their data structures in header files. This is
|
||||||
|
either a relic or had to be done for performance reasons.
|
||||||
|
|
||||||
|
The next concept is polymorphism. This describes the situation when a group
|
||||||
|
of objects respond to the same message but doing different things. For
|
||||||
|
instance a whole set of objects would implement a write functionality
|
||||||
|
which writes the objects state to a file. Higher level would then not need
|
||||||
|
to know of which type the actual object is, it just can send the write message
|
||||||
|
and the rest is taken care of by the object. This concept is used for all
|
||||||
|
hardware drivers in SICS. Mapping this to C requires to expose the objects
|
||||||
|
data structure and let the data structure include a pointer to that polymorphic
|
||||||
|
function. As an example, the ExampleInteger with a write function:
|
||||||
|
\begin{verbatim}
|
||||||
|
/*-----------------------------------------------------------------------
|
||||||
|
ExampleInt.h
|
||||||
|
------------------------------------------------------------------------*/
|
||||||
|
typedef struct __ExampleInt{
|
||||||
|
int iExample;
|
||||||
|
void (*write)(struct __ExampleInt *self, FILE *fd);
|
||||||
|
} *pExampleInt, ExampleInt;
|
||||||
|
|
||||||
|
pExampleInt MakeInt(int iNew);
|
||||||
|
|
||||||
|
int GetInt(pExampleInt self);
|
||||||
|
void SetInt(pExampleInt self, int iNew);
|
||||||
|
/*------------------- EOF ExampleInt.h---------------------------------*/
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------
|
||||||
|
ExampleInt.c, Implementation file
|
||||||
|
-----------------------------------------------------------------------*/
|
||||||
|
static void ExampleWrite(struct _-ExampleInt *self, FILE *fd)
|
||||||
|
{
|
||||||
|
fprintf(fd,"INT = %d",self->iExample);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------*/
|
||||||
|
pExampleInt MakeInt(int iNew)
|
||||||
|
{
|
||||||
|
pExampleInt pNew = NULL;
|
||||||
|
|
||||||
|
pNew = (pExampleInt)malloc(sizeof(ExampleInt));
|
||||||
|
pNew->iExample = iNew;
|
||||||
|
pNew->write = ExampleWrite;
|
||||||
|
return pNew;
|
||||||
|
}
|
||||||
|
.
|
||||||
|
.
|
||||||
|
.
|
||||||
|
\end{verbatim}
|
||||||
|
This can then be called:
|
||||||
|
\begin{verbatim}
|
||||||
|
void SomeFunc()
|
||||||
|
{
|
||||||
|
pExampleInt pTest;
|
||||||
|
|
||||||
|
pTest = MakeInt(25);
|
||||||
|
.
|
||||||
|
.
|
||||||
|
.
|
||||||
|
pTest->write(pTest,fd);
|
||||||
|
}
|
||||||
|
\end{verbatim}
|
||||||
|
This example also illustrates the concept of a special function which creates
|
||||||
|
a new object of the appropriate type and initializes its data structure
|
||||||
|
properly.
|
||||||
|
|
||||||
|
The last concept to discuss is inheritance. Inheritance can be used when
|
||||||
|
an object is a derivative of another object. For instance a truck is a
|
||||||
|
derivative of a motor car. Much of the behavior of a motor car will be the
|
||||||
|
same as for a truck. In order to prevent rewriting of code, the truck
|
||||||
|
should use the same data structures and code as the motor car. And add
|
||||||
|
or modify only what is special. Inheritance is not much used in SICS. It can
|
||||||
|
be implemented by overlaying data structures. This means the derived
|
||||||
|
classes data structure has the same fields in the same order as the parent
|
||||||
|
class and adds its specials at the end. For example:
|
||||||
|
\begin{verbatim}
|
||||||
|
typedef struct __MotorCar {
|
||||||
|
int iWheels;
|
||||||
|
float fSpeed;
|
||||||
|
} *pMotorCar, MotorCar;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct __Truck {
|
||||||
|
int iWheels;
|
||||||
|
float fSpeed; /* same as MotorCar */
|
||||||
|
double dPayLoad; /* special for Truck */
|
||||||
|
} *pTruck, Truck;
|
||||||
|
|
||||||
|
\end{verbatim}
|
||||||
|
Thus functions defined for motor car can operate on trucks as well.
|
||||||
|
For more details study the relationship between the ITC4 controller and
|
||||||
|
general environment controllers. This is the only place where SICS
|
||||||
|
currently uses inheritance.
|
||||||
|
|
||||||
|
|
||||||
|
\section{Command Writing Basics}
|
||||||
|
\subsubsection{The Object Wrapper Function}
|
||||||
|
The first thing needed in order to implement a new command in SICS is
|
||||||
|
the object wrapper function. This function has the following
|
||||||
|
signature:
|
||||||
|
\begin{verbatim}
|
||||||
|
int ObjectWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||||
|
int argc, char *argv[]);
|
||||||
|
\end{verbatim}
|
||||||
|
The parameters are:
|
||||||
|
\begin{description}
|
||||||
|
\item[pCon] A pointer to the connection object representing the client
|
||||||
|
invoking this command.
|
||||||
|
\item[pSics] A pointer to the SICS interpreter.
|
||||||
|
\item[pData] A pointer to a user data structure for this object. Can
|
||||||
|
be NULL if no such thing exists.
|
||||||
|
\item[argc] Number of arguments in argv to this function.
|
||||||
|
\item[argv] Arguments to this function. The argc, argv scheme is
|
||||||
|
the same as for a C--language main function. The first argument is
|
||||||
|
always the name of the object.
|
||||||
|
\end{description}
|
||||||
|
This object wrapper function must evaluate its arguments, do what it
|
||||||
|
is meant to do and write any results to the client connection. In the
|
||||||
|
case of an error this function must return 0, in case of success 1.
|
||||||
|
|
||||||
|
|
||||||
|
\subsubsection{The Object Data Structure}
|
||||||
|
Only the most primitive objects or commands get away without an own
|
||||||
|
data structure. Usually a data structure will be needed by SICS
|
||||||
|
objects in order to keep configuration parameters etc. A pointer to
|
||||||
|
such a datastructure is passed into the object wrapper function as the
|
||||||
|
pointer pData. This object data structure has to fulfill some
|
||||||
|
conditions in order to live happily within SICS. And actually, not
|
||||||
|
only the datastructure is needed but also a function which is able to
|
||||||
|
release any memory allocated by the datastructure. SICS needs this
|
||||||
|
function in order to clean things up properly.
|
||||||
|
|
||||||
|
|
||||||
|
A valid SICS object structure has to look like this:
|
||||||
|
\begin{verbatim}
|
||||||
|
typedef struct __MyObject {
|
||||||
|
pObjectDescriptor pDes;
|
||||||
|
int iMyExtremlyImportantInt;
|
||||||
|
.
|
||||||
|
.
|
||||||
|
.
|
||||||
|
} MyObject;
|
||||||
|
\end{verbatim}
|
||||||
|
Please note that the first item in the data structure MUST be a
|
||||||
|
pointer to an SICS object descriptor. Add your own stuff below
|
||||||
|
that. If you do not adhere to this requirement, SICS will dump core on
|
||||||
|
you rather sooner then later.
|
||||||
|
|
||||||
|
|
||||||
|
SICS needs this object descriptor for its own internal purposes. The
|
||||||
|
object descriptor is again a data structure with this signature:
|
||||||
|
\begin{verbatim}
|
||||||
|
typedef struct {
|
||||||
|
char *name;
|
||||||
|
int (*SaveStatus)(void *self, char *name,FILE *fd);
|
||||||
|
void *(*GetInterface)(void *self, int iInterfaceID);
|
||||||
|
} ObjectDescriptor, *pObjectDescriptor;
|
||||||
|
|
||||||
|
\end{verbatim}
|
||||||
|
\begin{description}
|
||||||
|
\item[name] This is a type identifier for the object. SICS uses this
|
||||||
|
identifier for run time type identification (RTTI). For example this
|
||||||
|
field says Motor for motors, Counter for counters etc.
|
||||||
|
\item[SaveStatus] is the function called by the SICS status backup
|
||||||
|
mechanism. The default implementation of this function does
|
||||||
|
nothing. But if your new object has to store configuration commands
|
||||||
|
into the status file you should create an own function with the same
|
||||||
|
signature and assign this function to the object descriptors
|
||||||
|
SaveStatus. A suitable function will print the necessary commands to
|
||||||
|
achieve the same configuration as the current state into the file
|
||||||
|
represented by fd.
|
||||||
|
\item[GetInterface] SICS objects can have various capabilities: a
|
||||||
|
motor can be driven or scanned, you may count on a counter etc. Such
|
||||||
|
capabilities are expressed as interfaces(see \ref{interface}) in SICS.
|
||||||
|
There is an integer ID for each of those interfaces. GetInterface now
|
||||||
|
returns a suitable
|
||||||
|
interface in return for a given interface ID or NULL if the object
|
||||||
|
does not implement the interface. The default version of this function
|
||||||
|
retuns NULL always. If your object implements an interface, this
|
||||||
|
function has to be overloaded to return this interface on demand.
|
||||||
|
\end{description}
|
||||||
|
|
||||||
|
A default object descriptor can be created with:
|
||||||
|
\begin{verbatim}
|
||||||
|
pObjectDescriptor CreateDescriptor(type);
|
||||||
|
\end{verbatim}
|
||||||
|
with type being the object type identifier. A descriptor can be
|
||||||
|
deleted with:
|
||||||
|
\begin{verbatim}
|
||||||
|
DeleteDescriptor(pDes);
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
|
|
||||||
|
As already mentioned, a function to release any memory allocated for
|
||||||
|
the object data structure is also needed. Its signature is simple:
|
||||||
|
\begin{verbatim}
|
||||||
|
void KillObject(void *pdata);
|
||||||
|
\end{verbatim}
|
||||||
|
with pdata being the object to delete.
|
||||||
|
|
||||||
|
|
||||||
|
\subsection{Installing the new Command into the SICS Interpreter}
|
||||||
|
A new command can be installed into SICS with the function:
|
||||||
|
\begin{verbatim}
|
||||||
|
int AddCommand(SicsInterp *pSics,
|
||||||
|
char *name,
|
||||||
|
ObjectFunc ofunc,
|
||||||
|
KillFunc killo,
|
||||||
|
void *objectData);
|
||||||
|
\end{verbatim}
|
||||||
|
with pSics being the interpreter into which to install the command,
|
||||||
|
name the name of the command, ofunc its wrapper function, killo the
|
||||||
|
object data structure deletion function and objectData being a pointer
|
||||||
|
to the object data structure. If no data structure is defined for the
|
||||||
|
command, killo and objectData must be NULL.
|
||||||
|
|
||||||
|
|
||||||
|
Now the question arise where AddCommand has to be placed. Various
|
||||||
|
cases have to be distinguished: The first case is that the new command
|
||||||
|
is relevant to SICS users in all corners of the world. Then the new
|
||||||
|
command should be added to the function InitIniCommand in file
|
||||||
|
ofac.c.
|
||||||
|
|
||||||
|
The second case is that the command is specific to a certain
|
||||||
|
instrument or a special hardware or implements a local fashion of
|
||||||
|
dealing with things. Then the new command should be installed from the
|
||||||
|
function AddSiteCommand in the site data structure (see \ref{site}).
|
||||||
|
|
||||||
|
Another scheme becomes valid when multiple instances of the object
|
||||||
|
need to be created. \label{factory} For instance the object represents
|
||||||
|
a motor of which you may have many. Then it is useful to create a factory
|
||||||
|
command. This is a special SICS command which creates the desired
|
||||||
|
objects and installs them in the interpreter. This factory command
|
||||||
|
then has to be installed according to the logic given above. Usually
|
||||||
|
such objects are installed in the SICS initialization file. After
|
||||||
|
processing this initialization file the factory command is not useful
|
||||||
|
any longer. Then such factory commands should be removed from the
|
||||||
|
interpreter with:
|
||||||
|
\begin{verbatim}
|
||||||
|
RemoveCommand(SicsInterp *pSics, char *name);
|
||||||
|
\end{verbatim}
|
||||||
|
This has to be placed into the sites member function RemoveSiteCommand
|
||||||
|
or into KillIniCommand in ofac.c, depending where you installed the
|
||||||
|
command in the first place.
|
||||||
|
|
||||||
|
Be careful with commands for deleting objects though. SICS objects may
|
||||||
|
be aliased, used by other objects or connected through the callback
|
||||||
|
interface (see \ref{inter}). SICS does not implement proper
|
||||||
|
bookeeping on all these relationships and thus deleting a command from
|
||||||
|
SICS without taking this into account may cause SICS to dump core on
|
||||||
|
you.
|
||||||
|
|
||||||
|
|
||||||
|
\section{Interacting with the Client Connection}
|
||||||
|
A SICS command writer needs to interact with the client connection for
|
||||||
|
a variety of reasons:
|
||||||
|
\begin{itemize}
|
||||||
|
\item To write error messages and other output
|
||||||
|
\item To prompt for more data
|
||||||
|
\item To check if the user has appropriate privileges for the command
|
||||||
|
implemented.
|
||||||
|
\item To tell upper level code that something went very wrong.
|
||||||
|
\end{itemize}
|
||||||
|
As these tasks are so common you will find that the connection object
|
||||||
|
has to be passed frequently into lower level code as an argument.
|
||||||
|
|
||||||
|
\subsection{Writing and Reading to the Client}
|
||||||
|
All I/O to the client has to be processed through the I/O functions
|
||||||
|
for connections defined in conman.h and implemented in conman.c. The
|
||||||
|
most bable of these are SCWrite and SCPrompt.
|
||||||
|
These function will now be inspected in more detail:
|
||||||
|
\begin{verbatim}
|
||||||
|
int SCWrite(SConnection *pCon, char *pText, int eCode);
|
||||||
|
int SCPrompt(SConnection *pCon, char *pPrompt, char *pBuffer, int iBufLen);
|
||||||
|
\end{verbatim}
|
||||||
|
SCWrite writes the data pText to the connection specified by pCon. The
|
||||||
|
parameter eCode denotes the output code of the data in pText. SICS clients
|
||||||
|
can choose to suppress some I/O from the SICS server. For instance a
|
||||||
|
GUI--client might chooses not to receive scan status reports. For this
|
||||||
|
purpose it was necessary to stick an output code onto each message to the
|
||||||
|
client. Possible output codes are: eError, eWarning, eValue, eStatus and
|
||||||
|
some internal codes. The names are self explaining. eValue denotes a value
|
||||||
|
which has been explicitly asked for by the client. The rule specified above
|
||||||
|
becomes understandable and thus bearable when looking at all the things
|
||||||
|
SCWrite does with the message:
|
||||||
|
\begin{itemize}
|
||||||
|
\item It is written to the client connection socket, subject to the output
|
||||||
|
code specified.
|
||||||
|
\item The message is written to all log files configured for the client
|
||||||
|
connection.
|
||||||
|
\item If the client privilege is useer or manager, the data isw ritten
|
||||||
|
to the command log.
|
||||||
|
\item The message is written to the server log together with the socket
|
||||||
|
number of the connection.
|
||||||
|
\item SCWrite stores the message into the Tcl macro interpreter in order to
|
||||||
|
enable processing of data from SICS commands in Tcl scripts.
|
||||||
|
\item SCWrite suppresses all messages to the client while executing a macro.
|
||||||
|
This stops spurious output to appear at the client connection when running a
|
||||||
|
command defined in the macro language. The exception are messages of type
|
||||||
|
eError and eWarning. Such messages are always sent to the client.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
SCPrompt prompts the user at the client connection for data. The prompt
|
||||||
|
string pPrompt is sent. Data entered by the user is returned in buffer
|
||||||
|
pBuffer. Maximum iBufLen character are returned. While waiting for client to
|
||||||
|
provide data, the SICS task switcher runs.
|
||||||
|
|
||||||
|
There is another convenience function SCSendOK(SConnection *pCon) which is
|
||||||
|
just a wrapper around SCWrite. SCSendOk sends an 'OK' to the client. It is good
|
||||||
|
practice to let the user know that the operation requested had been
|
||||||
|
performed.
|
||||||
|
|
||||||
|
There are some more conventions which are useful to adhere to:
|
||||||
|
\begin{itemize}
|
||||||
|
\item All error messages start with the string ERROR:
|
||||||
|
\item All warnings start with the string WARNING:
|
||||||
|
\item All requested values are returned in the format name = value.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
There exist special functions to send mass data through a connection
|
||||||
|
in either uuencoded or zipped form. The latter works only through
|
||||||
|
plain socket connections, telnet will mess up binary data. Please
|
||||||
|
note, that numeric data sent by the SICS server needs to be in network
|
||||||
|
byte order in order to be understood by the Java clients. Further
|
||||||
|
functions allow to tailor writing behavious further by overloading the
|
||||||
|
operations performed by SCWrite. This is documented in conman.h
|
||||||
|
|
||||||
|
|
||||||
|
\subsection{Checking Client Privileges}
|
||||||
|
One task any SICS object has to perform is to check if a client,
|
||||||
|
represented through a connection object, is privileged to perform a
|
||||||
|
requested operation. The most useful function to do this is:
|
||||||
|
\begin{verbatim}
|
||||||
|
int SCMatchRights(SConnection *pCon, int rights);
|
||||||
|
\end{verbatim}
|
||||||
|
This function not only checks if the user has at least the user rights
|
||||||
|
given as parameter rights but also checks if the SICS server is
|
||||||
|
currently performing a scan or something. It is generally a bad idea
|
||||||
|
to change parameters while the instrument is taking a measurement. If
|
||||||
|
all is good 1 is returned, 0 in case of trouble. All troubles will
|
||||||
|
already have been reported to the client by this function. SICS knows
|
||||||
|
four levels of user rights:
|
||||||
|
\begin{description}
|
||||||
|
\item[usSpy] may look at things but change nothing.
|
||||||
|
\item[usUser] may do those things a normal user is supposed to do.
|
||||||
|
\item[usMugger] may perform configuration tasks.
|
||||||
|
\item[usInternal] absolutely no restrictions, used only internally.
|
||||||
|
\end{description}
|
||||||
|
|
||||||
|
|
||||||
|
There are further functions for requesting client and setting client
|
||||||
|
rights codes. These functions are all defined in conman.h.
|
||||||
|
|
||||||
|
\subsection{Interrupting}
|
||||||
|
On occasion a SICS object may come to the conclusion that an error is
|
||||||
|
so bad that the measurement needs to be stopped. Clearly a means is
|
||||||
|
needed to communicate this to upper level code. This means is setting
|
||||||
|
an interrupt on the connection.
|
||||||
|
The current interrupt active interrupt is located at the connection object
|
||||||
|
and can be retrieved with {\bf SCGetInterrupt} and set with {\bf
|
||||||
|
SCSetInterrupt}. Interrupt codes are defined in interrupt.h and are ordered
|
||||||
|
into a hierarchy:
|
||||||
|
\begin{description}
|
||||||
|
\item[eContinue] Everything is just fine.
|
||||||
|
\item[eAbortOperation] Stop the current scan point or whatever is done,
|
||||||
|
but do not stop altogether.
|
||||||
|
\item[eAbortScan] Abort the current scan, but continue processing of further
|
||||||
|
commands in R\"unbuffers or command files.
|
||||||
|
\item[eAbortBatch] Aborts everything, operations, scans and batch processing
|
||||||
|
and leaves the system ready to enter new commands.
|
||||||
|
\item[eHaltSystem] As eAbortBatch, but lock the system.
|
||||||
|
\item[eFreeSystem] Unlocks a system halted with eHaltSystem.
|
||||||
|
\item[eEndServer] Makes the SICS server run down and exit.
|
||||||
|
For internal usage only.
|
||||||
|
\end{description}
|
||||||
|
|
||||||
|
Higher level SICS objects may come to the conclusion that the error
|
||||||
|
reported by lower level code is actually not that critical and clear
|
||||||
|
any pending interrupts by setting the interrupt code to eContinue and
|
||||||
|
thus consume the interrupt.
|
||||||
|
|
||||||
|
\subsection{Communicating with all Clients}
|
||||||
|
Two facilities exist which allow one SICS command to reach out to all
|
||||||
|
connected clients.
|
||||||
|
\begin{itemize}
|
||||||
|
\item There is a function which writes a message to all clients. This
|
||||||
|
is ServerWriteGlobal(char *text, int outCode);
|
||||||
|
\item There exists a global status code which can be set with
|
||||||
|
SetStatus and retrieved with GetStatus. See status.h for more
|
||||||
|
details. Use this when your SICS command starts lengthy operations
|
||||||
|
such as driving or counting.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\section{Using other SICS Objects}
|
||||||
|
In most cases a new command needs to make use of other SICS
|
||||||
|
objects. Before another SICS object can be used, it must be found
|
||||||
|
within the SICS interpreter. In order do this the name of the object
|
||||||
|
is obviously needed. This must be a configuration parameter or passed
|
||||||
|
in as a argument to the command. In general it is also necessary to
|
||||||
|
check if this name points to the right type of object. All this can be
|
||||||
|
achieved with the function:
|
||||||
|
\begin{verbatim}
|
||||||
|
void *FindCommandData(SicsInterp *pSics, char *name, char *type);
|
||||||
|
\end{verbatim}
|
||||||
|
This function tries to find a command name in the interpreter and also
|
||||||
|
checks if the objects type descriptor (the name parameter in the
|
||||||
|
object descriptor structure) matches type. If this is so, a pointer to
|
||||||
|
the objects data structure is returned. If one of the test fails, NULL
|
||||||
|
is returned. Suitable parameters for type can be found by searching
|
||||||
|
for CreateDescriptor in the implementation file of the desired
|
||||||
|
object. After a cast to the proper pointer type, all the functions
|
||||||
|
defined for the object and documented in its header file can be used.
|
||||||
|
|
||||||
|
\subsection{Running Motors and Counters}
|
||||||
|
There are special rules which apply if a new command is written which
|
||||||
|
coordinates motors and counters. For instance a special scan or drive
|
||||||
|
command. It is important that such higher level code starts motors,
|
||||||
|
virtual motors and counters through the interfaces defined by the
|
||||||
|
device executor. The device executor guarantees proper monitoring of
|
||||||
|
the device. The relevant functions are:
|
||||||
|
\begin{verbatim}
|
||||||
|
int StartMotor(pExeList self, SicsInterp *pSics, SConnection *pCon,
|
||||||
|
char *name, float fNew);
|
||||||
|
int StartCounter(pExeList self, SicsInterp *pSics, SConnection
|
||||||
|
*pCon, char *name);
|
||||||
|
|
||||||
|
\end{verbatim}
|
||||||
|
StartMotor starts the motor name to run to the new value
|
||||||
|
fNew. StartCounter starts the counter name. The counter must have been
|
||||||
|
loaded with proper presets etc. with the appropriate function
|
||||||
|
calls. The device executor hides behind the pExeList pointer. This is
|
||||||
|
always accessible through the global pointer: pServ->pExecutor.
|
||||||
|
|
||||||
|
Once a counter or motor has been started, quite often the command can
|
||||||
|
only continue if the operation has finished. But during this time the
|
||||||
|
SICS server should be responsive to other clients. In order to do this
|
||||||
|
we have to wait for the device executor task to finish. A code
|
||||||
|
fragment implementing all this for a count operation is shown below:
|
||||||
|
\begin{verbatim}
|
||||||
|
/*-------------- count */
|
||||||
|
iRet = StartCounter(pServ->pExecutor, pSics,
|
||||||
|
pCon,
|
||||||
|
``ScanCounter'');
|
||||||
|
if(!iRet)
|
||||||
|
{
|
||||||
|
SCWrite(self->pCon,"ERROR: Cannot Count, Scan aborted",eError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* get the ID of the device executor task */
|
||||||
|
lTask = GetDevexecID(pServ->pExecutor); /* get ID of device
|
||||||
|
executor task */
|
||||||
|
if(lTask > 0);
|
||||||
|
{
|
||||||
|
/* wait for the device executor to finish */
|
||||||
|
TaskWait(pServ->pTasker,lTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* finished, check for interrupts. Whatever happened, user
|
||||||
|
interrupt or HW interrupt, it will be on our connection
|
||||||
|
*/
|
||||||
|
iInt = SCGetInterrupt(self->pCon);
|
||||||
|
switch(iInt)
|
||||||
|
{
|
||||||
|
case eContinue:
|
||||||
|
break;
|
||||||
|
case eAbortOperation:
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
case eAbortScan:
|
||||||
|
SCWrite(self->pCon,"ERROR: Scan aborted",eError);
|
||||||
|
/* eat the interrupt, the requested op has been
|
||||||
|
done
|
||||||
|
*/
|
||||||
|
SCSetInterrupt(self->pCon,eContinue);
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
default: /* all others */
|
||||||
|
SCWrite(self->pCon,"ERROR: Scan aborted",eError);
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
\end{verbatim}
|
||||||
|
This code also shows the necessary error checking. It also shows how
|
||||||
|
to check for possible interrupts after such an operation. It is very
|
||||||
|
advisable to do this because the user may have interrupted the
|
||||||
|
process. And she might not be all to happy if the new command just
|
||||||
|
continues with the next step rather then aborting the process.
|
||||||
|
|
||||||
|
|
||||||
|
\section{SICS Interfaces}\label{interface}
|
||||||
|
The point about SICS interfaces can best be deduced from an example:
|
||||||
|
Everybody expects that a motor can be operated through a drive command
|
||||||
|
or scanned in a scan. But there are other things which should be
|
||||||
|
operated through a drive or scan commands too: environment controllers
|
||||||
|
(temperature), virtual motors, chopper speeds, chopper phases and
|
||||||
|
possibly other things. In order to make upper level scan or drive
|
||||||
|
commands independent of the implementation of the actual operation it
|
||||||
|
is useful to have an abstract interface for everything which can be
|
||||||
|
driven or scanned. This is the drivable interface. Any such object
|
||||||
|
which should be driven or scanned has to implement this interface.
|
||||||
|
|
||||||
|
Several of these interfaces exist in SICS:
|
||||||
|
\begin{description}
|
||||||
|
\item[Drivable] The drivable interface for everything which can be
|
||||||
|
moved and takes some time to complete its movement.
|
||||||
|
\item[Countable] Everything which counts: counters, histogram memories
|
||||||
|
etc.
|
||||||
|
\item[Environment] An interface which allows for monitoring of a
|
||||||
|
parameter through the environment monitor. Usually these are sample
|
||||||
|
environment things but it could also be chopper phases etc.
|
||||||
|
\item[Callback] This is an interface which allows object A to call a
|
||||||
|
special function, the callback function, in the context of object B
|
||||||
|
whenever a certain event in A occurs. This is a way to automatically
|
||||||
|
link object together in a component programming manner. This is also
|
||||||
|
used for automatic notification of status clients when instrument
|
||||||
|
parameters change.
|
||||||
|
\end{description}
|
||||||
|
|
||||||
|
There are several situations when the SICS interfaces have to be
|
||||||
|
considered:
|
||||||
|
\begin{itemize}
|
||||||
|
\item When hacking SICS kernel code or replacing parts of it.
|
||||||
|
\item The driveable interface should be implemented by virtual
|
||||||
|
motors. Virtual motors are objects which realize complex movements
|
||||||
|
possibly involving multiple motors. Examples include driving
|
||||||
|
wavelength (theta,two theta and possbly curvature motors have to be
|
||||||
|
moved) or omega two theta.
|
||||||
|
\item Any time objects are introduced into SICS which repesent
|
||||||
|
completely new hardware.
|
||||||
|
\item When automatical notifications between objects are needed, use
|
||||||
|
the callback interface.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
Adding any such interface to your new SICS object involves the
|
||||||
|
following steps:
|
||||||
|
\begin{itemize}
|
||||||
|
\item Add a data structure representing the interface to your objects
|
||||||
|
data structure.
|
||||||
|
\item Write all the functions required by the interface.
|
||||||
|
\item Populate the interface data structure with the pointers to your
|
||||||
|
function implementations.
|
||||||
|
\item Write a new GetInterface function for the object descriptor
|
||||||
|
which returns your new interface when requested and assign it to your
|
||||||
|
object descriptors GetInterface field. SICS needs this in order to be
|
||||||
|
able to find the objects new interface.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
The interfaces available are documented in the files interface.w,
|
||||||
|
interface.h and interface.tex in the main SICS directory and through
|
||||||
|
numerous examples in the source code.
|
||||||
|
|
||||||
|
A not overly complex example for the implementation of an interface is
|
||||||
|
the code in o2t.* which implements the coupled driving of two motors
|
||||||
|
where the second is always the double of the value of the first. This
|
||||||
|
is for omega two-theta scans.
|
@ -3,7 +3,7 @@ In this chapter the facilities of the SICS servers kernel will be examined
|
|||||||
more closely. All the kernel modules and their function will be listed,
|
more closely. All the kernel modules and their function will be listed,
|
||||||
together with some explanatory information and an overview about the
|
together with some explanatory information and an overview about the
|
||||||
application programmers interfaces (API) provided. This section should
|
application programmers interfaces (API) provided. This section should
|
||||||
answer the questions: WHat is available?, Where to find what?,
|
answer the questions: What is available?, Where to find what?,
|
||||||
Why did they do that? Details of
|
Why did they do that? Details of
|
||||||
the API's mentioned are given in the reference section.
|
the API's mentioned are given in the reference section.
|
||||||
|
|
||||||
@ -124,7 +124,7 @@ The network reader currently supports four types of sockets:
|
|||||||
\item User sockets.
|
\item User sockets.
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
The accept type of socket is the main server port where clients try to
|
The accept type of socket is the main server port to which clients try to
|
||||||
connect to. The network reader accepts the connection and tries to read a
|
connect to. The network reader accepts the connection and tries to read a
|
||||||
username/password pair for a specified amount of time.
|
username/password pair for a specified amount of time.
|
||||||
If the username/password is valid, the connection will be accepted,
|
If the username/password is valid, the connection will be accepted,
|
||||||
@ -175,16 +175,18 @@ mechanism. For more details see John Ousterhout's book.
|
|||||||
In an earlier stage it was considered to use the Tcl interpreter as the SICS
|
In an earlier stage it was considered to use the Tcl interpreter as the SICS
|
||||||
interpreter. This idea was discarded for some reasons: One was the
|
interpreter. This idea was discarded for some reasons: One was the
|
||||||
difficulty of transporting the client execution context (i.e. the connection
|
difficulty of transporting the client execution context (i.e. the connection
|
||||||
object) through the Tcl interpreter. There is no standard Tcl mechanism for
|
object) through the Tcl interpreter. This reason has become invalid
|
||||||
doing that. The second was security: the Tcl
|
now, with the advent of Tcl 8.+ which supports namespaces. The second
|
||||||
interpreter is very powerful and can be abused. It was felt that the system
|
was security: the Tcl interpreter is very powerful and can be
|
||||||
had to be protected against such problems. The third reasons was that the
|
abused. It was felt that the system had to be protected against such
|
||||||
set of user commands should not be cluttered with Tcl commands in order to
|
problems. The third reasons was that the set of user commands should
|
||||||
prevent confusion. Programming macros is anyway something which is done by
|
not be cluttered with Tcl commands in order to prevent
|
||||||
SICS managers or programmers. However, the SICS interpreter is still modeled
|
confusion. Programming macros is anyway something which is done by
|
||||||
very much like the Tcl-interpreter. A Tcl interpreter is still included in
|
SICS managers or programmers. However, the SICS interpreter is still
|
||||||
order to provide a full featured macro language. The SICS interpreter and the
|
modeled very much like the Tcl-interpreter. A Tcl interpreter is
|
||||||
Tcl macro interpreter are still tightly coupled.
|
still included in order to provide a full featured macro
|
||||||
|
language. The SICS interpreter and the Tcl macro interpreter are
|
||||||
|
still tightly coupled.
|
||||||
|
|
||||||
The SICS interpreter must forward commands to the SICS objects. For this the
|
The SICS interpreter must forward commands to the SICS objects. For this the
|
||||||
interpreter needs some help from the objects themselves. Each SICS object
|
interpreter needs some help from the objects themselves. Each SICS object
|
||||||
@ -290,26 +292,6 @@ important SICS components: the interpreter, the task switcher, the device
|
|||||||
executor, the environment monitor and the network reader. This module also
|
executor, the environment monitor and the network reader. This module also
|
||||||
contains the code for initializing, running and stopping the server.
|
contains the code for initializing, running and stopping the server.
|
||||||
|
|
||||||
\section{The ServerLog}
|
|
||||||
As part of the SICS kernel there exists a global server log file. This file
|
|
||||||
contains:
|
|
||||||
\begin{itemize}
|
|
||||||
\item All traffic on all client connections. Even messages suppressed by the
|
|
||||||
clients.
|
|
||||||
\item All internal error messages.
|
|
||||||
\item Notifications about important internal status changes.
|
|
||||||
\end{itemize}
|
|
||||||
This server log is meant as an aid in debugging the server. As the SICS
|
|
||||||
server may run for days, weeks and months uninterrupted this log file may
|
|
||||||
become very large. However, only the last thousand or so messages are really
|
|
||||||
of interest when tracking a problem. Therefore a scheme is implemented to
|
|
||||||
limit the disk space used by the server log. The server log writes
|
|
||||||
cyclically into a number of files. A count of the lines is kept which were
|
|
||||||
written to each file. Above a predefined count, a new file is started.
|
|
||||||
As an interface the server log provides a function which allows to write
|
|
||||||
a message to it. This can be used by any object in the system for
|
|
||||||
interesting messages. The number of files to cycle through and the length of
|
|
||||||
each file can be configured by defines at the top of servlog.c.
|
|
||||||
|
|
||||||
\section{The Performance Monitor}
|
\section{The Performance Monitor}
|
||||||
This facility provides the data for the Performance (see user documentation)
|
This facility provides the data for the Performance (see user documentation)
|
||||||
@ -351,5 +333,57 @@ users. If this becomes a serious concern, this module has to be rewritten.
|
|||||||
\section{The Server Main Function}
|
\section{The Server Main Function}
|
||||||
This does not do much, just initialize the server, run it, and stop it.
|
This does not do much, just initialize the server, run it, and stop it.
|
||||||
|
|
||||||
|
\section{Logging}
|
||||||
|
The SICS server offers multiple options for logging:
|
||||||
|
\begin{itemize}
|
||||||
|
\item There is a cyclical server log logging all traffic. This is
|
||||||
|
described below.
|
||||||
|
\item Per client connection log files can be configured. This is part
|
||||||
|
of the connection object interface.
|
||||||
|
\item A special module, the commandlog exists, which saves all traffic
|
||||||
|
issued on client connections with user or manager privilege. This is
|
||||||
|
the most useful log for finding problems. This facility can be
|
||||||
|
configured to create a log file per day. Or the user can demand to
|
||||||
|
have her very own log file.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
|
||||||
|
\subsection{The ServerLog}
|
||||||
|
As part of the SICS kernel there exists a global server log file. This file
|
||||||
|
contains:
|
||||||
|
\begin{itemize}
|
||||||
|
\item All traffic on all client connections. Even messages suppressed by the
|
||||||
|
clients.
|
||||||
|
\item All internal error messages.
|
||||||
|
\item Notifications about important internal status changes.
|
||||||
|
\end{itemize}
|
||||||
|
This server log is meant as an aid in debugging the server. As the SICS
|
||||||
|
server may run for days, weeks and months uninterrupted this log file may
|
||||||
|
become very large. However, only the last thousand or so messages are really
|
||||||
|
of interest when tracking a problem. Therefore a scheme is implemented to
|
||||||
|
limit the disk space used by the server log. The server log writes
|
||||||
|
cyclically into a number of files. A count of the lines is kept which were
|
||||||
|
written to each file. Above a predefined count, a new file is started.
|
||||||
|
As an interface the server log provides a function which allows to write
|
||||||
|
a message to it. This can be used by any object in the system for
|
||||||
|
interesting messages. The number of files to cycle through and the length of
|
||||||
|
each file can be configured by defines at the top of servlog.c.
|
||||||
|
|
||||||
|
|
||||||
|
\section{Instrument Status Persistence}
|
||||||
|
Real programs do dump core (the SICS server is good, but is no
|
||||||
|
exception in this respect) and real computers fall over. In such cases
|
||||||
|
it would be useful if instrument configuration parameters such as
|
||||||
|
zero points , variable settings etc. are not lost. SICS achieves this
|
||||||
|
by writing a status file each time a parameter changes. This
|
||||||
|
status file is read back whenever the SICS server starts. The default
|
||||||
|
status file is configured in the instrument startup file as the SicsOption
|
||||||
|
statusfile. The user
|
||||||
|
can also request a status file to be written or recovered manually.
|
||||||
|
The status file is just a file with SICS commands which configure
|
||||||
|
relevant parameters. The actual writing of these commands is delegated
|
||||||
|
to each SICS object. Each SICS object which whishes to save data into
|
||||||
|
the status file has to implement a function which will
|
||||||
|
automatically be called when a status file is written. For details,
|
||||||
|
consult the chapter on SICS object implementation.
|
||||||
|
|
||||||
|
@ -428,7 +428,8 @@ Sometimes error conditions arise in lower level code which should cause all
|
|||||||
upper level code to finish execution. Such conditions may be the result of a
|
upper level code to finish execution. Such conditions may be the result of a
|
||||||
critical hardware fault or may even be requested by a user who wants to
|
critical hardware fault or may even be requested by a user who wants to
|
||||||
abort an operation. A standard method for communicating such conditions
|
abort an operation. A standard method for communicating such conditions
|
||||||
through the system is necessary. SICS uses interrupts for such conditions.
|
through the system is necessary.
|
||||||
|
SICS uses interrupts for such conditions.
|
||||||
The current interrupt active interrupt is located at the connection object
|
The current interrupt active interrupt is located at the connection object
|
||||||
and can be retrieved with {\bf SCGetInterrupt} and set with {\bf
|
and can be retrieved with {\bf SCGetInterrupt} and set with {\bf
|
||||||
SCSetInterrupt}. Interrupt codes are defined in interrupt.h and are ordered
|
SCSetInterrupt}. Interrupt codes are defined in interrupt.h and are ordered
|
||||||
|
@ -28,14 +28,20 @@ matches the above criteria.
|
|||||||
\section{The SINQ Hardware Setup}
|
\section{The SINQ Hardware Setup}
|
||||||
SICS had to take in account the SINQ hardware setup which had been decided
|
SICS had to take in account the SINQ hardware setup which had been decided
|
||||||
upon earlier on. Most hardware such as motors and counters is controlled via
|
upon earlier on. Most hardware such as motors and counters is controlled via
|
||||||
RS--232 interfaces. These devices connect to a Macintosh PC which has a
|
RS--232 interfaces. These RS--232 interfaces are connected to a
|
||||||
terminal server program running on it. This terminal server program collects
|
terminal server which allows to access such devices through the TCP/IP
|
||||||
request to the hardware from a TCP/IP port and forwards them to the serial
|
network.
|
||||||
device. The instrument control program runs on a workstation running
|
|
||||||
DigitalUnix. Communication with the hardware happens via TCP/IP through the
|
For historical reasons the instrument control software does not access
|
||||||
terminal server. Some hardware devices, such as the histogram memory, can handle
|
the terminal server directly but through another software layer, the
|
||||||
|
SerPortServer program. The SerPortServer program is another TCP/IP
|
||||||
|
server which allows multiple network clients to access the same
|
||||||
|
terminal server port through a home grown protocoll. In the long run
|
||||||
|
this additional software layer will be abolished.
|
||||||
|
|
||||||
|
Some hardware devices, such as the histogram memory, can handle
|
||||||
TCP/IP themselves. With such devices the instrument control program
|
TCP/IP themselves. With such devices the instrument control program
|
||||||
communicates directly through TCP/IP, without a terminal server. All
|
communicates directly through TCP/IP. All
|
||||||
hardware devices take care of their real time needs themselves. Thus the
|
hardware devices take care of their real time needs themselves. Thus the
|
||||||
only task of the instrument control program is to orchestrate the hardware
|
only task of the instrument control program is to orchestrate the hardware
|
||||||
devices. SICS is designed with this setup up in mind, but is not restricted
|
devices. SICS is designed with this setup up in mind, but is not restricted
|
||||||
@ -90,15 +96,18 @@ client for a powder diffractometer is given in picture \ref{dmc}
|
|||||||
The SICS server is the core component of the SICS system. The SICS server is
|
The SICS server is the core component of the SICS system. The SICS server is
|
||||||
responsible for doing all the work in instrument control. Additionally the
|
responsible for doing all the work in instrument control. Additionally the
|
||||||
server has to answer the requests of possibly multiple clients.
|
server has to answer the requests of possibly multiple clients.
|
||||||
The SICS server can be subdivided into three subsystems: The kernel, a database
|
The SICS server can be subdivided into three subsystems:
|
||||||
of SICS objects and an interpreter. The SICS server kernel takes care of
|
\begin{description}
|
||||||
client multitasking and the preservation of the proper I/O and error context
|
\item[The kernel] The SICS server kernel
|
||||||
for each client command executing.
|
takes care of client multitasking and the preservation of the proper
|
||||||
SICS objects are software modules which represent all aspects
|
I/O and error context for each client command executing.
|
||||||
of an instrument: hardware devices, commands, measurement strategies
|
\item[SICS Object Database] SICS objects are software modules which
|
||||||
|
represent all aspects of an instrument: hardware devices, commands, measurement strategies
|
||||||
and data storage. This database of objects is initialized at server startup
|
and data storage. This database of objects is initialized at server startup
|
||||||
time from an initialization script. The third SICS server component is an
|
time from an initialization script.
|
||||||
interpreter which allows to issue commands to the objects in the objects database.
|
\item[The Interpreter] The interpreter allows to issue commands to the
|
||||||
|
objects in the objects database.
|
||||||
|
\end{description}
|
||||||
The schematic drawing of the SICS server's structure is given in picture
|
The schematic drawing of the SICS server's structure is given in picture
|
||||||
\ref{newsics}.
|
\ref{newsics}.
|
||||||
\begin{figure}
|
\begin{figure}
|
||||||
@ -130,10 +139,12 @@ executing one after another. The servers main loop does nothing but
|
|||||||
executing the tasks in this circular buffer in an endless loop.
|
executing the tasks in this circular buffer in an endless loop.
|
||||||
There are several system tasks and one such
|
There are several system tasks and one such
|
||||||
task for each living client connection. Thus only one task executes at any
|
task for each living client connection. Thus only one task executes at any
|
||||||
given time and data access is efficiently serialized. One of the main system
|
given time and data access is efficiently serialized.
|
||||||
|
|
||||||
|
One of the main system
|
||||||
tasks (and the one which will be always there) is the network reader. The
|
tasks (and the one which will be always there) is the network reader. The
|
||||||
network reader has a list of open network connections and checks each of
|
network reader has a list of open network connections and checks each of
|
||||||
them for pending requests. What happens when a data is pending on an open
|
them for pending requests. What happens when data is pending on an open
|
||||||
network port depends on the type of port: If it is the servers main
|
network port depends on the type of port: If it is the servers main
|
||||||
connection port, the network reader will try to accept and verify a new
|
connection port, the network reader will try to accept and verify a new
|
||||||
client connection and create the associated data structures. If the port
|
client connection and create the associated data structures. If the port
|
||||||
@ -190,9 +201,9 @@ Most experiments do not happen at ambient room conditions but
|
|||||||
require some special environment for the sample. Mostly this is temperature
|
require some special environment for the sample. Mostly this is temperature
|
||||||
but it can also be magnetic of electric fields etc. Most of such devices
|
but it can also be magnetic of electric fields etc. Most of such devices
|
||||||
can regulate themselves but the data acquisition program needs to monitor
|
can regulate themselves but the data acquisition program needs to monitor
|
||||||
such devices. Within SICS this is done via a special system object, the
|
such devices. Within SICS, this is done via a special system object, the
|
||||||
environment monitor. A environment device, for example a temperature
|
environment monitor. A environment device, for example a temperature
|
||||||
controller, registers it's presence with this object. Then an special system
|
controller, registers it's presence with this object. Then a special system
|
||||||
task will control this device when it is executing, check for possible out
|
task will control this device when it is executing, check for possible out
|
||||||
of range errors and initiates the proper error handling if such a problem is
|
of range errors and initiates the proper error handling if such a problem is
|
||||||
encountered.
|
encountered.
|
||||||
@ -241,15 +252,15 @@ to a system of protocols. There are protocols for:
|
|||||||
\item For checking the authorisation of the client who wants to execute the
|
\item For checking the authorisation of the client who wants to execute the
|
||||||
command.
|
command.
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
SICS uses NeXus$^{2}$, the upcoming standard for data exchange for neutron
|
|
||||||
and x\_ray scattering as its raw data format.
|
|
||||||
|
|
||||||
SICS objects have the ability to notify clients and other objects of
|
SICS objects have the ability to notify clients and other objects of
|
||||||
internal state changes. For example when a motor is driven, the motor object
|
internal state changes. For example when a motor is driven, the motor object
|
||||||
can be configured to tell SICS clients or other SICS objects about his new
|
can be configured to tell SICS clients or other SICS objects about his new
|
||||||
position.
|
position.
|
||||||
|
|
||||||
|
SICS uses NeXus$^{2}$, the upcoming standard for data exchange for neutron
|
||||||
|
and x\_ray scattering as its raw data format.
|
||||||
|
|
||||||
|
|
||||||
\section{SICS Working Examples}
|
\section{SICS Working Examples}
|
||||||
In order to get a better feeling for the internal working of SICS the course
|
In order to get a better feeling for the internal working of SICS the course
|
||||||
of a few different requests through the SICS system is traced in this
|
of a few different requests through the SICS system is traced in this
|
||||||
@ -284,7 +295,7 @@ pending commands.
|
|||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item The network reader finds data pending at one of the client ports.
|
\item The network reader finds data pending at one of the client ports.
|
||||||
\item The network reader reads the command, splits it into single lines and
|
\item The network reader reads the command, splits it into single lines and
|
||||||
put those on the top of the client connections command stack. The network
|
put those on top of the client connections command stack. The network
|
||||||
reader passes control to the task switcher.
|
reader passes control to the task switcher.
|
||||||
\item In due time the client connection task executes, inspects its command
|
\item In due time the client connection task executes, inspects its command
|
||||||
stack, pops the command pending and forwards it together with a pointer to
|
stack, pops the command pending and forwards it together with a pointer to
|
||||||
@ -415,23 +426,18 @@ new commands.
|
|||||||
driving whenever the task switcher allows it to execute.
|
driving whenever the task switcher allows it to execute.
|
||||||
\item In due time the device executor task will find that the motor finished
|
\item In due time the device executor task will find that the motor finished
|
||||||
driving. The task will then die silently. The clients grab of the hardware driving
|
driving. The task will then die silently. The clients grab of the hardware driving
|
||||||
permission will be released. If errors occurred, however a they will be reported.
|
permission will be released. Any errors however, will be reported.
|
||||||
\item At this stage the drive command wrapper function will awake and
|
|
||||||
continue execution. This means inspecting errors and reporting to the client
|
|
||||||
how things worked out.
|
|
||||||
\item This done, control passes back through the interpreter and the connection
|
|
||||||
task to the task switcher. The client connection is free to execute
|
|
||||||
other commands.
|
|
||||||
\item The next task executes.
|
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
All this seems to be pretty complex and time consuming. But it is the complexity needed to
|
All this seems to be pretty complex and time consuming. But it is the complexity needed to
|
||||||
do so many things, especially the non blocking mode of operation requested
|
do so many things, especially the non blocking mode of operation requested
|
||||||
by users. Tests have shown that the task switcher manages +900 cycles per second
|
by users. Tests have shown that the task switcher manages +900 cycles
|
||||||
through
|
per second through the task list on a DigitalUnix machine and 50
|
||||||
the task list on a DigitalUnix machine and 50 cycles per second on a pentium 133mhz
|
cycles per second on a pentium 133mhz machine running linux. Both data
|
||||||
machine running linux. Both data were obtained with software simulation of
|
were obtained with software simulation of hardware devices. With real
|
||||||
hardware devices. With real SINQ hardware these numbers drop 4 cycles per
|
SINQ hardware these numbers drop 4 cycles per second. This shows
|
||||||
second. This shows clearly that the communication with the hardware is the
|
clearly that the communication with the hardware is the systems
|
||||||
systems bottleneck and not the task switching scheme.
|
bottleneck and not the task switching scheme.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
% Copyleft (c) 1997-2000 by Mark Koennecke at PSI, Switzerland.
|
% Copyleft (c) 1997-2000 by Mark Koennecke at PSI, Switzerland.
|
||||||
%
|
%
|
||||||
|
% major upgrade: Mark Koennecke, July 2003
|
||||||
%
|
%
|
||||||
%
|
%
|
||||||
|
|
||||||
@ -31,7 +32,18 @@
|
|||||||
\include{overview}
|
\include{overview}
|
||||||
\include{proto}
|
\include{proto}
|
||||||
\include{kernelguide}
|
\include{kernelguide}
|
||||||
\include{oguide}
|
\include{command}
|
||||||
|
%%\include{oguide}
|
||||||
|
\include{sicsdriver}
|
||||||
|
\include{site}
|
||||||
\end{document}
|
\end{document}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,36 +1,33 @@
|
|||||||
\chapter{The SICS Server Client Protocol}
|
\chapter{The SICS Server Client Protocol}
|
||||||
This short chapter describes the command protocol between the SICS server
|
The SICS server actually listens for connections on two sockets, each
|
||||||
and possible SICS clients. All this is very simple.
|
implementing a different protocoll. The first type of connection
|
||||||
|
implements the telnet protocoll. The second type uses a plain socket
|
||||||
\section{Logging in to the SICS Server}
|
and has the advantage that binary data can be transferred.
|
||||||
In order to log in to the SICS server it needs to be known on which
|
|
||||||
machine the server runs and at which port number the server listens for
|
|
||||||
connection requests. Also needed is a valid username/ password pair for the
|
|
||||||
SICS server in question. Given that the procedure for connecting to a SICS
|
|
||||||
server requires the following steps:
|
|
||||||
\begin{enumerate}
|
|
||||||
\item Open a TCP/IP connection to the SICS server port at the machine
|
|
||||||
where it is running.
|
|
||||||
\item Immediately after opening the connection send the username/password
|
|
||||||
pair. If everything is OK, a string OK is sent. Else the server will break
|
|
||||||
the connection again.
|
|
||||||
\end{enumerate}
|
|
||||||
|
|
||||||
\section{Sending Commands}
|
|
||||||
After login, two means of communications exist. The communication
|
|
||||||
protocoll is choosen through the server port the client connects too.
|
|
||||||
The recommended way is
|
|
||||||
to adhere to the telnet protocoll as described in RFC-854. Just a
|
|
||||||
basic NVT (Network Virtual Terminal) with no options is
|
|
||||||
implemented. Binary communication is not possible on a telnet port.
|
|
||||||
|
|
||||||
The older way of communication is to send commands directly on the
|
|
||||||
TCP/IP port. Commands are strings terminated by a \verb+\n+. Return
|
|
||||||
messages from the server have the same format. This scheme is
|
|
||||||
obsolete but it has been left in because the need for a binary
|
|
||||||
communication may arise and this would help implement such a thing.
|
|
||||||
|
|
||||||
|
\section{Connecting using Telnet}
|
||||||
|
The SICS server implements the most primitive telnet server possible
|
||||||
|
and does not support any of the fancy options possible with
|
||||||
|
telnet. Using the telnet protocoll involves:
|
||||||
|
\begin{itemize}
|
||||||
|
\item Open a scoket conenction to SICS telnet port
|
||||||
|
\item Send a login word followed by a username and a password. The
|
||||||
|
login word is set in SICS initialization file as the SicsOption
|
||||||
|
TelWord.
|
||||||
|
\item On success a welcome message is printed, otherwise SICS
|
||||||
|
terminates the connection.
|
||||||
|
\item Now commands can be sent, but watch for the telnet protocoll
|
||||||
|
specification in RFC-?????.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\section{Connection using a plain Connection}
|
||||||
|
This protocoll involves:
|
||||||
|
\begin{itemize}
|
||||||
|
\item Open a scoket conenction to SICS telnet port
|
||||||
|
\item Send a username and a password.
|
||||||
|
\item On success OK is printed, otherwise SICS
|
||||||
|
terminates the connection.
|
||||||
|
\item Now commands can be sent as strings terminated with a newline.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
For a list of possible commands consult the
|
For a list of possible commands consult the
|
||||||
user documentation.
|
user documentation.
|
||||||
@ -59,3 +56,6 @@ ASCII string of the form: {\bf SICSINT num} must be sent. num must be
|
|||||||
replaced by the number of the interrupt to issue. Again interrupt codes are
|
replaced by the number of the interrupt to issue. Again interrupt codes are
|
||||||
resolved in file interrupt.h.
|
resolved in file interrupt.h.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
620
doc/programmer/sicsdriver.tex
Normal file
620
doc/programmer/sicsdriver.tex
Normal file
@ -0,0 +1,620 @@
|
|||||||
|
\chapter{Writing SICS Device Drivers}
|
||||||
|
This chapter deals with writing new hardware drivers for SICS. SICS
|
||||||
|
hardware has a dual identity: Towards upper level code SICS hardware
|
||||||
|
is represented by the logical hardware object. All the low level
|
||||||
|
detail is handled in the hardware driver. The point of this is that
|
||||||
|
upper level code does not need to know which type of hardware device
|
||||||
|
is being accessed. Experience shows that this scheme covers most usage
|
||||||
|
cases for a given hardware device. However, there were always
|
||||||
|
exceptions mostly in order to realize special configurations. Such
|
||||||
|
exceptions can be dealt with through special macros which implement
|
||||||
|
commands which do
|
||||||
|
special configuration tasks. In order to be able to write such scripts
|
||||||
|
it is feasible to organize hardware access into three layers:
|
||||||
|
\begin{itemize}
|
||||||
|
\item A communication layer. This layer allows for sending commands
|
||||||
|
and reading data along a given bus.
|
||||||
|
\item A controller layer. If a device or several share a controller
|
||||||
|
make the controller visible within the system. Allow for sending
|
||||||
|
suitable commands to it.
|
||||||
|
\item The actual SICS driver.
|
||||||
|
\end{itemize}
|
||||||
|
This organisation allows scripts to directly talk to devices through
|
||||||
|
either the controller or the communication layer. If something is
|
||||||
|
missing in the general driver interface it is usually easier to add
|
||||||
|
some code at controller or communications level, rather then change
|
||||||
|
all drivers present in the system.
|
||||||
|
|
||||||
|
All drivers use a common pattern for error handling. Please read the
|
||||||
|
section on the motor driver where this pattern is explained in more
|
||||||
|
detail. The same pattern is applied in most drivers.
|
||||||
|
|
||||||
|
This section describes the actual drivers. How these drivers are
|
||||||
|
integrated into SICS is described in the chapter on the site data
|
||||||
|
structure (see \ref{site}).
|
||||||
|
|
||||||
|
|
||||||
|
\section{The Motor Driver}
|
||||||
|
A motor driver again is represented by an interface encapsulated in a
|
||||||
|
data structure. Polymorphy is achieved in two ways:
|
||||||
|
\begin{itemize}
|
||||||
|
\item Through the functions you have to define for your motor and to
|
||||||
|
assign to the function pointers in the motor driver data structure.
|
||||||
|
\item For the data structure, polymorphy is achieved through
|
||||||
|
overlay. This means, if you define your own motor driver data
|
||||||
|
structure the first fields up to KillPrivate MUST be the same as
|
||||||
|
defined in the MotorDriver structure defined below. You MUST append
|
||||||
|
your own fields below KillPrivate.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
This is the motor driver data structure which has to be implemented:
|
||||||
|
\begin{verbatim}
|
||||||
|
typedef struct __AbstractMoDriv {
|
||||||
|
/* general motor driver interface
|
||||||
|
fields. REQUIRED!
|
||||||
|
*/
|
||||||
|
float fUpper; /* upper limit */
|
||||||
|
float fLower; /* lower limit */
|
||||||
|
char *name;
|
||||||
|
int (*GetPosition)(void *self, float *fPos);
|
||||||
|
int (*RunTo)(void *self,float fNewVal);
|
||||||
|
int (*GetStatus)(void *self);
|
||||||
|
void (*GetError)(void *self, int *iCode, char *buffer, int iBufLen);
|
||||||
|
int (*TryAndFixIt)(void *self, int iError,float fNew);
|
||||||
|
int (*Halt)(void *self);
|
||||||
|
int (*GetDriverPar)(void *self, char *name,
|
||||||
|
float *value);
|
||||||
|
int (*SetDriverPar)(void *self,SConnection *pCon,
|
||||||
|
char *name, float newValue);
|
||||||
|
void (*ListDriverPar)(void *self, char *motorName,
|
||||||
|
SConnection *pCon);
|
||||||
|
void (*KillPrivate)(void *self);
|
||||||
|
} MotorDriver;
|
||||||
|
\end{verbatim}
|
||||||
|
In order not to have to repeat trivial things all the time two general
|
||||||
|
things must be stated:
|
||||||
|
\begin{itemize}
|
||||||
|
\item The pointer self is always a pointer to the motor driver data
|
||||||
|
structure.
|
||||||
|
\item Functions return 1 on success or 0 on failure if not stated otherwise.
|
||||||
|
\end{itemize}
|
||||||
|
The elements of this data structure are:
|
||||||
|
\begin{description}
|
||||||
|
\item[fUpper,fLower] These are the motors hardware limits. These
|
||||||
|
values are supposed to be identical to the positions of the limit
|
||||||
|
switches on the real thing. Read them from the motor or initialize
|
||||||
|
them from parameters when initializing the motor driver.
|
||||||
|
\item[GetPosition] reads the position of the motor and puts the result
|
||||||
|
into fPos. This ought to be the position from the motor
|
||||||
|
controller. Software zeros are applied later by code in motor.c.
|
||||||
|
\item[RunTo] Starts the motor to run towards the new position
|
||||||
|
fNewVal. fNewVal must be a value valid for the controller. Software
|
||||||
|
zero points have already been taken account of by code in
|
||||||
|
motor.c. This function shall NOT wait for the completion of the
|
||||||
|
driving operation.
|
||||||
|
\item[GetStatus] This function is called repeatedly by upper level
|
||||||
|
code to poll for the progress of the driving operation. Possible
|
||||||
|
return values of this function are:
|
||||||
|
\begin{description}
|
||||||
|
\item[HWFault] If there is a fault in the hardware or the status
|
||||||
|
cannot be read.
|
||||||
|
\item[HWPosFault] The motor is still alive but the controller was
|
||||||
|
unable to position the motor.
|
||||||
|
\item[HWBusy] The motor is still driving.
|
||||||
|
\item[HWWarn] There is a warning from the controller.
|
||||||
|
\item[HWIdle] The motor has finished driving and is idle.
|
||||||
|
\end{description}
|
||||||
|
\item[GetError] retrieves information about an error which occurred on
|
||||||
|
the motor. An integer error code is returned in iCode. Up to iBufLen
|
||||||
|
characters of descriptive error information is copied into
|
||||||
|
buffer. This information is printed as error message by upper level
|
||||||
|
code.
|
||||||
|
\item[TryAndFixIt] Given an error code in iError, try to repair the
|
||||||
|
problem as far as this is possible in software. iError should be an
|
||||||
|
error code as returned by GetError in iCode. This function has the
|
||||||
|
following return codes:
|
||||||
|
\begin{description}
|
||||||
|
\item[MOTREDO] Problem fixed, try to redo the last the operation.
|
||||||
|
\item[MOTFAIL] The problem cannot be fixed in software.
|
||||||
|
\end{description}
|
||||||
|
The parameter fNew is the target position of the motor.
|
||||||
|
\item[Halt] stops the motor immediately.
|
||||||
|
\item[GetDriverPar] copies the value of the motor driver parameter
|
||||||
|
name into value, if such a parameter exists.
|
||||||
|
\item[SetDriverPar] sets the motor driver parameter name to
|
||||||
|
newValue. Report errors to pCon.
|
||||||
|
\item[ListDriverPar] write the names and values of all driver
|
||||||
|
parameters to the client connection pCon.
|
||||||
|
\item[KillPrivate] releases any memory possibly allocated for private
|
||||||
|
fields in the motor data structure.
|
||||||
|
\end{description}
|
||||||
|
|
||||||
|
In order to understand the relationship between GetError and
|
||||||
|
TryAndFixIt it helps to look at the way how errors are handled by
|
||||||
|
upper level code in motor.c: If an error in any function occurs,
|
||||||
|
GetError gets called. An error message is printed. Then TryAndFixIt is
|
||||||
|
called with the error code returned in iCode as a parameter. If
|
||||||
|
TryAndFixIt returns MOTFAIL, the code gives up. If TryAndFixIt
|
||||||
|
returns MOTREDO, the failed operation is retried. At max retries are
|
||||||
|
performed. If the operation does not succeed after three
|
||||||
|
retries, a motor failure is reported.
|
||||||
|
|
||||||
|
The GetDriverPar, SetDriverPar and ListDriverPar functions implement
|
||||||
|
some support for driver private configuration parameters. Such
|
||||||
|
parameters are meant to be configured from the instrument
|
||||||
|
initialization file. Currently there is no support to include these
|
||||||
|
parameters into the status file. If there are
|
||||||
|
no such parameters have these functions do nothing and return 1.
|
||||||
|
|
||||||
|
\section{The Counter Driver}
|
||||||
|
A counter driver is a driver for some box which allows to count for a
|
||||||
|
preset time or monitor and manages single counters and monitors. Such
|
||||||
|
a driver is reprsented by a data structure:
|
||||||
|
\begin{verbatim}
|
||||||
|
typedef struct __COUNTER {
|
||||||
|
/* variables */
|
||||||
|
char *name;
|
||||||
|
char *type;
|
||||||
|
CounterMode eMode;
|
||||||
|
float fPreset;
|
||||||
|
float fLastCurrent;
|
||||||
|
float fTime;
|
||||||
|
int iNoOfMonitors;
|
||||||
|
long lCounts[MAXCOUNT];
|
||||||
|
int iPause;
|
||||||
|
int iErrorCode;
|
||||||
|
/* functions */
|
||||||
|
int (*GetStatus)(struct __COUNTER *self, float *fControl);
|
||||||
|
int (*Start)(struct __COUNTER *self);
|
||||||
|
int (*Pause)(struct __COUNTER *self);
|
||||||
|
int (*Continue)(struct __COUNTER *self);
|
||||||
|
int (*Halt)(struct __COUNTER *self);
|
||||||
|
int (*ReadValues)(struct __COUNTER *self);
|
||||||
|
int (*GetError)(struct __COUNTER *self, int *iCode,
|
||||||
|
char *error, int iErrLen);
|
||||||
|
int (*TryAndFixIt)(struct __COUNTER *self, int iCode);
|
||||||
|
int (*Set)(struct __COUNTER *self,char *name,
|
||||||
|
int iCter, float fVal);
|
||||||
|
int (*Get)(struct __COUNTER *self,char *name,
|
||||||
|
int iCter, float *fVal);
|
||||||
|
int (*Send)(struct __COUNTER *self, char *pText,
|
||||||
|
char *pReply, int iReplyLen);
|
||||||
|
void (*KillPrivate)(struct __COUNTER *self);
|
||||||
|
void *pData; /* counter specific data goes here, ONLY for
|
||||||
|
internal driver use!
|
||||||
|
*/
|
||||||
|
} CounterDriver, *pCounterDriver;
|
||||||
|
\end{verbatim}
|
||||||
|
Polymorphy is achieved through the function pointers. Differences in
|
||||||
|
the data structure for different counter boxes are accounted for
|
||||||
|
through the pData pointer. This is meant to be initialized by the
|
||||||
|
actual counter driver to a private data structure which holds data
|
||||||
|
relevant to this particular counter. All functions take a pointer to
|
||||||
|
this counter driver structure as parameter self. If not stated
|
||||||
|
otherwise functions return 1 on success and 0 on failure. The fields:
|
||||||
|
\begin{description}
|
||||||
|
\item[name] The counter name in SICS
|
||||||
|
\item[type] The driver type.
|
||||||
|
\item[eMode] The counter mode. Possible values eTimer for preset timer
|
||||||
|
and eMonitor for preset monitor operation. This mode will be set by
|
||||||
|
upper level code.
|
||||||
|
\item[fPreset] The preset for either timer or monitor.
|
||||||
|
\item[fLastCurrent] the last known value for the control variable
|
||||||
|
during counting. Gets updated in GetStatus while counting and is used
|
||||||
|
for reporting count status.
|
||||||
|
\item[fTime] The time the last counting operation took. This is a time
|
||||||
|
read from the counter box. This could be different from elapsed time
|
||||||
|
because the count may have paused for instance because the beam was
|
||||||
|
low.
|
||||||
|
\item[iNoOfMonitors] is the number of monitors and counters this
|
||||||
|
counter box supports.
|
||||||
|
\item[lCounts] An array for storing the values of counters and
|
||||||
|
monitors after counting. The PSI EL7373 counter box allows to read
|
||||||
|
values only once after counting finished. This is why the values had to be
|
||||||
|
cached in lCounts.
|
||||||
|
\item[iPause] A flag which becomes true if the counter has been
|
||||||
|
paused.
|
||||||
|
\item[iErrorCode] A private variable holding error codes.
|
||||||
|
\item[GetStatus] This function is called while upper
|
||||||
|
elvel code polls for the counter to finish. It has to return the
|
||||||
|
status of the counting operation and update the current value of the
|
||||||
|
control variable in fControl. Possible return values are:
|
||||||
|
\begin{description}
|
||||||
|
\item[HWBusy] when counting.
|
||||||
|
\item[HWIdle] when finished counting or idle.
|
||||||
|
\item[HWNoBeam] when counting is interrupted due to lack of beam.
|
||||||
|
\item[HWPause] if counting is paused.
|
||||||
|
\item[HWFault] if the status cannot be obtained.
|
||||||
|
\end{description}
|
||||||
|
\item[Start] start counting in the count mode and with the preset
|
||||||
|
previously confugured. Do NOT wait for counting to finish!
|
||||||
|
\item[Pause] pause counting.
|
||||||
|
\item[Continue] continue a paused counting operation.
|
||||||
|
\item[Halt] stop counting.
|
||||||
|
\item[ReadValues] read all counters and monitors into lCounts.
|
||||||
|
\item[GetError] retrieves information about an error which occurred on
|
||||||
|
the counter. An integer error code is returned in iCode. Up to iBufLen
|
||||||
|
characters of descriptive error information is copied into
|
||||||
|
buffer. This information is printed as error message by upper level
|
||||||
|
code.
|
||||||
|
\item[TryAndFixIt] Given an error code in iError, try to repair the
|
||||||
|
problem as far as this is possible in software. iError should be an
|
||||||
|
error code as returned by GetError in iCode. This function has the
|
||||||
|
following return codes:
|
||||||
|
\begin{description}
|
||||||
|
\item[COREDO] Problem fixed, try to redo the last the operation.
|
||||||
|
\item[COTERM] The problem cannot be fixed in software.
|
||||||
|
\end{description}
|
||||||
|
\item[Set] set parameter name associated with counter iCter to fVal.
|
||||||
|
\item[Get] return in fVal the value of parameter name associated with
|
||||||
|
iCter. These two functions allow to set counter driver parameters.
|
||||||
|
\item[Send] send pText to the counter controller and return iReplylen
|
||||||
|
characters of repsonse from the counter controller in pReply. This is
|
||||||
|
a bypass to set controller parameters manually.
|
||||||
|
\item[KillPrivate] properly delete counter driver private data
|
||||||
|
pData. Also close any connections to the hardware.
|
||||||
|
\end{description}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\section{Environment Controller Driver}
|
||||||
|
This is the driver for all sample environment controllers, be it
|
||||||
|
temperature controllers, magnet controllers etc. An environment
|
||||||
|
controller driver is represented by the following data structure:
|
||||||
|
\begin{verbatim}
|
||||||
|
typedef struct __EVDriver {
|
||||||
|
int (*SetValue)(pEVDriver self, float fNew);
|
||||||
|
int (*GetValue)(pEVDriver self, float *fPos);
|
||||||
|
int (*GetValues)(pEVDriver self, float *fTarget,
|
||||||
|
float *fPos, float *fDelta);
|
||||||
|
int (*Send)(pEVDriver self, char *pCommand,
|
||||||
|
char *pReplyBuffer, int iReplBufLen);
|
||||||
|
int (*GetError)(pEVDriver self, int *iCode,
|
||||||
|
char *pError, int iErrLen);
|
||||||
|
int (*TryFixIt)(pEVDriver self, int iCode);
|
||||||
|
int (*Init)(pEVDriver self);
|
||||||
|
int (*Close)(pEVDriver self);
|
||||||
|
void *pPrivate;
|
||||||
|
void (*KillPrivate)(void *pData);
|
||||||
|
} EVDriver;
|
||||||
|
\end{verbatim}
|
||||||
|
All functions take a pointer to their own data structure as the first
|
||||||
|
argument (self). They return 1 on success or 0 on failure if not
|
||||||
|
stated otherwise.
|
||||||
|
The fields:
|
||||||
|
\begin{description}
|
||||||
|
\item[SetValue] set fNew as the new set value for the device. It
|
||||||
|
should start heating or cooling or whatever then.
|
||||||
|
\item[GetValue] reads the current value from the device into *fPos.
|
||||||
|
\item[GetValues] is used when the readout sensor and the control
|
||||||
|
sensor are very different. This function then reads the current set
|
||||||
|
value, the current position and calculates the difference between
|
||||||
|
these value into fDelta. This function does not need to be defined, it
|
||||||
|
is replaced by a standard one based on GetValue if not present.
|
||||||
|
\item[Send] send a command in pCommand to the controller and returns
|
||||||
|
at max iReplBuflen bytes of result in pReplyBuffer. This is breakout
|
||||||
|
which allows to send arbitray data to the controller.
|
||||||
|
\item[GetError] retrieves information about an error which occurred on
|
||||||
|
the device. An integer error code is returned in iCode. Up to iBufLen
|
||||||
|
characters of descriptive error information is copied into
|
||||||
|
buffer. This information is printed as error message by upper level
|
||||||
|
code.
|
||||||
|
\item[TryAndFixIt] Given an error code in iError, try to repair the
|
||||||
|
problem as far as this is possible in software. iError should be an
|
||||||
|
error code as returned by GetError in iCode. This function has the
|
||||||
|
following return codes:
|
||||||
|
\begin{description}
|
||||||
|
\item[DEVREDO] Problem fixed, try to redo the last the operation.
|
||||||
|
\item[DEVFAULT] The problem cannot be fixed in software.
|
||||||
|
\end{description}
|
||||||
|
\item[Init] initializes a connection to a controller and puts the
|
||||||
|
thing into the right mode (or mood?).
|
||||||
|
\item[Close] closes a connection to a controller.
|
||||||
|
\item[pPrivate] A pointer to a driver specific data structure which
|
||||||
|
can be filled with meaning by instances of drivers.
|
||||||
|
\item[KillPrivate] a function which has to release all memory associated
|
||||||
|
with pPrivate.
|
||||||
|
\end{description}
|
||||||
|
|
||||||
|
|
||||||
|
\section{Histogram Memory}
|
||||||
|
Histogram memories are devices in which neutron events for area
|
||||||
|
detector or time--of--flight detectors are assigned to their correct
|
||||||
|
bins. Then these usually large data sets have to be transferred to
|
||||||
|
SICS for further processing. In SICS, histogram memories are also able
|
||||||
|
to do count control, i.e. count until a preset monitor or time is
|
||||||
|
reached. This gives a slightly complicated driver interface. If this
|
||||||
|
assumption does not hold there are two options:
|
||||||
|
\begin{itemize}
|
||||||
|
\item Pass in a counter as a configuration parameter and chain count
|
||||||
|
control to this counter.
|
||||||
|
\item Make the count control functions dummies and let HMControl do
|
||||||
|
the rest. See hmcontrol.h and .c for details.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
Though never used so far the histogram memory driver has support for
|
||||||
|
multiple banks of detectors being controlled by one histogram memory.
|
||||||
|
|
||||||
|
A histogram memory driver is implemented by filling in the data
|
||||||
|
structure given below:
|
||||||
|
\begin{verbatim}
|
||||||
|
typedef struct __HistDriver {
|
||||||
|
pHMdata data;
|
||||||
|
/* counting operations data */
|
||||||
|
CounterMode eCount;
|
||||||
|
float fCountPreset;
|
||||||
|
/* status flags */
|
||||||
|
int iReconfig;
|
||||||
|
int iUpdate;
|
||||||
|
/* interface functions */
|
||||||
|
int (*Configure)(pHistDriver self,
|
||||||
|
SConnection *pCon,
|
||||||
|
pStringDict pOpt,
|
||||||
|
SicsInterp *pSics);
|
||||||
|
int (*Start)(pHistDriver self,
|
||||||
|
SConnection *pCon);
|
||||||
|
int (*Halt)(pHistDriver self);
|
||||||
|
int (*GetCountStatus)(pHistDriver self,
|
||||||
|
SConnection *pCon);
|
||||||
|
int (*GetError)(pHistDriver self,
|
||||||
|
int *iCode,
|
||||||
|
char *perror,
|
||||||
|
int iErrlen);
|
||||||
|
int (*TryAndFixIt)(pHistDriver self,
|
||||||
|
int iCode);
|
||||||
|
int (*GetData)(pHistDriver self,
|
||||||
|
SConnection *pCon);
|
||||||
|
int (*GetHistogram)(pHistDriver self,
|
||||||
|
SConnection *pCon,
|
||||||
|
int i,
|
||||||
|
int iStart, int iEnd,
|
||||||
|
HistInt *pData);
|
||||||
|
|
||||||
|
int (*SetHistogram)(pHistDriver self,
|
||||||
|
SConnection *pCon,
|
||||||
|
int i,
|
||||||
|
int iStart, int iEnd,
|
||||||
|
HistInt *pData);
|
||||||
|
long (*GetMonitor)(pHistDriver self,
|
||||||
|
int i,
|
||||||
|
SConnection *pCon);
|
||||||
|
float (*GetTime)(pHistDriver self,
|
||||||
|
SConnection *pCon);
|
||||||
|
int (*Preset)(pHistDriver self,
|
||||||
|
SConnection *pCon,
|
||||||
|
HistInt iVal);
|
||||||
|
int (*Pause)(pHistDriver self,
|
||||||
|
SConnection *pCon);
|
||||||
|
int (*Continue)(pHistDriver self,
|
||||||
|
SConnection *pCon);
|
||||||
|
int (*FreePrivate)(pHistDriver self);
|
||||||
|
void *pPriv;
|
||||||
|
} HistDriver;
|
||||||
|
\end{verbatim}
|
||||||
|
All functions take a pointer to their driver data structure as an
|
||||||
|
argument. If not stated otherwise they retun 1 on success, 0 on failure.
|
||||||
|
\begin{description}
|
||||||
|
\item[data] Is a pointer to an HMdata object which does all the
|
||||||
|
dimension handling, buffers histogram memory content, deals with time
|
||||||
|
binnings etc.
|
||||||
|
\item[eCount] A counter mode, as defined above for counters.
|
||||||
|
\item[fCountPreset] A preset for either monitor or time.
|
||||||
|
\item[iReconfig] A flag which will be set by upper level code when a
|
||||||
|
reconfiguration is necessary.
|
||||||
|
\item[iUpdate] a flag which invalidates the buffered histogram. Should
|
||||||
|
be set 1 in each call to GetCountStatus.
|
||||||
|
\item[Configure] configures the histogram memory to the specifications
|
||||||
|
given in the fields of the HMdriver structure. Further driver specific
|
||||||
|
information can be read from the options dictionary passed
|
||||||
|
in. Configuration options are stored in the string dictionary
|
||||||
|
pOpt. This dictionary holds name value pairs which must be interpreted
|
||||||
|
by this routine. Then configure has to configure the histogram memory
|
||||||
|
according to the options passed in.
|
||||||
|
\item[Start] starts a counting operation according to the current
|
||||||
|
settings of the counter mode parameters.
|
||||||
|
\item[Halt] implements an emergency stop of a counting operation.
|
||||||
|
\item[GetCountStatus] serves to monitor the status of the counting
|
||||||
|
operation. Possible return values to this call are:
|
||||||
|
\begin{itemize}
|
||||||
|
\item HWBUSY when still counting.
|
||||||
|
\item HWNoBeam when the monitor is to low.
|
||||||
|
\item HWIDLE or OKOK when nothing is going on.
|
||||||
|
\item HWFault when there is an error on the device.
|
||||||
|
\end{itemize}
|
||||||
|
\item[GetError] will be called whenever an error has been detected on
|
||||||
|
the device. The task is to put an internal error code into the iCode
|
||||||
|
parameter. The string parameter error will be filled with a text description
|
||||||
|
of the error. But maximum iLen characters will be transferred to the error
|
||||||
|
string in order to protect against memory corruption. Therefore iLen must be
|
||||||
|
the maximum field length of error.
|
||||||
|
\item[TryAndFixIt] is the next function called in case of an error on
|
||||||
|
the device. Its second parameter is the internal code obtained in the ICode
|
||||||
|
parameter of the call to GetError. The task of this function is to examine
|
||||||
|
the error code and do whatever is possible in software to fix the problem.
|
||||||
|
TryAndFixIt returns one of the following values:
|
||||||
|
\begin{itemize}
|
||||||
|
\item COREDO when the error could be fixed, but the upper level code will
|
||||||
|
need to rerun the command which failed.
|
||||||
|
\item COFAIL when the software is unable to fix the problem and a real
|
||||||
|
mechanic with a hammer is needed (or somebody able to reboot!).
|
||||||
|
\item MOTOK when the error was fixed and nor further action is necessary.
|
||||||
|
\end{itemize}
|
||||||
|
\item[GetData] transfers all the data collected in the HM into the
|
||||||
|
host computers memory buffer.
|
||||||
|
\item[GetHistogram] copies data betwen iStart and iend from histogram
|
||||||
|
bank i into the data space pData. Please make sure that pData is big
|
||||||
|
enough to hold the data.
|
||||||
|
\item[SetHistogram] presets the histogram bank i i with the data
|
||||||
|
given in lData. A conversion from different binwidth
|
||||||
|
to long is performed as well. iStart and iStop define the start and end of
|
||||||
|
the stretch of histogram to replace.
|
||||||
|
\item[GetMonitor] returns the counts in the monitor i. Returns a
|
||||||
|
negative value on error. The error will have been printed to pCon.
|
||||||
|
\item[GetTime] returns the actual counting time.
|
||||||
|
\item[Preset] initializes the histogram memory to the value given by
|
||||||
|
iVal.
|
||||||
|
\item[Pause] pauses data collection.
|
||||||
|
\item[Continue] continues a paused data collection.
|
||||||
|
\item[FreePrivate] will be called automatically by DeleteHistDriver and
|
||||||
|
has the task to remove the private data installed by implementations of an
|
||||||
|
actual histogram memory driver.
|
||||||
|
\item[pPriv] is a pointer which a actual histogram memory driver may
|
||||||
|
use to hold a driver specific data structure.
|
||||||
|
\end{description}
|
||||||
|
|
||||||
|
|
||||||
|
\section{Velocity Selector Driver}
|
||||||
|
This is a driver for velocity selectors as used at SANS machines. A
|
||||||
|
velocity selector is a kind of turbine which selects wavelength
|
||||||
|
through rotation speed. Though it rotates fast it is not a chopper,
|
||||||
|
which are handled in SICS through the general controller driver
|
||||||
|
described below. The velocity selector driver data structure includes:
|
||||||
|
\begin{verbatim}
|
||||||
|
typedef struct __VelSelDriv {
|
||||||
|
void *pPrivate;
|
||||||
|
void (*DeletePrivate)(void *pData);
|
||||||
|
float fTolerance;
|
||||||
|
int (*Halt)(pVelSelDriv self);
|
||||||
|
int (*GetError)(pVelSelDriv self,
|
||||||
|
int *iCode, char *pError,
|
||||||
|
int iErrlen);
|
||||||
|
int (*TryAndFixIt)(pVelSelDriv self,
|
||||||
|
int iCode);
|
||||||
|
int (*GetRotation)(pVelSelDriv self,
|
||||||
|
float *fRot);
|
||||||
|
int (*SetRotation)(pVelSelDriv self,
|
||||||
|
float fRot);
|
||||||
|
int (*GetStatus)(pVelSelDriv self,
|
||||||
|
int *iCall, float *fCur);
|
||||||
|
int (*GetDriverText)(pVelSelDriv self,
|
||||||
|
char *pText,
|
||||||
|
int iTextLen);
|
||||||
|
int (*GetLossCurrent)(pVelSelDriv self,
|
||||||
|
float *fLoss);
|
||||||
|
int (*Init)(pVelSelDriv self,
|
||||||
|
SConnection *pCon);
|
||||||
|
}VelSelDriv;
|
||||||
|
\end{verbatim}
|
||||||
|
All functions take a pointer to their driver data structure as an
|
||||||
|
argument. If not stated otherwise they retun 1 on success, 0 on failure.
|
||||||
|
The fields:
|
||||||
|
\begin{description}
|
||||||
|
\item[pPrivate] a pointer to a driver private data structure.
|
||||||
|
\item[DeletePrivate] a function which releases any memory associated
|
||||||
|
with pPrivate. DeletePrivate is called with a pointer to the driver
|
||||||
|
private data pPrivate as argument.
|
||||||
|
\item[fTolerance] This driver assumes it has reached the target speed
|
||||||
|
if the speed difference target speed - read speed is less then this
|
||||||
|
tolerance value for four consecutive times.
|
||||||
|
\item[Halt] stops the velocity selector.
|
||||||
|
\item[GetError] returns an error code in *iCode and iErrlen
|
||||||
|
bytes of textual description of the last error on the velocity
|
||||||
|
selector in pError.
|
||||||
|
\item[TryAndFixIt] tries to fix the error defined through iCode. iCode
|
||||||
|
should be the value as returned in *iCode in GetError. This function
|
||||||
|
returns:
|
||||||
|
\begin{description}
|
||||||
|
\item[VELOREDO] redo last operation, error fixed.
|
||||||
|
\item[VELOFAIL] cannot fix the error from software.
|
||||||
|
\end{description}
|
||||||
|
\item[GetRotation] reads the rotation speed into *fRot.
|
||||||
|
\item[SetRotation] sets a new rotation speed fRot for the selector. Do
|
||||||
|
NOT wait until finished.
|
||||||
|
\item[GetStatus] is used to poll for the status of the last driving
|
||||||
|
operation. It returns:
|
||||||
|
\begin{description}
|
||||||
|
\item[VSACCEL] when the velocity selector is accelerating.
|
||||||
|
\item[VSFAIL] is the status cannot be read.
|
||||||
|
\item[VSOK] when the velocity seelctor has reached its target speed.
|
||||||
|
\end{description}
|
||||||
|
The current rotation speed is returned in *fCur. iCall is a value
|
||||||
|
which indicates in which state the selector is:
|
||||||
|
\begin{description}
|
||||||
|
\item[ROTMOVE] normal running.
|
||||||
|
\item[ROTSTART] starting the velocity selector. The Dornier velocity
|
||||||
|
selector have a certain minimum speed. If they are standing they have
|
||||||
|
to be started first.
|
||||||
|
\end{description}
|
||||||
|
\item[GetDriverText] returns iTextLen bytes of additional status
|
||||||
|
information in pText. This is a list name: value pairs separated by
|
||||||
|
komma. This is meant to hold additional selector readouts such as
|
||||||
|
vacuum states, temperatures etc.
|
||||||
|
\item[GetLossCurrent] initiates a measurement of the loss current of
|
||||||
|
the velocity seelctor. The result is returned in *fLoss.
|
||||||
|
\item[Init] initiates a connection to a velocity selector.
|
||||||
|
\end{description}
|
||||||
|
|
||||||
|
It may be possible that this driver is not very general. It was
|
||||||
|
developed for Dornier velocity seelctors because these were the only
|
||||||
|
one seen.
|
||||||
|
|
||||||
|
\section{General Controller Driver}
|
||||||
|
This is driver for a SICS general controller object. SICS sports a
|
||||||
|
general controller object which allows to read a selection of parameters and
|
||||||
|
to set some parameters. Adapters exists which implement the driveable
|
||||||
|
or environment interface for parameters in such a controller. The
|
||||||
|
parameters supported are part of the drivers interface. This
|
||||||
|
scheme is currently used to control choppers in SICS, but it is not
|
||||||
|
restricted to this usage. The driver:
|
||||||
|
\begin{verbatim}
|
||||||
|
typedef struct __CODRI {
|
||||||
|
int (*Init)(pCodri self);
|
||||||
|
int (*Close)(pCodri self);
|
||||||
|
int (*Delete)(pCodri self);
|
||||||
|
int (*SetPar)(pCodri self,
|
||||||
|
char *parname,
|
||||||
|
float fValue);
|
||||||
|
int (*SetPar2)(pCodri self,
|
||||||
|
char *parname,
|
||||||
|
char *value);
|
||||||
|
int (*GetPar)(pCodri self,
|
||||||
|
char *parname,
|
||||||
|
char *pBuffer,
|
||||||
|
int iBufLen);
|
||||||
|
int (*CheckPar)(pCodri self,
|
||||||
|
char *parname);
|
||||||
|
int (*GetError)(pCodri self, int *iCode,
|
||||||
|
char *pError,
|
||||||
|
int iErrLen);
|
||||||
|
int (*TryFixIt)(pCodri self, int iCode);
|
||||||
|
int (*Halt)(pCodri self);
|
||||||
|
char *pParList;
|
||||||
|
void *pPrivate;
|
||||||
|
}Codri;
|
||||||
|
\end{verbatim}
|
||||||
|
All functions take a pointer to their driver data structure as an
|
||||||
|
argument. If not stated otherwise they retun 1 on success, 0 on failure.
|
||||||
|
The fields:
|
||||||
|
\begin{description}
|
||||||
|
\item[Init] initializes a connection to the controller and the driver.
|
||||||
|
\item[Close] closes the connection to a controller.
|
||||||
|
\item[Delete] releases all memory associated with this drivers private
|
||||||
|
data structure pPrivate.
|
||||||
|
\item[SetPar] sets the parameter parname to a new value fValue.
|
||||||
|
\item[SetPar2] same as SetPar but with new value as text.
|
||||||
|
\item[GetPar] read the current value of parname into pBuffer. The
|
||||||
|
value is formatted as text. At max iBufLen bytes are copied into
|
||||||
|
pBuffer.
|
||||||
|
\item[CheckPar] checks the progress of setting parname. CheckPar
|
||||||
|
returns:
|
||||||
|
\begin{description}
|
||||||
|
\item[HWFault] If there is a fault in the hardware or the status
|
||||||
|
cannot be read.
|
||||||
|
\item[HWBusy] The parameter is still driving.
|
||||||
|
\item[HWIdle] The parameter has finished changing and is idle.
|
||||||
|
\end{description}
|
||||||
|
\item[GetError] returns an error code in *iCode and iErrlen
|
||||||
|
bytes of textual description of the last error on the velocity
|
||||||
|
selector in pError.
|
||||||
|
\item[TryAndFixIt] tries to fix the error defined through iCode. iCode
|
||||||
|
should be the value as returned in *iCode in GetError. This function
|
||||||
|
returns:
|
||||||
|
\begin{description}
|
||||||
|
\item[CHREDO] redo last operation, error fixed.
|
||||||
|
\item[CHFAIL] cannot fix the error from software.
|
||||||
|
\end{description}
|
||||||
|
\item[Halt] stop any driving parameters.
|
||||||
|
\item[pParList] a comma separated list of parameters supported by this
|
||||||
|
driver.
|
||||||
|
\item[pPrivate] a driver private data structure.
|
||||||
|
\end{description}
|
129
doc/programmer/site.tex
Normal file
129
doc/programmer/site.tex
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
\chapter{Site Adaptions}\label{site}
|
||||||
|
Any new site adapting SICS will have different hardware and thus
|
||||||
|
require different drivers. Moreover additional commands may need to be
|
||||||
|
added in order to support special hardware, instrument specific
|
||||||
|
computations or status displays and local usage patterns. In order to
|
||||||
|
separate such site specific code from the SICS kernel, the site data
|
||||||
|
structure was conceived. Any new site is supposed to create a library
|
||||||
|
which provides site specific code and the site data structure which
|
||||||
|
allows SICS to locate the code. A site data structure can be retrieved
|
||||||
|
using:
|
||||||
|
\begin{verbatim}
|
||||||
|
pSite getSite(void);
|
||||||
|
\end{verbatim}
|
||||||
|
The site data structure is meant to be a singleton. It is a site's
|
||||||
|
programmers task to provide an implementation of getSite which returns
|
||||||
|
a nice site structure.
|
||||||
|
|
||||||
|
The site data structure is a structure which holds pointers to
|
||||||
|
functions. A user has to implement suitable functions along the
|
||||||
|
signatures given and assign them to this data structure.
|
||||||
|
\begin{verbatim}
|
||||||
|
typedef struct {
|
||||||
|
void (*AddSiteCommands)(SicsInterp *pSics);
|
||||||
|
void (*RemoveSiteCommands)(SicsInterp *pSics);
|
||||||
|
pMotor (*CreateMotor)(SConnection *pCon,
|
||||||
|
int argc, char *argv[]);
|
||||||
|
pCounterDriver (*CreateCounterDriver)(
|
||||||
|
SConnection *pCon,
|
||||||
|
int argc,
|
||||||
|
char *argv[]);
|
||||||
|
HistDriver *(*CreateHistogramMemoryDriver)(
|
||||||
|
char *name, pStringDict pOption);
|
||||||
|
pVelSelDriv (*CreateVelocitySelector)(char *name,
|
||||||
|
char *array, Tcl_Interp *pTcl);
|
||||||
|
pCodri (*CreateControllerDriver)(SConnection *pCon,
|
||||||
|
int argc,
|
||||||
|
char *argv[]);
|
||||||
|
pEVControl (*InstallEnvironmentController)(
|
||||||
|
SicsInterp *pSics,
|
||||||
|
SConnection *pCon,
|
||||||
|
int argc,
|
||||||
|
char *argv[]);
|
||||||
|
int (*ConfigureScan)(pScanData self,
|
||||||
|
char *option);
|
||||||
|
void (*KillSite)(void *pData);
|
||||||
|
}Site, *pSite;
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
|
The members of this data structure:
|
||||||
|
\begin{description}
|
||||||
|
\item[AddSiteCommand] adds site specific commands coded in C to the
|
||||||
|
SICS interpreter pSics.
|
||||||
|
\item[RemoveSiteCommands] removes object creation commands after SICS
|
||||||
|
has processed the instrument initialization file. See \ref{factory}
|
||||||
|
for details on the scheme.
|
||||||
|
\item[CreateMotor] creates a motor object. \verb+argv[0]+ contains the
|
||||||
|
motors name, \verb+argv[1]+ the identifier for the motor driver and
|
||||||
|
the rest of argv, argc holds further driver initialisation
|
||||||
|
parameters. Any errors in processing the arguments can be reported to
|
||||||
|
pCon. If CreateMotor can create a suitable motor object, a pointer to
|
||||||
|
it is returned, if not NULL must be returned.
|
||||||
|
\item[CreateCounterDriver] creates a driver for a counter. argc, argv
|
||||||
|
is the full array of arguments given to the MakeCounter factory
|
||||||
|
function. Of interest are: \verb+argv[1]+ the counter name,
|
||||||
|
\verb+argv[2]+, the driver identifier and the rest of the
|
||||||
|
initialization arguments. On success a pointer to
|
||||||
|
new driver is returned, on failure NULL.
|
||||||
|
\item[CreateHistogramMemoryDriver] creates a driver for a histogram
|
||||||
|
memory. The driver is identified through name, the options database is
|
||||||
|
in pOptions. Histogram memory initialization follows the following
|
||||||
|
pattern:
|
||||||
|
\begin{itemize}
|
||||||
|
\item At first the raw driver is created. This code has to initializie
|
||||||
|
defaults in the options data base.
|
||||||
|
\item Then, with calls to {\em hmname configure opt val} the options
|
||||||
|
database is populated with the histogram memories configuration
|
||||||
|
options. The options database is pOptions a dictionary of name value
|
||||||
|
pairs.
|
||||||
|
\item In the last step, with {\bf hmname init} the options are parsed
|
||||||
|
and the driver is supposed to connect to the histogram memory. See
|
||||||
|
Configure in the histogram memory driver.
|
||||||
|
\end{itemize}
|
||||||
|
On success a pointer to
|
||||||
|
new driver is returned, on failure NULL.
|
||||||
|
\item[CreateVelSelDriv] creates a driver for a velocity selector. The
|
||||||
|
driver is identified by nname, array is the name of a Tcl array in
|
||||||
|
pTcl holding initialization parameters for name.
|
||||||
|
\item[MakeController] generates a driver for a SICS general controller
|
||||||
|
object. \verb+argv[0]+ is the driver identifier, the rest of argc,
|
||||||
|
\verb+argv[]+ are further initialization parameters. Any errors in
|
||||||
|
parsing argc, argv can be reported to pCon. On success a pointer to
|
||||||
|
new driver is returned, on failure NULL.
|
||||||
|
\item[InstallEnvironmentController] installs a sample environment
|
||||||
|
controller into pSics. \verb+argv[3]+ is the driver indentifier,
|
||||||
|
\verb+argv[2]+ is the SICS name of the environment device command, the
|
||||||
|
rest are initialization parameters. This function must also install
|
||||||
|
the command into pSics with AddCommand. This is because for many PSI
|
||||||
|
environment devices special interpreter wrapper functions are
|
||||||
|
provided. Any errors encountered while processing the arguments has to
|
||||||
|
be reported to pCon. On success a pointer to the environment
|
||||||
|
controller is returned, on failure NULL.
|
||||||
|
\item[ConfigureScan] configures the SICS general scan object self according
|
||||||
|
to the value of option. Returns 1 on success and 0 on failure. SICS
|
||||||
|
general scan object is a data structure holding function pointers for
|
||||||
|
various steps in the scan. These functions can be overloaded in order
|
||||||
|
to provide for special scans. See the documentation ins scan.tex,
|
||||||
|
scan.h and scan.c from more details.
|
||||||
|
\end{description}
|
||||||
|
|
||||||
|
|
||||||
|
All the simulation drivers for the hardware are part of the SICS
|
||||||
|
kernel and need not be initialized from these functions. SICS also
|
||||||
|
handles sample environment devices built in Tcl or on the general
|
||||||
|
controller object.
|
||||||
|
|
||||||
|
|
||||||
|
The site data structure suffers a little from inconsistencies
|
||||||
|
introduced through varying concepts for initializing SICS objects introduced
|
||||||
|
during the development of SICS. If you need to bypass the schemes
|
||||||
|
introduced here, consider implementing an own factory command and
|
||||||
|
install it through AddSiteCommand, RemoveSiteCommand.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Good luck!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
4
make_gen
4
make_gen
@ -23,8 +23,8 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
|
|||||||
simchop.o choco.o chadapter.o trim.o scaldate.o \
|
simchop.o choco.o chadapter.o trim.o scaldate.o \
|
||||||
hklscan.o xytable.o \
|
hklscan.o xytable.o \
|
||||||
circular.o maximize.o sicscron.o \
|
circular.o maximize.o sicscron.o \
|
||||||
t_rlp.o t_conv.o d_sign.o d_mod.o \
|
d_sign.o d_mod.o \
|
||||||
synchronize.o definealias.o t_update.o \
|
synchronize.o definealias.o \
|
||||||
hmcontrol.o userscan.o rs232controller.o lomax.o \
|
hmcontrol.o userscan.o rs232controller.o lomax.o \
|
||||||
fourlib.o motreg.o motreglist.o anticollider.o \
|
fourlib.o motreg.o motreglist.o anticollider.o \
|
||||||
s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) \
|
s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) \
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
# Markus Zolliker, March 2003
|
# Markus Zolliker, March 2003
|
||||||
#==========================================================================
|
#==========================================================================
|
||||||
# the following lines only for fortified version
|
# the following lines only for fortified version
|
||||||
DFORTIFY=-DFORTIFY
|
#DFORTIFY=-DFORTIFY
|
||||||
FORTIFYOBJ=strdup.o fortify.o
|
#FORTIFYOBJ=strdup.o fortify.o
|
||||||
#==========================================================================
|
#==========================================================================
|
||||||
# assign if the National Instrument GPIB driver is available
|
# assign if the National Instrument GPIB driver is available
|
||||||
#NI= -DHAVENI
|
#NI= -DHAVENI
|
||||||
@ -25,9 +25,18 @@ HDFROOT=/afs/psi.ch/project/sinq/linux
|
|||||||
EXTRA=nintf.o
|
EXTRA=nintf.o
|
||||||
SUBLIBS = psi/libpsi.a psi/hardsup/libhlib.a matrix/libmatrix.a \
|
SUBLIBS = psi/libpsi.a psi/hardsup/libhlib.a matrix/libmatrix.a \
|
||||||
psi/tecs/libtecsl.a
|
psi/tecs/libtecsl.a
|
||||||
LIBS = -L$(HDFROOT)/lib $(SUBLIBS) \
|
LIBS = -static -L$(HDFROOT)/lib $(SUBLIBS) \
|
||||||
-ltcl8.3 $(HDFROOT)/lib/libhdf5.a \
|
-ltcl8.3 $(HDFROOT)/lib/libhdf5.a \
|
||||||
$(HDFROOT)/lib/libmfhdf.a $(HDFROOT)/lib/libdf.a \
|
$(HDFROOT)/lib/libmfhdf.a $(HDFROOT)/lib/libdf.a \
|
||||||
$(HDFROOT)/lib/libjpeg.a -lz -lm -ll -lc
|
$(HDFROOT)/lib/libjpeg.a -ldl -lz -lm -ll -lc
|
||||||
|
|
||||||
include $(SRC)make_gen
|
include $(SRC)make_gen
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
838
t_conv.c
838
t_conv.c
@ -1,838 +0,0 @@
|
|||||||
/* t_conv.f -- translated by f2c (version 20000817).
|
|
||||||
You must link the resulting object file with the libraries:
|
|
||||||
-lf2c -lm (in that order)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "f2c.h"
|
|
||||||
|
|
||||||
/* Common Block Declarations */
|
|
||||||
|
|
||||||
struct {
|
|
||||||
integer icrm, icra, iclm;
|
|
||||||
real cm1rx, cm2rx, ca1rx, ca2rx, rmmin, rmmax, ramin, ramax;
|
|
||||||
integer inx;
|
|
||||||
logical at_sinq__;
|
|
||||||
} curve_;
|
|
||||||
|
|
||||||
#define curve_1 curve_
|
|
||||||
|
|
||||||
/* Table of constant values */
|
|
||||||
|
|
||||||
static integer c__0 = 0;
|
|
||||||
static integer c__1 = 1;
|
|
||||||
static doublereal c_b10 = 1.;
|
|
||||||
static doublereal c_b12 = 360.;
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------ */
|
|
||||||
/* slightly edited version for inclusion into SICS */
|
|
||||||
|
|
||||||
/* Mark Koennecke, November 2000 */
|
|
||||||
|
|
||||||
/* Found that ERRESO looks error messages up in a 2D array. Modified IER */
|
|
||||||
/* values to refer to a 1D array. */
|
|
||||||
|
|
||||||
/* Mark Koennecke, January 2002 */
|
|
||||||
/* ------------------------------------------------------------------------- */
|
|
||||||
/* Subroutine */ int inicurve_(integer *midx, real *mrx1, real *mrx2, integer
|
|
||||||
*aidx, real *arx1, real *arx2, real *mmin, real *mmax, real *amin,
|
|
||||||
real *amax)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* Initializes a common with the curvature parameters. */
|
|
||||||
/* In: monochrmoator curvatuure motor index and parameters */
|
|
||||||
/* In: analyzer curvature motor index + parameters */
|
|
||||||
curve_1.icrm = *midx;
|
|
||||||
curve_1.icra = *aidx;
|
|
||||||
curve_1.cm1rx = *mrx1;
|
|
||||||
curve_1.cm2rx = *mrx2;
|
|
||||||
curve_1.ca1rx = *arx1;
|
|
||||||
curve_1.ca2rx = *arx2;
|
|
||||||
curve_1.rmmin = *mmin;
|
|
||||||
curve_1.rmmax = *mmax;
|
|
||||||
curve_1.ramin = *amin;
|
|
||||||
curve_1.ramax = *amax;
|
|
||||||
curve_1.inx = 0;
|
|
||||||
curve_1.at_sinq__ = TRUE_;
|
|
||||||
curve_1.iclm = 0;
|
|
||||||
return 0;
|
|
||||||
} /* inicurve_ */
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
/* Subroutine */ int t_conv__(real *ei, real *aki, real *ef, real *akf, real *
|
|
||||||
qhkl, real *en, real *hx, real *hy, real *hz, integer *if1, integer *
|
|
||||||
if2, logical *ldk, logical *ldh, logical *ldf, logical *lpa, real *dm,
|
|
||||||
real *da, real *helm, real *f1h, real *f1v, real *f2h, real *f2v,
|
|
||||||
real *f, integer *ifx, integer *iss, integer *ism, integer *isa, real
|
|
||||||
*t_a__, real *t_rm__, real *t_alm__, real *t_ra__, real *qm, logical *
|
|
||||||
ldra, logical *ldr_rm__, logical *ldr_alm__, logical *ldr_ra__, real *
|
|
||||||
p_ih__, real *c_ih__, doublereal *a4, integer *ier)
|
|
||||||
{
|
|
||||||
/* System generated locals */
|
|
||||||
doublereal d__1;
|
|
||||||
|
|
||||||
/* Builtin functions */
|
|
||||||
double sqrt(doublereal);
|
|
||||||
|
|
||||||
/* Local variables */
|
|
||||||
static doublereal edef[2], dakf, daki;
|
|
||||||
static integer imod;
|
|
||||||
extern /* Subroutine */ int sam_case__(doublereal *, doublereal *,
|
|
||||||
doublereal *, doublereal *, doublereal *, doublereal *,
|
|
||||||
doublereal *, integer *, integer *);
|
|
||||||
static integer i__;
|
|
||||||
static doublereal akdef[2];
|
|
||||||
extern /* Subroutine */ int helm_case__(real *, real *, real *, real *,
|
|
||||||
real *, real *, real *, doublereal *, real *, real *, integer *);
|
|
||||||
static doublereal dqhkl[3];
|
|
||||||
extern /* Subroutine */ int flip_case__(integer *, integer *, real *,
|
|
||||||
real *, real *, real *, real *, real *, real *, integer *);
|
|
||||||
static logical lmoan[2];
|
|
||||||
static doublereal a1, a2, a3, a5, a6;
|
|
||||||
static integer id;
|
|
||||||
static doublereal ra;
|
|
||||||
extern /* Subroutine */ int rl2spv_(doublereal *, doublereal *,
|
|
||||||
doublereal *, doublereal *, integer *);
|
|
||||||
static integer iq;
|
|
||||||
static doublereal rm;
|
|
||||||
static logical lqhkle;
|
|
||||||
extern /* Subroutine */ int erreso_(integer *, integer *);
|
|
||||||
static doublereal dda, ala, def, dei, ddm, alm, dqm, dqs, dqt[3];
|
|
||||||
extern /* Subroutine */ int ex_case__(doublereal *, integer *, doublereal
|
|
||||||
*, doublereal *, doublereal *, doublereal *, doublereal *,
|
|
||||||
integer *, integer *);
|
|
||||||
|
|
||||||
/* ================= */
|
|
||||||
|
|
||||||
/* dec$ ident 'V01D' */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Other routines in this file: */
|
|
||||||
|
|
||||||
/* SUBROUTINE EX_CASE (DX,ISX,AKX,AX1,AX2,RX,ALX,IER) */
|
|
||||||
/* SUBROUTINE SAM_CASE (QT,QM,QS,AKI,AKF,AX3,AX4,ISS,IER) */
|
|
||||||
/* SUBROUTINE HELM_CASE (HX,HY,HZ,P_IH,AKI,AKF,A4,QM,HELM,IER) */
|
|
||||||
/* SUBROUTINE FLIP_CASE (IF1,IF2,P_IH,F1V,F1H,F2V,F2H,AKI,AKF,IER) */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* INPUTS */
|
|
||||||
/* EI,AKI,EF,AKF,QHKL,EN,HX,HY,HZ : POTENTIAL TARGETS */
|
|
||||||
/* IF1,IF2 Status of flippers On (1) Off (0) */
|
|
||||||
/* LDK(8) LOGICAL INDICATING IF (ENERGY,K OR Q) ARE DRIVEN */
|
|
||||||
/* LDH,LDF LOGICAL INDICATING IF (HX,HY,HZ) OR (F1,F2) ARE DRIVEN */
|
|
||||||
|
|
||||||
/* configuration of the machine */
|
|
||||||
|
|
||||||
/* LPA LOGICAL TRUE IF MACHINE IN POLARIZATION MODE */
|
|
||||||
/* DM,DA,HELM,F1H,F1V,F2H,F2V,F,IFX,ISS,ISM,ISA,QM (F ENERGY UNIT) */
|
|
||||||
|
|
||||||
/* OUTPUTs */
|
|
||||||
/* T_A TARGETS OF ANGLES A1-A6 */
|
|
||||||
/* T_RM,T_ALM TARGETS OF RM ,LM */
|
|
||||||
/* T_RA TARGET OF RA */
|
|
||||||
/* QM TARGETS OF QM */
|
|
||||||
/* LDRA LOGICAL INDICATING WHICH ANGLES ARE TO BE DRIVEN */
|
|
||||||
/* LDR_RM LOGICAL INDICATING IF RM (mono curve) IS TO BE DRIVEN */
|
|
||||||
/* LDR_ALM LOGICAL INDICATING IF ALM (mono transl) IS TO BE DRIVEN */
|
|
||||||
/* LDR_RA LOGICAL INDICATING IF RA (anal curve) IS TO BE DRIVEN */
|
|
||||||
/* P_IH TARGETS OF CURRENTS FOR FLIPPERS AND HELMOTZ (8 CURRENTS) */
|
|
||||||
/* C_IH CONVERSION FACTORS FOR HELMOTZ (4 CURRENTS) */
|
|
||||||
|
|
||||||
/* SPECIAL OUTPUTS */
|
|
||||||
/* TARGET OF EI(EF) IS UPDATED IS KI(KF) IS DRIVEN */
|
|
||||||
/* TARGET OF VARIABLE ENERGY IS UPDATED IF EN IS DRIVEN */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* File [MAD.SRC]T_CONV.FOR */
|
|
||||||
|
|
||||||
|
|
||||||
/* include 'curve.inc' */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Define the dummy arguments */
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* LOCAL VARIABLES */
|
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* SET UP */
|
|
||||||
/* IMOD INDEX FOR ERROR TREATMENAT BY ERRESO */
|
|
||||||
/* LDQHKLE : LOGICAL INDICATING THAT WE ARE DEALING WITH A MOVE */
|
|
||||||
/* IN RECIPROCICAL SPACE */
|
|
||||||
/* WE REMAP THE ENERGY PB AS FIXED ENERGY IN EDEF(1) */
|
|
||||||
/* AND VARIABLE ENERGY IN EDEF(2) */
|
|
||||||
/* IF ISA IS NUL SET IFX TO 1 AND PUT EF,KF, EQUAL TO EI,KI */
|
|
||||||
|
|
||||||
/* Parameter adjustments */
|
|
||||||
--c_ih__;
|
|
||||||
--p_ih__;
|
|
||||||
--ldra;
|
|
||||||
--t_a__;
|
|
||||||
--ldk;
|
|
||||||
--qhkl;
|
|
||||||
|
|
||||||
/* Function Body */
|
|
||||||
imod = 3;
|
|
||||||
ddm = *dm;
|
|
||||||
dda = *da;
|
|
||||||
for (i__ = 1; i__ <= 2; ++i__) {
|
|
||||||
lmoan[i__ - 1] = FALSE_;
|
|
||||||
}
|
|
||||||
lqhkle = FALSE_;
|
|
||||||
for (iq = 5; iq <= 8; ++iq) {
|
|
||||||
lqhkle = lqhkle || ldk[iq];
|
|
||||||
}
|
|
||||||
daki = *aki;
|
|
||||||
dakf = *akf;
|
|
||||||
if (*isa == 0) {
|
|
||||||
*ifx = 1;
|
|
||||||
}
|
|
||||||
edef[*ifx - 1] = *ei;
|
|
||||||
akdef[*ifx - 1] = *aki;
|
|
||||||
edef[3 - *ifx - 1] = *ef;
|
|
||||||
akdef[3 - *ifx - 1] = *akf;
|
|
||||||
if (*isa == 0) {
|
|
||||||
edef[1] = edef[0];
|
|
||||||
akdef[1] = akdef[0];
|
|
||||||
ldk[3] = TRUE_;
|
|
||||||
ldk[4] = TRUE_;
|
|
||||||
t_a__[5] = 0.f;
|
|
||||||
t_a__[6] = 0.f;
|
|
||||||
ldra[5] = TRUE_;
|
|
||||||
ldra[6] = TRUE_;
|
|
||||||
}
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* FIRST TAKE IN ACCOUNT THE FIXED ENERGY PB */
|
|
||||||
|
|
||||||
if (ldk[(*ifx << 1) - 1] || ldk[*ifx * 2]) {
|
|
||||||
lmoan[*ifx - 1] = TRUE_;
|
|
||||||
if (ldk[(*ifx << 1) - 1]) {
|
|
||||||
*ier = 9;
|
|
||||||
if (edef[0] < .1f) {
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
*ier = 0;
|
|
||||||
akdef[0] = sqrt(edef[0] / *f);
|
|
||||||
} else {
|
|
||||||
*ier = 9;
|
|
||||||
if (akdef[0] < .1f) {
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
*ier = 0;
|
|
||||||
/* Computing 2nd power */
|
|
||||||
d__1 = akdef[0];
|
|
||||||
edef[0] = *f * (d__1 * d__1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* NOW TAKE IN ACCOUNT THE VARIABLE ENERGY PB */
|
|
||||||
/* VARIABLE ENERGUY IS DRIVEN EITHER EXPLICITLY */
|
|
||||||
/* E.G. BY DRIVING EI OR KI WITH IFX=2 */
|
|
||||||
/* ( AND WE MUST CALCULATE EN FROM EVAR) */
|
|
||||||
/* THE RULE IS : EI=EF+EN : EN IS THE ENERGY LOSS OF NEUTRONS */
|
|
||||||
/* OR ENERGY GAIN OF SAMPLE */
|
|
||||||
/* OR IMPLICITLY BY DRIVING THE TRANSFERED ENERGY EN */
|
|
||||||
/* ( AND WE MUST CALCULATE EVAR FROM EN) */
|
|
||||||
/* IF KI IS CONSTANT USE THE CURRENT VALUE CONTAINED IN POSN ARRAY */
|
|
||||||
/* TO CALCULATE THE NON-"CONSTANT" K. */
|
|
||||||
/* IF KF IS CONSTANT USE ALWAYS THE VALUE IN TARGET AND */
|
|
||||||
/* DO A DRIVE OF KF TO KEEP A5/A6 IN RIGHT POSITION */
|
|
||||||
|
|
||||||
if (ldk[5 - (*ifx << 1)] || ldk[6 - (*ifx << 1)]) {
|
|
||||||
lmoan[3 - *ifx - 1] = TRUE_;
|
|
||||||
if (ldk[5 - (*ifx << 1)]) {
|
|
||||||
*ier = 9;
|
|
||||||
if (edef[1] < 1e-4f) {
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
*ier = 0;
|
|
||||||
akdef[1] = sqrt(edef[1] / *f);
|
|
||||||
} else {
|
|
||||||
*ier = 9;
|
|
||||||
if (akdef[1] < 1e-4f) {
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
*ier = 0;
|
|
||||||
/* Computing 2nd power */
|
|
||||||
d__1 = akdef[1];
|
|
||||||
edef[1] = *f * (d__1 * d__1);
|
|
||||||
}
|
|
||||||
*en = (3 - (*ifx << 1)) * (edef[0] - edef[1]);
|
|
||||||
} else if (lqhkle) {
|
|
||||||
lmoan[3 - *ifx - 1] = TRUE_;
|
|
||||||
edef[1] = edef[0] + ((*ifx << 1) - 3) * *en;
|
|
||||||
*ier = 9;
|
|
||||||
if (edef[1] < 1e-4f) {
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
*ier = 0;
|
|
||||||
akdef[1] = sqrt(edef[1] / *f);
|
|
||||||
}
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* CALCULATE MONOCHROMATOR AND ANALYSER ANGLES */
|
|
||||||
|
|
||||||
if (lmoan[0]) {
|
|
||||||
dei = edef[*ifx - 1];
|
|
||||||
daki = akdef[*ifx - 1];
|
|
||||||
ex_case__(&ddm, ism, &daki, &a1, &a2, &rm, &alm, &c__0, ier);
|
|
||||||
if (*ier == 0) {
|
|
||||||
*aki = daki;
|
|
||||||
*ei = dei;
|
|
||||||
t_a__[1] = a1;
|
|
||||||
t_a__[2] = a2;
|
|
||||||
ldra[1] = TRUE_;
|
|
||||||
ldra[2] = TRUE_;
|
|
||||||
if (curve_1.icrm != 0) {
|
|
||||||
*t_rm__ = rm;
|
|
||||||
*ldr_rm__ = TRUE_;
|
|
||||||
}
|
|
||||||
if (curve_1.iclm != 0 && curve_1.inx != 0) {
|
|
||||||
*t_alm__ = alm;
|
|
||||||
*ldr_alm__ = TRUE_;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*ier += 8;
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (lmoan[1]) {
|
|
||||||
def = edef[3 - *ifx - 1];
|
|
||||||
dakf = akdef[3 - *ifx - 1];
|
|
||||||
ex_case__(&dda, isa, &dakf, &a5, &a6, &ra, &ala, &c__1, ier);
|
|
||||||
if (*ier == 0) {
|
|
||||||
*akf = dakf;
|
|
||||||
*ef = def;
|
|
||||||
t_a__[5] = a5;
|
|
||||||
t_a__[6] = a6;
|
|
||||||
ldra[5] = TRUE_;
|
|
||||||
ldra[6] = TRUE_;
|
|
||||||
if (curve_1.icra != 0) {
|
|
||||||
*t_ra__ = ra;
|
|
||||||
*ldr_ra__ = TRUE_;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*ier += 8;
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* USE (QH,QK,QL) TO CALCULATE A3 AND A4 */
|
|
||||||
/* CALCULATE Q1 AND Q2 IN SCATTERING PLANE */
|
|
||||||
|
|
||||||
imod = 2;
|
|
||||||
if (lqhkle) {
|
|
||||||
for (id = 1; id <= 3; ++id) {
|
|
||||||
dqhkl[id - 1] = qhkl[id];
|
|
||||||
}
|
|
||||||
rl2spv_(dqhkl, dqt, &dqm, &dqs, ier);
|
|
||||||
if (*ier != 0) {
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
sam_case__(dqt, &dqm, &dqs, &daki, &dakf, &a3, a4, iss, ier);
|
|
||||||
if (*ier == 0) {
|
|
||||||
t_a__[3] = a3;
|
|
||||||
t_a__[4] = *a4;
|
|
||||||
ldra[3] = TRUE_;
|
|
||||||
ldra[4] = TRUE_;
|
|
||||||
*qm = dqm;
|
|
||||||
} else {
|
|
||||||
*ier += 4;
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* DEAL WITH FLIPPERS AND HELMOTZ COILS IF LPA */
|
|
||||||
|
|
||||||
if (*lpa) {
|
|
||||||
if (*ldf) {
|
|
||||||
flip_case__(if1, if2, &p_ih__[1], f1v, f1h, f2v, f2h, aki, akf,
|
|
||||||
ier);
|
|
||||||
}
|
|
||||||
if (*ldh) {
|
|
||||||
helm_case__(hx, hy, hz, &p_ih__[1], &c_ih__[1], aki, akf, a4, qm,
|
|
||||||
helm, ier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
L999:
|
|
||||||
if (*ier != 0) {
|
|
||||||
erreso_(&imod, ier);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
} /* t_conv__ */
|
|
||||||
|
|
||||||
|
|
||||||
/* Subroutine */ int ex_case__(doublereal *dx, integer *isx, doublereal *akx,
|
|
||||||
doublereal *ax1, doublereal *ax2, doublereal *rx, doublereal *alx,
|
|
||||||
integer *mon_or_anal__, integer *ier)
|
|
||||||
{
|
|
||||||
/* System generated locals */
|
|
||||||
doublereal d__1;
|
|
||||||
|
|
||||||
/* Builtin functions */
|
|
||||||
double asin(doublereal), sin(doublereal), cos(doublereal), sqrt(
|
|
||||||
doublereal);
|
|
||||||
|
|
||||||
/* Local variables */
|
|
||||||
static integer indx;
|
|
||||||
static doublereal dcl1r, dc1rx, dc2rx, drmin, drmax, my_rx__, arg;
|
|
||||||
|
|
||||||
/* ================== */
|
|
||||||
|
|
||||||
/* CALCULATE ANGLES ON MONO/ANALYSER */
|
|
||||||
/* CALCULATE AX1 AX2 */
|
|
||||||
/* CALCULATE RX = MONO OR ANAL CURVATURE AND LM = MONO POSIT FOR IN8 */
|
|
||||||
|
|
||||||
/* INPUTS */
|
|
||||||
/* DX D-SPACINGS */
|
|
||||||
/* ISX SENS OF SCATTERING ON CRYSTAL. If =0, this is probably */
|
|
||||||
/* a 3-axis instr. in simulated 2-axis mode and the */
|
|
||||||
/* calculation is for the scattering at the analyser. */
|
|
||||||
/* In this case, we set AX1 = AX2 = 0 which gives a */
|
|
||||||
/* "straight-through" setting of A5 & A6 (because of */
|
|
||||||
/* a simultaneous 90 degree zero offset for A5 -- this */
|
|
||||||
/* is a bit of a hack, if you ask me!). */
|
|
||||||
/* AKX TARGET OF MOMENTUM */
|
|
||||||
/* MON_OR_ANAL =0 if calculation is for mono. */
|
|
||||||
/* =1 if calculation is for anal. */
|
|
||||||
/* OUTPUTS */
|
|
||||||
/* AX1 AX2 THETA 2*THETA ANGLES */
|
|
||||||
/* RX MONO OR ANALYSER CURVATURE */
|
|
||||||
/* ALX SPECIAL TRANSLATION FOR IN8 */
|
|
||||||
/* IER */
|
|
||||||
/* 1 'KI OR KF CANNOT BE OBTAINED CHECK D-SPACINGS', */
|
|
||||||
/* 2 'KI OR KF TOO SMALL', */
|
|
||||||
/* 3 'KI OR KF TOO BIG', */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Part of T_CONV.FOR */
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Define the dummy arguments */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* include 'curve.inc' */
|
|
||||||
/* include 'motdef.inc' */
|
|
||||||
/* include 'iolsddef.inc' */
|
|
||||||
|
|
||||||
/* real*4 tbut(5,NBMOT) */
|
|
||||||
/* equivalence (rbut, tbut) */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* LOCAL VAR */
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* INIT AND TEST */
|
|
||||||
|
|
||||||
*ier = 0;
|
|
||||||
*ax1 = 0.f;
|
|
||||||
*ax2 = 0.f;
|
|
||||||
*rx = 0.f;
|
|
||||||
*alx = 0.f;
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
/* Check validity of inputs. */
|
|
||||||
if (*dx < .1) {
|
|
||||||
*ier = 1;
|
|
||||||
}
|
|
||||||
if (*akx < .1) {
|
|
||||||
*ier = 2;
|
|
||||||
}
|
|
||||||
arg = 3.1415926535897932384626433832795 / (*dx * *akx);
|
|
||||||
if (abs(arg) > 1.f) {
|
|
||||||
*ier = 3;
|
|
||||||
}
|
|
||||||
if (*ier != 0) {
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
if (*mon_or_anal__ == 0) {
|
|
||||||
/* Use monochr or anal params? */
|
|
||||||
indx = curve_1.icrm;
|
|
||||||
/* Monochr, so set up params. */
|
|
||||||
dc1rx = curve_1.cm1rx;
|
|
||||||
dc2rx = curve_1.cm2rx;
|
|
||||||
dcl1r = (doublereal) curve_1.iclm;
|
|
||||||
drmin = curve_1.rmmin;
|
|
||||||
drmax = curve_1.rmmax;
|
|
||||||
} else {
|
|
||||||
indx = curve_1.icra;
|
|
||||||
/* Analyser, so set up params. */
|
|
||||||
dc1rx = curve_1.ca1rx;
|
|
||||||
/* There is no ALX in this case. */
|
|
||||||
dc2rx = curve_1.ca2rx;
|
|
||||||
drmin = curve_1.ramin;
|
|
||||||
drmax = curve_1.ramax;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if (indx .ne. 0) then ! Include zero-offset in min/max */
|
|
||||||
/* drmin = drmin + tbut(3,indx) */
|
|
||||||
/* drmax = drmax + tbut(3,indx) */
|
|
||||||
/* if (drmin .lt. tbut(1,indx)) drmin = tbut(1,indx) */
|
|
||||||
/* if (drmax .gt. tbut(2,indx)) drmax = tbut(2,indx) */
|
|
||||||
/* endif */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Calculation of the two angles */
|
|
||||||
|
|
||||||
if (*isx == 0) {
|
|
||||||
/* "Straight-through" mode? */
|
|
||||||
*ax1 = 0.f;
|
|
||||||
/* Yes. */
|
|
||||||
*ax2 = 0.f;
|
|
||||||
*rx = drmin;
|
|
||||||
*alx = 0.f;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
*ax1 = asin(arg) * *isx * 57.29577951308232087679815481410517;
|
|
||||||
*ax2 = *ax1 * 2.;
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Calculation of mono curvature RM or analyser curvature RA */
|
|
||||||
/* Standard law is: */
|
|
||||||
|
|
||||||
/* For monochr: */
|
|
||||||
/* CM1RX + CM2RX/SIN(abs(A1)/RD) */
|
|
||||||
|
|
||||||
/* For analyser: */
|
|
||||||
/* CA1RX + CA2RX*SIN(abs(A5)/RD) */
|
|
||||||
|
|
||||||
/* CM1RX/CM2RX/CA1RX/CA2RX are parameters depending on monochr/analyser and */
|
|
||||||
/* instrument. They are read from CURVE.INI in routine SETUP_MOT_CURVE. */
|
|
||||||
/* e.g. cm1rx = .47 */
|
|
||||||
/* cm2rx = .244 */
|
|
||||||
/* rmmin = 0. */
|
|
||||||
/* rmmax = 20. */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
if (*mon_or_anal__ == 0) {
|
|
||||||
/* Monochr or analyser? */
|
|
||||||
if (curve_1.inx != 0) {
|
|
||||||
/* Monochr. Is there a translation? */
|
|
||||||
if (curve_1.iclm != 0) {
|
|
||||||
/* Yes, IN8 case. If there's a .. */
|
|
||||||
*alx = dcl1r / sin(*ax2 / 57.29577951308232087679815481410517)
|
|
||||||
* cos(*ax2 / 57.29577951308232087679815481410517);
|
|
||||||
/* .. motor, do the .. */
|
|
||||||
*rx = dc2rx * sqrt(sin(abs(*ax2) /
|
|
||||||
57.29577951308232087679815481410517)) - dc1rx;
|
|
||||||
/* .. calculation. */
|
|
||||||
/* Computing MIN */
|
|
||||||
d__1 = max(*rx,drmin);
|
|
||||||
*rx = min(d__1,drmax);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Not IN8 case so, .. */
|
|
||||||
my_rx__ = dc1rx + dc2rx / sin(abs(*ax1) /
|
|
||||||
57.29577951308232087679815481410517);
|
|
||||||
/* .. simply calculate. */
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Analyser. */
|
|
||||||
my_rx__ = dc1rx + dc2rx * sin(abs(*ax1) /
|
|
||||||
57.29577951308232087679815481410517);
|
|
||||||
/* Simply calculate. */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (indx != 0) {
|
|
||||||
/* If there's a motor, return the curvature. */
|
|
||||||
/* Computing MIN */
|
|
||||||
d__1 = max(my_rx__,drmin);
|
|
||||||
*rx = min(d__1,drmax);
|
|
||||||
/* if (rx .ne. my_rx) then */
|
|
||||||
/* write (iolun, 101, iostat=ios) motnam(indx), my_rx */
|
|
||||||
/* 101 format (' Warning -- ', a8, 'curvature restricted by low ', */
|
|
||||||
/* + 'or high limits!'/ */
|
|
||||||
/* + ' Calculated curvature was', f9.2) */
|
|
||||||
/* endif */
|
|
||||||
}
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
L999:
|
|
||||||
return 0;
|
|
||||||
} /* ex_case__ */
|
|
||||||
|
|
||||||
|
|
||||||
/* Subroutine */ int sam_case__(doublereal *qt, doublereal *qm, doublereal *
|
|
||||||
qs, doublereal *aki, doublereal *akf, doublereal *ax3, doublereal *
|
|
||||||
ax4, integer *iss, integer *ier)
|
|
||||||
{
|
|
||||||
/* System generated locals */
|
|
||||||
doublereal d__1, d__2;
|
|
||||||
|
|
||||||
/* Builtin functions */
|
|
||||||
double acos(doublereal), atan2(doublereal, doublereal), d_sign(doublereal
|
|
||||||
*, doublereal *), d_mod(doublereal *, doublereal *);
|
|
||||||
|
|
||||||
/* Local variables */
|
|
||||||
static doublereal arg, sax3;
|
|
||||||
|
|
||||||
/* =================== */
|
|
||||||
|
|
||||||
/* DEAL WITH SAMPLE ANGLES CALCULATION FROM Q VECTOR IN C-N PLANE */
|
|
||||||
/* CALCULATE A3 AND A4 */
|
|
||||||
/* INPUTS */
|
|
||||||
/* QT Q-VECTOR IN SCATTERING PLANE */
|
|
||||||
/* QM,QS Q MODULUS AND QMODULUS SQUARED */
|
|
||||||
/* AKI,AKF MOMEMTA ON MONO AND ANYLSER */
|
|
||||||
/* ISS SENS OF SCATTERING ON SAMPLE */
|
|
||||||
|
|
||||||
/* OUTPUTS */
|
|
||||||
/* AX3 AX4 ANGLES ON SAMPLES */
|
|
||||||
/* IER SAME ERROR AS RL2SPV */
|
|
||||||
/* IER */
|
|
||||||
/* 1 'MATRIX S NOT OK', */
|
|
||||||
/* 2 'Q NOT IN SCATTERING PLANE', */
|
|
||||||
/* 3 'Q MODULUS TOO SMALL', */
|
|
||||||
/* 4 'Q MODULUS TOO BIG', */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Part of T_CONV.FOR */
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Define the dummy arguments */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Local variables */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* INIT AND TEST */
|
|
||||||
|
|
||||||
/* Parameter adjustments */
|
|
||||||
--qt;
|
|
||||||
|
|
||||||
/* Function Body */
|
|
||||||
*ier = 0;
|
|
||||||
if (abs(*qs) < 1e-6 || abs(*qm) < .001) {
|
|
||||||
*ier = 3;
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* CALCULATE A3 AND MOVE IT INTHE -180 ,+180 INTERVAL */
|
|
||||||
|
|
||||||
/* Computing 2nd power */
|
|
||||||
d__1 = *aki;
|
|
||||||
/* Computing 2nd power */
|
|
||||||
d__2 = *akf;
|
|
||||||
arg = (d__1 * d__1 + d__2 * d__2 - *qs) / (*aki * 2. * *akf);
|
|
||||||
if (abs(arg) > 1.) {
|
|
||||||
*ier = 4;
|
|
||||||
goto L999;
|
|
||||||
} else {
|
|
||||||
*ax4 = acos(arg) * *iss * 57.29577951308232087679815481410517;
|
|
||||||
}
|
|
||||||
/* Computing 2nd power */
|
|
||||||
d__1 = *akf;
|
|
||||||
/* Computing 2nd power */
|
|
||||||
d__2 = *aki;
|
|
||||||
*ax3 = (-atan2(qt[2], qt[1]) - acos((d__1 * d__1 - *qs - d__2 * d__2) / (*
|
|
||||||
qm * -2. * *aki)) * d_sign(&c_b10, ax4)) *
|
|
||||||
57.29577951308232087679815481410517;
|
|
||||||
sax3 = d_sign(&c_b10, ax3);
|
|
||||||
d__1 = *ax3 + sax3 * 180.;
|
|
||||||
*ax3 = d_mod(&d__1, &c_b12) - sax3 * 180.;
|
|
||||||
|
|
||||||
/* IF(LPLATE) AX3 = -ATAN(SIN(AX4/RD)/(LSA*TAN(AX5/RD)/(ALMS*C */
|
|
||||||
/* 1 TAN(AX1/RD))*(AKI/KF)**2-COS(AX4/RD)))*RD !PLATE FOCALIZATION OPTION */
|
|
||||||
/* IF(AXX3 .GT. 180.D0) AX3 = AX3-360.D0 */
|
|
||||||
/* IF( A3 .LT. -180.D0) AX3 = AX3+360.D0 */
|
|
||||||
/* IF(LPLATE .AND. (A3 .GT. 0.0)) AX3 = AX3-180 */
|
|
||||||
/* C----------------------------------------------------------------------- */
|
|
||||||
L999:
|
|
||||||
return 0;
|
|
||||||
} /* sam_case__ */
|
|
||||||
|
|
||||||
|
|
||||||
/* Subroutine */ int helm_case__(real *hx, real *hy, real *hz, real *t_ih__,
|
|
||||||
real *c_ih__, real *aki, real *akf, doublereal *a4, real *qm, real *
|
|
||||||
helm, integer *ier)
|
|
||||||
{
|
|
||||||
/* System generated locals */
|
|
||||||
integer i__1;
|
|
||||||
real r__1, r__2;
|
|
||||||
|
|
||||||
/* Builtin functions */
|
|
||||||
double cos(doublereal), sin(doublereal), atan2(doublereal, doublereal),
|
|
||||||
sqrt(doublereal);
|
|
||||||
|
|
||||||
/* Local variables */
|
|
||||||
static doublereal hrad, hdir, qpar, hdir2;
|
|
||||||
static integer ncoef;
|
|
||||||
static doublereal qperp;
|
|
||||||
static integer ic;
|
|
||||||
static doublereal phi;
|
|
||||||
static logical at_sinq__;
|
|
||||||
|
|
||||||
/* ==================== */
|
|
||||||
|
|
||||||
/* DEAL WITH HELMOTZ COIL FIELD CALCULATIONS */
|
|
||||||
/* CALCULATE HX HY HZ */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* At ILL: */
|
|
||||||
/* There are 3 coils for Hx/Hy at 120 degrees to each other. */
|
|
||||||
|
|
||||||
/* There is a 4th coil for Hz. */
|
|
||||||
|
|
||||||
/* At SINQ: */
|
|
||||||
/* There is an Hx coil and an Hy coil (actually each is 4 coils powered */
|
|
||||||
/* in series). They are mounted on a ring (SRO). The value of HELM is */
|
|
||||||
/* the angle between the Hx coil and ki. */
|
|
||||||
|
|
||||||
/* There is a 3rd coil for Hz. */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Part of T_CONV.FOR */
|
|
||||||
|
|
||||||
/* include 'common_sinq.inc' */
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Define the dummy arguments */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Local variables */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* INIT AND TEST */
|
|
||||||
|
|
||||||
/* Parameter adjustments */
|
|
||||||
--c_ih__;
|
|
||||||
--t_ih__;
|
|
||||||
|
|
||||||
/* Function Body */
|
|
||||||
at_sinq__ = TRUE_;
|
|
||||||
ncoef = 4;
|
|
||||||
if (at_sinq__) {
|
|
||||||
ncoef = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
*ier = 1;
|
|
||||||
if (dabs(*qm) < 1e-4) {
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
*ier = 0;
|
|
||||||
i__1 = ncoef;
|
|
||||||
for (ic = 1; ic <= i__1; ++ic) {
|
|
||||||
if (c_ih__[ic] < 1e-4) {
|
|
||||||
*ier = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (*ier != 0) {
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* CALCULATE MODULE AND ANGLES OF IN PLANE FIELD H */
|
|
||||||
/* PHI ! Angle between Q and KI (in radians) */
|
|
||||||
/* HRAD ! Radial comp. of H */
|
|
||||||
/* HDIR ! Direction of H relative to PHI (in radians) */
|
|
||||||
/* HDIR2 ! Angle between field and axis of Coil 1 (in radians) */
|
|
||||||
|
|
||||||
qpar = *aki - *akf * cos(*a4 / 57.29577951308232087679815481410517);
|
|
||||||
qperp = -(*akf) * sin(*a4 / 57.29577951308232087679815481410517);
|
|
||||||
if (abs(qpar) > .001 && abs(qperp) > .001) {
|
|
||||||
phi = atan2((abs(qperp)), (abs(qpar)));
|
|
||||||
if (qpar > 0. && qperp < 0.) {
|
|
||||||
phi = -phi;
|
|
||||||
} else if (qpar < 0. && qperp > 0.) {
|
|
||||||
phi = 3.1415926535897932384626433832795 - phi;
|
|
||||||
} else if (qpar < 0. && qperp < 0.) {
|
|
||||||
phi += -3.1415926535897932384626433832795;
|
|
||||||
}
|
|
||||||
} else if (abs(qpar) > .001) {
|
|
||||||
if (qpar >= 0.f) {
|
|
||||||
phi = 0.f;
|
|
||||||
}
|
|
||||||
if (qpar < 0.f) {
|
|
||||||
phi = 3.1415926535897932384626433832795;
|
|
||||||
}
|
|
||||||
} else if (abs(qperp) > .001) {
|
|
||||||
if (qperp >= 0.f) {
|
|
||||||
phi = 1.5707963267948966;
|
|
||||||
}
|
|
||||||
if (qperp < 0.f) {
|
|
||||||
phi = -1.5707963267948966;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
phi = 0.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Computing 2nd power */
|
|
||||||
r__1 = *hx;
|
|
||||||
/* Computing 2nd power */
|
|
||||||
r__2 = *hy;
|
|
||||||
hrad = sqrt(r__1 * r__1 + r__2 * r__2);
|
|
||||||
if (dabs(*hx) > .001 && dabs(*hy) > .001) {
|
|
||||||
hdir = atan2((dabs(*hy)), (dabs(*hx)));
|
|
||||||
if (*hx > 0.f && *hy < 0.f) {
|
|
||||||
hdir = -hdir;
|
|
||||||
} else if (*hx < 0.f && *hy > 0.f) {
|
|
||||||
hdir = 3.1415926535897932384626433832795 - hdir;
|
|
||||||
} else if (*hx < 0.f && *hy < 0.f) {
|
|
||||||
hdir += -3.1415926535897932384626433832795;
|
|
||||||
}
|
|
||||||
} else if (dabs(*hx) > .001) {
|
|
||||||
if (*hx >= 0.f) {
|
|
||||||
hdir = 0.f;
|
|
||||||
}
|
|
||||||
if (*hx < 0.f) {
|
|
||||||
hdir = 3.1415926535897932384626433832795;
|
|
||||||
}
|
|
||||||
} else if (dabs(*hy) > .001) {
|
|
||||||
if (*hy >= 0.f) {
|
|
||||||
hdir = 1.5707963267948966;
|
|
||||||
}
|
|
||||||
if (*hy < 0.f) {
|
|
||||||
hdir = -1.5707963267948966;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
hdir = 0.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
hdir2 = hdir + phi - *helm / 57.29577951308232087679815481410517;
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* !CALC CURRENTS */
|
|
||||||
/* !POSITION OF PSP FOR COIL I */
|
|
||||||
|
|
||||||
if (! at_sinq__) {
|
|
||||||
hdir2 += 1.5707963267948966;
|
|
||||||
/* ??? */
|
|
||||||
for (ic = 1; ic <= 3; ++ic) {
|
|
||||||
t_ih__[ic + 4] = cos(hdir2 + (ic - 1) * 2.f *
|
|
||||||
3.1415926535897932384626433832795 / 3.f) * hrad / c_ih__[
|
|
||||||
ic] / 1.5f;
|
|
||||||
}
|
|
||||||
t_ih__[8] = *hz / c_ih__[4];
|
|
||||||
} else {
|
|
||||||
t_ih__[5] = cos(hdir2) * hrad / c_ih__[1];
|
|
||||||
t_ih__[6] = sin(hdir2) * hrad / c_ih__[2];
|
|
||||||
t_ih__[7] = *hz / c_ih__[3];
|
|
||||||
}
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
L999:
|
|
||||||
return 0;
|
|
||||||
} /* helm_case__ */
|
|
||||||
|
|
||||||
|
|
||||||
/* Subroutine */ int flip_case__(integer *if1, integer *if2, real *t_ih__,
|
|
||||||
real *f1v, real *f1h, real *f2v, real *f2h, real *aki, real *akf,
|
|
||||||
integer *ier)
|
|
||||||
{
|
|
||||||
/* ==================== */
|
|
||||||
|
|
||||||
/* DEAL WITH FLIPPER COIL CALCULATIONS */
|
|
||||||
/* CALCULATE P_IF CURRENTS FOR THE TWO FLIPPERS */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Define the dummy arguments */
|
|
||||||
/* Part of T_CONV.FOR */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* INIT AND TEST */
|
|
||||||
|
|
||||||
/* Parameter adjustments */
|
|
||||||
--t_ih__;
|
|
||||||
|
|
||||||
/* Function Body */
|
|
||||||
*ier = 0;
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
if (*if1 == 1) {
|
|
||||||
t_ih__[1] = *f1v;
|
|
||||||
t_ih__[2] = *aki * *f1h;
|
|
||||||
} else {
|
|
||||||
t_ih__[1] = 0.f;
|
|
||||||
t_ih__[2] = 0.f;
|
|
||||||
}
|
|
||||||
if (*if2 == 1) {
|
|
||||||
t_ih__[3] = *f2v;
|
|
||||||
t_ih__[4] = *akf * *f2h;
|
|
||||||
} else {
|
|
||||||
t_ih__[3] = 0.f;
|
|
||||||
t_ih__[4] = 0.f;
|
|
||||||
}
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* L999: */
|
|
||||||
return 0;
|
|
||||||
} /* flip_case__ */
|
|
||||||
|
|
690
t_conv.f
690
t_conv.f
@ -1,690 +0,0 @@
|
|||||||
C------------------------------------------------------------------------
|
|
||||||
C slightly edited version for inclusion into SICS
|
|
||||||
C
|
|
||||||
C Mark Koennecke, November 2000
|
|
||||||
C
|
|
||||||
C Found that ERRESO looks error messages up in a 2D array. Modified IER
|
|
||||||
C values to refer to a 1D array.
|
|
||||||
C
|
|
||||||
C Mark Koennecke, January 2002
|
|
||||||
C-------------------------------------------------------------------------
|
|
||||||
SUBROUTINE INICURVE(MIDX, MRX1, MRX2, AIDX, ARX1, ARX2,
|
|
||||||
+ MMIN, MMAX, AMIN, AMAX)
|
|
||||||
C
|
|
||||||
C Initializes a common with the curvature parameters.
|
|
||||||
C In: monochrmoator curvatuure motor index and parameters
|
|
||||||
C In: analyzer curvature motor index + parameters
|
|
||||||
INTEGER MIDX, AIDX
|
|
||||||
REAL*4 MRX1, MRX2, ARX1, ARX2, MMIN, MMAX, AMIN, AMAX
|
|
||||||
REAL*4 CM1RX, CM2RX, CA1RX, CA2RX, RMMIN, RMMAX
|
|
||||||
REAL*4 RAMIN, RAMAX
|
|
||||||
INTEGER ICRM, ICRA, ICLM, INX
|
|
||||||
LOGICAL AT_SINQ
|
|
||||||
COMMON/CURVE/ICRM,ICRA, ICLM, CM1RX, CM2RX, CA1RX, CA2RX,
|
|
||||||
+ RMMIN, RMMAX, RAMIN, RAMAX, INX, AT_SINQ
|
|
||||||
|
|
||||||
ICRM = MIDX
|
|
||||||
ICRA = AIDX
|
|
||||||
CM1RX = MRX1
|
|
||||||
CM2RX = MRX2
|
|
||||||
CA1RX = ARX1
|
|
||||||
CA2RX = ARX2
|
|
||||||
RMMIN = MMIN
|
|
||||||
RMMAX = MMAX
|
|
||||||
RAMIN = AMIN
|
|
||||||
RAMAX = AMAX
|
|
||||||
INX = 0
|
|
||||||
AT_SINQ = .TRUE.
|
|
||||||
ICLM = 0
|
|
||||||
RETURN
|
|
||||||
END
|
|
||||||
C--------------------------------------------------------------------------
|
|
||||||
SUBROUTINE T_CONV ( ! File [MAD.SRC]T_CONV.FOR
|
|
||||||
c =================
|
|
||||||
+ EI, AKI, EF, AKF, QHKL, EN,
|
|
||||||
+ HX, HY, HZ,
|
|
||||||
+ IF1, IF2,
|
|
||||||
+ LDK, LDH, LDF, LPA,
|
|
||||||
+ DM, DA,
|
|
||||||
+ HELM, F1H, F1V, F2H, F2V, F,
|
|
||||||
+ IFX, ISS, ISM, ISA,
|
|
||||||
+ T_A, T_RM, T_ALM, T_RA, QM,
|
|
||||||
+ LDRA, LDR_RM, LDR_ALM, LDR_RA,
|
|
||||||
+ P_IH, C_IH, A4,
|
|
||||||
+ IER)
|
|
||||||
c
|
|
||||||
cdec$ ident 'V01D'
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C Other routines in this file:
|
|
||||||
c
|
|
||||||
C SUBROUTINE EX_CASE (DX,ISX,AKX,AX1,AX2,RX,ALX,IER)
|
|
||||||
C SUBROUTINE SAM_CASE (QT,QM,QS,AKI,AKF,AX3,AX4,ISS,IER)
|
|
||||||
C SUBROUTINE HELM_CASE (HX,HY,HZ,P_IH,AKI,AKF,A4,QM,HELM,IER)
|
|
||||||
C SUBROUTINE FLIP_CASE (IF1,IF2,P_IH,F1V,F1H,F2V,F2H,AKI,AKF,IER)
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C INPUTS
|
|
||||||
C EI,AKI,EF,AKF,QHKL,EN,HX,HY,HZ : POTENTIAL TARGETS
|
|
||||||
C IF1,IF2 Status of flippers On (1) Off (0)
|
|
||||||
C LDK(8) LOGICAL INDICATING IF (ENERGY,K OR Q) ARE DRIVEN
|
|
||||||
C LDH,LDF LOGICAL INDICATING IF (HX,HY,HZ) OR (F1,F2) ARE DRIVEN
|
|
||||||
C
|
|
||||||
C configuration of the machine
|
|
||||||
c
|
|
||||||
C LPA LOGICAL TRUE IF MACHINE IN POLARIZATION MODE
|
|
||||||
C DM,DA,HELM,F1H,F1V,F2H,F2V,F,IFX,ISS,ISM,ISA,QM (F ENERGY UNIT)
|
|
||||||
C
|
|
||||||
C OUTPUTs
|
|
||||||
C T_A TARGETS OF ANGLES A1-A6
|
|
||||||
C T_RM,T_ALM TARGETS OF RM ,LM
|
|
||||||
C T_RA TARGET OF RA
|
|
||||||
C QM TARGETS OF QM
|
|
||||||
C LDRA LOGICAL INDICATING WHICH ANGLES ARE TO BE DRIVEN
|
|
||||||
C LDR_RM LOGICAL INDICATING IF RM (mono curve) IS TO BE DRIVEN
|
|
||||||
C LDR_ALM LOGICAL INDICATING IF ALM (mono transl) IS TO BE DRIVEN
|
|
||||||
C LDR_RA LOGICAL INDICATING IF RA (anal curve) IS TO BE DRIVEN
|
|
||||||
C P_IH TARGETS OF CURRENTS FOR FLIPPERS AND HELMOTZ (8 CURRENTS)
|
|
||||||
C C_IH CONVERSION FACTORS FOR HELMOTZ (4 CURRENTS)
|
|
||||||
C
|
|
||||||
C SPECIAL OUTPUTS
|
|
||||||
C TARGET OF EI(EF) IS UPDATED IS KI(KF) IS DRIVEN
|
|
||||||
C TARGET OF VARIABLE ENERGY IS UPDATED IF EN IS DRIVEN
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
implicit none
|
|
||||||
c
|
|
||||||
REAL*4 EPS1, EPS4
|
|
||||||
parameter (EPS1 = 1.D-1)
|
|
||||||
parameter (EPS4 = 1.D-4)
|
|
||||||
INTEGER ICRM, ICRA, ICLM, INX
|
|
||||||
LOGICAL AT_SINQ
|
|
||||||
REAL*4 CM1RX, CM2RX, CA1RX, CA2RX, RMMIN, RMMAX
|
|
||||||
REAL*4 RAMIN, RAMAX
|
|
||||||
COMMON/CURVE/ICRM,ICRA, ICLM, CM1RX, CM2RX, CA1RX, CA2RX,
|
|
||||||
+ RMMIN, RMMAX, RAMIN, RAMAX, INX, AT_SINQ
|
|
||||||
c
|
|
||||||
C include 'curve.inc'
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C Define the dummy arguments
|
|
||||||
c
|
|
||||||
real*4 ei, aki, ef, akf, qhkl(3), en
|
|
||||||
real*4 hx, hy, hz
|
|
||||||
integer*4 if1, if2
|
|
||||||
logical*4 ldk(8), ldh, ldf, lpa
|
|
||||||
real*4 dm, da
|
|
||||||
real*4 helm, f1h, f1v, f2h, f2v, f
|
|
||||||
integer*4 ifx, iss, ism, isa
|
|
||||||
real*4 t_a(6), t_rm, t_alm, t_ra, qm
|
|
||||||
logical*4 ldra(6), ldr_rm, ldr_alm, ldr_ra
|
|
||||||
real*4 p_ih(8), c_ih(4)
|
|
||||||
integer*4 ier
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C LOCAL VARIABLES
|
|
||||||
C
|
|
||||||
integer*4 i, id, imod, iq
|
|
||||||
logical*4 lmoan(2), lqhkle
|
|
||||||
c
|
|
||||||
double precision a1, a2, a3, a4, a5, a6
|
|
||||||
double precision ala, alm, dakf, daki, dqm, dqs
|
|
||||||
double precision def, dei
|
|
||||||
double precision ra, rm
|
|
||||||
double precision edef(2), akdef(2), dqhkl(3), dqt(3)
|
|
||||||
double precision ddm, dda
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C SET UP
|
|
||||||
C IMOD INDEX FOR ERROR TREATMENAT BY ERRESO
|
|
||||||
C LDQHKLE : LOGICAL INDICATING THAT WE ARE DEALING WITH A MOVE
|
|
||||||
C IN RECIPROCICAL SPACE
|
|
||||||
C WE REMAP THE ENERGY PB AS FIXED ENERGY IN EDEF(1)
|
|
||||||
C AND VARIABLE ENERGY IN EDEF(2)
|
|
||||||
C IF ISA IS NUL SET IFX TO 1 AND PUT EF,KF, EQUAL TO EI,KI
|
|
||||||
C
|
|
||||||
IMOD = 3
|
|
||||||
DDM = DM
|
|
||||||
DDA = DA
|
|
||||||
DO I = 1,2
|
|
||||||
LMOAN(I) = .FALSE.
|
|
||||||
ENDDO
|
|
||||||
LQHKLE = .FALSE.
|
|
||||||
DO IQ = 5,8
|
|
||||||
LQHKLE = (LQHKLE .OR. LDK(IQ))
|
|
||||||
ENDDO
|
|
||||||
DAKI = AKI
|
|
||||||
DAKF = AKF
|
|
||||||
IF (ISA .EQ. 0) IFX = 1
|
|
||||||
EDEF(IFX) = EI
|
|
||||||
AKDEF(IFX) = AKI
|
|
||||||
EDEF(3-IFX) = EF
|
|
||||||
AKDEF(3-IFX) = AKF
|
|
||||||
IF( ISA .EQ. 0) THEN
|
|
||||||
EDEF(2) = EDEF(1)
|
|
||||||
AKDEF(2) = AKDEF(1)
|
|
||||||
LDK(3) = .TRUE.
|
|
||||||
LDK(4) = .TRUE.
|
|
||||||
T_A(5) = 0.
|
|
||||||
T_A(6) = 0.
|
|
||||||
LDRA(5) = .TRUE.
|
|
||||||
LDRA(6) = .TRUE.
|
|
||||||
ENDIF
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C FIRST TAKE IN ACCOUNT THE FIXED ENERGY PB
|
|
||||||
C
|
|
||||||
IF (LDK(2*IFX-1) .OR. LDK(2*IFX)) THEN
|
|
||||||
LMOAN(IFX) = .TRUE.
|
|
||||||
IF (LDK(2*IFX-1)) THEN
|
|
||||||
IER = 1 + 8
|
|
||||||
IF(EDEF(1) .LT. EPS1) GOTO 999
|
|
||||||
IER = 0
|
|
||||||
AKDEF(1) = SQRT(EDEF(1)/F)
|
|
||||||
ELSE
|
|
||||||
IER = 1 + 8
|
|
||||||
IF(AKDEF(1) .LT. EPS1) GOTO 999
|
|
||||||
IER = 0
|
|
||||||
EDEF(1) = F*AKDEF(1)**2
|
|
||||||
ENDIF
|
|
||||||
ENDIF
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C NOW TAKE IN ACCOUNT THE VARIABLE ENERGY PB
|
|
||||||
C VARIABLE ENERGUY IS DRIVEN EITHER EXPLICITLY
|
|
||||||
C E.G. BY DRIVING EI OR KI WITH IFX=2
|
|
||||||
C ( AND WE MUST CALCULATE EN FROM EVAR)
|
|
||||||
C THE RULE IS : EI=EF+EN : EN IS THE ENERGY LOSS OF NEUTRONS
|
|
||||||
C OR ENERGY GAIN OF SAMPLE
|
|
||||||
C OR IMPLICITLY BY DRIVING THE TRANSFERED ENERGY EN
|
|
||||||
C ( AND WE MUST CALCULATE EVAR FROM EN)
|
|
||||||
C IF KI IS CONSTANT USE THE CURRENT VALUE CONTAINED IN POSN ARRAY
|
|
||||||
C TO CALCULATE THE NON-"CONSTANT" K.
|
|
||||||
C IF KF IS CONSTANT USE ALWAYS THE VALUE IN TARGET AND
|
|
||||||
C DO A DRIVE OF KF TO KEEP A5/A6 IN RIGHT POSITION
|
|
||||||
C
|
|
||||||
IF (LDK(5-2*IFX) .OR. LDK(6-2*IFX)) THEN
|
|
||||||
LMOAN(3-IFX) = .TRUE.
|
|
||||||
IF (LDK(5-2*IFX)) THEN
|
|
||||||
IER = 1 + 8
|
|
||||||
IF(EDEF(2) .LT. EPS4) GOTO 999
|
|
||||||
IER = 0
|
|
||||||
AKDEF(2) = SQRT(EDEF(2)/F)
|
|
||||||
ELSE
|
|
||||||
IER = 1 + 8
|
|
||||||
IF(AKDEF(2) .LT. EPS4) GOTO 999
|
|
||||||
IER = 0
|
|
||||||
EDEF(2) = F*AKDEF(2)**2
|
|
||||||
ENDIF
|
|
||||||
EN = (3-2*IFX)*(EDEF(1)-EDEF(2))
|
|
||||||
ELSEIF (LQHKLE) THEN
|
|
||||||
LMOAN(3-IFX) = .TRUE.
|
|
||||||
EDEF(2) = EDEF(1)+(2*IFX-3)*EN
|
|
||||||
IER = 1 + 8
|
|
||||||
IF(EDEF(2) .LT. EPS4) GOTO 999
|
|
||||||
IER = 0
|
|
||||||
AKDEF(2) = SQRT(EDEF(2)/F)
|
|
||||||
ENDIF
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C CALCULATE MONOCHROMATOR AND ANALYSER ANGLES
|
|
||||||
C
|
|
||||||
IF(LMOAN(1)) THEN
|
|
||||||
DEI = EDEF(IFX)
|
|
||||||
DAKI = AKDEF(IFX)
|
|
||||||
CALL EX_CASE(DDM,ISM,DAKI,A1,A2,RM,ALM,0,IER)
|
|
||||||
IF (IER .EQ. 0) THEN
|
|
||||||
AKI = DAKI
|
|
||||||
EI = DEI
|
|
||||||
T_A(1) = A1
|
|
||||||
T_A(2) = A2
|
|
||||||
LDRA(1) = .TRUE.
|
|
||||||
LDRA(2) = .TRUE.
|
|
||||||
if (icrm .ne. 0) then
|
|
||||||
T_RM = RM
|
|
||||||
LDR_RM = .TRUE.
|
|
||||||
endif
|
|
||||||
if ((iclm .ne. 0) .and. (inx .ne. 0)) then
|
|
||||||
T_ALM = ALM
|
|
||||||
LDR_ALM = .TRUE.
|
|
||||||
endif
|
|
||||||
ELSE
|
|
||||||
IER = IER + 8
|
|
||||||
GOTO 999
|
|
||||||
ENDIF
|
|
||||||
ENDIF
|
|
||||||
IF(LMOAN(2)) THEN
|
|
||||||
DEF = EDEF(3-IFX)
|
|
||||||
DAKF = AKDEF(3-IFX)
|
|
||||||
CALL EX_CASE(DDA,ISA,DAKF,A5,A6,RA,ALA,1,IER)
|
|
||||||
IF (IER .EQ. 0) THEN
|
|
||||||
AKF = DAKF
|
|
||||||
EF = DEF
|
|
||||||
T_A(5) = A5
|
|
||||||
T_A(6) = A6
|
|
||||||
LDRA(5) = .TRUE.
|
|
||||||
LDRA(6) = .TRUE.
|
|
||||||
if (icra .ne. 0) then
|
|
||||||
T_RA = RA
|
|
||||||
LDR_RA = .TRUE.
|
|
||||||
endif
|
|
||||||
ELSE
|
|
||||||
IER = IER + 8
|
|
||||||
GOTO 999
|
|
||||||
ENDIF
|
|
||||||
ENDIF
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C USE (QH,QK,QL) TO CALCULATE A3 AND A4
|
|
||||||
C CALCULATE Q1 AND Q2 IN SCATTERING PLANE
|
|
||||||
C
|
|
||||||
IMOD = 2
|
|
||||||
IF (LQHKLE) THEN
|
|
||||||
DO ID = 1,3
|
|
||||||
DQHKL(ID) = QHKL(ID)
|
|
||||||
ENDDO
|
|
||||||
CALL RL2SPV(DQHKL,DQT,DQM,DQS,IER)
|
|
||||||
IF (IER .NE. 0) GOTO 999
|
|
||||||
CALL SAM_CASE(DQT,DQM,DQS,DAKI,DAKF,A3,A4,ISS,IER)
|
|
||||||
IF (IER .EQ. 0) THEN
|
|
||||||
T_A(3) = A3
|
|
||||||
T_A(4) = A4
|
|
||||||
LDRA(3) = .TRUE.
|
|
||||||
LDRA(4) = .TRUE.
|
|
||||||
QM = DQM
|
|
||||||
ELSE
|
|
||||||
IER = IER + 4
|
|
||||||
GOTO 999
|
|
||||||
ENDIF
|
|
||||||
ENDIF
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C DEAL WITH FLIPPERS AND HELMOTZ COILS IF LPA
|
|
||||||
C
|
|
||||||
IF (LPA) THEN
|
|
||||||
IF (LDF) CALL FLIP_CASE(IF1,IF2,P_IH,F1V,F1H,F2V,F2H,
|
|
||||||
+ AKI,AKF,IER)
|
|
||||||
IF (LDH) CALL HELM_CASE(HX,HY,HZ,P_IH,C_IH,AKI,AKF,
|
|
||||||
+ A4,QM,HELM,IER)
|
|
||||||
endif
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
999 CONTINUE
|
|
||||||
IF (IER .NE. 0) CALL ERRESO(IMOD,IER)
|
|
||||||
RETURN
|
|
||||||
END
|
|
||||||
c
|
|
||||||
SUBROUTINE EX_CASE ( ! Part of T_CONV.FOR
|
|
||||||
c ==================
|
|
||||||
+ DX,ISX,AKX,AX1,AX2,RX,ALX,MON_OR_ANAL,IER)
|
|
||||||
C
|
|
||||||
C CALCULATE ANGLES ON MONO/ANALYSER
|
|
||||||
C CALCULATE AX1 AX2
|
|
||||||
C CALCULATE RX = MONO OR ANAL CURVATURE AND LM = MONO POSIT FOR IN8
|
|
||||||
C
|
|
||||||
C INPUTS
|
|
||||||
C DX D-SPACINGS
|
|
||||||
C ISX SENS OF SCATTERING ON CRYSTAL. If =0, this is probably
|
|
||||||
c a 3-axis instr. in simulated 2-axis mode and the
|
|
||||||
c calculation is for the scattering at the analyser.
|
|
||||||
c In this case, we set AX1 = AX2 = 0 which gives a
|
|
||||||
c "straight-through" setting of A5 & A6 (because of
|
|
||||||
c a simultaneous 90 degree zero offset for A5 -- this
|
|
||||||
c is a bit of a hack, if you ask me!).
|
|
||||||
C AKX TARGET OF MOMENTUM
|
|
||||||
c MON_OR_ANAL =0 if calculation is for mono.
|
|
||||||
c =1 if calculation is for anal.
|
|
||||||
C OUTPUTS
|
|
||||||
C AX1 AX2 THETA 2*THETA ANGLES
|
|
||||||
C RX MONO OR ANALYSER CURVATURE
|
|
||||||
C ALX SPECIAL TRANSLATION FOR IN8
|
|
||||||
C IER
|
|
||||||
C 1 'KI OR KF CANNOT BE OBTAINED CHECK D-SPACINGS',
|
|
||||||
C 2 'KI OR KF TOO SMALL',
|
|
||||||
C 3 'KI OR KF TOO BIG',
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
implicit none
|
|
||||||
c
|
|
||||||
double precision PI, RD, EPS1
|
|
||||||
PARAMETER (PI = 3.14159265358979323846264338327950D0)
|
|
||||||
PARAMETER (RD = 57.29577951308232087679815481410517D0)
|
|
||||||
PARAMETER (EPS1 = 1.D-1)
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C Define the dummy arguments
|
|
||||||
double precision dx
|
|
||||||
integer*4 isx
|
|
||||||
double precision akx, ax1, ax2, rx, alx
|
|
||||||
integer*4 mon_or_anal, ier
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C include 'curve.inc'
|
|
||||||
C include 'motdef.inc'
|
|
||||||
C include 'iolsddef.inc'
|
|
||||||
c
|
|
||||||
INTEGER ICRM, ICRA, ICLM, INX
|
|
||||||
LOGICAL AT_SINQ
|
|
||||||
REAL*4 CM1RX, CM2RX, CA1RX, CA2RX, RMMIN, RMMAX
|
|
||||||
REAL*4 RAMIN, RAMAX
|
|
||||||
COMMON/CURVE/ICRM,ICRA, ICLM, CM1RX, CM2RX, CA1RX, CA2RX,
|
|
||||||
+ RMMIN, RMMAX, RAMIN, RAMAX, INX, AT_SINQ
|
|
||||||
|
|
||||||
C real*4 tbut(5,NBMOT)
|
|
||||||
C equivalence (rbut, tbut)
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C LOCAL VAR
|
|
||||||
c
|
|
||||||
double precision arg, dc1rx, dc2rx, drmin, drmax, dcl1r, my_rx
|
|
||||||
integer*4 ios, indx
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C INIT AND TEST
|
|
||||||
C
|
|
||||||
ier = 0
|
|
||||||
ax1 = 0.0
|
|
||||||
ax2 = 0.0
|
|
||||||
rx = 0.0
|
|
||||||
alx = 0.0
|
|
||||||
c----------------------------------------------------------------------
|
|
||||||
c Check validity of inputs.
|
|
||||||
if (dx .lt. EPS1) ier = 1
|
|
||||||
if (akx .lt. EPS1) ier = 2
|
|
||||||
arg = PI/(dx * akx)
|
|
||||||
if (abs(arg) .gt. 1.0) ier = 3
|
|
||||||
if (ier .ne. 0) goto 999
|
|
||||||
c----------------------------------------------------------------------
|
|
||||||
if (mon_or_anal .eq. 0) then ! Use monochr or anal params?
|
|
||||||
indx = icrm ! Monochr, so set up params.
|
|
||||||
dc1rx = cm1rx
|
|
||||||
dc2rx = cm2rx
|
|
||||||
dcl1r = ICLM
|
|
||||||
drmin = rmmin
|
|
||||||
drmax = rmmax
|
|
||||||
else
|
|
||||||
indx = icra ! Analyser, so set up params.
|
|
||||||
dc1rx = ca1rx ! There is no ALX in this case.
|
|
||||||
dc2rx = ca2rx
|
|
||||||
drmin = ramin
|
|
||||||
drmax = ramax
|
|
||||||
endif
|
|
||||||
c
|
|
||||||
C if (indx .ne. 0) then ! Include zero-offset in min/max
|
|
||||||
C drmin = drmin + tbut(3,indx)
|
|
||||||
C drmax = drmax + tbut(3,indx)
|
|
||||||
C if (drmin .lt. tbut(1,indx)) drmin = tbut(1,indx)
|
|
||||||
C if (drmax .gt. tbut(2,indx)) drmax = tbut(2,indx)
|
|
||||||
C endif
|
|
||||||
c-----------------------------------------------------------------------
|
|
||||||
c Calculation of the two angles
|
|
||||||
c
|
|
||||||
if (isx .eq. 0) then ! "Straight-through" mode?
|
|
||||||
ax1 = 0.0 ! Yes.
|
|
||||||
ax2 = 0.0
|
|
||||||
rx = drmin
|
|
||||||
alx = 0.0
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
c
|
|
||||||
ax1 = asin (arg) * isx * rd
|
|
||||||
ax2 = 2.0d0 * ax1
|
|
||||||
c-----------------------------------------------------------------------
|
|
||||||
c Calculation of mono curvature RM or analyser curvature RA
|
|
||||||
c Standard law is:
|
|
||||||
c
|
|
||||||
c For monochr:
|
|
||||||
c CM1RX + CM2RX/SIN(abs(A1)/RD)
|
|
||||||
c
|
|
||||||
c For analyser:
|
|
||||||
c CA1RX + CA2RX*SIN(abs(A5)/RD)
|
|
||||||
c
|
|
||||||
c CM1RX/CM2RX/CA1RX/CA2RX are parameters depending on monochr/analyser and
|
|
||||||
c instrument. They are read from CURVE.INI in routine SETUP_MOT_CURVE.
|
|
||||||
c e.g. cm1rx = .47
|
|
||||||
c cm2rx = .244
|
|
||||||
c rmmin = 0.
|
|
||||||
c rmmax = 20.
|
|
||||||
c-----------------------------------------------------------------------
|
|
||||||
if (mon_or_anal .eq. 0) then ! Monochr or analyser?
|
|
||||||
if (inx .ne. 0) then ! Monochr. Is there a translation?
|
|
||||||
if (iclm .ne. 0) then ! Yes, IN8 case. If there's a ..
|
|
||||||
alx = (dcl1r/sin(ax2/rd)) * cos(ax2/rd) ! .. motor, do the ..
|
|
||||||
rx = dc2rx * sqrt(sin(abs(ax2)/rd)) - dc1rx ! .. calculation.
|
|
||||||
rx = dmin1 (dmax1 (rx, drmin), drmax)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
else ! Not IN8 case so, ..
|
|
||||||
my_rx = dc1rx + dc2rx/sin(abs(ax1)/rd) ! .. simply calculate.
|
|
||||||
endif
|
|
||||||
else ! Analyser.
|
|
||||||
my_rx = dc1rx + dc2rx * sin(abs(ax1)/rd) ! Simply calculate.
|
|
||||||
endif
|
|
||||||
c
|
|
||||||
if (indx .ne. 0) then ! If there's a motor, return the curvature.
|
|
||||||
rx = dmin1 (dmax1 (my_rx, drmin), drmax)
|
|
||||||
C if (rx .ne. my_rx) then
|
|
||||||
C write (iolun, 101, iostat=ios) motnam(indx), my_rx
|
|
||||||
C 101 format (' Warning -- ', a8, 'curvature restricted by low ',
|
|
||||||
C + 'or high limits!'/
|
|
||||||
C + ' Calculated curvature was', f9.2)
|
|
||||||
C endif
|
|
||||||
endif
|
|
||||||
c-----------------------------------------------------------------------
|
|
||||||
999 continue
|
|
||||||
return
|
|
||||||
end
|
|
||||||
c
|
|
||||||
SUBROUTINE SAM_CASE ( ! Part of T_CONV.FOR
|
|
||||||
c ===================
|
|
||||||
+ QT,QM,QS,AKI,AKF,AX3,AX4,ISS,IER)
|
|
||||||
C
|
|
||||||
C DEAL WITH SAMPLE ANGLES CALCULATION FROM Q VECTOR IN C-N PLANE
|
|
||||||
C CALCULATE A3 AND A4
|
|
||||||
C INPUTS
|
|
||||||
C QT Q-VECTOR IN SCATTERING PLANE
|
|
||||||
C QM,QS Q MODULUS AND QMODULUS SQUARED
|
|
||||||
C AKI,AKF MOMEMTA ON MONO AND ANYLSER
|
|
||||||
C ISS SENS OF SCATTERING ON SAMPLE
|
|
||||||
C
|
|
||||||
C OUTPUTS
|
|
||||||
C AX3 AX4 ANGLES ON SAMPLES
|
|
||||||
C IER SAME ERROR AS RL2SPV
|
|
||||||
C IER
|
|
||||||
C 1 'MATRIX S NOT OK',
|
|
||||||
C 2 'Q NOT IN SCATTERING PLANE',
|
|
||||||
C 3 'Q MODULUS TOO SMALL',
|
|
||||||
C 4 'Q MODULUS TOO BIG',
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
implicit none
|
|
||||||
c
|
|
||||||
double precision RD, EPS3, EPS6
|
|
||||||
PARAMETER (RD = 57.29577951308232087679815481410517D0)
|
|
||||||
PARAMETER (EPS3 = 1.D-3)
|
|
||||||
PARAMETER (EPS6 = 1.D-6)
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C Define the dummy arguments
|
|
||||||
double precision qt(3)
|
|
||||||
double precision qm, qs, aki, akf, ax3, ax4
|
|
||||||
integer*4 iss, ier
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
c Local variables
|
|
||||||
double precision arg, sax3
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C INIT AND TEST
|
|
||||||
C
|
|
||||||
IER = 0
|
|
||||||
IF ((ABS(QS) .LT. EPS6) .OR. (ABS(QM) .LT. EPS3)) THEN
|
|
||||||
IER = 3
|
|
||||||
GOTO 999
|
|
||||||
ENDIF
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C CALCULATE A3 AND MOVE IT INTHE -180 ,+180 INTERVAL
|
|
||||||
C
|
|
||||||
ARG = (AKI**2 + AKF**2 - QS)/(2.D0*AKI*AKF)
|
|
||||||
IF(ABS(ARG) .GT. 1.D0)THEN
|
|
||||||
IER = 4
|
|
||||||
GOTO 999
|
|
||||||
ELSE
|
|
||||||
AX4 = ACOS(ARG)*ISS*RD
|
|
||||||
ENDIF
|
|
||||||
AX3 = (-ATAN2(QT(2),QT(1))-ACOS((AKF**2-QS-AKI**2)/
|
|
||||||
+ (-2.D0*QM*AKI))*DSIGN(1.D0,AX4))*RD
|
|
||||||
sax3 = Dsign(1.D0,ax3)
|
|
||||||
AX3 = DMOD(AX3+sax3*180.D0,360.D0)-sax3*180.D0
|
|
||||||
C
|
|
||||||
C IF(LPLATE) AX3 = -ATAN(SIN(AX4/RD)/(LSA*TAN(AX5/RD)/(ALMS*C
|
|
||||||
C 1 TAN(AX1/RD))*(AKI/KF)**2-COS(AX4/RD)))*RD !PLATE FOCALIZATION OPTION
|
|
||||||
C IF(AXX3 .GT. 180.D0) AX3 = AX3-360.D0
|
|
||||||
C IF( A3 .LT. -180.D0) AX3 = AX3+360.D0
|
|
||||||
C IF(LPLATE .AND. (A3 .GT. 0.0)) AX3 = AX3-180
|
|
||||||
CC-----------------------------------------------------------------------
|
|
||||||
999 CONTINUE
|
|
||||||
RETURN
|
|
||||||
END
|
|
||||||
c
|
|
||||||
SUBROUTINE HELM_CASE ( ! Part of T_CONV.FOR
|
|
||||||
c ====================
|
|
||||||
+ HX,HY,HZ,T_IH,C_IH,AKI,AKF,A4,QM,HELM,IER)
|
|
||||||
C
|
|
||||||
C DEAL WITH HELMOTZ COIL FIELD CALCULATIONS
|
|
||||||
C CALCULATE HX HY HZ
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
c At ILL:
|
|
||||||
c There are 3 coils for Hx/Hy at 120 degrees to each other.
|
|
||||||
c
|
|
||||||
c There is a 4th coil for Hz.
|
|
||||||
c
|
|
||||||
c At SINQ:
|
|
||||||
c There is an Hx coil and an Hy coil (actually each is 4 coils powered
|
|
||||||
c in series). They are mounted on a ring (SRO). The value of HELM is
|
|
||||||
c the angle between the Hx coil and ki.
|
|
||||||
c
|
|
||||||
c There is a 3rd coil for Hz.
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
implicit none
|
|
||||||
c
|
|
||||||
C include 'common_sinq.inc'
|
|
||||||
c
|
|
||||||
double precision PI, RD, EPS3, EPS4
|
|
||||||
PARAMETER (PI = 3.14159265358979323846264338327950D0)
|
|
||||||
PARAMETER (RD = 57.29577951308232087679815481410517D0)
|
|
||||||
PARAMETER (EPS3 = 1.0D-3)
|
|
||||||
PARAMETER (EPS4 = 1.0D-4)
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C Define the dummy arguments
|
|
||||||
real*4 hx, hy, hz
|
|
||||||
real*4 t_ih(8)
|
|
||||||
real*4 c_ih(4)
|
|
||||||
real*4 aki, akf
|
|
||||||
double precision a4
|
|
||||||
real*4 qm, helm
|
|
||||||
integer*4 ier
|
|
||||||
LOGICAL AT_SINQ
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
c Local variables
|
|
||||||
integer*4 ic, ncoef
|
|
||||||
double precision hdir, hdir2, hrad, phi, qpar, qperp
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C INIT AND TEST
|
|
||||||
C
|
|
||||||
AT_SINQ = .TRUE.
|
|
||||||
ncoef = 4
|
|
||||||
if (at_sinq) ncoef = 3
|
|
||||||
c
|
|
||||||
IER = 1
|
|
||||||
IF (ABS(QM) .LT. EPS4) goto 999
|
|
||||||
IER = 0
|
|
||||||
DO IC = 1,ncoef
|
|
||||||
IF (C_IH(IC) .LT. EPS4) IER = 2
|
|
||||||
ENDDO
|
|
||||||
IF (IER .NE. 0) GOTO 999
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C CALCULATE MODULE AND ANGLES OF IN PLANE FIELD H
|
|
||||||
C PHI ! Angle between Q and KI (in radians)
|
|
||||||
C HRAD ! Radial comp. of H
|
|
||||||
C HDIR ! Direction of H relative to PHI (in radians)
|
|
||||||
C HDIR2 ! Angle between field and axis of Coil 1 (in radians)
|
|
||||||
C
|
|
||||||
qpar = aki - akf * cos(a4/RD)
|
|
||||||
qperp = -akf * sin(a4/RD)
|
|
||||||
if (abs(qpar) .gt. EPS3 .and. abs(qperp) .gt. EPS3) then
|
|
||||||
phi = atan2 (abs(qperp), abs(qpar))
|
|
||||||
if (qpar .gt. 0 .and. qperp .lt. 0) then
|
|
||||||
phi = -phi
|
|
||||||
elseif (qpar .lt. 0 .and. qperp .gt. 0) then
|
|
||||||
phi = PI - phi
|
|
||||||
elseif (qpar .lt. 0 .and. qperp .lt. 0) then
|
|
||||||
phi = phi - PI
|
|
||||||
endif
|
|
||||||
elseif (abs(qpar) .gt. EPS3) then
|
|
||||||
if (qpar .ge. 0.0) phi = 0.0
|
|
||||||
if (qpar .lt. 0.0) phi = PI
|
|
||||||
elseif (abs(qperp) .gt. EPS3) then
|
|
||||||
if (qperp .ge. 0.0) phi = 0.5 * PI
|
|
||||||
if (qperp .lt. 0.0) phi = -0.5 * PI
|
|
||||||
else
|
|
||||||
phi = 0.0
|
|
||||||
endif
|
|
||||||
c
|
|
||||||
hrad = sqrt (hx**2 + hy**2)
|
|
||||||
if (abs(hx) .gt. EPS3 .and. abs(hy) .gt. EPS3) then
|
|
||||||
hdir = atan2 (abs(hy), abs(hx))
|
|
||||||
if (hx .gt. 0 .and. hy .lt. 0) then
|
|
||||||
hdir = -hdir
|
|
||||||
elseif (hx .lt. 0 .and. hy .gt. 0) then
|
|
||||||
hdir = PI - hdir
|
|
||||||
elseif (hx .lt. 0 .and. hy .lt. 0) then
|
|
||||||
hdir = hdir - PI
|
|
||||||
endif
|
|
||||||
elseif (abs(hx) .gt. EPS3) then
|
|
||||||
if (hx .ge. 0.0) hdir = 0.0
|
|
||||||
if (hx .lt. 0.0) hdir = PI
|
|
||||||
elseif (abs(hy) .gt. EPS3) then
|
|
||||||
if (hy .ge. 0.0) hdir = 0.5 * PI
|
|
||||||
if (hy .lt. 0.0) hdir = -0.5 * PI
|
|
||||||
else
|
|
||||||
hdir = 0.0
|
|
||||||
endif
|
|
||||||
c
|
|
||||||
hdir2 = hdir + phi - (helm/RD)
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C !CALC CURRENTS
|
|
||||||
C !POSITION OF PSP FOR COIL I
|
|
||||||
C
|
|
||||||
if (.not. at_sinq) then
|
|
||||||
hdir2 = hdir2 + 0.5 * PI ! ???
|
|
||||||
do ic = 1,3
|
|
||||||
t_ih(ic+4) = cos(hdir2+(ic-1)*2.*PI/3.)*hrad/c_ih(ic)/1.5
|
|
||||||
enddo
|
|
||||||
t_ih(8) = hz/c_ih(4)
|
|
||||||
else
|
|
||||||
t_ih(5) = cos(hdir2) * hrad/c_ih(1)
|
|
||||||
t_ih(6) = sin(hdir2) * hrad/c_ih(2)
|
|
||||||
t_ih(7) = hz/c_ih(3)
|
|
||||||
endif
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
999 CONTINUE
|
|
||||||
RETURN
|
|
||||||
END
|
|
||||||
c
|
|
||||||
SUBROUTINE FLIP_CASE ( ! Part of T_CONV.FOR
|
|
||||||
C ====================
|
|
||||||
+ IF1,IF2,T_IH,F1V,F1H,F2V,F2H,AKI,AKF,IER)
|
|
||||||
C
|
|
||||||
C DEAL WITH FLIPPER COIL CALCULATIONS
|
|
||||||
C CALCULATE P_IF CURRENTS FOR THE TWO FLIPPERS
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C Define the dummy arguments
|
|
||||||
integer*4 if1, if2
|
|
||||||
real*4 t_ih(8)
|
|
||||||
real*4 f1v, f1h, f2v, f2h
|
|
||||||
real*4 aki, akf
|
|
||||||
integer*4 ier
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C INIT AND TEST
|
|
||||||
C
|
|
||||||
IER = 0
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C
|
|
||||||
IF (IF1 .EQ. 1) THEN
|
|
||||||
T_IH(1) = F1V
|
|
||||||
T_IH(2) = AKI*F1H
|
|
||||||
ELSE
|
|
||||||
T_IH(1) = 0.
|
|
||||||
T_IH(2) = 0.
|
|
||||||
ENDIF
|
|
||||||
IF (IF2 .EQ. 1) THEN
|
|
||||||
T_IH(3) = F2V
|
|
||||||
T_IH(4) = AKF*F2H
|
|
||||||
ELSE
|
|
||||||
T_IH(3) = 0.
|
|
||||||
T_IH(4) = 0.
|
|
||||||
ENDIF
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
999 CONTINUE
|
|
||||||
RETURN
|
|
||||||
END
|
|
516
t_rlp.c
516
t_rlp.c
@ -1,516 +0,0 @@
|
|||||||
/* t_rlp.f -- translated by f2c (version 20000817).
|
|
||||||
You must link the resulting object file with the libraries:
|
|
||||||
-lf2c -lm (in that order)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "f2c.h"
|
|
||||||
|
|
||||||
/* Common Block Declarations */
|
|
||||||
|
|
||||||
struct {
|
|
||||||
doublereal s[16] /* was [4][4] */, sinv[16] /* was [4][4] */;
|
|
||||||
integer iok;
|
|
||||||
} osolem_;
|
|
||||||
|
|
||||||
#define osolem_1 osolem_
|
|
||||||
|
|
||||||
/* Subroutine */ int t_rlp__(void)
|
|
||||||
{
|
|
||||||
/* ================ */
|
|
||||||
|
|
||||||
/* dec$ Ident 'V01A' */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* Updates: */
|
|
||||||
/* V01A 7-May-1996 DM. Put error output to IOLUN, use IMPLICIT NONE and */
|
|
||||||
/* get the code indented so that it is readable! */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* Routines to deal with the reciprocical lattice PB */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* Entry points in this file: */
|
|
||||||
|
|
||||||
/* SETRLP : CALCULATION OF S AND INVS , ORIENTATION MATRIX */
|
|
||||||
/* RL2SPV : TRANSFO FROM RECIP LAT TO SCAT PLANE */
|
|
||||||
/* SP2RLV : TRANSFO FROM SCAT PLANE TO RECIP LAT */
|
|
||||||
/* INVS : INVERT MATRIX S, GENERATED BY SETRLP. */
|
|
||||||
/* ERRESO : DEAL ITH ERROR MESSAGES FOR ALL MODULES */
|
|
||||||
|
|
||||||
/* SUBROUTINE SETRLP(SAM,IER) */
|
|
||||||
/* SUBROUTINE RL2SPV(QHKL,QT,QM,QS,IER) */
|
|
||||||
/* SUBROUTINE SP2RLV(QHKL,QT,QM,QS,IER) */
|
|
||||||
/* SUBROUTINE INVS(S,SINV,IER) */
|
|
||||||
/* SUBROUTINE ERRESO(MODULE,IER) */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* File [MAD.SRC]T_RLP.FOR */
|
|
||||||
return 0;
|
|
||||||
} /* t_rlp__ */
|
|
||||||
|
|
||||||
|
|
||||||
/* Subroutine */ int setrlp_(real *sam, integer *ier)
|
|
||||||
{
|
|
||||||
/* System generated locals */
|
|
||||||
doublereal d__1;
|
|
||||||
|
|
||||||
/* Builtin functions */
|
|
||||||
double cos(doublereal), sin(doublereal), sqrt(doublereal), atan(
|
|
||||||
doublereal);
|
|
||||||
|
|
||||||
/* Local variables */
|
|
||||||
static doublereal alfa[3], cosa[3], cosb[3];
|
|
||||||
static integer imod;
|
|
||||||
static doublereal sina[3], sinb[3], aspv[6] /* was [3][2] */;
|
|
||||||
extern /* Subroutine */ int invs_(doublereal *, doublereal *, integer *);
|
|
||||||
static doublereal a[3], b[3], c__[3], bb[9] /* was [3][3] */, cc;
|
|
||||||
static integer id, ie, jd, je, jf, kg, lf, lh, md, me, ne;
|
|
||||||
static doublereal zp, vv[9] /* was [3][3] */;
|
|
||||||
extern /* Subroutine */ int erreso_(integer *, integer *);
|
|
||||||
static doublereal rlb[6] /* was [3][2] */;
|
|
||||||
|
|
||||||
/* ============================ */
|
|
||||||
|
|
||||||
/* SETRLP: Computation of matrix S which transforms (QH,QK,QL) to */
|
|
||||||
/* vector (Q1,Q2) in scattering plane (defined by vectors A1,A2) */
|
|
||||||
/* and SINV matrix for the inverse transformation */
|
|
||||||
|
|
||||||
/* INPUT SAM SAMPLE CHARACTERISTICS */
|
|
||||||
/* SAM(1)=AS LATTICE PARAMETERS */
|
|
||||||
/* SAM(2)=BS ------------------ */
|
|
||||||
/* SAM(3)=CS ------------------ */
|
|
||||||
/* SAM(4)=AA LATTICE ANGLES */
|
|
||||||
/* SAM(5)=BB -------------- */
|
|
||||||
/* SAM(6)=CC -------------- */
|
|
||||||
/* SAM(7)=AX VECTOR A IN SCATTERING PLANE */
|
|
||||||
/* SAM(8)=AY ---------------------------- */
|
|
||||||
/* SAM(9)=AZ ---------------------------- */
|
|
||||||
/* SAM(10)=BX VECTOR B IN SCATTERING PLANE */
|
|
||||||
/* SAM(11)=BY ---------------------------- */
|
|
||||||
/* SAM(12)=BZ ---------------------------- */
|
|
||||||
/* OUTPUT IER ERROR RETURN TO BE TREATED BY ERRESO */
|
|
||||||
/* IER=1 ERROR ON LATTICE PARAMETERS */
|
|
||||||
/* IER=2 ERROR ON LATTICE ANGLES */
|
|
||||||
/* IER=3 ERROR ON VECTORS A1, A2 */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* Part of [MAD.SRC]T_RLP.FOR */
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* Define the dummy arguments */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* DO NOT EXPORT THE FOLLOWING COMMON ! */
|
|
||||||
/* IT IS JUST FOR PERMANENT STORAGE USE */
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* SOME TESTS AND INIT OF CALCUALTION */
|
|
||||||
|
|
||||||
/* Parameter adjustments */
|
|
||||||
--sam;
|
|
||||||
|
|
||||||
/* Function Body */
|
|
||||||
*ier = 0;
|
|
||||||
imod = 1;
|
|
||||||
zp = 6.2831853071795862;
|
|
||||||
osolem_1.iok = 0;
|
|
||||||
for (id = 1; id <= 3; ++id) {
|
|
||||||
a[id - 1] = sam[id];
|
|
||||||
alfa[id - 1] = sam[id + 3];
|
|
||||||
aspv[id - 1] = sam[id + 6];
|
|
||||||
aspv[id + 2] = sam[id + 9];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (id = 1; id <= 3; ++id) {
|
|
||||||
*ier = 1;
|
|
||||||
if ((d__1 = a[id - 1], abs(d__1)) <= 1e-8) {
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
*ier = 0;
|
|
||||||
}
|
|
||||||
for (id = 1; id <= 3; ++id) {
|
|
||||||
a[id - 1] /= zp;
|
|
||||||
alfa[id - 1] /= 57.29577951308232087679815481410517;
|
|
||||||
cosa[id - 1] = cos(alfa[id - 1]);
|
|
||||||
sina[id - 1] = sin(alfa[id - 1]);
|
|
||||||
}
|
|
||||||
cc = cosa[0] * cosa[0] + cosa[1] * cosa[1] + cosa[2] * cosa[2];
|
|
||||||
cc = cosa[0] * 2. * cosa[1] * cosa[2] + 1. - cc;
|
|
||||||
*ier = 2;
|
|
||||||
if (cc <= .1) {
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
*ier = 0;
|
|
||||||
cc = sqrt(cc);
|
|
||||||
je = 2;
|
|
||||||
kg = 3;
|
|
||||||
for (id = 1; id <= 3; ++id) {
|
|
||||||
b[id - 1] = sina[id - 1] / (a[id - 1] * cc);
|
|
||||||
cosb[id - 1] = (cosa[je - 1] * cosa[kg - 1] - cosa[id - 1]) / (sina[
|
|
||||||
je - 1] * sina[kg - 1]);
|
|
||||||
sinb[id - 1] = sqrt(1. - cosb[id - 1] * cosb[id - 1]);
|
|
||||||
rlb[id + 2] = (d__1 = atan(sinb[id - 1] / cosb[id - 1]), abs(d__1)) *
|
|
||||||
57.29577951308232087679815481410517;
|
|
||||||
je = kg;
|
|
||||||
kg = id;
|
|
||||||
}
|
|
||||||
bb[0] = b[0];
|
|
||||||
bb[1] = 0.;
|
|
||||||
bb[2] = 0.;
|
|
||||||
bb[3] = b[1] * cosb[2];
|
|
||||||
bb[4] = b[1] * sinb[2];
|
|
||||||
bb[5] = 0.;
|
|
||||||
bb[6] = b[2] * cosb[1];
|
|
||||||
bb[7] = -b[2] * sinb[1] * cosa[0];
|
|
||||||
bb[8] = 1. / a[2];
|
|
||||||
|
|
||||||
for (id = 1; id <= 3; ++id) {
|
|
||||||
rlb[id - 1] = 0.;
|
|
||||||
for (je = 1; je <= 3; ++je) {
|
|
||||||
/* Computing 2nd power */
|
|
||||||
d__1 = bb[je + id * 3 - 4];
|
|
||||||
rlb[id - 1] += d__1 * d__1;
|
|
||||||
}
|
|
||||||
*ier = 1;
|
|
||||||
if ((d__1 = rlb[id - 1], abs(d__1)) <= 1e-8) {
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
*ier = 0;
|
|
||||||
rlb[id - 1] = sqrt(rlb[id - 1]);
|
|
||||||
}
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* GENERATION OF S ORIENTATION MATRIX REC. LATTICE TO SCATTERING PLANE */
|
|
||||||
|
|
||||||
for (kg = 1; kg <= 2; ++kg) {
|
|
||||||
for (ie = 1; ie <= 3; ++ie) {
|
|
||||||
vv[kg + ie * 3 - 4] = 0.;
|
|
||||||
for (jf = 1; jf <= 3; ++jf) {
|
|
||||||
vv[kg + ie * 3 - 4] += bb[ie + jf * 3 - 4] * aspv[jf + kg * 3
|
|
||||||
- 4];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (md = 3; md >= 2; --md) {
|
|
||||||
for (ne = 1; ne <= 3; ++ne) {
|
|
||||||
id = md % 3 + 1;
|
|
||||||
je = (md + 1) % 3 + 1;
|
|
||||||
kg = ne % 3 + 1;
|
|
||||||
lh = (ne + 1) % 3 + 1;
|
|
||||||
vv[md + ne * 3 - 4] = vv[id + kg * 3 - 4] * vv[je + lh * 3 - 4] -
|
|
||||||
vv[id + lh * 3 - 4] * vv[je + kg * 3 - 4];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (id = 1; id <= 3; ++id) {
|
|
||||||
c__[id - 1] = 0.;
|
|
||||||
for (je = 1; je <= 3; ++je) {
|
|
||||||
/* Computing 2nd power */
|
|
||||||
d__1 = vv[id + je * 3 - 4];
|
|
||||||
c__[id - 1] += d__1 * d__1;
|
|
||||||
}
|
|
||||||
*ier = 3;
|
|
||||||
if ((d__1 = c__[id - 1], abs(d__1)) <= 1e-6) {
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
*ier = 0;
|
|
||||||
c__[id - 1] = sqrt(c__[id - 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (id = 1; id <= 3; ++id) {
|
|
||||||
for (je = 1; je <= 3; ++je) {
|
|
||||||
vv[je + id * 3 - 4] /= c__[je - 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (kg = 1; kg <= 3; ++kg) {
|
|
||||||
for (me = 1; me <= 3; ++me) {
|
|
||||||
osolem_1.s[kg + (me << 2) - 5] = 0.;
|
|
||||||
for (lf = 1; lf <= 3; ++lf) {
|
|
||||||
osolem_1.s[kg + (me << 2) - 5] += vv[kg + lf * 3 - 4] * bb[lf
|
|
||||||
+ me * 3 - 4];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
osolem_1.s[15] = 1.;
|
|
||||||
for (jd = 1; jd <= 3; ++jd) {
|
|
||||||
osolem_1.s[(jd << 2) - 1] = 0.;
|
|
||||||
osolem_1.s[jd + 11] = 0.;
|
|
||||||
}
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* INVERT TRANSFORMATION MATRIX S AND PU RESULT IN SINV */
|
|
||||||
|
|
||||||
*ier = 3;
|
|
||||||
invs_(osolem_1.s, osolem_1.sinv, ier);
|
|
||||||
*ier = 0;
|
|
||||||
if (*ier != 0) {
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
osolem_1.iok = 123;
|
|
||||||
/* --------------------------------------------------------------------------- */
|
|
||||||
/* SORTIE */
|
|
||||||
|
|
||||||
L999:
|
|
||||||
if (*ier != 0) {
|
|
||||||
erreso_(&imod, ier);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
} /* setrlp_ */
|
|
||||||
|
|
||||||
|
|
||||||
/* Subroutine */ int rl2spv_(doublereal *qhkl, doublereal *qt, doublereal *qm,
|
|
||||||
doublereal *qs, integer *ier)
|
|
||||||
{
|
|
||||||
/* System generated locals */
|
|
||||||
doublereal d__1;
|
|
||||||
|
|
||||||
/* Builtin functions */
|
|
||||||
double sqrt(doublereal);
|
|
||||||
|
|
||||||
/* Local variables */
|
|
||||||
static integer id, je;
|
|
||||||
|
|
||||||
/* ========================================= */
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* INPUT QHKL QHKL -> QT */
|
|
||||||
/* A Q-VECTOR TO BE TRANSFORM FROM RECIP LATTICE TO SCATTERING PLANE */
|
|
||||||
/* CHECK THAT Q-VECTOR IS IN THE PLANE */
|
|
||||||
|
|
||||||
/* INPUT Q-VECTOR QHKL(3) Q-VECTOR IN RECIPROCICAL LATTICVE */
|
|
||||||
|
|
||||||
/* OUTPUT Q-VECTOR QT(3) Q-VECTOR IN SCATTERING PLANE */
|
|
||||||
/* OUTPUT QM AND QS QMODULUS AND ITS SQUARE ( TO BE VERIFIED ) */
|
|
||||||
/* OUTPUT ERROR IER */
|
|
||||||
/* IER=1 MATRIX S NOT OK */
|
|
||||||
/* IER=2 Q NOT IN SCATTERING PLANE */
|
|
||||||
/* IER=3 Q MODULUS TOO SMALL */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* Part of [MAD.SRC]T_RLP.FOR */
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* Define the dummy arguments */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* DO NOT EXPORT THE FOLLWING COOMON ! */
|
|
||||||
/* IT IS JUST FOR PERMANENT STORAGE USE */
|
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------- */
|
|
||||||
/* --------------------------------------------------------------------------- */
|
|
||||||
/* INIT AND TEST IF TRANSFO MATRICES ARE OK */
|
|
||||||
/* Parameter adjustments */
|
|
||||||
--qt;
|
|
||||||
--qhkl;
|
|
||||||
|
|
||||||
/* Function Body */
|
|
||||||
*ier = 1;
|
|
||||||
if (osolem_1.iok != 123) {
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
*ier = 0;
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
for (id = 1; id <= 3; ++id) {
|
|
||||||
qt[id] = 0.;
|
|
||||||
for (je = 1; je <= 3; ++je) {
|
|
||||||
qt[id] += qhkl[je] * osolem_1.s[id + (je << 2) - 5];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*ier = 2;
|
|
||||||
if (abs(qt[3]) > 1e-4) {
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
*ier = 0;
|
|
||||||
*qs = 0.;
|
|
||||||
for (id = 1; id <= 3; ++id) {
|
|
||||||
/* Computing 2nd power */
|
|
||||||
d__1 = qt[id];
|
|
||||||
*qs += d__1 * d__1;
|
|
||||||
}
|
|
||||||
if (*qs < 1e-8) {
|
|
||||||
*ier = 3;
|
|
||||||
} else {
|
|
||||||
*qm = sqrt(*qs);
|
|
||||||
}
|
|
||||||
/* --------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
L999:
|
|
||||||
return 0;
|
|
||||||
} /* rl2spv_ */
|
|
||||||
|
|
||||||
|
|
||||||
/* Subroutine */ int sp2rlv_(doublereal *qhkl, doublereal *qt, doublereal *qm,
|
|
||||||
doublereal *qs, integer *ier)
|
|
||||||
{
|
|
||||||
/* System generated locals */
|
|
||||||
doublereal d__1;
|
|
||||||
|
|
||||||
/* Builtin functions */
|
|
||||||
double sqrt(doublereal);
|
|
||||||
|
|
||||||
/* Local variables */
|
|
||||||
static integer id, je;
|
|
||||||
|
|
||||||
/* ========================================= */
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* INPUT QT QHKL <- QT */
|
|
||||||
/* A Q-VECTOR TO BE TRANSFORM FROM SCATTERING PLANE TO RECIP LATTICE */
|
|
||||||
/* CHECK THAT Q, D & G VECTORS ARE IN THE SCATTERING PLANE */
|
|
||||||
|
|
||||||
/* INPUT Q-VECTOR QT(3) Q-VECTOR IN SCATTERING PLANE */
|
|
||||||
|
|
||||||
/* OUTPUT Q-VECTOR QHKL(3) Q-VECTOR IN RECIPROCICAL LATTICVE */
|
|
||||||
/* OUTPUT QM AND QS QMODULUS AND ITS SQUARE ( TO BE VERIFIED ) */
|
|
||||||
/* OUTPUT ERROR IER */
|
|
||||||
/* IER=1 MATRIX S NOT OK */
|
|
||||||
/* IER=2 Q NOT IN SCATTERING PLANE */
|
|
||||||
/* IER=3 Q MODULUS TOO SMALL */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* Part of [MAD.SRC]T_RLP.FOR */
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* Define the dummy arguments */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* DO NOT EXPORT THE FOLLWING COOMON ! */
|
|
||||||
/* IT IS JUST FOR PERMANENT STORAGE USE */
|
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------- */
|
|
||||||
/* --------------------------------------------------------------------------- */
|
|
||||||
/* INIT AND TEST IF TRANSFO MATRICES ARE OK */
|
|
||||||
/* Parameter adjustments */
|
|
||||||
--qt;
|
|
||||||
--qhkl;
|
|
||||||
|
|
||||||
/* Function Body */
|
|
||||||
*ier = 1;
|
|
||||||
if (osolem_1.iok != 123) {
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
*ier = 2;
|
|
||||||
if (abs(qt[3]) > 1e-4) {
|
|
||||||
goto L999;
|
|
||||||
}
|
|
||||||
*ier = 0;
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
*qs = 0.;
|
|
||||||
for (id = 1; id <= 3; ++id) {
|
|
||||||
/* Computing 2nd power */
|
|
||||||
d__1 = qt[id];
|
|
||||||
*qs += d__1 * d__1;
|
|
||||||
}
|
|
||||||
if (*qs < 1e-8) {
|
|
||||||
*ier = 3;
|
|
||||||
} else {
|
|
||||||
*qm = sqrt(*qs);
|
|
||||||
}
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
for (id = 1; id <= 3; ++id) {
|
|
||||||
qhkl[id] = 0.;
|
|
||||||
for (je = 1; je <= 3; ++je) {
|
|
||||||
qhkl[id] += osolem_1.sinv[id + (je << 2) - 5] * qt[je];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* --------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
L999:
|
|
||||||
return 0;
|
|
||||||
} /* sp2rlv_ */
|
|
||||||
|
|
||||||
|
|
||||||
/* Subroutine */ int invs_(doublereal *s, doublereal *sinv, integer *ier)
|
|
||||||
{
|
|
||||||
/* Initialized data */
|
|
||||||
|
|
||||||
static integer m[3] = { 2,3,1 };
|
|
||||||
static integer n[3] = { 3,1,2 };
|
|
||||||
|
|
||||||
static integer id, je, mi, mj, ni, nj;
|
|
||||||
static doublereal det;
|
|
||||||
|
|
||||||
/* ============================== */
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* ROUTINE TO INVERT MATRIX S, GENERATED BY SETRLP, WHICH TRANSFORMS */
|
|
||||||
/* (QH,QK,QL) TO (Q1,Q2) IN THE SCATTERING PLANE */
|
|
||||||
/* INPUT MATRIX DOUBLE PRECISION S(4,4) */
|
|
||||||
/* OUTPUT MATRIX DOUBLE PRECISION SINV(4,4) */
|
|
||||||
/* OUTPUT ERROR IER */
|
|
||||||
/* IER=1 DETERMINANT OF MATRIX S TOO SMALL */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* Part of [MAD.SRC]T_RLP.FOR */
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* Define the dummy arguments */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* Parameter adjustments */
|
|
||||||
sinv -= 5;
|
|
||||||
s -= 5;
|
|
||||||
|
|
||||||
/* Function Body */
|
|
||||||
*ier = 0;
|
|
||||||
for (id = 1; id <= 4; ++id) {
|
|
||||||
for (je = 1; je <= 4; ++je) {
|
|
||||||
sinv[id + (je << 2)] = 0.;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
det = 0.;
|
|
||||||
for (id = 1; id <= 3; ++id) {
|
|
||||||
for (je = 1; je <= 3; ++je) {
|
|
||||||
mi = m[id - 1];
|
|
||||||
mj = m[je - 1];
|
|
||||||
ni = n[id - 1];
|
|
||||||
nj = n[je - 1];
|
|
||||||
sinv[je + (id << 2)] = s[mi + (mj << 2)] * s[ni + (nj << 2)] - s[
|
|
||||||
ni + (mj << 2)] * s[mi + (nj << 2)];
|
|
||||||
}
|
|
||||||
det += s[id + 4] * sinv[(id << 2) + 1];
|
|
||||||
}
|
|
||||||
if (abs(det) < 1e-6) {
|
|
||||||
*ier = 1;
|
|
||||||
} else {
|
|
||||||
for (id = 1; id <= 3; ++id) {
|
|
||||||
for (je = 1; je <= 3; ++je) {
|
|
||||||
sinv[id + (je << 2)] /= det;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sinv[20] = 1.;
|
|
||||||
return 0;
|
|
||||||
} /* invs_ */
|
|
||||||
|
|
||||||
|
|
||||||
/* Subroutine */ int erreso_(integer *module, integer *ier)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* System generated locals */
|
|
||||||
integer i__1;
|
|
||||||
|
|
||||||
/* Local variables */
|
|
||||||
static integer lier, lmodule;
|
|
||||||
|
|
||||||
/* ============================= */
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* SUBROUTINE TO TREAT ERRORS FROM RESOLUTION CALCULATIONS */
|
|
||||||
/* MODULE = 1 -> SETRLP */
|
|
||||||
/* MODULE = 2 -> RL2SPV */
|
|
||||||
/* MODULE = 3 -> EX_CASE */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* Part of [MAD.SRC]T_RLP.FOR */
|
|
||||||
|
|
||||||
|
|
||||||
/* include 'iolsddef.inc' */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* Define the dummy arguments */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
|
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------- */
|
|
||||||
/* Computing MIN */
|
|
||||||
i__1 = max(*ier,1);
|
|
||||||
lier = min(i__1,4);
|
|
||||||
/* Computing MIN */
|
|
||||||
i__1 = max(*module,1);
|
|
||||||
lmodule = min(i__1,3);
|
|
||||||
/* WRITE(iolun,501) MESER(LIER,LMODULE) */
|
|
||||||
/* L501: */
|
|
||||||
return 0;
|
|
||||||
} /* erreso_ */
|
|
||||||
|
|
463
t_rlp.f
463
t_rlp.f
@ -1,463 +0,0 @@
|
|||||||
SUBROUTINE T_RLP ! File [MAD.SRC]T_RLP.FOR
|
|
||||||
c ================
|
|
||||||
c
|
|
||||||
cdec$ Ident 'V01A'
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
c Updates:
|
|
||||||
c V01A 7-May-1996 DM. Put error output to IOLUN, use IMPLICIT NONE and
|
|
||||||
c get the code indented so that it is readable!
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
c Routines to deal with the reciprocical lattice PB
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
c Entry points in this file:
|
|
||||||
c
|
|
||||||
c SETRLP : CALCULATION OF S AND INVS , ORIENTATION MATRIX
|
|
||||||
C RL2SPV : TRANSFO FROM RECIP LAT TO SCAT PLANE
|
|
||||||
C SP2RLV : TRANSFO FROM SCAT PLANE TO RECIP LAT
|
|
||||||
C INVS : INVERT MATRIX S, GENERATED BY SETRLP.
|
|
||||||
C ERRESO : DEAL ITH ERROR MESSAGES FOR ALL MODULES
|
|
||||||
C
|
|
||||||
C SUBROUTINE SETRLP(SAM,IER)
|
|
||||||
C SUBROUTINE RL2SPV(QHKL,QT,QM,QS,IER)
|
|
||||||
C SUBROUTINE SP2RLV(QHKL,QT,QM,QS,IER)
|
|
||||||
C SUBROUTINE INVS(S,SINV,IER)
|
|
||||||
C SUBROUTINE ERRESO(MODULE,IER)
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
implicit none
|
|
||||||
end
|
|
||||||
c
|
|
||||||
SUBROUTINE SETRLP (SAM, IER) ! Part of [MAD.SRC]T_RLP.FOR
|
|
||||||
c ============================
|
|
||||||
c
|
|
||||||
C SETRLP: Computation of matrix S which transforms (QH,QK,QL) to
|
|
||||||
C vector (Q1,Q2) in scattering plane (defined by vectors A1,A2)
|
|
||||||
C and SINV matrix for the inverse transformation
|
|
||||||
C
|
|
||||||
C INPUT SAM SAMPLE CHARACTERISTICS
|
|
||||||
C SAM(1)=AS LATTICE PARAMETERS
|
|
||||||
C SAM(2)=BS ------------------
|
|
||||||
C SAM(3)=CS ------------------
|
|
||||||
C SAM(4)=AA LATTICE ANGLES
|
|
||||||
C SAM(5)=BB --------------
|
|
||||||
C SAM(6)=CC --------------
|
|
||||||
C SAM(7)=AX VECTOR A IN SCATTERING PLANE
|
|
||||||
C SAM(8)=AY ----------------------------
|
|
||||||
C SAM(9)=AZ ----------------------------
|
|
||||||
C SAM(10)=BX VECTOR B IN SCATTERING PLANE
|
|
||||||
C SAM(11)=BY ----------------------------
|
|
||||||
C SAM(12)=BZ ----------------------------
|
|
||||||
C OUTPUT IER ERROR RETURN TO BE TREATED BY ERRESO
|
|
||||||
C IER=1 ERROR ON LATTICE PARAMETERS
|
|
||||||
C IER=2 ERROR ON LATTICE ANGLES
|
|
||||||
C IER=3 ERROR ON VECTORS A1, A2
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
IMPLICIT NONE
|
|
||||||
c
|
|
||||||
DOUBLE PRECISION PI
|
|
||||||
PARAMETER (PI=3.14159265358979323846264338327950D0)
|
|
||||||
DOUBLE PRECISION RD
|
|
||||||
PARAMETER (RD=57.29577951308232087679815481410517D0)
|
|
||||||
DOUBLE PRECISION EPS
|
|
||||||
PARAMETER (EPS=1.D-1)
|
|
||||||
DOUBLE PRECISION EPS6
|
|
||||||
PARAMETER (EPS6=1.D-6)
|
|
||||||
DOUBLE PRECISION EPS8
|
|
||||||
PARAMETER (EPS8=1.D-8)
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
C Define the dummy arguments
|
|
||||||
real*4 sam(64)
|
|
||||||
integer*4 ier
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
C DO NOT EXPORT THE FOLLOWING COMMON !
|
|
||||||
C IT IS JUST FOR PERMANENT STORAGE USE
|
|
||||||
C
|
|
||||||
DOUBLE PRECISION S, SINV
|
|
||||||
integer*4 iok
|
|
||||||
COMMON /OSOLEM/ S(4,4), SINV(4,4), iok
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
double precision a(3), aspv(3,2), rlb(3,2)
|
|
||||||
double precision alfa(3), sina(3), sinb(3), cosa(3), cosb(3)
|
|
||||||
double precision b(3), c(3)
|
|
||||||
double precision vv(3,3), bb(3,3)
|
|
||||||
C
|
|
||||||
double precision zp, cc
|
|
||||||
integer*4 imod
|
|
||||||
integer*4 id, ie
|
|
||||||
integer*4 jd, je, jf
|
|
||||||
integer*4 kg
|
|
||||||
integer*4 lh, lf
|
|
||||||
integer*4 md, me
|
|
||||||
integer*4 ne
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C SOME TESTS AND INIT OF CALCUALTION
|
|
||||||
C
|
|
||||||
ier = 0
|
|
||||||
IMOD = 1
|
|
||||||
ZP = 2.D0*PI
|
|
||||||
IOK = 0
|
|
||||||
DO ID = 1,3
|
|
||||||
A(ID) = SAM(ID)
|
|
||||||
ALFA(ID) = SAM(ID+3)
|
|
||||||
ASPV(ID,1) = SAM(6+ID)
|
|
||||||
ASPV(ID,2) = SAM(9+ID)
|
|
||||||
ENDDO
|
|
||||||
C
|
|
||||||
DO ID = 1,3
|
|
||||||
IER = 1
|
|
||||||
IF(ABS(A(ID)).LE.EPS8) GOTO 999
|
|
||||||
IER = 0
|
|
||||||
ENDDO
|
|
||||||
DO ID = 1,3
|
|
||||||
A(ID) = A(ID)/ZP
|
|
||||||
ALFA(ID) = ALFA(ID)/RD
|
|
||||||
COSA(ID) = COS(ALFA(ID))
|
|
||||||
SINA(ID) = SIN(ALFA(ID))
|
|
||||||
ENDDO
|
|
||||||
CC = COSA(1)*COSA(1)+COSA(2)*COSA(2)+COSA(3)*COSA(3)
|
|
||||||
CC = (1.D0+2.D0*COSA(1)*COSA(2)*COSA(3)-CC)
|
|
||||||
IER = 2
|
|
||||||
IF(CC.LE.EPS) GOTO 999
|
|
||||||
IER = 0
|
|
||||||
CC = SQRT(CC)
|
|
||||||
JE = 2
|
|
||||||
KG = 3
|
|
||||||
DO ID = 1,3
|
|
||||||
B(ID) = SINA(ID)/(A(ID)*CC)
|
|
||||||
COSB(ID) = (COSA(JE)*COSA(KG)-COSA(ID))/(SINA(JE)*SINA(KG))
|
|
||||||
SINB(ID) = SQRT(1.D0-COSB(ID)*COSB(ID))
|
|
||||||
RLB(ID,2) = ABS(ATAN(SINB(ID)/COSB(ID)))*RD
|
|
||||||
JE = KG
|
|
||||||
KG = ID
|
|
||||||
ENDDO
|
|
||||||
BB(1,1) = B(1)
|
|
||||||
BB(2,1) = 0.D0
|
|
||||||
BB(3,1) = 0.D0
|
|
||||||
BB(1,2) = B(2)*COSB(3)
|
|
||||||
BB(2,2) = B(2)*SINB(3)
|
|
||||||
BB(3,2) = 0.D0
|
|
||||||
BB(1,3) = B(3)*COSB(2)
|
|
||||||
BB(2,3) = -B(3)*SINB(2)*COSA(1)
|
|
||||||
BB(3,3) = 1.D0/A(3)
|
|
||||||
C
|
|
||||||
DO ID = 1,3
|
|
||||||
RLB(ID,1) = 0.D0
|
|
||||||
DO JE = 1,3
|
|
||||||
RLB(ID,1) = RLB(ID,1)+BB(JE,ID)**2
|
|
||||||
ENDDO
|
|
||||||
IER = 1
|
|
||||||
IF (ABS(RLB(ID,1)).LE.EPS8) GOTO 999
|
|
||||||
IER = 0
|
|
||||||
RLB(ID,1) = SQRT(RLB(ID,1))
|
|
||||||
ENDDO
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C GENERATION OF S ORIENTATION MATRIX REC. LATTICE TO SCATTERING PLANE
|
|
||||||
C
|
|
||||||
DO KG = 1,2
|
|
||||||
DO IE = 1,3
|
|
||||||
VV(KG,IE) = 0.D0
|
|
||||||
DO JF = 1,3
|
|
||||||
VV(KG,IE) = VV(KG,IE)+BB(IE,JF)*ASPV(JF,KG)
|
|
||||||
ENDDO
|
|
||||||
ENDDO
|
|
||||||
ENDDO
|
|
||||||
DO MD = 3,2,-1
|
|
||||||
DO NE = 1,3
|
|
||||||
ID = MOD(MD,3)+1
|
|
||||||
JE = MOD(MD+1,3)+1
|
|
||||||
KG = MOD(NE,3)+1
|
|
||||||
LH = MOD(NE+1,3)+1
|
|
||||||
VV(MD,NE) = VV(ID,KG)*VV(JE,LH)-VV(ID,LH)*VV(JE,KG)
|
|
||||||
ENDDO
|
|
||||||
ENDDO
|
|
||||||
C
|
|
||||||
DO ID = 1,3
|
|
||||||
C(ID) = 0.D0
|
|
||||||
DO JE = 1,3
|
|
||||||
C(ID) = C(ID)+VV(ID,JE)**2
|
|
||||||
ENDDO
|
|
||||||
IER = 3
|
|
||||||
IF (ABS(C(ID)).LE.EPS6) GOTO 999
|
|
||||||
IER = 0
|
|
||||||
C(ID) = SQRT(C(ID))
|
|
||||||
ENDDO
|
|
||||||
C
|
|
||||||
DO ID = 1,3
|
|
||||||
DO JE = 1,3
|
|
||||||
VV(JE,ID) = VV(JE,ID)/C(JE)
|
|
||||||
ENDDO
|
|
||||||
ENDDO
|
|
||||||
DO KG = 1,3
|
|
||||||
DO ME = 1,3
|
|
||||||
S(KG,ME) = 0.D0
|
|
||||||
DO LF = 1,3
|
|
||||||
S(KG,ME) = S(KG,ME)+VV(KG,LF)*BB(LF,ME)
|
|
||||||
ENDDO
|
|
||||||
ENDDO
|
|
||||||
ENDDO
|
|
||||||
S(4,4) = 1.D0
|
|
||||||
DO JD = 1,3
|
|
||||||
S(4,JD) = 0.D0
|
|
||||||
S(JD,4) = 0.D0
|
|
||||||
ENDDO
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C INVERT TRANSFORMATION MATRIX S AND PU RESULT IN SINV
|
|
||||||
C
|
|
||||||
IER = 3
|
|
||||||
CALL INVS(S,SINV,IER)
|
|
||||||
IER = 0
|
|
||||||
IF (IER.NE.0)GOTO 999
|
|
||||||
IOK = 123
|
|
||||||
C---------------------------------------------------------------------------
|
|
||||||
C SORTIE
|
|
||||||
C
|
|
||||||
999 CONTINUE
|
|
||||||
IF (IER.NE.0) CALL ERRESO(IMOD,IER)
|
|
||||||
RETURN
|
|
||||||
END
|
|
||||||
c
|
|
||||||
SUBROUTINE RL2SPV (QHKL, QT, QM, QS, IER) ! Part of [MAD.SRC]T_RLP.FOR
|
|
||||||
c =========================================
|
|
||||||
c
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
C INPUT QHKL QHKL -> QT
|
|
||||||
C A Q-VECTOR TO BE TRANSFORM FROM RECIP LATTICE TO SCATTERING PLANE
|
|
||||||
C CHECK THAT Q-VECTOR IS IN THE PLANE
|
|
||||||
C
|
|
||||||
C INPUT Q-VECTOR QHKL(3) Q-VECTOR IN RECIPROCICAL LATTICVE
|
|
||||||
C
|
|
||||||
C OUTPUT Q-VECTOR QT(3) Q-VECTOR IN SCATTERING PLANE
|
|
||||||
C OUTPUT QM AND QS QMODULUS AND ITS SQUARE ( TO BE VERIFIED )
|
|
||||||
C OUTPUT ERROR IER
|
|
||||||
C IER=1 MATRIX S NOT OK
|
|
||||||
C IER=2 Q NOT IN SCATTERING PLANE
|
|
||||||
C IER=3 Q MODULUS TOO SMALL
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
IMPLICIT NONE
|
|
||||||
c
|
|
||||||
DOUBLE PRECISION DEPS4
|
|
||||||
PARAMETER (DEPS4=1.D-4)
|
|
||||||
DOUBLE PRECISION DEPS8
|
|
||||||
PARAMETER (DEPS8=1.D-8)
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
c Define the dummy arguments
|
|
||||||
DOUBLE PRECISION QHKL(3)
|
|
||||||
DOUBLE PRECISION QT(3)
|
|
||||||
DOUBLE PRECISION QM
|
|
||||||
DOUBLE PRECISION QS
|
|
||||||
integer*4 IER
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
C DO NOT EXPORT THE FOLLWING COOMON !
|
|
||||||
C IT IS JUST FOR PERMANENT STORAGE USE
|
|
||||||
C
|
|
||||||
DOUBLE PRECISION S, SINV
|
|
||||||
integer*4 iok
|
|
||||||
COMMON /OSOLEM/ S(4,4), SINV(4,4), iok
|
|
||||||
C---------------------------------------------------------------------------
|
|
||||||
integer*4 id, je
|
|
||||||
C---------------------------------------------------------------------------
|
|
||||||
C INIT AND TEST IF TRANSFO MATRICES ARE OK
|
|
||||||
IER = 1
|
|
||||||
IF (IOK.NE.123) GOTO 999
|
|
||||||
IER = 0
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C
|
|
||||||
DO ID = 1,3
|
|
||||||
QT(ID) = 0.D0
|
|
||||||
DO JE = 1,3
|
|
||||||
QT(ID) = QT(ID) + QHKL(JE)*S(ID,JE)
|
|
||||||
ENDDO
|
|
||||||
ENDDO
|
|
||||||
IER = 2
|
|
||||||
IF(ABS(QT(3)).GT.DEPS4) GOTO 999
|
|
||||||
IER = 0
|
|
||||||
QS = 0.D0
|
|
||||||
DO ID = 1,3
|
|
||||||
QS = QS+QT(ID)**2
|
|
||||||
ENDDO
|
|
||||||
IF(QS.LT.DEPS8) THEN
|
|
||||||
IER = 3
|
|
||||||
ELSE
|
|
||||||
QM = SQRT(QS)
|
|
||||||
ENDIF
|
|
||||||
C---------------------------------------------------------------------------
|
|
||||||
C
|
|
||||||
999 CONTINUE
|
|
||||||
RETURN
|
|
||||||
END
|
|
||||||
c
|
|
||||||
SUBROUTINE SP2RLV (QHKL, QT, QM, QS, IER) ! Part of [MAD.SRC]T_RLP.FOR
|
|
||||||
c =========================================
|
|
||||||
c
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
C INPUT QT QHKL <- QT
|
|
||||||
C A Q-VECTOR TO BE TRANSFORM FROM SCATTERING PLANE TO RECIP LATTICE
|
|
||||||
C CHECK THAT Q, D & G VECTORS ARE IN THE SCATTERING PLANE
|
|
||||||
C
|
|
||||||
C INPUT Q-VECTOR QT(3) Q-VECTOR IN SCATTERING PLANE
|
|
||||||
C
|
|
||||||
C OUTPUT Q-VECTOR QHKL(3) Q-VECTOR IN RECIPROCICAL LATTICVE
|
|
||||||
C OUTPUT QM AND QS QMODULUS AND ITS SQUARE ( TO BE VERIFIED )
|
|
||||||
C OUTPUT ERROR IER
|
|
||||||
C IER=1 MATRIX S NOT OK
|
|
||||||
C IER=2 Q NOT IN SCATTERING PLANE
|
|
||||||
C IER=3 Q MODULUS TOO SMALL
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
IMPLICIT NONE
|
|
||||||
C
|
|
||||||
DOUBLE PRECISION EPS4
|
|
||||||
PARAMETER (EPS4=1.D-4)
|
|
||||||
DOUBLE PRECISION EPS8
|
|
||||||
PARAMETER (EPS8=1.D-8)
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
c Define the dummy arguments
|
|
||||||
DOUBLE PRECISION QHKL(3)
|
|
||||||
DOUBLE PRECISION QT(3)
|
|
||||||
DOUBLE PRECISION QM
|
|
||||||
DOUBLE PRECISION QS
|
|
||||||
integer*4 IER
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
C DO NOT EXPORT THE FOLLWING COOMON !
|
|
||||||
C IT IS JUST FOR PERMANENT STORAGE USE
|
|
||||||
C
|
|
||||||
DOUBLE PRECISION S, SINV
|
|
||||||
integer*4 iok
|
|
||||||
COMMON /OSOLEM/ S(4,4), SINV(4,4), iok
|
|
||||||
C---------------------------------------------------------------------------
|
|
||||||
integer*4 id, je
|
|
||||||
C---------------------------------------------------------------------------
|
|
||||||
C INIT AND TEST IF TRANSFO MATRICES ARE OK
|
|
||||||
IER = 1
|
|
||||||
IF (IOK.NE.123) GOTO 999
|
|
||||||
IER = 2
|
|
||||||
IF(ABS(QT(3)).GT.EPS4) GOTO 999
|
|
||||||
IER = 0
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
QS = 0.D0
|
|
||||||
DO ID = 1,3
|
|
||||||
QS = QS+QT(ID)**2
|
|
||||||
ENDDO
|
|
||||||
IF(QS.LT.EPS8) THEN
|
|
||||||
IER = 3
|
|
||||||
ELSE
|
|
||||||
QM = SQRT(QS)
|
|
||||||
ENDIF
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C
|
|
||||||
DO ID = 1,3
|
|
||||||
QHKL(ID) = 0.D0
|
|
||||||
DO JE = 1,3
|
|
||||||
QHKL(ID) = QHKL(ID)+SINV(ID,JE)*QT(JE)
|
|
||||||
ENDDO
|
|
||||||
ENDDO
|
|
||||||
C---------------------------------------------------------------------------
|
|
||||||
C
|
|
||||||
999 CONTINUE
|
|
||||||
RETURN
|
|
||||||
END
|
|
||||||
c
|
|
||||||
SUBROUTINE INVS (S, SINV, IER) ! Part of [MAD.SRC]T_RLP.FOR
|
|
||||||
c ==============================
|
|
||||||
c
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
C ROUTINE TO INVERT MATRIX S, GENERATED BY SETRLP, WHICH TRANSFORMS
|
|
||||||
C (QH,QK,QL) TO (Q1,Q2) IN THE SCATTERING PLANE
|
|
||||||
C INPUT MATRIX DOUBLE PRECISION S(4,4)
|
|
||||||
C OUTPUT MATRIX DOUBLE PRECISION SINV(4,4)
|
|
||||||
C OUTPUT ERROR IER
|
|
||||||
C IER=1 DETERMINANT OF MATRIX S TOO SMALL
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
IMPLICIT NONE
|
|
||||||
c
|
|
||||||
DOUBLE PRECISION EPS6
|
|
||||||
PARAMETER (EPS6=1.D-6)
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
c Define the dummy arguments
|
|
||||||
DOUBLE PRECISION S(4,4)
|
|
||||||
DOUBLE PRECISION SINV(4,4)
|
|
||||||
integer*4 IER
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
integer*4 m(3)
|
|
||||||
integer*4 n(3)
|
|
||||||
c
|
|
||||||
integer*4 id, je
|
|
||||||
integer*4 mi, mj, ni, nj
|
|
||||||
double precision det
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
DATA M/2,3,1/
|
|
||||||
DATA N/3,1,2/
|
|
||||||
IER = 0
|
|
||||||
DO ID = 1,4
|
|
||||||
DO JE = 1,4
|
|
||||||
SINV(ID,JE) = 0.D0
|
|
||||||
ENDDO
|
|
||||||
ENDDO
|
|
||||||
DET = 0.D0
|
|
||||||
DO ID = 1,3
|
|
||||||
DO JE = 1,3
|
|
||||||
MI = M(ID)
|
|
||||||
MJ = M(JE)
|
|
||||||
NI = N(ID)
|
|
||||||
NJ = N(JE)
|
|
||||||
SINV(JE,ID) = S(MI,MJ)*S(NI,NJ)-S(NI,MJ)*S(MI,NJ)
|
|
||||||
ENDDO
|
|
||||||
DET = DET+S(ID,1)*SINV(1,ID)
|
|
||||||
ENDDO
|
|
||||||
IF(ABS(DET).LT.EPS6) THEN
|
|
||||||
IER = 1
|
|
||||||
ELSE
|
|
||||||
DO ID = 1,3
|
|
||||||
DO JE = 1,3
|
|
||||||
SINV(ID,JE) = SINV(ID,JE)/DET
|
|
||||||
ENDDO
|
|
||||||
ENDDO
|
|
||||||
ENDIF
|
|
||||||
SINV(4,4) = 1.D0
|
|
||||||
RETURN
|
|
||||||
END
|
|
||||||
c
|
|
||||||
SUBROUTINE ERRESO(MODULE,IER) ! Part of [MAD.SRC]T_RLP.FOR
|
|
||||||
c =============================
|
|
||||||
c
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
C SUBROUTINE TO TREAT ERRORS FROM RESOLUTION CALCULATIONS
|
|
||||||
C MODULE = 1 -> SETRLP
|
|
||||||
C MODULE = 2 -> RL2SPV
|
|
||||||
C MODULE = 3 -> EX_CASE
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
IMPLICIT NONE
|
|
||||||
c
|
|
||||||
integer*4 MXER
|
|
||||||
PARAMETER (MXER = 4)
|
|
||||||
integer*4 MXMOD
|
|
||||||
PARAMETER (MXMOD = 3)
|
|
||||||
c
|
|
||||||
C include 'iolsddef.inc'
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
c Define the dummy arguments
|
|
||||||
integer*4 module
|
|
||||||
integer*4 ier
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
integer*4 lmodule, lier
|
|
||||||
CHARACTER*64 MESER(MXER,MXMOD)
|
|
||||||
DATA MESER/
|
|
||||||
+ ' Check lattice spacings (AS,BS,CS)',
|
|
||||||
+ ' Check cell angles (AA,BB,CC)',
|
|
||||||
+ ' Check scattering plane (AX....BZ)',
|
|
||||||
+ ' Check lattice and scattering plane',
|
|
||||||
C
|
|
||||||
+ ' Check Lattice and Scattering Plane',
|
|
||||||
+ ' Q not in scattering plane',
|
|
||||||
+ ' Q modulus too small',
|
|
||||||
+ ' KI,KF,Q triangle cannot close',
|
|
||||||
C
|
|
||||||
+ ' Error in KI or KF. Check D-spacings & units',
|
|
||||||
+ ' KI or KF cannot be obtained',
|
|
||||||
+ ' KI or KF too small',
|
|
||||||
+ ' KI,KF,Q triangle will not close'/
|
|
||||||
C---------------------------------------------------------------------------
|
|
||||||
LIER = MIN(MAX(IER,1),MXER)
|
|
||||||
LMODULE = MIN(MAX(MODULE,1),MXMOD)
|
|
||||||
C WRITE(iolun,501) MESER(LIER,LMODULE)
|
|
||||||
501 FORMAT(A)
|
|
||||||
RETURN
|
|
||||||
END
|
|
495
t_update.c
495
t_update.c
@ -1,495 +0,0 @@
|
|||||||
/* t_update.f -- translated by f2c (version 20000817).
|
|
||||||
You must link the resulting object file with the libraries:
|
|
||||||
-lf2c -lm (in that order)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "f2c.h"
|
|
||||||
|
|
||||||
/* Subroutine */ int t_update__(p_a__, p_ih__, c_ih__, lpa, dm, da, isa, helm,
|
|
||||||
f1h, f1v, f2h, f2v, f, ei, aki, ef, akf, qhkl, en, hx, hy, hz, if1,
|
|
||||||
if2, qm, ier)
|
|
||||||
real *p_a__, *p_ih__, *c_ih__;
|
|
||||||
logical *lpa;
|
|
||||||
real *dm, *da;
|
|
||||||
integer *isa;
|
|
||||||
real *helm, *f1h, *f1v, *f2h, *f2v, *f, *ei, *aki, *ef, *akf, *qhkl, *en, *hx,
|
|
||||||
*hy, *hz;
|
|
||||||
integer *if1, *if2;
|
|
||||||
real *qm;
|
|
||||||
integer *ier;
|
|
||||||
{
|
|
||||||
static doublereal dakf, daki, dphi;
|
|
||||||
static integer ieri, imod, ieru;
|
|
||||||
extern /* Subroutine */ int ex_up__();
|
|
||||||
static doublereal df;
|
|
||||||
static integer id;
|
|
||||||
static real qs;
|
|
||||||
static doublereal dbqhkl[3];
|
|
||||||
extern /* Subroutine */ int sam_up__();
|
|
||||||
static doublereal da2, da3, da4, da6;
|
|
||||||
extern /* Subroutine */ int erreso_();
|
|
||||||
static doublereal dda, def, dei, ddm, dqm, dhx, dhy, dhz, dqs;
|
|
||||||
extern /* Subroutine */ int helm_up__(), flip_up__();
|
|
||||||
|
|
||||||
/* =================== */
|
|
||||||
|
|
||||||
/* dec$ Ident 'V01C' */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* Note: */
|
|
||||||
/* IF1,If2 changed to Int*4. They were Real*4 in ILL version. */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* Updates: */
|
|
||||||
/* V01A 7-May-1996 DM. Put error output to IOLUN, use IMPLICIT NONE and */
|
|
||||||
/* get the code indented so that it is readable! */
|
|
||||||
/* V01C 12-Oct-1998 DM. Put in Mag Field calculation for SINQ Helmolz coils. */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Entry points in this file: */
|
|
||||||
/* T_UPDATE : USE THE MOTOR ANGLES TO CALCULATE VALUES OF */
|
|
||||||
/* EI,KI,EF,KF,QH,QK,QL,EN AND TO DETERMINE */
|
|
||||||
/* WHETHER FLIPPERS F1,F2 ARE 'ON' OR 'OFF'. */
|
|
||||||
/* EX_UP : CALCULATE EX AND AKX FORM AX2 VALUES. */
|
|
||||||
/* SAM_UP : CALCULATE THINGS IN RECIPROCICAL LATTICE. */
|
|
||||||
/* HELM_UP : CALCULATE HELMHOLTZ FIELDS. */
|
|
||||||
/* FLIP_UP : CHECK IF FLIPPERS ON OR OFF. */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* T_UPDATE: */
|
|
||||||
/* ROUTINE TO USE THE MOTOR ANGLES TO */
|
|
||||||
/* CALCULATE VALUES OF EI,KI,EF,KF,QH,QK,QL,EN */
|
|
||||||
/* USE CURRENT-SUPPLY VALUES TO COMPUTE HELMHOLTZ FIELDS HX,HY,HZ */
|
|
||||||
/* AND TO DETERMINE WHETHER FLIPPERS F1,F2 ARE 'ON' OR 'OFF'. */
|
|
||||||
/* FLIPPERS ARE 'ON' ONLY IF CURRENTS ARE THOSE GIVEN BY */
|
|
||||||
/* F1V,F1H,F2V,F2H */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* File [MAD.SRC]T_UPDATE.FOR */
|
|
||||||
/* cc IMPLICIT DOUBLE PRECISION (A-H,O-Z) */
|
|
||||||
/* include 'iolsddef.inc' */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Define the dummy arguments */
|
|
||||||
/* Input: */
|
|
||||||
/* Positions of angles A1-A6. */
|
|
||||||
/* .. helmotz (8 currents). */
|
|
||||||
/* Position of currents for flippers and .. */
|
|
||||||
/* Configuration of the machine ... */
|
|
||||||
/* Conversion factors for Helmotz (4 currents). */
|
|
||||||
/* True if machine in polarization mode. */
|
|
||||||
/* Monochr. d-spacing */
|
|
||||||
/* Analyser d-spacing */
|
|
||||||
/* .. +ve to the left. */
|
|
||||||
/* Scattering sense at analyser (probably) .. */
|
|
||||||
/* .. ki (probably). */
|
|
||||||
/* Angle between axis of Helmolz pair one and .. */
|
|
||||||
/* .. current is possibly ki*f1h ??) */
|
|
||||||
/* Flipper 1 hor and vert currents (hor .. */
|
|
||||||
/* .. current is possibly kf*f2h ??) */
|
|
||||||
/* Flipper 2 hor and vert currents (hor .. */
|
|
||||||
/* Output: */
|
|
||||||
/* Energy unit */
|
|
||||||
/* Incident neutron energy */
|
|
||||||
/* Incident neutron wave vector */
|
|
||||||
/* Final neutron energy */
|
|
||||||
/* Final neutron wave vector */
|
|
||||||
/* Components of q in reciprocal space */
|
|
||||||
/* Energy transfer */
|
|
||||||
/* Components of Helmolz field on sample */
|
|
||||||
/* Status of Flippers 1 and 2 */
|
|
||||||
/* Length of q */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Error status */
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* SET UP */
|
|
||||||
|
|
||||||
/* Parameter adjustments */
|
|
||||||
--qhkl;
|
|
||||||
--c_ih__;
|
|
||||||
--p_ih__;
|
|
||||||
--p_a__;
|
|
||||||
|
|
||||||
/* Function Body */
|
|
||||||
ddm = *dm;
|
|
||||||
dda = *da;
|
|
||||||
df = *f;
|
|
||||||
da2 = p_a__[2];
|
|
||||||
da3 = p_a__[3];
|
|
||||||
da4 = p_a__[4];
|
|
||||||
da6 = p_a__[6];
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
ieri = 0;
|
|
||||||
ieru = 9;
|
|
||||||
ex_up__(&ddm, &dei, &daki, &da2, &df, &ieri);
|
|
||||||
if (ieri == 0) {
|
|
||||||
*ei = dei;
|
|
||||||
*aki = daki;
|
|
||||||
ieru = 0;
|
|
||||||
} else {
|
|
||||||
imod = 3;
|
|
||||||
erreso_(&imod, &ieri);
|
|
||||||
ieru = ieri + 8;
|
|
||||||
}
|
|
||||||
ieri = 0;
|
|
||||||
ieru = 9;
|
|
||||||
ex_up__(&dda, &def, &dakf, &da6, &df, &ieri);
|
|
||||||
if (ieri == 0) {
|
|
||||||
*ef = def;
|
|
||||||
*akf = dakf;
|
|
||||||
ieru = 0;
|
|
||||||
} else {
|
|
||||||
if (*isa == 0) {
|
|
||||||
*ef = dei;
|
|
||||||
*akf = daki;
|
|
||||||
def = dei;
|
|
||||||
dakf = daki;
|
|
||||||
ieru = 0;
|
|
||||||
} else {
|
|
||||||
imod = 3;
|
|
||||||
erreso_(&imod, &ieri);
|
|
||||||
ieru = ieri + 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (*isa == 0) {
|
|
||||||
*ef = dei;
|
|
||||||
*akf = daki;
|
|
||||||
def = dei;
|
|
||||||
dakf = daki;
|
|
||||||
ieru = 0;
|
|
||||||
}
|
|
||||||
if (ieru == 0) {
|
|
||||||
*en = dei - def;
|
|
||||||
}
|
|
||||||
ieri = 0;
|
|
||||||
ieru = 5;
|
|
||||||
sam_up__(dbqhkl, &dqm, &dqs, &dphi, &daki, &dakf, &da3, &da4, &ieri);
|
|
||||||
if (ieri == 0) {
|
|
||||||
for (id = 1; id <= 3; ++id) {
|
|
||||||
qhkl[id] = dbqhkl[id - 1];
|
|
||||||
}
|
|
||||||
*qm = dqm;
|
|
||||||
qs = dqs;
|
|
||||||
ieru = 0;
|
|
||||||
} else {
|
|
||||||
imod = 2;
|
|
||||||
erreso_(&imod, &ieri);
|
|
||||||
ieru = ieri + 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
ieri = 0;
|
|
||||||
if (*lpa) {
|
|
||||||
ieru = 1;
|
|
||||||
helm_up__(&dphi, helm, &p_ih__[1], &c_ih__[1], &dhx, &dhy, &dhz, &
|
|
||||||
ieri);
|
|
||||||
if (ieri != 0) {
|
|
||||||
/* WRITE(6,*) 'ERROR IN HELM_UP CHECK COEFF' */
|
|
||||||
} else {
|
|
||||||
*hx = dhx;
|
|
||||||
*hy = dhy;
|
|
||||||
*hz = dhz;
|
|
||||||
ieru = 0;
|
|
||||||
}
|
|
||||||
flip_up__(if1, if2, &p_ih__[1], f1v, f1h, f2v, f2h, aki, akf, &ieri);
|
|
||||||
}
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
*ier = ieru;
|
|
||||||
return 0;
|
|
||||||
} /* t_update__ */
|
|
||||||
|
|
||||||
|
|
||||||
/* Subroutine */ int ex_up__(dx, ex, akx, ax2, f, ier)
|
|
||||||
doublereal *dx, *ex, *akx, *ax2, *f;
|
|
||||||
integer *ier;
|
|
||||||
{
|
|
||||||
/* System generated locals */
|
|
||||||
doublereal d__1;
|
|
||||||
|
|
||||||
/* Builtin functions */
|
|
||||||
double sin();
|
|
||||||
|
|
||||||
/* Local variables */
|
|
||||||
static doublereal arg;
|
|
||||||
|
|
||||||
/* ================ */
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* CALCULATE EX AND AKX FORM AX2 VALUES */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Part of [MAD.SRC]T_UPDATE.FOR */
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Define the dummy arguments */
|
|
||||||
/* Input: */
|
|
||||||
/* D-SPACING OF CRISTAL */
|
|
||||||
/* TAKE OFF ANGLE */
|
|
||||||
/* Output: */
|
|
||||||
/* ENERGY UNIT */
|
|
||||||
/* ENERGY */
|
|
||||||
/* MOMENTUM */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Error - IER=1 if DX OR AX TOO SMALL */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* !!!!!!!!!! This has to be fixed manually after conversion by f2c. */
|
|
||||||
/* !!!!!!!!!! The reason is a different definition of the abs function. */
|
|
||||||
/* !!!!!!!!!! MK, May 2001 */
|
|
||||||
arg = (d__1 = *dx * sin(*ax2 / 114.59155902616465), abs(d__1));
|
|
||||||
if (arg <= 1e-4) {
|
|
||||||
*ier = 1;
|
|
||||||
} else {
|
|
||||||
*ier = 0;
|
|
||||||
*akx = 3.1415926535897932384626433832795 / arg;
|
|
||||||
/* Computing 2nd power */
|
|
||||||
d__1 = *akx;
|
|
||||||
*ex = *f * (d__1 * d__1);
|
|
||||||
}
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
return 0;
|
|
||||||
} /* ex_up__ */
|
|
||||||
|
|
||||||
|
|
||||||
/* Subroutine */ int sam_up__(qhkl, qm, qs, phi, aki, akf, a3, a4, ier)
|
|
||||||
doublereal *qhkl, *qm, *qs, *phi, *aki, *akf, *a3, *a4;
|
|
||||||
integer *ier;
|
|
||||||
{
|
|
||||||
/* Builtin functions */
|
|
||||||
double cos(), sin(), atan2();
|
|
||||||
|
|
||||||
/* Local variables */
|
|
||||||
static doublereal qpar, qperp;
|
|
||||||
extern /* Subroutine */ int sp2rlv_();
|
|
||||||
static doublereal qt[3];
|
|
||||||
|
|
||||||
/* ================= */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Part of [MAD.SRC]T_UPDATE.FOR */
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Define the dummy arguments */
|
|
||||||
/* Input: */
|
|
||||||
/* Actual value of KI */
|
|
||||||
/* Actual value of KF */
|
|
||||||
/* Actual value of A3 */
|
|
||||||
/* Output: */
|
|
||||||
/* Actual value of A4 */
|
|
||||||
/* CALCULATED POSITIONS IN RECIP. LATTICE */
|
|
||||||
/* Q MODULUS */
|
|
||||||
/* Q MODULUS SQUARED */
|
|
||||||
/* ANGLE BETWEEN KI AND Q */
|
|
||||||
/* NOT CALCULATED) */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* LOCAL PARAMETERS */
|
|
||||||
/* Error status. IER=1 if QM TOO SMALL (PHI */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* QPAR AND QPERP ARE COMPONENTS OF Q PARALLEL AND PERP TO KI */
|
|
||||||
/* TRANSFORM FROM SCATTERING PLANE INTO RECIPROCAL LATTICE */
|
|
||||||
|
|
||||||
/* Parameter adjustments */
|
|
||||||
--qhkl;
|
|
||||||
|
|
||||||
/* Function Body */
|
|
||||||
qpar = *aki - *akf * cos(*a4 / 57.29577951308232087679815481410517);
|
|
||||||
qperp = -(*akf) * sin(*a4 / 57.29577951308232087679815481410517);
|
|
||||||
qt[0] = qpar * cos(*a3 / 57.29577951308232087679815481410517) + qperp *
|
|
||||||
sin(*a3 / 57.29577951308232087679815481410517);
|
|
||||||
qt[1] = -qpar * sin(*a3 / 57.29577951308232087679815481410517) + qperp *
|
|
||||||
cos(*a3 / 57.29577951308232087679815481410517);
|
|
||||||
qt[2] = 0.;
|
|
||||||
sp2rlv_(&qhkl[1], qt, qm, qs, ier);
|
|
||||||
*ier = 3;
|
|
||||||
if (*qm > .001) {
|
|
||||||
*ier = 0;
|
|
||||||
}
|
|
||||||
*phi = 0.;
|
|
||||||
if (abs(qperp) > .001 && abs(qpar) > .001) {
|
|
||||||
*phi = atan2(qperp, qpar);
|
|
||||||
} else if (abs(qpar) < .001) {
|
|
||||||
if (*a4 > (float)0.) {
|
|
||||||
*phi = -1.5707963267948966;
|
|
||||||
} else {
|
|
||||||
*phi = 1.5707963267948966;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
return 0;
|
|
||||||
} /* sam_up__ */
|
|
||||||
|
|
||||||
|
|
||||||
/* Subroutine */ int helm_up__(phi, helm, p_ih__, c_ih__, dhx, dhy, dhz, ier)
|
|
||||||
doublereal *phi;
|
|
||||||
real *helm, *p_ih__, *c_ih__;
|
|
||||||
doublereal *dhx, *dhy, *dhz;
|
|
||||||
integer *ier;
|
|
||||||
{
|
|
||||||
/* System generated locals */
|
|
||||||
real r__1;
|
|
||||||
doublereal d__1, d__2;
|
|
||||||
|
|
||||||
/* Builtin functions */
|
|
||||||
double sqrt(), atan2(), cos(), sin();
|
|
||||||
|
|
||||||
/* Local variables */
|
|
||||||
static doublereal hdir, hmod, hpar, hdir2, h__[4], hperp;
|
|
||||||
static integer ic;
|
|
||||||
static logical at_sinq__;
|
|
||||||
|
|
||||||
/* ================== */
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------- */
|
|
||||||
/* HELMHOLTZ COILS UPDATE (ONLY IF LPA IS TRUE) */
|
|
||||||
/* ---------------------------------------------------------------- */
|
|
||||||
/* Part of [MAD.SRC]T_UPDATE.FOR */
|
|
||||||
|
|
||||||
/* include 'common_sinq.inc' */
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* At ILL: */
|
|
||||||
/* There are 3 coils for Hx/Hy at 120 degrees to each other. */
|
|
||||||
|
|
||||||
/* There is a 4th coil for Hz. */
|
|
||||||
|
|
||||||
/* At SINQ: */
|
|
||||||
/* There is an Hx coil and an Hy coil (actually each is 4 coils powered */
|
|
||||||
/* in series). They are mounted on a ring (SRO). The value of HELM is */
|
|
||||||
/* the angle between the Hx coil and ki. */
|
|
||||||
|
|
||||||
/* There is a 3rd coil for Hz. */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Define the dummy arguments */
|
|
||||||
/* Input: */
|
|
||||||
/* Angle between KI and Q in scatt'g plane (rad) */
|
|
||||||
/* Angle between first coil and KI (degrees) */
|
|
||||||
/* with Helmolz coils */
|
|
||||||
/* Current values of 4 currents associated .. */
|
|
||||||
/* Output: */
|
|
||||||
/* Conversion factor between Amperes and Gauss */
|
|
||||||
/* \ */
|
|
||||||
/* > The calculated fields */
|
|
||||||
/* / */
|
|
||||||
/* ---------------------------------------------------------------- */
|
|
||||||
/* LOCAL VARIABLES */
|
|
||||||
/* Error status. IER=1 if C_I HAS A ZERO COEF */
|
|
||||||
/* ---------------------------------------------------------------- */
|
|
||||||
/* H !FIELD OF 4 COILS AROUND SAMPLE */
|
|
||||||
/* HPAR !FIELD PAR COIL 1 */
|
|
||||||
/* HPERP !FIELD PERP. TO COIL 1 */
|
|
||||||
/* HDIR2 !ANGLE BETWEEN FIELD AND COIL 1 */
|
|
||||||
/* HDIR !ANGLE BETWEEN FIELD AND Q */
|
|
||||||
/* ---------------------------------------------------------------- */
|
|
||||||
/* Parameter adjustments */
|
|
||||||
--c_ih__;
|
|
||||||
--p_ih__;
|
|
||||||
|
|
||||||
/* Function Body */
|
|
||||||
*ier = 0;
|
|
||||||
at_sinq__ = TRUE_;
|
|
||||||
if (! at_sinq__) {
|
|
||||||
for (ic = 1; ic <= 4; ++ic) {
|
|
||||||
h__[ic - 1] = 0.;
|
|
||||||
if ((r__1 = c_ih__[ic], dabs(r__1)) > .001) {
|
|
||||||
h__[ic - 1] = p_ih__[ic + 4] * c_ih__[ic];
|
|
||||||
} else {
|
|
||||||
*ier = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hpar = h__[0] - (h__[1] + h__[2]) * .5;
|
|
||||||
hperp = sqrt(3.) * .5 * (h__[1] - h__[2]);
|
|
||||||
*dhz = h__[3];
|
|
||||||
} else {
|
|
||||||
for (ic = 1; ic <= 3; ++ic) {
|
|
||||||
h__[ic - 1] = 0.;
|
|
||||||
if ((r__1 = c_ih__[ic], dabs(r__1)) > .001) {
|
|
||||||
h__[ic - 1] = p_ih__[ic + 4] * c_ih__[ic];
|
|
||||||
} else {
|
|
||||||
*ier = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hpar = h__[0];
|
|
||||||
hperp = h__[1];
|
|
||||||
*dhz = h__[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Computing 2nd power */
|
|
||||||
d__1 = hpar;
|
|
||||||
/* Computing 2nd power */
|
|
||||||
d__2 = hperp;
|
|
||||||
hmod = sqrt(d__1 * d__1 + d__2 * d__2);
|
|
||||||
if (abs(hpar) > .001 && abs(hperp) > .001) {
|
|
||||||
hdir2 = atan2((abs(hperp)), (abs(hpar)));
|
|
||||||
if (hpar > 0. && hperp < 0.) {
|
|
||||||
hdir2 = -hdir2;
|
|
||||||
} else if (hpar < 0. && hperp > 0.) {
|
|
||||||
hdir2 = 3.1415926535897932384626433832795 - hdir2;
|
|
||||||
} else if (hpar < 0. && hperp < 0.) {
|
|
||||||
hdir2 += -3.1415926535897932384626433832795;
|
|
||||||
}
|
|
||||||
} else if (abs(hpar) > .001) {
|
|
||||||
if (hpar >= (float)0.) {
|
|
||||||
hdir2 = (float)0.;
|
|
||||||
}
|
|
||||||
if (hpar < (float)0.) {
|
|
||||||
hdir2 = 3.1415926535897932384626433832795;
|
|
||||||
}
|
|
||||||
} else if (abs(hperp) > .001) {
|
|
||||||
if (hperp >= (float)0.) {
|
|
||||||
hdir2 = 1.5707963267948966;
|
|
||||||
}
|
|
||||||
if (hperp < (float)0.) {
|
|
||||||
hdir2 = -1.5707963267948966;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
hdir2 = (float)0.;
|
|
||||||
}
|
|
||||||
hdir = hdir2 + *helm / 57.29577951308232087679815481410517 - *phi;
|
|
||||||
*dhx = hmod * cos(hdir);
|
|
||||||
*dhy = hmod * sin(hdir);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
} /* helm_up__ */
|
|
||||||
|
|
||||||
|
|
||||||
/* Subroutine */ int flip_up__(if1, if2, p_ih__, f1v, f1h, f2v, f2h, aki, akf,
|
|
||||||
ier)
|
|
||||||
integer *if1, *if2;
|
|
||||||
real *p_ih__, *f1v, *f1h, *f2v, *f2h, *aki, *akf;
|
|
||||||
integer *ier;
|
|
||||||
{
|
|
||||||
/* System generated locals */
|
|
||||||
real r__1, r__2;
|
|
||||||
|
|
||||||
/* ================== */
|
|
||||||
/* ---------------------------------------------------------------- */
|
|
||||||
/* FLIPPERS; ONLY IF LPA */
|
|
||||||
/* ---------------------------------------------------------------- */
|
|
||||||
/* Part of [MAD.SRC]T_UPDATE.FOR */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* Define the dummy arguments */
|
|
||||||
/* Input: */
|
|
||||||
/* with flipper coils */
|
|
||||||
/* Current values of 4 currents associated .. */
|
|
||||||
/* .. current is possibly aki*f1h ??) */
|
|
||||||
/* Flipper 1 vert and hor currents (hor .. */
|
|
||||||
/* .. current is possibly akf*f2h ??) */
|
|
||||||
/* Flipper 2 vert and hor currents (hor .. */
|
|
||||||
/* Incident neutron wave vector */
|
|
||||||
/* Output: */
|
|
||||||
/* Final neutron wave vector */
|
|
||||||
/* Status of Flipper 1 (=1 if on and set OK) */
|
|
||||||
/* Status of Flipper 2 (=1 if on and set OK) */
|
|
||||||
/* ---------------------------------------------------------------- */
|
|
||||||
/* Error status. 0 if no error. */
|
|
||||||
/* Parameter adjustments */
|
|
||||||
--p_ih__;
|
|
||||||
|
|
||||||
/* Function Body */
|
|
||||||
*ier = 0;
|
|
||||||
*if1 = 0;
|
|
||||||
*if2 = 0;
|
|
||||||
if ((r__1 = p_ih__[1] - *f1v, dabs(r__1)) < (float).05 && (r__2 = p_ih__[
|
|
||||||
2] - *aki * *f1h, dabs(r__2)) < (float).05) {
|
|
||||||
*if1 = 1;
|
|
||||||
}
|
|
||||||
if ((r__1 = p_ih__[3] - *f2v, dabs(r__1)) < (float).05 && (r__2 = p_ih__[
|
|
||||||
4] - *akf * *f2h, dabs(r__2)) < (float).05) {
|
|
||||||
*if2 = 1;
|
|
||||||
}
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
return 0;
|
|
||||||
} /* flip_up__ */
|
|
||||||
|
|
409
t_update.f
409
t_update.f
@ -1,409 +0,0 @@
|
|||||||
SUBROUTINE T_UPDATE ( ! File [MAD.SRC]T_UPDATE.FOR
|
|
||||||
c ===================
|
|
||||||
+ P_A, P_IH, C_IH,
|
|
||||||
+ LPA ,DM, DA, ISA, HELM, F1H, F1V, F2H, F2V, F,
|
|
||||||
+ EI, AKI, EF, AKF, QHKL, EN,
|
|
||||||
+ HX, HY, HZ, IF1, IF2, QM, IER)
|
|
||||||
c
|
|
||||||
cdec$ Ident 'V01C'
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
c Note:
|
|
||||||
c IF1,If2 changed to Int*4. They were Real*4 in ILL version.
|
|
||||||
c------------------------------------------------------------------
|
|
||||||
c Updates:
|
|
||||||
c V01A 7-May-1996 DM. Put error output to IOLUN, use IMPLICIT NONE and
|
|
||||||
c get the code indented so that it is readable!
|
|
||||||
c V01C 12-Oct-1998 DM. Put in Mag Field calculation for SINQ Helmolz coils.
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
c Entry points in this file:
|
|
||||||
C T_UPDATE : USE THE MOTOR ANGLES TO CALCULATE VALUES OF
|
|
||||||
c EI,KI,EF,KF,QH,QK,QL,EN AND TO DETERMINE
|
|
||||||
c WHETHER FLIPPERS F1,F2 ARE 'ON' OR 'OFF'.
|
|
||||||
|
|
||||||
c EX_UP : CALCULATE EX AND AKX FORM AX2 VALUES.
|
|
||||||
c SAM_UP : CALCULATE THINGS IN RECIPROCICAL LATTICE.
|
|
||||||
c HELM_UP : CALCULATE HELMHOLTZ FIELDS.
|
|
||||||
c FLIP_UP : CHECK IF FLIPPERS ON OR OFF.
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
c T_UPDATE:
|
|
||||||
C ROUTINE TO USE THE MOTOR ANGLES TO
|
|
||||||
C CALCULATE VALUES OF EI,KI,EF,KF,QH,QK,QL,EN
|
|
||||||
C USE CURRENT-SUPPLY VALUES TO COMPUTE HELMHOLTZ FIELDS HX,HY,HZ
|
|
||||||
C AND TO DETERMINE WHETHER FLIPPERS F1,F2 ARE 'ON' OR 'OFF'.
|
|
||||||
C FLIPPERS ARE 'ON' ONLY IF CURRENTS ARE THOSE GIVEN BY
|
|
||||||
C F1V,F1H,F2V,F2H
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
IMPLICIT NONE
|
|
||||||
ccc IMPLICIT DOUBLE PRECISION (A-H,O-Z)
|
|
||||||
C include 'iolsddef.inc'
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
c Define the dummy arguments
|
|
||||||
c Input:
|
|
||||||
real*4 p_a(6) ! Positions of angles A1-A6.
|
|
||||||
real*4 p_ih(8) ! Position of currents for flippers and ..
|
|
||||||
! .. helmotz (8 currents).
|
|
||||||
real*4 c_ih(4) ! Conversion factors for Helmotz (4 currents).
|
|
||||||
! Configuration of the machine ...
|
|
||||||
logical*4 lpa ! True if machine in polarization mode.
|
|
||||||
real*4 dm ! Monochr. d-spacing
|
|
||||||
real*4 da ! Analyser d-spacing
|
|
||||||
integer*4 isa ! Scattering sense at analyser (probably) ..
|
|
||||||
! .. +ve to the left.
|
|
||||||
real*4 helm ! Angle between axis of Helmolz pair one and ..
|
|
||||||
! .. ki (probably).
|
|
||||||
real*4 f1h, f1v ! Flipper 1 hor and vert currents (hor ..
|
|
||||||
! .. current is possibly ki*f1h ??)
|
|
||||||
real*4 f2h, f2v ! Flipper 2 hor and vert currents (hor ..
|
|
||||||
! .. current is possibly kf*f2h ??)
|
|
||||||
real*4 f ! Energy unit
|
|
||||||
c Output:
|
|
||||||
real*4 ei ! Incident neutron energy
|
|
||||||
real*4 aki ! Incident neutron wave vector
|
|
||||||
real*4 ef ! Final neutron energy
|
|
||||||
real*4 akf ! Final neutron wave vector
|
|
||||||
real*4 qhkl(3) ! Components of q in reciprocal space
|
|
||||||
real*4 en ! Energy transfer
|
|
||||||
real*4 hx, hy, hz ! Components of Helmolz field on sample
|
|
||||||
integer*4 if1, if2 ! Status of Flippers 1 and 2
|
|
||||||
real*4 qm ! Length of q
|
|
||||||
integer*4 ier ! Error status
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
double precision dbqhkl(3), dhx, dhy, dhz
|
|
||||||
double precision ddm, dda, df
|
|
||||||
double precision da2, da3, da4, da6
|
|
||||||
double precision dei, daki, def, dakf
|
|
||||||
double precision dqm, dqs, dphi
|
|
||||||
real*4 qs
|
|
||||||
c
|
|
||||||
integer*4 ieri, ieru, imod, id
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C SET UP
|
|
||||||
C
|
|
||||||
DDM=DM
|
|
||||||
DDA=DA
|
|
||||||
DF=F
|
|
||||||
DA2=P_A(2)
|
|
||||||
DA3=P_A(3)
|
|
||||||
DA4=P_A(4)
|
|
||||||
DA6=P_A(6)
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C
|
|
||||||
IERI=0
|
|
||||||
IERU=1 + 8
|
|
||||||
CALL EX_UP(DDM,DEI,DAKI,DA2,DF,IERI)
|
|
||||||
IF (IERI.EQ.0) THEN
|
|
||||||
EI=DEI
|
|
||||||
AKI=DAKI
|
|
||||||
IERU=0
|
|
||||||
ELSE
|
|
||||||
IMOD=3
|
|
||||||
CALL ERRESO(IMOD,IERI)
|
|
||||||
IERU = IERI + 8
|
|
||||||
ENDIF
|
|
||||||
IERI=0
|
|
||||||
IERU=1 + 8
|
|
||||||
CALL EX_UP(DDA,DEF,DAKF,DA6,DF,IERI)
|
|
||||||
IF (IERI.EQ.0) THEN
|
|
||||||
EF=DEF
|
|
||||||
AKF=DAKF
|
|
||||||
IERU=0
|
|
||||||
ELSE
|
|
||||||
IF (ISA.EQ.0) THEN
|
|
||||||
EF=DEI
|
|
||||||
AKF=DAKI
|
|
||||||
DEF=DEI
|
|
||||||
DAKF=DAKI
|
|
||||||
IERU=0
|
|
||||||
ELSE
|
|
||||||
IMOD=3
|
|
||||||
CALL ERRESO(IMOD,IERI)
|
|
||||||
IERU = 8 + IERI
|
|
||||||
ENDIF
|
|
||||||
ENDIF
|
|
||||||
IF (ISA.EQ.0) THEN
|
|
||||||
EF=DEI
|
|
||||||
AKF=DAKI
|
|
||||||
DEF=DEI
|
|
||||||
DAKF=DAKI
|
|
||||||
IERU=0
|
|
||||||
ENDIF
|
|
||||||
IF (IERU.EQ.0) EN=DEI-DEF
|
|
||||||
IERI=0
|
|
||||||
IERU=1 + 4
|
|
||||||
CALL SAM_UP(DBQHKL,DQM,DQS,DPHI,DAKI,DAKF,DA3,DA4,IERI)
|
|
||||||
IF (IERI.EQ.0) THEN
|
|
||||||
DO ID=1,3
|
|
||||||
QHKL(ID)=DBQHKL(ID)
|
|
||||||
ENDDO
|
|
||||||
QM=DQM
|
|
||||||
QS=DQS
|
|
||||||
IERU=0
|
|
||||||
ELSE
|
|
||||||
IMOD=2
|
|
||||||
CALL ERRESO(IMOD,IERI)
|
|
||||||
IERU = IERI + 4
|
|
||||||
ENDIF
|
|
||||||
C
|
|
||||||
IERI=0
|
|
||||||
IF (LPA) THEN
|
|
||||||
IERU=1
|
|
||||||
CALL HELM_UP(DPHI,HELM,P_IH,C_IH,DHX,DHY,DHZ,IERI)
|
|
||||||
IF (IERI.NE.0) THEN
|
|
||||||
C WRITE(6,*) 'ERROR IN HELM_UP CHECK COEFF'
|
|
||||||
ELSE
|
|
||||||
HX=DHX
|
|
||||||
HY=DHY
|
|
||||||
HZ=DHZ
|
|
||||||
IERU=0
|
|
||||||
ENDIF
|
|
||||||
CALL FLIP_UP(IF1,IF2,P_IH,F1V,F1H,F2V,F2H,AKI,AKF,IERI)
|
|
||||||
ENDIF
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
IER=IERU
|
|
||||||
RETURN
|
|
||||||
END
|
|
||||||
c
|
|
||||||
SUBROUTINE EX_UP(DX,EX,AKX,AX2,F,IER) ! Part of [MAD.SRC]T_UPDATE.FOR
|
|
||||||
c ================
|
|
||||||
c
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C CALCULATE EX AND AKX FORM AX2 VALUES
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
implicit none
|
|
||||||
c
|
|
||||||
DOUBLE PRECISION PI
|
|
||||||
PARAMETER (PI=3.1415926535897932384626433832795E0)
|
|
||||||
DOUBLE PRECISION RD
|
|
||||||
PARAMETER (RD=57.29577951308232087679815481410517E0)
|
|
||||||
DOUBLE PRECISION EPS4
|
|
||||||
PARAMETER (EPS4=1.D-4)
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
c Define the dummy arguments
|
|
||||||
c Input:
|
|
||||||
DOUBLE PRECISION DX ! D-SPACING OF CRISTAL
|
|
||||||
DOUBLE PRECISION AX2 ! TAKE OFF ANGLE
|
|
||||||
DOUBLE PRECISION F ! ENERGY UNIT
|
|
||||||
c Output:
|
|
||||||
DOUBLE PRECISION EX ! ENERGY
|
|
||||||
DOUBLE PRECISION AKX ! MOMENTUM
|
|
||||||
INTEGER*4 IER ! Error - IER=1 if DX OR AX TOO SMALL
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
DOUBLE PRECISION ARG
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C!!!!!!!!!! This has to be fixed manually after conversion by f2c.
|
|
||||||
C!!!!!!!!!! The reason is a different definition of the abs function.
|
|
||||||
C!!!!!!!!!! MK, May 2001
|
|
||||||
|
|
||||||
ARG=ABS(DX*SIN(AX2/(2.D0*RD)))
|
|
||||||
IF(ARG.LE.EPS4) THEN
|
|
||||||
IER=1
|
|
||||||
ELSE
|
|
||||||
IER=0
|
|
||||||
AKX=PI/ARG
|
|
||||||
EX=F*AKX**2
|
|
||||||
ENDIF
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
RETURN
|
|
||||||
END
|
|
||||||
c
|
|
||||||
SUBROUTINE SAM_UP ( ! Part of [MAD.SRC]T_UPDATE.FOR
|
|
||||||
c =================
|
|
||||||
+ QHKL, QM, QS, PHI,
|
|
||||||
+ AKI, AKF, A3, A4, IER)
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
implicit none
|
|
||||||
c
|
|
||||||
double precision PI
|
|
||||||
PARAMETER (PI=3.1415926535897932384626433832795D0)
|
|
||||||
double precision RD
|
|
||||||
PARAMETER (RD=57.29577951308232087679815481410517D0)
|
|
||||||
double precision EPS3
|
|
||||||
PARAMETER (EPS3=1.D-3)
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
c Define the dummy arguments
|
|
||||||
c Input:
|
|
||||||
double precision AKI ! Actual value of KI
|
|
||||||
double precision AKF ! Actual value of KF
|
|
||||||
double precision A3 ! Actual value of A3
|
|
||||||
double precision A4 ! Actual value of A4
|
|
||||||
c Output:
|
|
||||||
double precision QHKL(3) ! CALCULATED POSITIONS IN RECIP. LATTICE
|
|
||||||
double precision QM ! Q MODULUS
|
|
||||||
double precision QS ! Q MODULUS SQUARED
|
|
||||||
double precision PHI ! ANGLE BETWEEN KI AND Q
|
|
||||||
integer*4 IER ! Error status. IER=1 if QM TOO SMALL (PHI
|
|
||||||
! NOT CALCULATED)
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C LOCAL PARAMETERS
|
|
||||||
double precision QT(3)
|
|
||||||
double precision QPAR, QPERP
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
C QPAR AND QPERP ARE COMPONENTS OF Q PARALLEL AND PERP TO KI
|
|
||||||
C TRANSFORM FROM SCATTERING PLANE INTO RECIPROCAL LATTICE
|
|
||||||
C
|
|
||||||
qpar = aki - akf * cos(a4/RD)
|
|
||||||
qperp = -akf * sin(a4/RD)
|
|
||||||
qt(1) = qpar * cos(a3/RD) + qperp * sin(a3/RD)
|
|
||||||
qt(2) = -qpar * sin(a3/RD) + qperp * cos(a3/RD)
|
|
||||||
qt(3) = 0.d0
|
|
||||||
call sp2rlv (qhkl, qt, qm, qs, ier)
|
|
||||||
ier = 3
|
|
||||||
if (qm .gt. EPS3) ier = 0
|
|
||||||
phi = 0.d0
|
|
||||||
if (abs(qperp) .gt. EPS3 .and. abs(qpar) .gt. EPS3) then
|
|
||||||
phi = atan2 (qperp, qpar)
|
|
||||||
elseif (abs(qpar) .lt. EPS3) then
|
|
||||||
if (a4 .gt. 0.0) then
|
|
||||||
phi = -0.5 * PI
|
|
||||||
else
|
|
||||||
phi = 0.5 * PI
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
c-----------------------------------------------------------------------
|
|
||||||
return
|
|
||||||
end
|
|
||||||
c
|
|
||||||
SUBROUTINE HELM_UP ( ! Part of [MAD.SRC]T_UPDATE.FOR
|
|
||||||
c ==================
|
|
||||||
+ PHI, HELM, P_IH, C_IH,
|
|
||||||
+ DHX, DHY, DHZ, IER)
|
|
||||||
c
|
|
||||||
C----------------------------------------------------------------
|
|
||||||
C HELMHOLTZ COILS UPDATE (ONLY IF LPA IS TRUE)
|
|
||||||
C----------------------------------------------------------------
|
|
||||||
implicit none
|
|
||||||
c
|
|
||||||
C include 'common_sinq.inc'
|
|
||||||
c
|
|
||||||
double precision PI
|
|
||||||
PARAMETER (PI = 3.1415926535897932384626433832795D0)
|
|
||||||
double precision RD
|
|
||||||
PARAMETER (RD = 57.29577951308232087679815481410517D0)
|
|
||||||
double precision EPS3
|
|
||||||
PARAMETER (EPS3 = 1.0D-3)
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
c At ILL:
|
|
||||||
c There are 3 coils for Hx/Hy at 120 degrees to each other.
|
|
||||||
c
|
|
||||||
c There is a 4th coil for Hz.
|
|
||||||
c
|
|
||||||
c At SINQ:
|
|
||||||
c There is an Hx coil and an Hy coil (actually each is 4 coils powered
|
|
||||||
c in series). They are mounted on a ring (SRO). The value of HELM is
|
|
||||||
c the angle between the Hx coil and ki.
|
|
||||||
c
|
|
||||||
c There is a 3rd coil for Hz.
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
c Define the dummy arguments
|
|
||||||
c Input:
|
|
||||||
double precision PHI ! Angle between KI and Q in scatt'g plane (rad)
|
|
||||||
real*4 HELM ! Angle between first coil and KI (degrees)
|
|
||||||
real*4 P_IH(8) ! Current values of 4 currents associated ..
|
|
||||||
! with Helmolz coils
|
|
||||||
real*4 C_IH(4) ! Conversion factor between Amperes and Gauss
|
|
||||||
c Output:
|
|
||||||
double precision DHX ! \
|
|
||||||
double precision DHY ! > The calculated fields
|
|
||||||
double precision DHZ ! /
|
|
||||||
integer*4 IER ! Error status. IER=1 if C_I HAS A ZERO COEF
|
|
||||||
C----------------------------------------------------------------
|
|
||||||
C LOCAL VARIABLES
|
|
||||||
integer*4 ic
|
|
||||||
double precision h(4), hpar, hperp, hmod, hdir, hdir2
|
|
||||||
LOGICAL AT_SINQ
|
|
||||||
C----------------------------------------------------------------
|
|
||||||
C H !FIELD OF 4 COILS AROUND SAMPLE
|
|
||||||
C HPAR !FIELD PAR COIL 1
|
|
||||||
C HPERP !FIELD PERP. TO COIL 1
|
|
||||||
C HDIR2 !ANGLE BETWEEN FIELD AND COIL 1
|
|
||||||
C HDIR !ANGLE BETWEEN FIELD AND Q
|
|
||||||
C----------------------------------------------------------------
|
|
||||||
ier = 0
|
|
||||||
AT_SINQ = .TRUE.
|
|
||||||
if (.not. at_sinq) then
|
|
||||||
do ic = 1, 4
|
|
||||||
h(ic) = 0.d0
|
|
||||||
if (abs(c_ih(ic)) .gt. EPS3) then
|
|
||||||
h(ic) = p_ih(ic+4) * c_ih(ic)
|
|
||||||
else
|
|
||||||
ier = 1
|
|
||||||
endif
|
|
||||||
enddo
|
|
||||||
hpar = h(1) - .5d0 * (h(2) + h(3))
|
|
||||||
hperp = .5d0 * sqrt(3.d0) * (h(2) - h(3))
|
|
||||||
dhz = h(4)
|
|
||||||
else
|
|
||||||
do ic = 1, 3
|
|
||||||
h(ic) = 0.d0
|
|
||||||
if (abs(c_ih(ic)) .gt. EPS3) then
|
|
||||||
h(ic) = p_ih(ic+4) * c_ih(ic)
|
|
||||||
else
|
|
||||||
ier = 1
|
|
||||||
endif
|
|
||||||
enddo
|
|
||||||
hpar = h(1)
|
|
||||||
hperp = h(2)
|
|
||||||
dhz = h(3)
|
|
||||||
endif
|
|
||||||
c
|
|
||||||
hmod = sqrt (hpar**2 + hperp**2)
|
|
||||||
if (abs(hpar) .gt. EPS3 .and. abs(hperp) .gt. EPS3) then
|
|
||||||
hdir2 = atan2 (abs(hperp), abs(hpar))
|
|
||||||
if (hpar .gt. 0 .and. hperp .lt. 0) then
|
|
||||||
hdir2 = -hdir2
|
|
||||||
elseif (hpar .lt. 0 .and. hperp .gt. 0) then
|
|
||||||
hdir2 = PI - hdir2
|
|
||||||
elseif (hpar .lt. 0 .and. hperp .lt. 0) then
|
|
||||||
hdir2 = hdir2 - PI
|
|
||||||
endif
|
|
||||||
elseif (abs(hpar) .gt. EPS3) then
|
|
||||||
if (hpar .ge. 0.0) hdir2 = 0.0
|
|
||||||
if (hpar .lt. 0.0) hdir2 = PI
|
|
||||||
elseif (abs(hperp) .gt. EPS3) then
|
|
||||||
if (hperp .ge. 0.0) hdir2 = 0.5 * PI
|
|
||||||
if (hperp .lt. 0.0) hdir2 = -0.5 * PI
|
|
||||||
else
|
|
||||||
hdir2 = 0.0
|
|
||||||
endif
|
|
||||||
hdir = hdir2 + (helm/RD) - phi
|
|
||||||
dhx = hmod * cos(hdir)
|
|
||||||
dhy = hmod * sin(hdir)
|
|
||||||
c
|
|
||||||
return
|
|
||||||
end
|
|
||||||
c
|
|
||||||
SUBROUTINE FLIP_UP ( ! Part of [MAD.SRC]T_UPDATE.FOR
|
|
||||||
c ==================
|
|
||||||
+ IF1, IF2,
|
|
||||||
+ P_IH, F1V, F1H, F2V, F2H,
|
|
||||||
+ AKI, AKF, IER)
|
|
||||||
C----------------------------------------------------------------
|
|
||||||
C FLIPPERS; ONLY IF LPA
|
|
||||||
C----------------------------------------------------------------
|
|
||||||
implicit none
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
c Define the dummy arguments
|
|
||||||
c Input:
|
|
||||||
real*4 p_ih(8) ! Current values of 4 currents associated ..
|
|
||||||
! with flipper coils
|
|
||||||
real*4 f1v, f1h ! Flipper 1 vert and hor currents (hor ..
|
|
||||||
! .. current is possibly aki*f1h ??)
|
|
||||||
real*4 f2v, f2h ! Flipper 2 vert and hor currents (hor ..
|
|
||||||
! .. current is possibly akf*f2h ??)
|
|
||||||
real*4 aki ! Incident neutron wave vector
|
|
||||||
real*4 akf ! Final neutron wave vector
|
|
||||||
c Output:
|
|
||||||
integer*4 if1 ! Status of Flipper 1 (=1 if on and set OK)
|
|
||||||
integer*4 if2 ! Status of Flipper 2 (=1 if on and set OK)
|
|
||||||
integer*4 ier ! Error status. 0 if no error.
|
|
||||||
C----------------------------------------------------------------
|
|
||||||
IER = 0
|
|
||||||
IF1 = 0
|
|
||||||
IF2 = 0
|
|
||||||
IF ((ABS(P_IH(1) - F1V) .LT. 0.05) .AND.
|
|
||||||
+ (ABS(P_IH(2) - AKI*F1H) .LT. 0.05)) IF1 = 1
|
|
||||||
IF ((ABS(P_IH(3) - F2V) .LT. 0.05) .AND.
|
|
||||||
+ (ABS(P_IH(4) - AKF*F2H) .LT. 0.05)) IF2 = 1
|
|
||||||
C-----------------------------------------------------------------------
|
|
||||||
RETURN
|
|
||||||
END
|
|
Reference in New Issue
Block a user