2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team,
6 * check out http://www.gromacs.org for more information.
7 * Copyright (c) 2012, by the GROMACS development team, led by
8 * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9 * others, as listed in the AUTHORS file in the top-level source
10 * directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
64 /****************************************************************************/
65 /* This program calculates the order parameter per atom for an interface or */
66 /* bilayer, averaged over time. */
67 /* S = 1/2 * (3 * cos(i)cos(j) - delta(ij)) */
68 /* It is assumed that the order parameter with respect to a box-axis */
69 /* is calculated. In that case i = j = axis, and delta(ij) = 1. */
71 /* Peter Tieleman, April 1995 */
72 /* P.J. van Maaren, November 2005 Added tetrahedral stuff */
73 /****************************************************************************/
75 static void find_nearest_neighbours(t_topology top
, int ePBC
,
76 int natoms
, matrix box
,
77 rvec x
[],int maxidx
,atom_id index
[],
79 real
*sgmean
, real
*skmean
,
80 int nslice
,int slice_dim
,
81 real sgslice
[],real skslice
[],
86 int ix
,jx
,nsgbin
, *sgbin
;
87 int i1
,i2
,i
,ibin
,j
,k
,l
,n
,*nn
[4];
88 rvec dx
,dx1
,dx2
,rj
,rk
,urk
,urj
;
89 real cost
,cost2
,*sgmol
,*skmol
,rmean
,rmean2
,r2
,box2
,*r_nn
[4];
95 real onethird
=1.0/3.0;
96 /* dmat = init_mat(maxidx, FALSE); */
97 box2
= box
[XX
][XX
] * box
[XX
][XX
];
98 snew(sl_count
,nslice
);
99 for (i
=0; (i
<4); i
++) {
100 snew(r_nn
[i
],natoms
);
103 for (j
=0; (j
<natoms
); j
++) {
111 /* Must init pbc every step because of pressure coupling */
112 set_pbc(&pbc
,ePBC
,box
);
114 gmx_rmpbc(gpbc
,natoms
,box
,x
);
116 nsgbin
= 1 + 1/0.0005;
122 for (i
=0; (i
<maxidx
); i
++) { /* loop over index file */
124 for (j
=0; (j
<maxidx
); j
++) {
125 if (i
== j
) continue;
129 pbc_dx(&pbc
,x
[ix
],x
[jx
],dx
);
132 /* set_mat_entry(dmat,i,j,r2); */
134 /* determine the nearest neighbours */
135 if (r2
< r_nn
[0][i
]) {
136 r_nn
[3][i
] = r_nn
[2][i
]; nn
[3][i
] = nn
[2][i
];
137 r_nn
[2][i
] = r_nn
[1][i
]; nn
[2][i
] = nn
[1][i
];
138 r_nn
[1][i
] = r_nn
[0][i
]; nn
[1][i
] = nn
[0][i
];
139 r_nn
[0][i
] = r2
; nn
[0][i
] = j
;
140 } else if (r2
< r_nn
[1][i
]) {
141 r_nn
[3][i
] = r_nn
[2][i
]; nn
[3][i
] = nn
[2][i
];
142 r_nn
[2][i
] = r_nn
[1][i
]; nn
[2][i
] = nn
[1][i
];
143 r_nn
[1][i
] = r2
; nn
[1][i
] = j
;
144 } else if (r2
< r_nn
[2][i
]) {
145 r_nn
[3][i
] = r_nn
[2][i
]; nn
[3][i
] = nn
[2][i
];
146 r_nn
[2][i
] = r2
; nn
[2][i
] = j
;
147 } else if (r2
< r_nn
[3][i
]) {
148 r_nn
[3][i
] = r2
; nn
[3][i
] = j
;
153 /* calculate mean distance between nearest neighbours */
155 for (j
=0; (j
<4); j
++) {
156 r_nn
[j
][i
] = sqrt(r_nn
[j
][i
]);
165 /* Chau1998a eqn 3 */
166 /* angular part tetrahedrality order parameter per atom */
167 for (j
=0; (j
<3); j
++) {
168 for (k
=j
+1; (k
<4); k
++) {
169 pbc_dx(&pbc
,x
[ix
],x
[index
[nn
[k
][i
]]],rk
);
170 pbc_dx(&pbc
,x
[ix
],x
[index
[nn
[j
][i
]]],rj
);
175 cost
= iprod(urk
,urj
) + onethird
;
178 /* sgmol[i] += 3*cost2/32; */
181 /* determine distribution */
182 ibin
= nsgbin
* cost2
;
185 /* printf("%d %d %f %d %d\n", j, k, cost * cost, ibin, sgbin[ibin]);*/
191 /* normalize sgmol between 0.0 and 1.0 */
192 sgmol
[i
] = 3*sgmol
[i
]/32;
195 /* distance part tetrahedrality order parameter per atom */
196 rmean2
= 4 * 3 * rmean
* rmean
;
197 for (j
=0; (j
<4); j
++) {
198 skmol
[i
] += (rmean
- r_nn
[j
][i
]) * (rmean
- r_nn
[j
][i
]) / rmean2
;
199 /* printf("%d %f (%f %f %f %f) \n",
200 i, skmol[i], rmean, rmean2, r_nn[j][i], (rmean - r_nn[j][i]) );
206 /* Compute sliced stuff */
207 sl_index
= gmx_nint((1+x
[i
][slice_dim
]/box
[slice_dim
][slice_dim
])*nslice
) % nslice
;
208 sgslice
[sl_index
] += sgmol
[i
];
209 skslice
[sl_index
] += skmol
[i
];
210 sl_count
[sl_index
]++;
211 } /* loop over entries in index file */
216 for(i
=0; (i
<nslice
); i
++) {
217 if (sl_count
[i
] > 0) {
218 sgslice
[i
] /= sl_count
[i
];
219 skslice
[i
] /= sl_count
[i
];
226 for (i
=0; (i
<4); i
++) {
233 static void calc_tetra_order_parm(const char *fnNDX
,const char *fnTPS
,
234 const char *fnTRX
, const char *sgfn
,
236 int nslice
,int slice_dim
,
237 const char *sgslfn
,const char *skslfn
,
238 const output_env_t oenv
)
240 FILE *fpsg
=NULL
,*fpsk
=NULL
;
243 char title
[STRLEN
],fn
[STRLEN
],subtitle
[STRLEN
];
252 int i
,*isize
,ng
,nframes
;
253 real
*sg_slice
,*sg_slice_tot
,*sk_slice
,*sk_slice_tot
;
254 gmx_rmpbc_t gpbc
=NULL
;
257 read_tps_conf(fnTPS
,title
,&top
,&ePBC
,&xtop
,NULL
,box
,FALSE
);
259 snew(sg_slice
,nslice
);
260 snew(sk_slice
,nslice
);
261 snew(sg_slice_tot
,nslice
);
262 snew(sk_slice_tot
,nslice
);
264 /* get index groups */
265 printf("Select the group that contains the atoms you want to use for the tetrahedrality order parameter calculation:\n");
269 get_index(&top
.atoms
,fnNDX
,ng
,isize
,index
,grpname
);
271 /* Analyze trajectory */
272 natoms
=read_first_x(oenv
,&status
,fnTRX
,&t
,&x
,box
);
273 if ( natoms
> top
.atoms
.nr
)
274 gmx_fatal(FARGS
,"Topology (%d atoms) does not match trajectory (%d atoms)",
275 top
.atoms
.nr
,natoms
);
276 check_index(NULL
,ng
,index
[0],NULL
,natoms
);
278 fpsg
=xvgropen(sgfn
,"S\\sg\\N Angle Order Parameter","Time (ps)","S\\sg\\N",
280 fpsk
=xvgropen(skfn
,"S\\sk\\N Distance Order Parameter","Time (ps)","S\\sk\\N",
283 /* loop over frames */
284 gpbc
= gmx_rmpbc_init(&top
.idef
,ePBC
,natoms
,box
);
287 find_nearest_neighbours(top
,ePBC
,natoms
,box
,x
,isize
[0],index
[0],t
,
288 &sg
,&sk
,nslice
,slice_dim
,sg_slice
,sk_slice
,gpbc
);
289 for(i
=0; (i
<nslice
); i
++) {
290 sg_slice_tot
[i
] += sg_slice
[i
];
291 sk_slice_tot
[i
] += sk_slice
[i
];
293 fprintf(fpsg
,"%f %f\n", t
, sg
);
294 fprintf(fpsk
,"%f %f\n", t
, sk
);
296 } while (read_next_x(oenv
,status
,&t
,natoms
,x
,box
));
298 gmx_rmpbc_done(gpbc
);
307 fpsg
= xvgropen(sgslfn
,
308 "S\\sg\\N Angle Order Parameter / Slab","(nm)","S\\sg\\N",
310 fpsk
= xvgropen(skslfn
,
311 "S\\sk\\N Distance Order Parameter / Slab","(nm)","S\\sk\\N",
313 for(i
=0; (i
<nslice
); i
++) {
314 fprintf(fpsg
,"%10g %10g\n",(i
+0.5)*box
[slice_dim
][slice_dim
]/nslice
,
315 sg_slice_tot
[i
]/nframes
);
316 fprintf(fpsk
,"%10g %10g\n",(i
+0.5)*box
[slice_dim
][slice_dim
]/nslice
,
317 sk_slice_tot
[i
]/nframes
);
324 /* Print name of first atom in all groups in index file */
325 static void print_types(atom_id index
[], atom_id a
[], int ngrps
,
326 char *groups
[], t_topology
*top
)
330 fprintf(stderr
,"Using following groups: \n");
331 for(i
= 0; i
< ngrps
; i
++)
332 fprintf(stderr
,"Groupname: %s First atomname: %s First atomnr %u\n",
333 groups
[i
], *(top
->atoms
.atomname
[a
[index
[i
]]]), a
[index
[i
]]);
334 fprintf(stderr
,"\n");
337 static void check_length(real length
, int a
, int b
)
340 fprintf(stderr
,"WARNING: distance between atoms %d and "
341 "%d > 0.3 nm (%f). Index file might be corrupt.\n",
345 void calc_order(const char *fn
, atom_id
*index
, atom_id
*a
, rvec
**order
,
346 real
***slOrder
, real
*slWidth
, int nslices
, gmx_bool bSliced
,
347 gmx_bool bUnsat
, t_topology
*top
, int ePBC
, int ngrps
, int axis
,
348 gmx_bool permolecule
, gmx_bool radial
, gmx_bool distcalc
, const char *radfn
,
350 const output_env_t oenv
)
352 /* if permolecule = TRUE, order parameters will be calculed per molecule
353 * and stored in slOrder with #slices = # molecules */
354 rvec
*x0
, /* coordinates with pbc */
355 *x1
, /* coordinates without pbc */
356 dist
; /* vector between two atoms */
357 matrix box
; /* box (3x3) */
359 rvec cossum
, /* sum of vector angles for three axes */
360 Sx
, Sy
, Sz
, /* the three molecular axes */
361 tmp1
, tmp2
, /* temp. rvecs for calculating dot products */
362 frameorder
; /* order parameters for one frame */
363 real
*slFrameorder
; /* order parameter for one frame, per slice */
364 real length
, /* total distance between two atoms */
365 t
, /* time from trajectory */
366 z_ave
,z1
,z2
; /* average z, used to det. which slice atom is in */
367 int natoms
, /* nr. atoms in trj */
368 nr_tails
, /* nr tails, to check if index file is correct */
369 size
=0, /* nr. of atoms in group. same as nr_tails */
370 i
,j
,m
,k
,l
,teller
= 0,
371 slice
, /* current slice number */
373 *slCount
; /* nr. of atoms in one slice */
374 real dbangle
= 0, /* angle between double bond and axis */
375 sdbangle
= 0;/* sum of these angles */
376 gmx_bool use_unitvector
= FALSE
; /* use a specified unit vector instead of axis to specify unit normal*/
377 rvec direction
, com
,dref
,dvec
;
378 int comsize
, distsize
;
379 atom_id
*comidx
=NULL
, *distidx
=NULL
;
383 gmx_rmpbc_t gpbc
=NULL
;
385 /* PBC added for center-of-mass vector*/
386 /* Initiate the pbc structure */
387 memset(&pbc
,0,sizeof(pbc
));
389 if ((natoms
= read_first_x(oenv
,&status
,fn
,&t
,&x0
,box
)) == 0)
390 gmx_fatal(FARGS
,"Could not read coordinates from statusfile\n");
392 nr_tails
= index
[1] - index
[0];
393 fprintf(stderr
,"Number of elements in first group: %d\n",nr_tails
);
394 /* take first group as standard. Not rocksolid, but might catch error in index*/
399 bSliced
=FALSE
; /*force slices off */
400 fprintf(stderr
,"Calculating order parameters for each of %d molecules\n",
407 fprintf(stderr
,"Select an index group to calculate the radial membrane normal\n");
408 get_index(&top
->atoms
,radfn
,1,&comsize
,&comidx
,&grpname
);
413 fprintf(stderr
,"Select an index group to use as distance reference\n");
414 get_index(&top
->atoms
,radfn
,1,&distsize
,&distidx
,&grpname
);
415 bSliced
=FALSE
; /*force slices off*/
419 if (use_unitvector
&& bSliced
)
420 fprintf(stderr
,"Warning: slicing and specified unit vectors are not currently compatible\n");
422 snew(slCount
, nslices
);
423 snew(*slOrder
, nslices
);
424 for(i
= 0; i
< nslices
; i
++)
425 snew((*slOrder
)[i
],ngrps
);
428 snew(*distvals
, nslices
);
429 for(i
= 0; i
< nslices
; i
++)
430 snew((*distvals
)[i
],ngrps
);
433 snew(slFrameorder
, nslices
);
437 *slWidth
= box
[axis
][axis
]/nslices
;
438 fprintf(stderr
,"Box divided in %d slices. Initial width of slice: %f\n",
443 nr_tails
= index
[1] - index
[0];
444 fprintf(stderr
,"Number of elements in first group: %d\n",nr_tails
);
445 /* take first group as standard. Not rocksolid, but might catch error
451 gpbc
= gmx_rmpbc_init(&top
->idef
,ePBC
,natoms
,box
);
452 /*********** Start processing trajectory ***********/
455 *slWidth
= box
[axis
][axis
]/nslices
;
458 set_pbc(&pbc
,ePBC
,box
);
459 gmx_rmpbc_copy(gpbc
,natoms
,box
,x0
,x1
);
461 /* Now loop over all groups. There are ngrps groups, the order parameter can
462 be calculated for grp 1 to grp ngrps - 1. For each group, loop over all
463 atoms in group, which is index[i] to (index[i+1] - 1) See block.h. Of
464 course, in this case index[i+1] -index[i] has to be the same for all
465 groups, namely the number of tails. i just runs over all atoms in a tail,
466 so for DPPC ngrps = 16 and i runs from 1 to 14, including 14
471 /*center-of-mass determination*/
472 com
[XX
]=0.0; com
[YY
]=0.0; com
[ZZ
]=0.0;
473 for (j
=0;j
<comsize
;j
++)
474 rvec_inc(com
,x1
[comidx
[j
]]);
475 svmul(1.0/comsize
,com
,com
);
479 dref
[XX
]=0.0; dref
[YY
]=0.0;dref
[ZZ
]=0.0;
480 for (j
=0;j
<distsize
;j
++)
481 rvec_inc(dist
,x1
[distidx
[j
]]);
482 svmul(1.0/distsize
,dref
,dref
);
483 pbc_dx(&pbc
,dref
,com
,dvec
);
487 for (i
= 1; i
< ngrps
- 1; i
++) {
488 clear_rvec(frameorder
);
490 size
= index
[i
+1] - index
[i
];
491 if (size
!= nr_tails
)
492 gmx_fatal(FARGS
,"grp %d does not have same number of"
493 " elements as grp 1\n",i
);
495 for (j
= 0; j
< size
; j
++) {
497 /*create unit vector*/
499 pbc_dx(&pbc
,x1
[a
[index
[i
]+j
]],com
,direction
);
500 unitv(direction
,direction
);
503 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],
504 direction[0],direction[1],direction[2]);*/
508 /* Using convention for unsaturated carbons */
509 /* first get Sz, the vector from Cn to Cn+1 */
510 rvec_sub(x1
[a
[index
[i
+1]+j
]], x1
[a
[index
[i
]+j
]], dist
);
512 check_length(length
, a
[index
[i
]+j
], a
[index
[i
+1]+j
]);
513 svmul(1/length
, dist
, Sz
);
515 /* this is actually the cosine of the angle between the double bond
516 and axis, because Sz is normalized and the two other components of
517 the axis on the bilayer are zero */
520 sdbangle
+= acos(iprod(direction
,Sz
)); /*this can probably be optimized*/
523 sdbangle
+= acos(Sz
[axis
]);
525 /* get vector dist(Cn-1,Cn+1) for tail atoms */
526 rvec_sub(x1
[a
[index
[i
+1]+j
]], x1
[a
[index
[i
-1]+j
]], dist
);
527 length
= norm(dist
); /* determine distance between two atoms */
528 check_length(length
, a
[index
[i
-1]+j
], a
[index
[i
+1]+j
]);
530 svmul(1/length
, dist
, Sz
);
531 /* Sz is now the molecular axis Sz, normalized and all that */
534 /* now get Sx. Sx is normal to the plane of Cn-1, Cn and Cn+1 so
535 we can use the outer product of Cn-1->Cn and Cn+1->Cn, I hope */
536 rvec_sub(x1
[a
[index
[i
+1]+j
]], x1
[a
[index
[i
]+j
]], tmp1
);
537 rvec_sub(x1
[a
[index
[i
-1]+j
]], x1
[a
[index
[i
]+j
]], tmp2
);
538 cprod(tmp1
, tmp2
, Sx
);
539 svmul(1/norm(Sx
), Sx
, Sx
);
541 /* now we can get Sy from the outer product of Sx and Sz */
543 svmul(1/norm(Sy
), Sy
, Sy
);
545 /* the square of cosine of the angle between dist and the axis.
546 Using the innerproduct, but two of the three elements are zero
547 Determine the sum of the orderparameter of all atoms in group
551 cossum
[XX
] = sqr(iprod(Sx
,direction
)); /* this is allowed, since Sa is normalized */
552 cossum
[YY
] = sqr(iprod(Sy
,direction
));
553 cossum
[ZZ
] = sqr(iprod(Sz
,direction
));
557 cossum
[XX
] = sqr(Sx
[axis
]); /* this is allowed, since Sa is normalized */
558 cossum
[YY
] = sqr(Sy
[axis
]);
559 cossum
[ZZ
] = sqr(Sz
[axis
]);
562 for (m
= 0; m
< DIM
; m
++)
563 frameorder
[m
] += 0.5 * (3 * cossum
[m
] - 1);
566 /* get average coordinate in box length for slicing,
567 determine which slice atom is in, increase count for that
568 slice. slFrameorder and slOrder are reals, not
569 rvecs. Only the component [axis] of the order tensor is
570 kept, until I find it necessary to know the others too
573 z1
= x1
[a
[index
[i
-1]+j
]][axis
];
574 z2
= x1
[a
[index
[i
+1]+j
]][axis
];
575 z_ave
= 0.5 * (z1
+ z2
);
577 z_ave
+= box
[axis
][axis
];
578 if (z_ave
> box
[axis
][axis
])
579 z_ave
-= box
[axis
][axis
];
581 slice
= (int)(0.5 + (z_ave
/ (*slWidth
))) - 1;
582 slCount
[slice
]++; /* determine slice, increase count */
584 slFrameorder
[slice
] += 0.5 * (3 * cossum
[axis
] - 1);
586 else if (permolecule
)
588 /* store per-molecule order parameter
589 * To just track single-axis order: (*slOrder)[j][i] += 0.5 * (3 * iprod(cossum,direction) - 1);
590 * following is for Scd order: */
591 (*slOrder
)[j
][i
] += -1* (0.3333 * (3 * cossum
[XX
] - 1) + 0.3333 * 0.5 * (3 * cossum
[YY
] - 1));
595 /* bin order parameter by arc distance from reference group*/
596 arcdist
=acos(iprod(dvec
,direction
));
597 (*distvals
)[j
][i
]+=arcdist
;
599 } /* end loop j, over all atoms in group */
601 for (m
= 0; m
< DIM
; m
++)
602 (*order
)[i
][m
] += (frameorder
[m
]/size
);
605 { /*Skip following if doing per-molecule*/
606 for (k
= 0; k
< nslices
; k
++) {
607 if (slCount
[k
]) { /* if no elements, nothing has to be added */
608 (*slOrder
)[k
][i
] += slFrameorder
[k
]/slCount
[k
];
609 slFrameorder
[k
] = 0; slCount
[k
] = 0;
612 } /* end loop i, over all groups in indexfile */
616 } while (read_next_x(oenv
,status
,&t
,natoms
,x0
,box
));
617 /*********** done with status file **********/
619 fprintf(stderr
,"\nRead trajectory. Printing parameters to file\n");
620 gmx_rmpbc_done(gpbc
);
622 /* average over frames */
623 for (i
= 1; i
< ngrps
- 1; i
++) {
624 svmul(1.0/nr_frames
, (*order
)[i
], (*order
)[i
]);
625 fprintf(stderr
,"Atom %d Tensor: x=%g , y=%g, z=%g\n",i
,(*order
)[i
][XX
],
626 (*order
)[i
][YY
], (*order
)[i
][ZZ
]);
627 if (bSliced
|| permolecule
) {
628 for (k
= 0; k
< nslices
; k
++)
629 (*slOrder
)[k
][i
] /= nr_frames
;
632 for (k
= 0; k
< nslices
; k
++)
633 (*distvals
)[k
][i
] /= nr_frames
;
637 fprintf(stderr
,"Average angle between double bond and normal: %f\n",
638 180*sdbangle
/(nr_frames
* size
*M_PI
));
640 sfree(x0
); /* free memory used by coordinate arrays */
651 void order_plot(rvec order
[], real
*slOrder
[], const char *afile
, const char *bfile
,
652 const char *cfile
, int ngrps
, int nslices
, real slWidth
, gmx_bool bSzonly
,
653 gmx_bool permolecule
, real
**distvals
, const output_env_t oenv
)
655 FILE *ord
, *slOrd
; /* xvgr files with order parameters */
656 int atom
, slice
; /* atom corresponding to order para.*/
657 char buf
[256]; /* for xvgr title */
658 real S
; /* order parameter averaged over all atoms */
662 sprintf(buf
,"Scd order parameters");
663 ord
= xvgropen(afile
,buf
,"Atom","S",oenv
);
664 sprintf(buf
, "Orderparameters per atom per slice");
665 slOrd
= xvgropen(bfile
, buf
, "Molecule", "S",oenv
);
666 for (atom
= 1; atom
< ngrps
- 1; atom
++) {
667 fprintf(ord
,"%12d %12g\n", atom
, -1 * (0.6667 * order
[atom
][XX
] +
668 0.333 * order
[atom
][YY
]));
671 for (slice
= 0; slice
< nslices
; slice
++) {
672 fprintf(slOrd
,"%12d\t",slice
);
674 fprintf(slOrd
,"%12g\t", distvals
[slice
][1]); /*use distance value at second carbon*/
675 for (atom
= 1; atom
< ngrps
- 1; atom
++)
676 fprintf(slOrd
,"%12g\t", slOrder
[slice
][atom
]);
682 sprintf(buf
,"Orderparameters Sz per atom");
683 ord
= xvgropen(afile
,buf
,"Atom","S",oenv
);
684 fprintf(stderr
,"ngrps = %d, nslices = %d",ngrps
, nslices
);
686 sprintf(buf
, "Orderparameters per atom per slice");
687 slOrd
= xvgropen(bfile
, buf
, "Slice", "S",oenv
);
689 for (atom
= 1; atom
< ngrps
- 1; atom
++)
690 fprintf(ord
,"%12d %12g\n", atom
, order
[atom
][ZZ
]);
692 for (slice
= 0; slice
< nslices
; slice
++) {
694 for (atom
= 1; atom
< ngrps
- 1; atom
++)
695 S
+= slOrder
[slice
][atom
];
696 fprintf(slOrd
,"%12g %12g\n", slice
*slWidth
, S
/atom
);
700 sprintf(buf
,"Order tensor diagonal elements");
701 ord
= xvgropen(afile
,buf
,"Atom","S",oenv
);
702 sprintf(buf
,"Deuterium order parameters");
703 slOrd
= xvgropen(cfile
,buf
, "Atom", "Scd",oenv
);
705 for (atom
= 1; atom
< ngrps
- 1; atom
++) {
706 fprintf(ord
,"%12d %12g %12g %12g\n", atom
, order
[atom
][XX
],
707 order
[atom
][YY
], order
[atom
][ZZ
]);
708 fprintf(slOrd
,"%12d %12g\n", atom
, -1 * (0.6667 * order
[atom
][XX
] +
709 0.333 * order
[atom
][YY
]));
717 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
)
719 /*function to write order parameters as B factors in PDB file using
720 first frame of trajectory*/
723 t_trxframe fr
, frout
;
727 ngrps
-=2; /*we don't have an order parameter for the first or
728 last atom in each chain*/
730 natoms
=read_first_frame(oenv
,&status
,ftp2fn(efTRX
,nfile
,fnm
),&fr
,
740 init_t_atoms(&useatoms
,nout
,TRUE
);
743 /*initialize PDBinfo*/
744 for (i
=0;i
<useatoms
.nr
;++i
)
746 useatoms
.pdbinfo
[i
].type
=0;
747 useatoms
.pdbinfo
[i
].occup
=0.0;
748 useatoms
.pdbinfo
[i
].bfac
=0.0;
749 useatoms
.pdbinfo
[i
].bAnisotropic
=FALSE
;
752 for (j
=0,ctr
=0;j
<nslices
;j
++)
753 for (i
=0;i
<ngrps
;i
++,ctr
++)
755 /*iterate along each chain*/
756 useatoms
.pdbinfo
[ctr
].bfac
=order
[j
][i
+1];
758 useatoms
.pdbinfo
[ctr
].occup
=distvals
[j
][i
+1];
759 copy_rvec(fr
.x
[a
[index
[i
+1]+j
]],frout
.x
[ctr
]);
760 useatoms
.atomname
[ctr
]=top
->atoms
.atomname
[a
[index
[i
+1]+j
]];
761 useatoms
.atom
[ctr
]=top
->atoms
.atom
[a
[index
[i
+1]+j
]];
762 useatoms
.nres
=max(useatoms
.nres
,useatoms
.atom
[ctr
].resind
+1);
763 useatoms
.resinfo
[useatoms
.atom
[ctr
].resind
]=top
->atoms
.resinfo
[useatoms
.atom
[ctr
].resind
]; /*copy resinfo*/
766 write_sto_conf(opt2fn("-ob",nfile
,fnm
),"Order parameters",&useatoms
,frout
.x
,NULL
,frout
.ePBC
,frout
.box
);
769 free_t_atoms(&useatoms
,FALSE
);
772 int gmx_order(int argc
,char *argv
[])
774 const char *desc
[] = {
775 "Compute the order parameter per atom for carbon tails. For atom i the",
776 "vector i-1, i+1 is used together with an axis. ",
777 "The index file should contain only the groups to be used for calculations,",
778 "with each group of equivalent carbons along the relevant acyl chain in its own",
779 "group. There should not be any generic groups (like System, Protein) in the index",
780 "file to avoid confusing the program (this is not relevant to tetrahedral order",
781 "parameters however, which only work for water anyway).[PAR]",
782 "The program can also give all",
783 "diagonal elements of the order tensor and even calculate the deuterium",
784 "order parameter Scd (default). If the option [TT]-szonly[tt] is given, only one",
785 "order tensor component (specified by the [TT]-d[tt] option) is given and the",
786 "order parameter per slice is calculated as well. If [TT]-szonly[tt] is not",
787 "selected, all diagonal elements and the deuterium order parameter is",
789 "The tetrahedrality order parameters can be determined",
790 "around an atom. Both angle an distance order parameters are calculated. See",
791 "P.-L. Chau and A.J. Hardwick, Mol. Phys., 93, (1998), 511-518.",
792 "for more details.[BR]",
796 static int nslices
= 1; /* nr of slices defined */
797 static gmx_bool bSzonly
= FALSE
; /* True if only Sz is wanted */
798 static gmx_bool bUnsat
= FALSE
; /* True if carbons are unsat. */
799 static const char *normal_axis
[] = { NULL
, "z", "x", "y", NULL
};
800 static gmx_bool permolecule
= FALSE
; /*compute on a per-molecule basis */
801 static gmx_bool radial
= FALSE
; /*compute a radial membrane normal */
802 static gmx_bool distcalc
= FALSE
; /*calculate distance from a reference group */
804 { "-d", FALSE
, etENUM
, {normal_axis
},
805 "Direction of the normal on the membrane" },
806 { "-sl", FALSE
, etINT
, {&nslices
},
807 "Calculate order parameter as function of box length, dividing the box"
808 " into this number of slices." },
809 { "-szonly", FALSE
, etBOOL
,{&bSzonly
},
810 "Only give Sz element of order tensor. (axis can be specified with [TT]-d[tt])" },
811 { "-unsat", FALSE
, etBOOL
,{&bUnsat
},
812 "Calculate order parameters for unsaturated carbons. Note that this can"
813 "not be mixed with normal order parameters." },
814 { "-permolecule", FALSE
, etBOOL
,{&permolecule
},
815 "Compute per-molecule Scd order parameters" },
816 { "-radial", FALSE
, etBOOL
,{&radial
},
817 "Compute a radial membrane normal" },
818 { "-calcdist", FALSE
, etBOOL
,{&distcalc
},
819 "Compute distance from a reference (currently defined only for radial and permolecule)" },
822 rvec
*order
; /* order par. for each atom */
823 real
**slOrder
; /* same, per slice */
824 real slWidth
= 0.0; /* width of a slice */
825 char **grpname
; /* groupnames */
826 int ngrps
, /* nr. of groups */
828 axis
=0; /* normal axis */
829 t_topology
*top
; /* topology */
831 atom_id
*index
, /* indices for a */
832 *a
; /* atom numbers in each group */
833 t_blocka
*block
; /* data from index file */
834 t_filenm fnm
[] = { /* files for g_order */
835 { efTRX
, "-f", NULL
, ffREAD
}, /* trajectory file */
836 { efNDX
, "-n", NULL
, ffREAD
}, /* index file */
837 { efNDX
, "-nr", NULL
, ffREAD
}, /* index for radial axis calculation */
838 { efTPX
, NULL
, NULL
, ffREAD
}, /* topology file */
839 { efXVG
,"-o","order", ffWRITE
}, /* xvgr output file */
840 { efXVG
,"-od","deuter", ffWRITE
}, /* xvgr output file */
841 { efPDB
,"-ob",NULL
, ffWRITE
}, /* write Scd as B factors to PDB if permolecule */
842 { efXVG
,"-os","sliced", ffWRITE
}, /* xvgr output file */
843 { efXVG
,"-Sg","sg-ang", ffOPTWR
}, /* xvgr output file */
844 { efXVG
,"-Sk","sk-dist", ffOPTWR
}, /* xvgr output file */
845 { efXVG
,"-Sgsl","sg-ang-slice", ffOPTWR
}, /* xvgr output file */
846 { efXVG
,"-Sksl","sk-dist-slice", ffOPTWR
}, /* xvgr output file */
848 gmx_bool bSliced
= FALSE
; /* True if box is sliced */
849 #define NFILE asize(fnm)
850 real
**distvals
=NULL
;
851 const char *sgfnm
,*skfnm
,*ndxfnm
,*tpsfnm
,*trxfnm
;
854 CopyRight(stderr
,argv
[0]);
856 parse_common_args(&argc
,argv
,PCA_CAN_VIEW
| PCA_CAN_TIME
| PCA_BE_NICE
,
857 NFILE
,fnm
,asize(pa
),pa
,asize(desc
),desc
,0, NULL
,&oenv
);
859 gmx_fatal(FARGS
,"Can not have nslices < 1");
860 sgfnm
= opt2fn_null("-Sg",NFILE
,fnm
);
861 skfnm
= opt2fn_null("-Sk",NFILE
,fnm
);
862 ndxfnm
= opt2fn_null("-n",NFILE
,fnm
);
863 tpsfnm
= ftp2fn(efTPX
,NFILE
,fnm
);
864 trxfnm
= ftp2fn(efTRX
,NFILE
,fnm
);
867 if (strcmp(normal_axis
[0],"x") == 0) axis
= XX
;
868 else if (strcmp(normal_axis
[0],"y") == 0) axis
= YY
;
869 else if (strcmp(normal_axis
[0],"z") == 0) axis
= ZZ
;
870 else gmx_fatal(FARGS
,"Invalid axis, use x, y or z");
874 fprintf(stderr
,"Taking x axis as normal to the membrane\n");
877 fprintf(stderr
,"Taking y axis as normal to the membrane\n");
880 fprintf(stderr
,"Taking z axis as normal to the membrane\n");
884 /* tetraheder order parameter */
885 if (skfnm
|| sgfnm
) {
886 /* If either of theoptions is set we compute both */
887 sgfnm
= opt2fn("-Sg",NFILE
,fnm
);
888 skfnm
= opt2fn("-Sk",NFILE
,fnm
);
889 calc_tetra_order_parm(ndxfnm
,tpsfnm
,trxfnm
,sgfnm
,skfnm
,nslices
,axis
,
890 opt2fn("-Sgsl",NFILE
,fnm
),opt2fn("-Sksl",NFILE
,fnm
),
892 /* view xvgr files */
893 do_view(oenv
,opt2fn("-Sg",NFILE
,fnm
), NULL
);
894 do_view(oenv
,opt2fn("-Sk",NFILE
,fnm
), NULL
);
896 do_view(oenv
,opt2fn("-Sgsl",NFILE
,fnm
), NULL
);
897 do_view(oenv
,opt2fn("-Sksl",NFILE
,fnm
), NULL
);
901 /* tail order parameter */
905 fprintf(stderr
,"Dividing box in %d slices.\n\n", nslices
);
909 fprintf(stderr
,"Only calculating Sz\n");
911 fprintf(stderr
,"Taking carbons as unsaturated!\n");
913 top
= read_top(ftp2fn(efTPX
,NFILE
,fnm
),&ePBC
); /* read topology file */
915 block
= init_index(ftp2fn(efNDX
,NFILE
,fnm
),&grpname
);
916 index
= block
->index
; /* get indices from t_block block */
917 a
= block
->a
; /* see block.h */
922 nslices
= index
[1] - index
[0]; /*I think this assumes contiguous lipids in topology*/
923 fprintf(stderr
,"Calculating Scd order parameters for each of %d molecules\n",nslices
);
929 fprintf(stderr
,"Calculating radial distances\n");
931 gmx_fatal(FARGS
,"Cannot yet output radial distances without permolecule\n");
934 /* show atomtypes, to check if index file is correct */
935 print_types(index
, a
, ngrps
, grpname
, top
);
937 calc_order(ftp2fn(efTRX
,NFILE
,fnm
), index
, a
, &order
,
938 &slOrder
, &slWidth
, nslices
, bSliced
, bUnsat
,
939 top
, ePBC
, ngrps
, axis
,permolecule
,radial
,distcalc
,opt2fn_null("-nr",NFILE
,fnm
),&distvals
, oenv
);
942 ngrps
--; /*don't print the last group--was used for
943 center-of-mass determination*/
945 order_plot(order
, slOrder
, opt2fn("-o",NFILE
,fnm
), opt2fn("-os",NFILE
,fnm
),
946 opt2fn("-od",NFILE
,fnm
), ngrps
, nslices
, slWidth
, bSzonly
,permolecule
,distvals
,oenv
);
948 if (opt2bSet("-ob",NFILE
,fnm
))
952 "Won't write B-factors with averaged order parameters; use -permolecule\n");
954 write_bfactors(fnm
,NFILE
,index
,a
,nslices
,ngrps
,slOrder
,top
,distvals
,oenv
);
958 do_view(oenv
,opt2fn("-o",NFILE
,fnm
), NULL
); /* view xvgr file */
959 do_view(oenv
,opt2fn("-os",NFILE
,fnm
), NULL
); /* view xvgr file */
960 do_view(oenv
,opt2fn("-od",NFILE
,fnm
), NULL
); /* view xvgr file */
966 for (i
=0;i
<nslices
;++i
)