Redefine the default boolean type to gmx_bool.
[gromacs.git] / src / tools / gmx_order.c
blobcd473100ad6233951d8d36b8aad066f5161f29a1
1 /*
2 *
3 * This source code is part of
4 *
5 * G R O M A C S
6 *
7 * GROningen MAchine for Chemical Simulations
8 *
9 * VERSION 3.2.0
10 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12 * Copyright (c) 2001-2004, The GROMACS development team,
13 * check out http://www.gromacs.org for more information.
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * If you want to redistribute modifications, please consider that
21 * scientific software is very special. Version control is crucial -
22 * bugs must be traceable. We will be happy to consider code for
23 * inclusion in the official distribution, but derived work must not
24 * be called official GROMACS. Details are found in the README & COPYING
25 * files - if they are missing, get the official version at www.gromacs.org.
27 * To help us fund GROMACS development, we humbly ask that you cite
28 * the papers on the package - you can find them in the top README file.
30 * For more info, check our website at http://www.gromacs.org
32 * And Hey:
33 * Green Red Orange Magenta Azure Cyan Skyblue
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
39 #include <math.h>
40 #include <ctype.h>
42 #include "sysstuff.h"
43 #include "string.h"
44 #include "typedefs.h"
45 #include "smalloc.h"
46 #include "macros.h"
47 #include "gstat.h"
48 #include "vec.h"
49 #include "xvgr.h"
50 #include "pbc.h"
51 #include "copyrite.h"
52 #include "futil.h"
53 #include "statutil.h"
54 #include "index.h"
55 #include "tpxio.h"
56 #include "confio.h"
57 #include "cmat.h"
58 #include "gmx_ana.h"
61 /****************************************************************************/
62 /* This program calculates the order parameter per atom for an interface or */
63 /* bilayer, averaged over time. */
64 /* S = 1/2 * (3 * cos(i)cos(j) - delta(ij)) */
65 /* It is assumed that the order parameter with respect to a box-axis */
66 /* is calculated. In that case i = j = axis, and delta(ij) = 1. */
67 /* */
68 /* Peter Tieleman, April 1995 */
69 /* P.J. van Maaren, November 2005 Added tetrahedral stuff */
70 /****************************************************************************/
72 static void find_nearest_neighbours(t_topology top, int ePBC,
73 int natoms, matrix box,
74 rvec x[],int maxidx,atom_id index[],
75 real time,
76 real *sgmean, real *skmean,
77 int nslice,int slice_dim,
78 real sgslice[],real skslice[],
79 gmx_rmpbc_t gpbc)
81 FILE *fpoutdist;
82 char fnsgdist[32];
83 int ix,jx,nsgbin, *sgbin;
84 int i1,i2,i,ibin,j,k,l,n,*nn[4];
85 rvec dx,dx1,dx2,rj,rk,urk,urj;
86 real cost,cost2,*sgmol,*skmol,rmean,rmean2,r2,box2,*r_nn[4];
87 t_pbc pbc;
88 t_mat *dmat;
89 t_dist *d;
90 int m1,mm,sl_index;
91 int **nnb,*sl_count;
92 real onethird=1.0/3.0;
93 /* dmat = init_mat(maxidx, FALSE); */
94 box2 = box[XX][XX] * box[XX][XX];
95 snew(sl_count,nslice);
96 for (i=0; (i<4); i++) {
97 snew(r_nn[i],natoms);
98 snew(nn[i],natoms);
100 for (j=0; (j<natoms); j++) {
101 r_nn[i][j] = box2;
105 snew(sgmol,maxidx);
106 snew(skmol,maxidx);
108 /* Must init pbc every step because of pressure coupling */
109 set_pbc(&pbc,ePBC,box);
111 gmx_rmpbc(gpbc,natoms,box,x);
113 nsgbin = 1 + 1/0.0005;
114 snew(sgbin,nsgbin);
116 *sgmean = 0.0;
117 *skmean = 0.0;
118 l=0;
119 for (i=0; (i<maxidx); i++) { /* loop over index file */
120 ix = index[i];
121 for (j=0; (j<maxidx); j++) {
122 if (i == j) continue;
124 jx = index[j];
126 pbc_dx(&pbc,x[ix],x[jx],dx);
127 r2=iprod(dx,dx);
129 /* set_mat_entry(dmat,i,j,r2); */
131 /* determine the nearest neighbours */
132 if (r2 < r_nn[0][i]) {
133 r_nn[3][i] = r_nn[2][i]; nn[3][i] = nn[2][i];
134 r_nn[2][i] = r_nn[1][i]; nn[2][i] = nn[1][i];
135 r_nn[1][i] = r_nn[0][i]; nn[1][i] = nn[0][i];
136 r_nn[0][i] = r2; nn[0][i] = j;
137 } else if (r2 < r_nn[1][i]) {
138 r_nn[3][i] = r_nn[2][i]; nn[3][i] = nn[2][i];
139 r_nn[2][i] = r_nn[1][i]; nn[2][i] = nn[1][i];
140 r_nn[1][i] = r2; nn[1][i] = j;
141 } else if (r2 < r_nn[2][i]) {
142 r_nn[3][i] = r_nn[2][i]; nn[3][i] = nn[2][i];
143 r_nn[2][i] = r2; nn[2][i] = j;
144 } else if (r2 < r_nn[3][i]) {
145 r_nn[3][i] = r2; nn[3][i] = j;
150 /* calculate mean distance between nearest neighbours */
151 rmean = 0;
152 for (j=0; (j<4); j++) {
153 r_nn[j][i] = sqrt(r_nn[j][i]);
154 rmean += r_nn[j][i];
156 rmean /= 4;
158 n = 0;
159 sgmol[i] = 0.0;
160 skmol[i] = 0.0;
162 /* Chau1998a eqn 3 */
163 /* angular part tetrahedrality order parameter per atom */
164 for (j=0; (j<3); j++) {
165 for (k=j+1; (k<4); k++) {
166 pbc_dx(&pbc,x[ix],x[index[nn[k][i]]],rk);
167 pbc_dx(&pbc,x[ix],x[index[nn[j][i]]],rj);
169 unitv(rk,urk);
170 unitv(rj,urj);
172 cost = iprod(urk,urj) + onethird;
173 cost2 = cost * cost;
175 /* sgmol[i] += 3*cost2/32; */
176 sgmol[i] += cost2;
178 /* determine distribution */
179 ibin = nsgbin * cost2;
180 if (ibin < nsgbin)
181 sgbin[ibin]++;
182 /* printf("%d %d %f %d %d\n", j, k, cost * cost, ibin, sgbin[ibin]);*/
183 l++;
184 n++;
188 /* normalize sgmol between 0.0 and 1.0 */
189 sgmol[i] = 3*sgmol[i]/32;
190 *sgmean += sgmol[i];
192 /* distance part tetrahedrality order parameter per atom */
193 rmean2 = 4 * 3 * rmean * rmean;
194 for (j=0; (j<4); j++) {
195 skmol[i] += (rmean - r_nn[j][i]) * (rmean - r_nn[j][i]) / rmean2;
196 /* printf("%d %f (%f %f %f %f) \n",
197 i, skmol[i], rmean, rmean2, r_nn[j][i], (rmean - r_nn[j][i]) );
201 *skmean += skmol[i];
203 /* Compute sliced stuff */
204 sl_index = gmx_nint((1+x[i][slice_dim]/box[slice_dim][slice_dim])*nslice) % nslice;
205 sgslice[sl_index] += sgmol[i];
206 skslice[sl_index] += skmol[i];
207 sl_count[sl_index]++;
208 } /* loop over entries in index file */
210 *sgmean /= maxidx;
211 *skmean /= maxidx;
213 for(i=0; (i<nslice); i++) {
214 if (sl_count[i] > 0) {
215 sgslice[i] /= sl_count[i];
216 skslice[i] /= sl_count[i];
219 sfree(sl_count);
220 sfree(sgbin);
221 sfree(sgmol);
222 sfree(skmol);
223 for (i=0; (i<4); i++) {
224 sfree(r_nn[i]);
225 sfree(nn[i]);
230 static void calc_tetra_order_parm(const char *fnNDX,const char *fnTPS,
231 const char *fnTRX, const char *sgfn,
232 const char *skfn,
233 int nslice,int slice_dim,
234 const char *sgslfn,const char *skslfn,
235 const output_env_t oenv)
237 FILE *fpsg=NULL,*fpsk=NULL;
238 t_topology top;
239 int ePBC;
240 char title[STRLEN],fn[STRLEN],subtitle[STRLEN];
241 t_trxstatus *status;
242 int natoms;
243 real t;
244 rvec *xtop,*x;
245 matrix box;
246 real sg,sk;
247 atom_id **index;
248 char **grpname;
249 int i,*isize,ng,nframes;
250 real *sg_slice,*sg_slice_tot,*sk_slice,*sk_slice_tot;
251 gmx_rmpbc_t gpbc=NULL;
254 read_tps_conf(fnTPS,title,&top,&ePBC,&xtop,NULL,box,FALSE);
256 snew(sg_slice,nslice);
257 snew(sk_slice,nslice);
258 snew(sg_slice_tot,nslice);
259 snew(sk_slice_tot,nslice);
260 ng = 1;
261 /* get index groups */
262 printf("Select the group that contains the atoms you want to use for the tetrahedrality order parameter calculation:\n");
263 snew(grpname,ng);
264 snew(index,ng);
265 snew(isize,ng);
266 get_index(&top.atoms,fnNDX,ng,isize,index,grpname);
268 /* Analyze trajectory */
269 natoms=read_first_x(oenv,&status,fnTRX,&t,&x,box);
270 if ( natoms > top.atoms.nr )
271 gmx_fatal(FARGS,"Topology (%d atoms) does not match trajectory (%d atoms)",
272 top.atoms.nr,natoms);
273 check_index(NULL,ng,index[0],NULL,natoms);
275 fpsg=xvgropen(sgfn,"S\\sg\\N Angle Order Parameter","Time (ps)","S\\sg\\N",
276 oenv);
277 fpsk=xvgropen(skfn,"S\\sk\\N Distance Order Parameter","Time (ps)","S\\sk\\N",
278 oenv);
280 /* loop over frames */
281 gpbc = gmx_rmpbc_init(&top.idef,ePBC,natoms,box);
282 nframes = 0;
283 do {
284 find_nearest_neighbours(top,ePBC,natoms,box,x,isize[0],index[0],t,
285 &sg,&sk,nslice,slice_dim,sg_slice,sk_slice,gpbc);
286 for(i=0; (i<nslice); i++) {
287 sg_slice_tot[i] += sg_slice[i];
288 sk_slice_tot[i] += sk_slice[i];
290 fprintf(fpsg,"%f %f\n", t, sg);
291 fprintf(fpsk,"%f %f\n", t, sk);
292 nframes++;
293 } while (read_next_x(oenv,status,&t,natoms,x,box));
294 close_trj(status);
295 gmx_rmpbc_done(gpbc);
297 sfree(grpname);
298 sfree(index);
299 sfree(isize);
301 ffclose(fpsg);
302 ffclose(fpsk);
304 fpsg = xvgropen(sgslfn,
305 "S\\sg\\N Angle Order Parameter / Slab","(nm)","S\\sg\\N",
306 oenv);
307 fpsk = xvgropen(skslfn,
308 "S\\sk\\N Distance Order Parameter / Slab","(nm)","S\\sk\\N",
309 oenv);
310 for(i=0; (i<nslice); i++) {
311 fprintf(fpsg,"%10g %10g\n",(i+0.5)*box[slice_dim][slice_dim]/nslice,
312 sg_slice_tot[i]/nframes);
313 fprintf(fpsk,"%10g %10g\n",(i+0.5)*box[slice_dim][slice_dim]/nslice,
314 sk_slice_tot[i]/nframes);
316 ffclose(fpsg);
317 ffclose(fpsk);
321 /* Print name of first atom in all groups in index file */
322 static void print_types(atom_id index[], atom_id a[], int ngrps,
323 char *groups[], t_topology *top)
325 int i;
327 fprintf(stderr,"Using following groups: \n");
328 for(i = 0; i < ngrps; i++)
329 fprintf(stderr,"Groupname: %s First atomname: %s First atomnr %u\n",
330 groups[i], *(top->atoms.atomname[a[index[i]]]), a[index[i]]);
331 fprintf(stderr,"\n");
334 static void check_length(real length, int a, int b)
336 if (length > 0.3)
337 fprintf(stderr,"WARNING: distance between atoms %d and "
338 "%d > 0.3 nm (%f). Index file might be corrupt.\n",
339 a, b, length);
342 void calc_order(const char *fn, atom_id *index, atom_id *a, rvec **order,
343 real ***slOrder, real *slWidth, int nslices, gmx_bool bSliced,
344 gmx_bool bUnsat, t_topology *top, int ePBC, int ngrps, int axis,
345 gmx_bool permolecule, gmx_bool radial, gmx_bool distcalc, const char *radfn,
346 real ***distvals,
347 const output_env_t oenv)
349 /* if permolecule = TRUE, order parameters will be calculed per molecule
350 * and stored in slOrder with #slices = # molecules */
351 rvec *x0, /* coordinates with pbc */
352 *x1, /* coordinates without pbc */
353 dist; /* vector between two atoms */
354 matrix box; /* box (3x3) */
355 t_trxstatus *status;
356 rvec cossum, /* sum of vector angles for three axes */
357 Sx, Sy, Sz, /* the three molecular axes */
358 tmp1, tmp2, /* temp. rvecs for calculating dot products */
359 frameorder; /* order parameters for one frame */
360 real *slFrameorder; /* order parameter for one frame, per slice */
361 real length, /* total distance between two atoms */
362 t, /* time from trajectory */
363 z_ave,z1,z2; /* average z, used to det. which slice atom is in */
364 int natoms, /* nr. atoms in trj */
365 nr_tails, /* nr tails, to check if index file is correct */
366 size=0, /* nr. of atoms in group. same as nr_tails */
367 i,j,m,k,l,teller = 0,
368 slice, /* current slice number */
369 nr_frames = 0,
370 *slCount; /* nr. of atoms in one slice */
371 real dbangle = 0, /* angle between double bond and axis */
372 sdbangle = 0;/* sum of these angles */
373 gmx_bool use_unitvector = FALSE; /* use a specified unit vector instead of axis to specify unit normal*/
374 rvec direction, com,dref,dvec;
375 int comsize, distsize;
376 atom_id *comidx=NULL, *distidx=NULL;
377 char *grpname=NULL;
378 t_pbc pbc;
379 real arcdist;
380 gmx_rmpbc_t gpbc=NULL;
382 /* PBC added for center-of-mass vector*/
383 /* Initiate the pbc structure */
384 memset(&pbc,0,sizeof(pbc));
386 if ((natoms = read_first_x(oenv,&status,fn,&t,&x0,box)) == 0)
387 gmx_fatal(FARGS,"Could not read coordinates from statusfile\n");
389 nr_tails = index[1] - index[0];
390 fprintf(stderr,"Number of elements in first group: %d\n",nr_tails);
391 /* take first group as standard. Not rocksolid, but might catch error in index*/
393 if (permolecule)
395 nslices=nr_tails;
396 bSliced=FALSE; /*force slices off */
397 fprintf(stderr,"Calculating order parameters for each of %d molecules\n",
398 nslices);
401 if (radial)
403 use_unitvector=TRUE;
404 fprintf(stderr,"Select an index group to calculate the radial membrane normal\n");
405 get_index(&top->atoms,radfn,1,&comsize,&comidx,&grpname);
406 if (distcalc)
408 if (grpname!=NULL)
409 sfree(grpname);
410 fprintf(stderr,"Select an index group to use as distance reference\n");
411 get_index(&top->atoms,radfn,1,&distsize,&distidx,&grpname);
412 bSliced=FALSE; /*force slices off*/
416 if (use_unitvector && bSliced)
417 fprintf(stderr,"Warning: slicing and specified unit vectors are not currently compatible\n");
419 snew(slCount, nslices);
420 snew(*slOrder, nslices);
421 for(i = 0; i < nslices; i++)
422 snew((*slOrder)[i],ngrps);
423 if (distcalc)
425 snew(*distvals, nslices);
426 for(i = 0; i < nslices; i++)
427 snew((*distvals)[i],ngrps);
429 snew(*order,ngrps);
430 snew(slFrameorder, nslices);
431 snew(x1, natoms);
433 if (bSliced) {
434 *slWidth = box[axis][axis]/nslices;
435 fprintf(stderr,"Box divided in %d slices. Initial width of slice: %f\n",
436 nslices, *slWidth);
439 #if 0
440 nr_tails = index[1] - index[0];
441 fprintf(stderr,"Number of elements in first group: %d\n",nr_tails);
442 /* take first group as standard. Not rocksolid, but might catch error
443 in index*/
444 #endif
446 teller = 0;
448 gpbc = gmx_rmpbc_init(&top->idef,ePBC,natoms,box);
449 /*********** Start processing trajectory ***********/
450 do {
451 if (bSliced)
452 *slWidth = box[axis][axis]/nslices;
453 teller++;
455 set_pbc(&pbc,ePBC,box);
456 gmx_rmpbc_copy(gpbc,natoms,box,x0,x1);
458 /* Now loop over all groups. There are ngrps groups, the order parameter can
459 be calculated for grp 1 to grp ngrps - 1. For each group, loop over all
460 atoms in group, which is index[i] to (index[i+1] - 1) See block.h. Of
461 course, in this case index[i+1] -index[i] has to be the same for all
462 groups, namely the number of tails. i just runs over all atoms in a tail,
463 so for DPPC ngrps = 16 and i runs from 1 to 14, including 14
466 if (radial)
468 /*center-of-mass determination*/
469 com[XX]=0.0; com[YY]=0.0; com[ZZ]=0.0;
470 for (j=0;j<comsize;j++)
471 rvec_inc(com,x1[comidx[j]]);
472 svmul(1.0/comsize,com,com);
474 if (distcalc)
476 dref[XX]=0.0; dref[YY]=0.0;dref[ZZ]=0.0;
477 for (j=0;j<distsize;j++)
478 rvec_inc(dist,x1[distidx[j]]);
479 svmul(1.0/distsize,dref,dref);
480 pbc_dx(&pbc,dref,com,dvec);
481 unitv(dvec,dvec);
484 for (i = 1; i < ngrps - 1; i++) {
485 clear_rvec(frameorder);
487 size = index[i+1] - index[i];
488 if (size != nr_tails)
489 gmx_fatal(FARGS,"grp %d does not have same number of"
490 " elements as grp 1\n",i);
492 for (j = 0; j < size; j++) {
493 if (radial)
494 /*create unit vector*/
496 pbc_dx(&pbc,x1[a[index[i]+j]],com,direction);
497 unitv(direction,direction);
498 /*DEBUG*/
499 /*if (j==0)
500 fprintf(stderr,"X %f %f %f\tcom %f %f %f\tdirection %f %f %f\n",x1[a[index[i]+j]][0],x1[a[index[i]+j]][1],x1[a[index[i]+j]][2],com[0],com[1],com[2],
501 direction[0],direction[1],direction[2]);*/
504 if (bUnsat) {
505 /* Using convention for unsaturated carbons */
506 /* first get Sz, the vector from Cn to Cn+1 */
507 rvec_sub(x1[a[index[i+1]+j]], x1[a[index[i]+j]], dist);
508 length = norm(dist);
509 check_length(length, a[index[i]+j], a[index[i+1]+j]);
510 svmul(1/length, dist, Sz);
512 /* this is actually the cosine of the angle between the double bond
513 and axis, because Sz is normalized and the two other components of
514 the axis on the bilayer are zero */
515 if (use_unitvector)
517 sdbangle += acos(iprod(direction,Sz)); /*this can probably be optimized*/
519 else
520 sdbangle += acos(Sz[axis]);
521 } else {
522 /* get vector dist(Cn-1,Cn+1) for tail atoms */
523 rvec_sub(x1[a[index[i+1]+j]], x1[a[index[i-1]+j]], dist);
524 length = norm(dist); /* determine distance between two atoms */
525 check_length(length, a[index[i-1]+j], a[index[i+1]+j]);
527 svmul(1/length, dist, Sz);
528 /* Sz is now the molecular axis Sz, normalized and all that */
531 /* now get Sx. Sx is normal to the plane of Cn-1, Cn and Cn+1 so
532 we can use the outer product of Cn-1->Cn and Cn+1->Cn, I hope */
533 rvec_sub(x1[a[index[i+1]+j]], x1[a[index[i]+j]], tmp1);
534 rvec_sub(x1[a[index[i-1]+j]], x1[a[index[i]+j]], tmp2);
535 cprod(tmp1, tmp2, Sx);
536 svmul(1/norm(Sx), Sx, Sx);
538 /* now we can get Sy from the outer product of Sx and Sz */
539 cprod(Sz, Sx, Sy);
540 svmul(1/norm(Sy), Sy, Sy);
542 /* the square of cosine of the angle between dist and the axis.
543 Using the innerproduct, but two of the three elements are zero
544 Determine the sum of the orderparameter of all atoms in group
546 if (use_unitvector)
548 cossum[XX] = sqr(iprod(Sx,direction)); /* this is allowed, since Sa is normalized */
549 cossum[YY] = sqr(iprod(Sy,direction));
550 cossum[ZZ] = sqr(iprod(Sz,direction));
552 else
554 cossum[XX] = sqr(Sx[axis]); /* this is allowed, since Sa is normalized */
555 cossum[YY] = sqr(Sy[axis]);
556 cossum[ZZ] = sqr(Sz[axis]);
559 for (m = 0; m < DIM; m++)
560 frameorder[m] += 0.5 * (3 * cossum[m] - 1);
562 if (bSliced) {
563 /* get average coordinate in box length for slicing,
564 determine which slice atom is in, increase count for that
565 slice. slFrameorder and slOrder are reals, not
566 rvecs. Only the component [axis] of the order tensor is
567 kept, until I find it necessary to know the others too
570 z1 = x1[a[index[i-1]+j]][axis];
571 z2 = x1[a[index[i+1]+j]][axis];
572 z_ave = 0.5 * (z1 + z2);
573 if (z_ave < 0)
574 z_ave += box[axis][axis];
575 if (z_ave > box[axis][axis])
576 z_ave -= box[axis][axis];
578 slice = (int)(0.5 + (z_ave / (*slWidth))) - 1;
579 slCount[slice]++; /* determine slice, increase count */
581 slFrameorder[slice] += 0.5 * (3 * cossum[axis] - 1);
583 else if (permolecule)
585 /* store per-molecule order parameter
586 * To just track single-axis order: (*slOrder)[j][i] += 0.5 * (3 * iprod(cossum,direction) - 1);
587 * following is for Scd order: */
588 (*slOrder)[j][i] += -1* (0.3333 * (3 * cossum[XX] - 1) + 0.3333 * 0.5 * (3 * cossum[YY] - 1));
590 if (distcalc)
592 /* bin order parameter by arc distance from reference group*/
593 arcdist=acos(iprod(dvec,direction));
594 (*distvals)[j][i]+=arcdist;
596 } /* end loop j, over all atoms in group */
598 for (m = 0; m < DIM; m++)
599 (*order)[i][m] += (frameorder[m]/size);
601 if (!permolecule)
602 { /*Skip following if doing per-molecule*/
603 for (k = 0; k < nslices; k++) {
604 if (slCount[k]) { /* if no elements, nothing has to be added */
605 (*slOrder)[k][i] += slFrameorder[k]/slCount[k];
606 slFrameorder[k] = 0; slCount[k] = 0;
609 } /* end loop i, over all groups in indexfile */
611 nr_frames++;
613 } while (read_next_x(oenv,status,&t,natoms,x0,box));
614 /*********** done with status file **********/
616 fprintf(stderr,"\nRead trajectory. Printing parameters to file\n");
617 gmx_rmpbc_done(gpbc);
619 /* average over frames */
620 for (i = 1; i < ngrps - 1; i++) {
621 svmul(1.0/nr_frames, (*order)[i], (*order)[i]);
622 fprintf(stderr,"Atom %d Tensor: x=%g , y=%g, z=%g\n",i,(*order)[i][XX],
623 (*order)[i][YY], (*order)[i][ZZ]);
624 if (bSliced || permolecule) {
625 for (k = 0; k < nslices; k++)
626 (*slOrder)[k][i] /= nr_frames;
628 if (distcalc)
629 for (k = 0; k < nslices; k++)
630 (*distvals)[k][i] /= nr_frames;
633 if (bUnsat)
634 fprintf(stderr,"Average angle between double bond and normal: %f\n",
635 180*sdbangle/(nr_frames * size*M_PI));
637 sfree(x0); /* free memory used by coordinate arrays */
638 sfree(x1);
639 if (comidx!=NULL)
640 sfree(comidx);
641 if (distidx!=NULL)
642 sfree(distidx);
643 if (grpname!=NULL)
644 sfree(grpname);
648 void order_plot(rvec order[], real *slOrder[], const char *afile, const char *bfile,
649 const char *cfile, int ngrps, int nslices, real slWidth, gmx_bool bSzonly,
650 gmx_bool permolecule, real **distvals, const output_env_t oenv)
652 FILE *ord, *slOrd; /* xvgr files with order parameters */
653 int atom, slice; /* atom corresponding to order para.*/
654 char buf[256]; /* for xvgr title */
655 real S; /* order parameter averaged over all atoms */
657 if (permolecule)
659 sprintf(buf,"Scd order parameters");
660 ord = xvgropen(afile,buf,"Atom","S",oenv);
661 sprintf(buf, "Orderparameters per atom per slice");
662 slOrd = xvgropen(bfile, buf, "Molecule", "S",oenv);
663 for (atom = 1; atom < ngrps - 1; atom++) {
664 fprintf(ord,"%12d %12g\n", atom, -1 * (0.6667 * order[atom][XX] +
665 0.333 * order[atom][YY]));
668 for (slice = 0; slice < nslices; slice++) {
669 fprintf(slOrd,"%12d\t",slice);
670 if (distvals)
671 fprintf(slOrd,"%12g\t", distvals[slice][1]); /*use distance value at second carbon*/
672 for (atom = 1; atom < ngrps - 1; atom++)
673 fprintf(slOrd,"%12g\t", slOrder[slice][atom]);
674 fprintf(slOrd,"\n");
678 else if (bSzonly) {
679 sprintf(buf,"Orderparameters Sz per atom");
680 ord = xvgropen(afile,buf,"Atom","S",oenv);
681 fprintf(stderr,"ngrps = %d, nslices = %d",ngrps, nslices);
683 sprintf(buf, "Orderparameters per atom per slice");
684 slOrd = xvgropen(bfile, buf, "Slice", "S",oenv);
686 for (atom = 1; atom < ngrps - 1; atom++)
687 fprintf(ord,"%12d %12g\n", atom, order[atom][ZZ]);
689 for (slice = 0; slice < nslices; slice++) {
690 S = 0;
691 for (atom = 1; atom < ngrps - 1; atom++)
692 S += slOrder[slice][atom];
693 fprintf(slOrd,"%12g %12g\n", slice*slWidth, S/atom);
696 } else {
697 sprintf(buf,"Order tensor diagonal elements");
698 ord = xvgropen(afile,buf,"Atom","S",oenv);
699 sprintf(buf,"Deuterium order parameters");
700 slOrd = xvgropen(cfile,buf, "Atom", "Scd",oenv);
702 for (atom = 1; atom < ngrps - 1; atom++) {
703 fprintf(ord,"%12d %12g %12g %12g\n", atom, order[atom][XX],
704 order[atom][YY], order[atom][ZZ]);
705 fprintf(slOrd,"%12d %12g\n", atom, -1 * (0.6667 * order[atom][XX] +
706 0.333 * order[atom][YY]));
709 ffclose(ord);
710 ffclose(slOrd);
714 void write_bfactors(t_filenm *fnm, int nfile, atom_id *index, atom_id *a, int nslices, int ngrps, real **order, t_topology *top, real **distvals,output_env_t oenv)
716 /*function to write order parameters as B factors in PDB file using
717 first frame of trajectory*/
718 t_trxstatus *status;
719 int natoms;
720 t_trxframe fr, frout;
721 t_atoms useatoms;
722 int i,j,ctr,nout;
724 ngrps-=2; /*we don't have an order parameter for the first or
725 last atom in each chain*/
726 nout=nslices*ngrps;
727 natoms=read_first_frame(oenv,&status,ftp2fn(efTRX,nfile,fnm),&fr,
728 TRX_NEED_X);
729 close_trj(status);
730 frout = fr;
731 frout.natoms=nout;
732 frout.bF=FALSE;
733 frout.bV=FALSE;
734 frout.x=0;
735 snew(frout.x,nout);
737 init_t_atoms(&useatoms,nout,TRUE);
738 useatoms.nr=nout;
740 /*initialize PDBinfo*/
741 for (i=0;i<useatoms.nr;++i)
743 useatoms.pdbinfo[i].type=0;
744 useatoms.pdbinfo[i].occup=0.0;
745 useatoms.pdbinfo[i].bfac=0.0;
746 useatoms.pdbinfo[i].bAnisotropic=FALSE;
749 for (j=0,ctr=0;j<nslices;j++)
750 for (i=0;i<ngrps;i++,ctr++)
752 /*iterate along each chain*/
753 useatoms.pdbinfo[ctr].bfac=order[j][i+1];
754 if (distvals)
755 useatoms.pdbinfo[ctr].occup=distvals[j][i+1];
756 copy_rvec(fr.x[a[index[i+1]+j]],frout.x[ctr]);
757 useatoms.atomname[ctr]=top->atoms.atomname[a[index[i+1]+j]];
758 useatoms.atom[ctr]=top->atoms.atom[a[index[i+1]+j]];
759 useatoms.nres=max(useatoms.nres,useatoms.atom[ctr].resind+1);
760 useatoms.resinfo[useatoms.atom[ctr].resind]=top->atoms.resinfo[useatoms.atom[ctr].resind]; /*copy resinfo*/
763 write_sto_conf(opt2fn("-ob",nfile,fnm),"Order parameters",&useatoms,frout.x,NULL,frout.ePBC,frout.box);
765 sfree(frout.x);
766 free_t_atoms(&useatoms,FALSE);
769 int gmx_order(int argc,char *argv[])
771 const char *desc[] = {
772 "Compute the order parameter per atom for carbon tails. For atom i the",
773 "vector i-1, i+1 is used together with an axis. ",
774 "The index file should contain only the groups to be used for calculations,",
775 "with each group of equivalent carbons along the relevant acyl chain in its own",
776 "group. There should not be any generic groups (like System, Protein) in the index",
777 "file to avoid confusing the program (this is not relevant to tetrahedral order",
778 "parameters however, which only work for water anyway).[PAR]",
779 "The program can also give all",
780 "diagonal elements of the order tensor and even calculate the deuterium",
781 "order parameter Scd (default). If the option -szonly is given, only one",
782 "order tensor component (specified by the -d option) is given and the",
783 "order parameter per slice is calculated as well. If -szonly is not",
784 "selected, all diagonal elements and the deuterium order parameter is",
785 "given.[PAR]"
786 "The tetrahedrality order parameters can be determined",
787 "around an atom. Both angle an distance order parameters are calculated. See",
788 "P.-L. Chau and A.J. Hardwick, Mol. Phys., 93, (1998), 511-518.",
789 "for more details.[BR]",
793 static int nslices = 1; /* nr of slices defined */
794 static gmx_bool bSzonly = FALSE; /* True if only Sz is wanted */
795 static gmx_bool bUnsat = FALSE; /* True if carbons are unsat. */
796 static const char *normal_axis[] = { NULL, "z", "x", "y", NULL };
797 static gmx_bool permolecule = FALSE; /*compute on a per-molecule basis */
798 static gmx_bool radial = FALSE; /*compute a radial membrane normal */
799 static gmx_bool distcalc = FALSE; /*calculate distance from a reference group */
800 t_pargs pa[] = {
801 { "-d", FALSE, etENUM, {normal_axis},
802 "Direction of the normal on the membrane" },
803 { "-sl", FALSE, etINT, {&nslices},
804 "Calculate order parameter as function of boxlength, dividing the box"
805 " in #nr slices." },
806 { "-szonly", FALSE, etBOOL,{&bSzonly},
807 "Only give Sz element of order tensor. (axis can be specified with -d)" },
808 { "-unsat", FALSE, etBOOL,{&bUnsat},
809 "Calculate order parameters for unsaturated carbons. Note that this can"
810 "not be mixed with normal order parameters." },
811 { "-permolecule", FALSE, etBOOL,{&permolecule},
812 "Compute per-molecule Scd order parameters" },
813 { "-radial", FALSE, etBOOL,{&radial},
814 "Compute a radial membrane normal" },
815 { "-calcdist", FALSE, etBOOL,{&distcalc},
816 "Compute distance from a reference (currently defined only for radial and permolecule)" },
819 rvec *order; /* order par. for each atom */
820 real **slOrder; /* same, per slice */
821 real slWidth = 0.0; /* width of a slice */
822 char **grpname; /* groupnames */
823 int ngrps, /* nr. of groups */
825 axis=0; /* normal axis */
826 t_topology *top; /* topology */
827 int ePBC;
828 atom_id *index, /* indices for a */
829 *a; /* atom numbers in each group */
830 t_blocka *block; /* data from index file */
831 t_filenm fnm[] = { /* files for g_order */
832 { efTRX, "-f", NULL, ffREAD }, /* trajectory file */
833 { efNDX, "-n", NULL, ffREAD }, /* index file */
834 { efNDX, "-nr", NULL, ffREAD }, /* index for radial axis calculation */
835 { efTPX, NULL, NULL, ffREAD }, /* topology file */
836 { efXVG,"-o","order", ffWRITE }, /* xvgr output file */
837 { efXVG,"-od","deuter", ffWRITE }, /* xvgr output file */
838 { efPDB,"-ob",NULL, ffWRITE }, /* write Scd as B factors to PDB if permolecule */
839 { efXVG,"-os","sliced", ffWRITE }, /* xvgr output file */
840 { efXVG,"-Sg","sg-ang", ffOPTWR }, /* xvgr output file */
841 { efXVG,"-Sk","sk-dist", ffOPTWR }, /* xvgr output file */
842 { efXVG,"-Sgsl","sg-ang-slice", ffOPTWR }, /* xvgr output file */
843 { efXVG,"-Sksl","sk-dist-slice", ffOPTWR }, /* xvgr output file */
845 gmx_bool bSliced = FALSE; /* True if box is sliced */
846 #define NFILE asize(fnm)
847 real **distvals=NULL;
848 const char *sgfnm,*skfnm,*ndxfnm,*tpsfnm,*trxfnm;
849 output_env_t oenv;
851 CopyRight(stderr,argv[0]);
853 parse_common_args(&argc,argv,PCA_CAN_VIEW | PCA_CAN_TIME | PCA_BE_NICE,
854 NFILE,fnm,asize(pa),pa,asize(desc),desc,0, NULL,&oenv);
855 if (nslices < 1)
856 gmx_fatal(FARGS,"Can not have nslices < 1");
857 sgfnm = opt2fn_null("-Sg",NFILE,fnm);
858 skfnm = opt2fn_null("-Sk",NFILE,fnm);
859 ndxfnm = opt2fn_null("-n",NFILE,fnm);
860 tpsfnm = ftp2fn(efTPX,NFILE,fnm);
861 trxfnm = ftp2fn(efTRX,NFILE,fnm);
863 /* Calculate axis */
864 if (strcmp(normal_axis[0],"x") == 0) axis = XX;
865 else if (strcmp(normal_axis[0],"y") == 0) axis = YY;
866 else if (strcmp(normal_axis[0],"z") == 0) axis = ZZ;
867 else gmx_fatal(FARGS,"Invalid axis, use x, y or z");
869 switch (axis) {
870 case 0:
871 fprintf(stderr,"Taking x axis as normal to the membrane\n");
872 break;
873 case 1:
874 fprintf(stderr,"Taking y axis as normal to the membrane\n");
875 break;
876 case 2:
877 fprintf(stderr,"Taking z axis as normal to the membrane\n");
878 break;
881 /* tetraheder order parameter */
882 if (skfnm || sgfnm) {
883 /* If either of theoptions is set we compute both */
884 sgfnm = opt2fn("-Sg",NFILE,fnm);
885 skfnm = opt2fn("-Sk",NFILE,fnm);
886 calc_tetra_order_parm(ndxfnm,tpsfnm,trxfnm,sgfnm,skfnm,nslices,axis,
887 opt2fn("-Sgsl",NFILE,fnm),opt2fn("-Sksl",NFILE,fnm),
888 oenv);
889 /* view xvgr files */
890 do_view(oenv,opt2fn("-Sg",NFILE,fnm), NULL);
891 do_view(oenv,opt2fn("-Sk",NFILE,fnm), NULL);
892 if (nslices > 1) {
893 do_view(oenv,opt2fn("-Sgsl",NFILE,fnm), NULL);
894 do_view(oenv,opt2fn("-Sksl",NFILE,fnm), NULL);
897 else {
898 /* tail order parameter */
900 if (nslices > 1) {
901 bSliced = TRUE;
902 fprintf(stderr,"Dividing box in %d slices.\n\n", nslices);
905 if (bSzonly)
906 fprintf(stderr,"Only calculating Sz\n");
907 if (bUnsat)
908 fprintf(stderr,"Taking carbons as unsaturated!\n");
910 top = read_top(ftp2fn(efTPX,NFILE,fnm),&ePBC); /* read topology file */
912 block = init_index(ftp2fn(efNDX,NFILE,fnm),&grpname);
913 index = block->index; /* get indices from t_block block */
914 a = block->a; /* see block.h */
915 ngrps = block->nr;
917 if (permolecule)
919 nslices = index[1] - index[0]; /*I think this assumes contiguous lipids in topology*/
920 fprintf(stderr,"Calculating Scd order parameters for each of %d molecules\n",nslices);
923 if (distcalc)
925 radial=TRUE;
926 fprintf(stderr,"Calculating radial distances\n");
927 if (!permolecule)
928 gmx_fatal(FARGS,"Cannot yet output radial distances without permolecule\n");
931 /* show atomtypes, to check if index file is correct */
932 print_types(index, a, ngrps, grpname, top);
934 calc_order(ftp2fn(efTRX,NFILE,fnm), index, a, &order,
935 &slOrder, &slWidth, nslices, bSliced, bUnsat,
936 top, ePBC, ngrps, axis,permolecule,radial,distcalc,opt2fn_null("-nr",NFILE,fnm),&distvals, oenv);
938 if (radial)
939 ngrps--; /*don't print the last group--was used for
940 center-of-mass determination*/
942 order_plot(order, slOrder, opt2fn("-o",NFILE,fnm), opt2fn("-os",NFILE,fnm),
943 opt2fn("-od",NFILE,fnm), ngrps, nslices, slWidth, bSzonly,permolecule,distvals,oenv);
945 if (opt2bSet("-ob",NFILE,fnm))
947 if (!permolecule)
948 fprintf(stderr,
949 "Won't write B-factors with averaged order parameters; use -permolecule\n");
950 else
951 write_bfactors(fnm,NFILE,index,a,nslices,ngrps,slOrder,top,distvals,oenv);
955 do_view(oenv,opt2fn("-o",NFILE,fnm), NULL); /* view xvgr file */
956 do_view(oenv,opt2fn("-os",NFILE,fnm), NULL); /* view xvgr file */
957 do_view(oenv,opt2fn("-od",NFILE,fnm), NULL); /* view xvgr file */
960 thanx(stderr);
961 if (distvals!=NULL)
963 for (i=0;i<nslices;++i)
964 sfree(distvals[i]);
965 sfree(distvals);
968 return 0;