Programming XtalView
To add a program to xtalview, you must edit the list of programs kept in $XTALVIEWHOME/data/applications. When xtalmgr starts, it reads this list and displays the choices in the two pull-down menus: Applications and Utilities. Applications are window-based programs that have an XView format icon associated with them. Utilities are nonwindow-based programs that run in a text window. A utility can be a simple filter, such as a reformatter for importing/exporting data to non-xtalview programs. The new program must be included in the user's path.The format for a window-based application in the file is:
program icon-name arg1 arg2 arg3
where icon-name is a file containing an icon image in ASCII HEX format, and arg1-3 act as file filters that are put into the file filter lines in the three scrolling window lists in xtalmgr. Commas separate items for multiple arguments. For example:
xprepfin images/xprepfin.icon *.fin,*.df,*.mu - *.fin
The "-" indicates that there are no arguments for the second list. The first field will contain all files in the current directory that match *.fin, *.df, and *.mu.
Nonwindow applications are similar, except that the image name is replaced with a short description of the format. Spaces in this description are replaced with commas, which are replaced by spaces when xtalmgr loads the file.
Using the XtalView Database in Other Programs
You can access the data in the crystal file from other programs by linking in subroutines for this purpose in the $XTALVIEWHOME/make_arch/lib directory, where arch is the architecture of your machine. Your program can be either in C or Fortran. To link in the subroutines, add the following to the end of the compile or load line: $XTALVIEWHOME/make_arch/lib/crystlib.a.Fortran Routines (lib/f77subs.c):To pass messages from the lib routines, a routine emess is expected. This should consist of the following C subroutine:
#include <stdio.h>
int emess(message)
char *message;
{
fprintf(stderr,"%s\n",message);
}
Put this in a file and compile it with the command cc -c emess.c. Then add emess.o to the compile line:
f77 -o program program.f emess.o $XTALVIEWHOME/lib/crystlib.a
The following routines may be called from Fortran programs.C Functions in crystlib.aThe routine
subroutine xf_getcell(crystal, a, b, c, alpha, beta, gamma)returns the unit cell information for the crystal file crystal. That is, it opens the file ./crystal if it exists. If not, it tries $CRYSTALDATA/crystal and reads the information on the line starting with cell.character*80 crystal
real*4 a, b, c, alpha, beta, gamma
The routine
subroutine xf_get_ctof(crystal,ctof,ftoc)returns the matrices for transforming coordinates from Cartesian orthogonal to fractional (ctof), and vice versa (ftoc).character*80 crystal
real*4 ctof(9), ftoc(9)
The elements of the transformation matrix ctof are defined as follows:
xf = xc*ctof(1) + yc*ctof(2) + zc*ctof(3)The elements of the transformation matrix ftoc are defined similarly.yf = xc*ctof(4) + yc*ctof(5) + zc*ctof(6)
zf = xc*ctof(7) + yc*ctof(8) + zc*ctof(9)
The routine
subroutine xf_getnequiv(crystal,nequiv)gets the number of symmetry operators (or equivalent positions) from the symm record in the crystal file. It is used in conjunction with xf_getsymmop().character*80 crystal
integer*4 nequiv
The routine
subroutine xf_getsymmop(crystal,nop,symchar,ns)returns the ASCII representation of the symmetry operator found at the nops position.character*80 crystal, symchar
integer*4 nop, ns
Here, ns is the length of the string symchar, which is 80 in this case. This routine is called in turn for each symmetry operator (see xf_getnequiv). For example, if the crystal file myprotein contains the line:
symm x,y,z; -x,y,-zand the call xf_getsymmop(myprotein, 2, symmop, 80) is made, symmop will contain -x,y,-z afterwards. You can use this routine to list the symmetry operators, or you can use the translate routine by B.C. Wang and Bill Forey of the University of Pittsburgh to translate symchar. The xf_scansymmops routine (below) can also be used to return symmetry operators.
The routine
subroutine xf_scansymmops(crystal, nops, symmops)returns the number of symmetry operators on the symm record of the crystal file in nops. The operators themselves are returned in the symmops array. See also the scan_symmops2 function described later.character*80 crystal
integer*4 nops
real*4 symmops(2304)
To access the iop symmetry operator at position irow, icol, use the formula:
symmops(iop+192*((irow-1)+4*(icol-1)))Thus, to find the equivalent x of the second symmetry operator:
x2 = x * symmops(2+192*((1-1)+4*(1-1)))See also xf_transform below.+ y * symmops(2+192*((2-1)+4*(1-1)))
+ z * symmops(2+192*((3-1)+4*(1-1)))
+ symmops(2+192*((4-1)+4*(1-1)))
The routine
function xf_transform(x, y, z, symmops, iop)returns the transformed x, y, z of the symmetry operator number iop.real*4 x, y, z
real*4 symmops(2304)
integer*4 iop
The routine
integer function xf_iscentric(h, k, l, symmops, nops)returns 0 if a reflection is acentric, given the symmops, which are from xf_scansymmops.integer*4 h, k, l
real*4 symmops(2304)
If the reflection is centric, it returns one of the allowed phases divided by 15. The other allowed phase is plus 180 degrees. Thus, if the reflection is centric and the allowed phases are 0 and 180, the function returns 180/15, or 12. Since xf_iscentric is an integer function but starts with the letter x, be sure to tell the compiler it is an integer with integer*4 xf_iscentric in the variables declaration part of your program.
The routine
integer function xf_getdata(crystal,key,data,ndata)retrieves some arbitrary data from the crystal file, where crystal is as above, key is the keyword of the data line you are searching for, and data is a string to contain the returned data. Ndata tells the routine how long the string data can be before overflowing. This function returns 0 if unsuccessful, and the length of the data if successful.character*80 crystal
character*20 key
character*1024 data
integer*4 ndata
data ndata/1024/
Several C functions are described in this section.The function
int get_celln(crystal, A, B, C, Alpha, Beta, Gamma)puts cell from crystal in A, B, C, Alpha, Beta, Gamma. It returns 0 if unsuccessful; otherwise, it returns 1. Non-xview programs should use get_celln.float *A, *B, *C, *Alpha, *Beta, *Gamma,
char *crystal;
The function
char *get_data(crystal, key)returns a pointer to the start of the data in the crystal file that matches key. It returns NULL if the a line starting with key cannot be found. The pointer is valid until the next call of get_data, which is also called by other xtalview routines; therefore, you should copy the data if it is to be used later. For example:char *crystal;
char *key;
#include "lib/Xguicryst.h"
if(get_data(cystal,"cell")) strcpy(save, get_data(crystal,"symm"));The function
int scan_symmops2(crystal, symmops, opstring)gets the symmetry operators for crystal and returns the number of symmetry operators. If unsuccessful, it sends messages to stderr and returns 0.char *crystal;
symmops[3][4][MAXSYMMOPS];
char opstring[MAXSYMMOPS][MAXSTRING];
#include "lib/Xguicryst.h"
symmops contains the matrices, and opstring contains the ASCII string equivalents. Even if you don't need opstring, you must allocate the string or the subroutine will crash for lack of space. Here's an example of using the matrices:
x2 = x*symmops[0][0][2] + y*symmops[0][1][2] + z*symmops[0][2][2] + symmops[0][3][2];The functiony2 = x*symmops[1][0][2] + y*symmops[1][1][2] + z*symmops[1][2][2] + symmops[1][3][2];
z2 = x*symmops[2][0][2] + y*symmops[2][1][2] + z*symmops[2][2][2] + symmops[2][3][2];
int addcenter2(n,symmops)changes the symmetry operators to the equivalent Patterson space group by adding a center of symmetry and negating all translations. The new number of symmetry operators is returned, and the starting number of symmops should be in n.int n;
float symmops[3][4][MAXSYMMOPS];
The function
int get_ctof(ctof,crystal)gets the Cartesian-to-fractional transformation matrix for the crystal. Usually, this is derived from the unit cell by the same algorithm as used by FRODO and XPLOR, in which case a 9 is returned.float ctof[3][3];
char *crystal;
This matrix can be overridden if the line ctof is included in the crystal file, in which case the return value is 1. If 0 is returned, the operation failed. The most likely value for this is the wrong number of numbers on the ctof line. There should be 9. Usage of the matrix is:
xf = x*ctof[0][0] + y*ctof[0][1] + z*ctof[0][2]See also transform (below). To get the opposite matrix for fractional to Cartesian, invert this matrix with uinv:yf = x*ctof[1][0] + y*ctof[1][1] + z*ctof[1][2]
zf = x*ctof[2][0] + y*ctof[2][1] + z*ctof[2][2]
uinv(ctof,ftoc)
float ctof[3][3];
float ftoc[3][3];
The function
int transform (ctof,x,y,z)transforms x, y, and z by the ctof matrix.float ctof [3][3];
float *x,*y,*z;
The function
int iscentric(h, symmops, nops)returns 0 if a reflection is acentric, given the symmetry operators and the Miller indices in the vector h. If the reflection is centric, it returns one of the allowed phases, divided by 15. The other allowed phase is plus 180 degrees. Thus, if the reflection is centric and the allowed phases are 0 and 180, the function returns 180/15, or 12.int h[3], nops;
float symmops[3][4][MAXSYMMOPS];
#include "lib/Xguicryst.h"
A sister function which uses individual integers for the indices is:
int iscentrichkl(h,k,l, symmops, nops)The functionint h, k, l, nops;
float symmops[3][4][MAXSYMMOPS];
int ReadFin(fp, refl)reads in a fin format file fp into an array of FIN structures. (FIN is defined in Xguicryst.h). The number of records read is returned.FILE *fp;
FIN **refl;
#include "lib/Xguicryst.h"
The function dynamically allocates all the space needed so that the address of a pointer of type FIN is sent ; that is, in your code you should have:
FIN *refl;The functionint nrefl=0;
nrefl = ReadFin(fp, &refl);
int ReadMu(fp, refl)reads in an XENGEN .mu (mulist) format file fp into an array of FIN structures. It's similar to ReadFin (see previous discussion).FILE *fp;
FIN **refl;
#include "lib/Xguicryst.h"
The function
int ReadDF(fp, refl, control)is similar to ReadFin (previous), except that it reads in a df (double fin) format file.FILE *fp;
FIN **refl;
int control;
#include "lib/Xguicryst.h"
Since there are 4 columns (a column is the pair F, s(F)) in a df file, and only 2 in a fin file, control specifies how this information is read:
If control is: The information is read as:
0 Average 1 with 2 and 3 with 4 (zeros are ignored in the averaging)
1 Return 1 and 2 only (usually the native anomalous)
2 Return 3 and 4 only (usually the derivative anomalous)
The function
int ReadPhs(fp, refl, hmin, hmax, kmin, kmax, lmin, lmax, scalefc)reads in a phase file and dynamically allocates space (see ReadFin, previously discussed). A REFL structure is defined in Xguicryst.h. It also returns the min and maximum of the indices and the scale for Fc to Fo. The function return is the number of reflections read.FILE *fp;
REFL **refl;
int *hmin, *hmax, *kmin, *kmax, *lmin, *lmax;
float *scalefc;
#include "lib/Xguicryst.h"
If the scale is to be applied:
nrefl = ReadPhs(fp, &refl, &hmin, &hmax, &kmin, &kmax, &lmin, &lmax, &scalefc);The latter is usually more useful, since it puts the data on an absolute scale.for(i=0; i< nrefl; i++) refl.fc *= scalefc;
OR
for(i=0; i< nrefl; i++) refl.fo /= scalefo;
The function
float *fft3d(refl,nrefl,mapheader)performs a Fast-Fourier Transform of data in refl with information in mapheader (defined in Xguicryst.h). The following mapheader data must be set:REFL *refl;
int nrefl;
MAPHEADER *mapheader;
#include "lib/Xguicryst.h"
#include "lib/fft.h"
nx, ny, nzwhere nx, ny, nz must be factors of 2, 3, 5, and 7, and nx must be even. A pointer to a one-dimensional array of size nx*ny*nz is returned that contains the entire unit cell. When you are through with the array, it can be deallocated with free(). The array is sorted as: nx = fast, ny = medium, and nz = slow. The point ix, iy, iz is indexed with:a, b, c, alpha, beta, gamma /*from get_cell*/
resmax, resmin
nsym, symops /*from scan_symmops2*/
maptype /*as defined in fft.h*/
rho = map[nx*(ny*((iz+64*nz)%nz) + (iy+64*ny)%ny ) + (ix+64*nx)%nx]The modulo arithmetic guarantees that ix, iy, iz wrap around the unit cell properly. The program must link in fftlib.o to access the FFT routines. The routines are very fast. On most workstations, the combination of ReadPhs, fft3d is faster than reading a precomputed map from disk.
The function
int fsread(rho, nx, ny, nz, rhoscale, rmsrho, fp, err)reads a map file into the array rho. Map files are in the same format as those calculated by Bill Furey's FSFOUR program. rho must be pre-allocated to be nx*ny*nz. This information can be obtained from a call to fssize (see below). The map will be scaled so that r.m.s rho is 50.0. rhoscale can be used to retrieve the original scale of the map. The string err will contain any errors. All three possible sort orders are auto-detected and resort to x = fast, y = medium, and z = slow when read in.int rho[]
int *nx, *ny, *nz;
float *rhoscale;
float *rmsrho;
FILE *fp;
char *err;
For example:
fp = fopen("mapfile","r");The array map is indexed as described in fft3d (described previously).nmax = fssize(fp);
map = (int *)malloc(nmax*sizeof(int));
rewind(fp);
nmap = fsread(map, &nx, &ny, &nz, &rhoscale, &rmsrho, fp, err);
if(nmap <= 0 || nmap != nmax){
emess("Error in map file: "); emess(err);
}
fclose(fp);
The function
int fssize(fp)returns the total dimensions nx*ny*nz of the map stored in the map file fp.FILE *fp;
The function
int fswrite(rho, fp, mh, direction, centric)writes out a map file in xtalview/FSFOUR format. Note that the map in this case is an array of floats. This is for historical reasons. The map format is written out as integers, and floats are rounded to the nearest integer; thus, the map should be scaled so that this will not result in all 0s in the output. (I.e., the r.m.s. of the map should be above at least 10.0; xtalview uses 50.0.)float map[];/* sorted x fast, y medium, z slow ascending */
FILE *fp;
MAPHEADER *mh; /* see Xguicryst.h */
int direction;
int centric;
direction controls the output sort order: 0 is planes of y, 1 is planes of x, and 2 is planes of z. Set centric to 0.
The following information is used in the mapheader structure:
a, b, c, alpha, beta, gammaThe symmetry operator positions in the file are filled with zeroes.nx, ny, nz
scale, nsym
The function
float rescalc(ih, ik, il, a, b, c, alpha, beta, gamma, init)returns the resolution in Ångstroms, given the Miller indices and the unit cell. The first time it is used, init must be 1. Afterwards, init is not 1 unless a new unit cell is used; in this case, init should be set to 1 once.int ih, ik, il; /* the Miller indices */
float a, b, c, alpha, beta, gamma; /* the unit cell */
int init;