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.

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.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

Fortran Routines (lib/f77subs.c):

The following routines may be called from Fortran programs.The routine

subroutine xf_getcell(crystal, a, b, c, alpha, beta, gamma)

character*80 crystal

real*4 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.The routine

subroutine xf_get_ctof(crystal,ctof,ftoc)

character*80 crystal

real*4 ctof(9), ftoc(9)

returns the matrices for transforming coordinates from Cartesian orthogonal to fractional (ctof), andvice versa(ftoc).The elements of the transformation matrix ctof are defined as follows:

xf = xc*ctof(1) + yc*ctof(2) + zc*ctof(3)

yf = xc*ctof(4) + yc*ctof(5) + zc*ctof(6)

zf = xc*ctof(7) + yc*ctof(8) + zc*ctof(9)

The elements of the transformation matrix ftoc are defined similarly.The routine

subroutine xf_getnequiv(crystal,nequiv)

character*80 crystal

integer*4 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().The routine

subroutine xf_getsymmop(crystal,nop,symchar,ns)

character*80 crystal, symchar

integer*4 nop, ns

returns the ASCII representation of the symmetry operator found at the nops position.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,-z

and the call xf_getsymmop(myprotein, 2, symmop, 80) is made,symmopwill 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

xf_scansymmops(crystal, nops, symmops)subroutine

character*80 crystal

integer*4 nops

real*4 symmops(2304)

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.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)))

+ 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)))

See also xf_transform below.The routine

function xf_transform(x, y, z, symmops, iop)

real*4 x, y, z

real*4 symmops(2304)

integer*4 iop

returns the transformed x, y, z of the symmetry operator number iop.The routine

integer function xf_iscentric(h, k, l, symmops, nops)

integer*4 h, k, l

real*4 symmops(2304)

returns 0 if a reflection is acentric, given the symmops, which are from xf_scansymmops.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)

character*80 crystal

character*20 key

character*1024 data

integer*4 ndata

data ndata/1024/

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.

C Functions in crystlib.a

Several C functions are described in this section.The function

int get_celln(crystal, A, B, C, Alpha, Beta, Gamma)

float *A, *B, *C, *Alpha, *Beta, *Gamma,

char *crystal;

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.The function

char *get_data(crystal, key)

char *crystal;

char *key;

#include "lib/Xguicryst.h"

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:

if(get_data(cystal,"cell")) strcpy(save, get_data(crystal,"symm"));

The function

int scan_symmops2(crystal, symmops, opstring)

char *crystal;

symmops[3][4][MAXSYMMOPS];

char opstring[MAXSYMMOPS][MAXSTRING];

#include "lib/Xguicryst.h"

gets the symmetry operators for crystal and returns the number of symmetry operators. If unsuccessful, it sends messages to stderr and returns 0.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];

y2 = 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];

The function

int addcenter2(n,symmops)

int n;

float symmops[3][4][MAXSYMMOPS];

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.The function

int get_ctof(ctof,crystal)

float ctof[3][3];

char *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.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]

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]

See also transform (below). To get the opposite matrix for fractional to Cartesian, invert this matrix with uinv:

uinv(ctof,ftoc)

float ctof[3][3];

float ftoc[3][3];

The function

int transform (ctof,x,y,z)

float ctof [3][3];

float *x,*y,*z;

transforms x, y, and z by the ctof matrix.The function

int iscentric(h, symmops, nops)

int h[3], nops;

float symmops[3][4][MAXSYMMOPS];

#include "lib/Xguicryst.h"

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.A sister function which uses individual integers for the indices is:

int iscentrichkl(h,k,l, symmops, nops)

int h, k, l, nops;

float symmops[3][4][MAXSYMMOPS];

The function

int ReadFin(fp, refl)

FILE *fp;

FIN **refl;

#include "lib/Xguicryst.h"

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.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;

int nrefl=0;

nrefl = ReadFin(fp, &refl);

The function

int ReadMu(fp, refl)

FILE *fp;

FIN **refl;

#include "lib/Xguicryst.h"

reads in an XENGEN .mu (mulist) format file fp into an array of FIN structures. It's similar to ReadFin (see previous discussion).The function

int ReadDF(fp, refl, control)

FILE *fp;

FIN **refl;

int control;

#include "lib/Xguicryst.h"

is similar to ReadFin (previous), except that it reads in a df (double fin) format file.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)

FILE *fp;

REFL **refl;

int *hmin, *hmax, *kmin, *kmax, *lmin, *lmax;

float *scalefc;

#include "lib/Xguicryst.h"

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.If the scale is to be applied:

nrefl = ReadPhs(fp, &refl, &hmin, &hmax, &kmin, &kmax, &lmin, &lmax, &scalefc);

for(i=0; i< nrefl; i++) refl.fc *= scalefc;

OR

for(i=0; i< nrefl; i++) refl.fo /= scalefo;

The latter is usually more useful, since it puts the data on an absolute scale.The function

float *fft3d(refl,nrefl,mapheader)

REFL *refl;

int nrefl;

MAPHEADER *mapheader;

#include "lib/Xguicryst.h"

#include "lib/fft.h"

performs a Fast-Fourier Transform of data in refl with information in mapheader (defined in Xguicryst.h). The following mapheader data must be set:

nx, ny, nz

a, b, c, alpha, beta, gamma /*from get_cell*/

resmax, resmin

nsym, symops /*from scan_symmops2*/

maptype /*as defined in fft.h*/

where 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:

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)

int rho[]

int *nx, *ny, *nz;

float *rhoscale;

float *rmsrho;

FILE *fp;

char *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.For example:

fp = fopen("mapfile","r");

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 array map is indexed as described in fft3d (described previously).The function

int fssize(fp)

FILE *fp;

returns the total dimensions nx*ny*nz of the map stored in the map file fp.The function

int fswrite(rho, fp, mh, direction, centric)

float map[];/* sorted x fast, y medium, z slow ascending */

FILE *fp;

MAPHEADER *mh; /* see Xguicryst.h */

int direction;

int 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.)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, gamma

nx, ny, nz

scale, nsym

The symmetry operator positions in the file are filled with zeroes.The function

float rescalc(ih, ik, il, a, b, c, alpha, beta, gamma, init)

int ih, ik, il; /* the Miller indices */

float a, b, c, alpha, beta, gamma; /* the unit cell */

int 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.