3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
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
33 * Green Red Orange Magenta Azure Cyan Skyblue
64 /****************************************************************************/
65 /* This program calculates the partial density across the box. */
66 /* Peter Tieleman, Mei 1995 */
67 /****************************************************************************/
69 /* used for sorting the list */
70 int compare(void *a
, void *b
)
72 t_electron
*tmp1
,*tmp2
;
73 tmp1
= (t_electron
*)a
; tmp2
= (t_electron
*)b
;
75 return strcmp(tmp1
->atomname
,tmp2
->atomname
);
78 int get_electrons(t_electron
**eltab
, const char *fn
)
80 char buffer
[256]; /* to read in a line */
81 char tempname
[80]; /* buffer to hold name */
85 int nr
; /* number of atomstypes to read */
88 if ( !(in
= ffopen(fn
,"r")))
89 gmx_fatal(FARGS
,"Couldn't open %s. Exiting.\n",fn
);
91 if(NULL
==fgets(buffer
, 255, in
))
93 gmx_fatal(FARGS
,"Error reading from file %s",fn
);
96 if (sscanf(buffer
, "%d", &nr
) != 1)
97 gmx_fatal(FARGS
,"Invalid number of atomtypes in datafile\n");
102 if (fgets(buffer
, 255, in
) == NULL
)
103 gmx_fatal(FARGS
,"reading datafile. Check your datafile.\n");
104 if (sscanf(buffer
, "%s = %d", tempname
, &tempnr
) != 2)
105 gmx_fatal(FARGS
,"Invalid line in datafile at line %d\n",i
+1);
106 (*eltab
)[i
].nr_el
= tempnr
;
107 (*eltab
)[i
].atomname
= strdup(tempname
);
112 fprintf(stderr
,"Sorting list..\n");
113 qsort ((void*)*eltab
, nr
, sizeof(t_electron
),
114 (int(*)(const void*, const void*))compare
);
119 void center_coords(t_atoms
*atoms
,matrix box
,rvec x0
[],int axis
)
123 rvec com
,shift
,box_center
;
127 for(i
=0; (i
<atoms
->nr
); i
++) {
128 mm
= atoms
->atom
[i
].m
;
130 for(m
=0; (m
<DIM
); m
++)
131 com
[m
] += mm
*x0
[i
][m
];
133 for(m
=0; (m
<DIM
); m
++)
135 calc_box_center(ecenterDEF
,box
,box_center
);
136 rvec_sub(box_center
,com
,shift
);
137 shift
[axis
] -= box_center
[axis
];
139 for(i
=0; (i
<atoms
->nr
); i
++)
140 rvec_dec(x0
[i
],shift
);
143 void calc_electron_density(const char *fn
, atom_id
**index
, int gnx
[],
144 real
***slDensity
, int *nslices
, t_topology
*top
,
146 int axis
, int nr_grps
, real
*slWidth
,
147 t_electron eltab
[], int nr
,gmx_bool bCenter
,
148 const output_env_t oenv
)
150 rvec
*x0
; /* coordinates without pbc */
151 matrix box
; /* box (3x3) */
153 int natoms
; /* nr. atoms in trj */
155 int i
,n
, /* loop indices */
156 nr_frames
= 0, /* number of frames */
157 slice
; /* current slice */
158 t_electron
*found
; /* found by bsearch */
159 t_electron sought
; /* thingie thought by bsearch */
160 gmx_rmpbc_t gpbc
=NULL
;
165 if (axis
< 0 || axis
>= DIM
) {
166 gmx_fatal(FARGS
,"Invalid axes. Terminating\n");
169 if ((natoms
= read_first_x(oenv
,&status
,fn
,&t
,&x0
,box
)) == 0)
170 gmx_fatal(FARGS
,"Could not read coordinates from statusfile\n");
173 *nslices
= (int)(box
[axis
][axis
] * 10); /* default value */
174 fprintf(stderr
,"\nDividing the box in %d slices\n",*nslices
);
176 snew(*slDensity
, nr_grps
);
177 for (i
= 0; i
< nr_grps
; i
++)
178 snew((*slDensity
)[i
], *nslices
);
180 gpbc
= gmx_rmpbc_init(&top
->idef
,ePBC
,top
->atoms
.nr
,box
);
181 /*********** Start processing trajectory ***********/
183 gmx_rmpbc(gpbc
,natoms
,box
,x0
);
186 center_coords(&top
->atoms
,box
,x0
,axis
);
188 *slWidth
= box
[axis
][axis
]/(*nslices
);
189 invvol
= *nslices
/(box
[XX
][XX
]*box
[YY
][YY
]*box
[ZZ
][ZZ
]);
191 for (n
= 0; n
< nr_grps
; n
++) {
192 for (i
= 0; i
< gnx
[n
]; i
++) { /* loop over all atoms in index file */
193 z
= x0
[index
[n
][i
]][axis
];
195 z
+= box
[axis
][axis
];
196 while (z
> box
[axis
][axis
])
197 z
-= box
[axis
][axis
];
199 /* determine which slice atom is in */
200 slice
= (z
/ (*slWidth
));
202 sought
.atomname
= strdup(*(top
->atoms
.atomname
[index
[n
][i
]]));
204 /* now find the number of electrons. This is not efficient. */
205 found
= (t_electron
*)
206 bsearch((const void *)&sought
,
207 (const void *)eltab
, nr
, sizeof(t_electron
),
208 (int(*)(const void*, const void*))compare
);
211 fprintf(stderr
,"Couldn't find %s. Add it to the .dat file\n",
212 *(top
->atoms
.atomname
[index
[n
][i
]]));
214 (*slDensity
)[n
][slice
] += (found
->nr_el
-
215 top
->atoms
.atom
[index
[n
][i
]].q
)*invvol
;
216 free(sought
.atomname
);
220 } while (read_next_x(oenv
,status
,&t
,natoms
,x0
,box
));
221 gmx_rmpbc_done(gpbc
);
223 /*********** done with status file **********/
226 /* slDensity now contains the total number of electrons per slice, summed
227 over all frames. Now divide by nr_frames and volume of slice
230 fprintf(stderr
,"\nRead %d frames from trajectory. Counting electrons\n",
233 for (n
=0; n
< nr_grps
; n
++) {
234 for (i
= 0; i
< *nslices
; i
++)
235 (*slDensity
)[n
][i
] /= nr_frames
;
238 sfree(x0
); /* free memory used by coordinate array */
241 void calc_density(const char *fn
, atom_id
**index
, int gnx
[],
242 real
***slDensity
, int *nslices
, t_topology
*top
, int ePBC
,
243 int axis
, int nr_grps
, real
*slWidth
, gmx_bool bCenter
,
244 const output_env_t oenv
)
246 rvec
*x0
; /* coordinates without pbc */
247 matrix box
; /* box (3x3) */
249 int natoms
; /* nr. atoms in trj */
251 int **slCount
, /* nr. of atoms in one slice for a group */
252 i
,j
,n
, /* loop indices */
255 nr_frames
= 0, /* number of frames */
256 slice
; /* current slice */
259 char *buf
; /* for tmp. keeping atomname */
260 gmx_rmpbc_t gpbc
=NULL
;
262 if (axis
< 0 || axis
>= DIM
) {
263 gmx_fatal(FARGS
,"Invalid axes. Terminating\n");
266 if ((natoms
= read_first_x(oenv
,&status
,fn
,&t
,&x0
,box
)) == 0)
267 gmx_fatal(FARGS
,"Could not read coordinates from statusfile\n");
270 *nslices
= (int)(box
[axis
][axis
] * 10); /* default value */
271 fprintf(stderr
,"\nDividing the box in %d slices\n",*nslices
);
274 snew(*slDensity
, nr_grps
);
275 for (i
= 0; i
< nr_grps
; i
++)
276 snew((*slDensity
)[i
], *nslices
);
278 gpbc
= gmx_rmpbc_init(&top
->idef
,ePBC
,top
->atoms
.nr
,box
);
279 /*********** Start processing trajectory ***********/
281 gmx_rmpbc(gpbc
,natoms
,box
,x0
);
284 center_coords(&top
->atoms
,box
,x0
,axis
);
286 *slWidth
= box
[axis
][axis
]/(*nslices
);
287 invvol
= *nslices
/(box
[XX
][XX
]*box
[YY
][YY
]*box
[ZZ
][ZZ
]);
290 for (n
= 0; n
< nr_grps
; n
++) {
291 for (i
= 0; i
< gnx
[n
]; i
++) { /* loop over all atoms in index file */
292 z
= x0
[index
[n
][i
]][axis
];
294 z
+= box
[axis
][axis
];
295 while (z
> box
[axis
][axis
])
296 z
-= box
[axis
][axis
];
298 /* determine which slice atom is in */
299 slice
= (int)(z
/ (*slWidth
));
300 (*slDensity
)[n
][slice
] += top
->atoms
.atom
[index
[n
][i
]].m
*invvol
;
304 } while (read_next_x(oenv
,status
,&t
,natoms
,x0
,box
));
305 gmx_rmpbc_done(gpbc
);
307 /*********** done with status file **********/
310 /* slDensity now contains the total mass per slice, summed over all
311 frames. Now divide by nr_frames and volume of slice
314 fprintf(stderr
,"\nRead %d frames from trajectory. Calculating density\n",
317 for (n
=0; n
< nr_grps
; n
++) {
318 for (i
= 0; i
< *nslices
; i
++) {
319 (*slDensity
)[n
][i
] /= nr_frames
;
323 sfree(x0
); /* free memory used by coordinate array */
326 void plot_density(real
*slDensity
[], const char *afile
, int nslices
,
327 int nr_grps
, char *grpname
[], real slWidth
,
328 const char **dens_opt
,
329 gmx_bool bSymmetrize
, const output_env_t oenv
)
332 const char *ylabel
=NULL
;
336 switch (dens_opt
[0][0]) {
337 case 'm': ylabel
= "Density (kg m\\S-3\\N)"; break;
338 case 'n': ylabel
= "Number density (nm\\S-3\\N)"; break;
339 case 'c': ylabel
= "Charge density (e nm\\S-3\\N)"; break;
340 case 'e': ylabel
= "Electron density (e nm\\S-3\\N)"; break;
343 den
= xvgropen(afile
, "Partial densities", "Box (nm)", ylabel
,oenv
);
345 xvgr_legend(den
,nr_grps
,(const char**)grpname
,oenv
);
347 for (slice
= 0; (slice
< nslices
); slice
++) {
348 fprintf(den
,"%12g ", slice
* slWidth
);
349 for (n
= 0; (n
< nr_grps
); n
++) {
351 ddd
= (slDensity
[n
][slice
]+slDensity
[n
][nslices
-slice
-1])*0.5;
353 ddd
= slDensity
[n
][slice
];
354 if (dens_opt
[0][0] == 'm')
355 fprintf(den
," %12g", ddd
*AMU
/(NANO
*NANO
*NANO
));
357 fprintf(den
," %12g", ddd
);
365 int gmx_density(int argc
,char *argv
[])
367 const char *desc
[] = {
368 "Compute partial densities across the box, using an index file.[PAR]",
369 "For the total density of NPT simulations, use [TT]g_energy[tt] instead.",
371 "Densities in kg/m^3, number densities or electron densities can be",
372 "calculated. For electron densities, a file describing the number of",
373 "electrons for each type of atom should be provided using [TT]-ei[tt].",
374 "It should look like:[BR]",
376 " atomname = nrelectrons[BR]",
377 " atomname = nrelectrons[BR]",
378 "The first line contains the number of lines to read from the file.",
379 "There should be one line for each unique atom name in your system.",
380 "The number of electrons for each atom is modified by its atomic",
385 static const char *dens_opt
[] =
386 { NULL
, "mass", "number", "charge", "electron", NULL
};
387 static int axis
= 2; /* normal to memb. default z */
388 static const char *axtitle
="Z";
389 static int nslices
= 50; /* nr of slices defined */
390 static int ngrps
= 1; /* nr. of groups */
391 static gmx_bool bSymmetrize
=FALSE
;
392 static gmx_bool bCenter
=FALSE
;
394 { "-d", FALSE
, etSTR
, {&axtitle
},
395 "Take the normal on the membrane in direction X, Y or Z." },
396 { "-sl", FALSE
, etINT
, {&nslices
},
397 "Divide the box in #nr slices." },
398 { "-dens", FALSE
, etENUM
, {dens_opt
},
400 { "-ng", FALSE
, etINT
, {&ngrps
},
401 "Number of groups to compute densities of" },
402 { "-symm", FALSE
, etBOOL
, {&bSymmetrize
},
403 "Symmetrize the density along the axis, with respect to the center. Useful for bilayers." },
404 { "-center", FALSE
, etBOOL
, {&bCenter
},
405 "Shift the center of mass along the axis to zero. This means if your axis is Z and your box is bX, bY, bZ, the center of mass will be at bX/2, bY/2, 0."}
408 const char *bugs
[] = {
409 "When calculating electron densities, atomnames are used instead of types. This is bad.",
412 real
**density
; /* density per slice */
413 real slWidth
; /* width of one slice */
414 char **grpname
; /* groupnames */
415 int nr_electrons
; /* nr. electrons */
416 int *ngx
; /* sizes of groups */
417 t_electron
*el_tab
; /* tabel with nr. of electrons*/
418 t_topology
*top
; /* topology */
420 atom_id
**index
; /* indices for all groups */
423 t_filenm fnm
[] = { /* files for g_density */
424 { efTRX
, "-f", NULL
, ffREAD
},
425 { efNDX
, NULL
, NULL
, ffOPTRD
},
426 { efTPX
, NULL
, NULL
, ffREAD
},
427 { efDAT
, "-ei", "electrons", ffOPTRD
}, /* file with nr. of electrons */
428 { efXVG
,"-o","density",ffWRITE
},
431 #define NFILE asize(fnm)
433 CopyRight(stderr
,argv
[0]);
435 parse_common_args(&argc
,argv
,PCA_CAN_VIEW
| PCA_CAN_TIME
| PCA_BE_NICE
,
436 NFILE
,fnm
,asize(pa
),pa
,asize(desc
),desc
,asize(bugs
),bugs
,
439 if (bSymmetrize
&& !bCenter
) {
440 fprintf(stderr
,"Can not symmetrize without centering. Turning on -center\n");
444 axis
= toupper(axtitle
[0]) - 'X';
446 top
= read_top(ftp2fn(efTPX
,NFILE
,fnm
),&ePBC
); /* read topology file */
447 if (dens_opt
[0][0] == 'n') {
448 for(i
=0; (i
<top
->atoms
.nr
); i
++)
449 top
->atoms
.atom
[i
].m
= 1;
450 } else if (dens_opt
[0][0] == 'c') {
451 for(i
=0; (i
<top
->atoms
.nr
); i
++)
452 top
->atoms
.atom
[i
].m
= top
->atoms
.atom
[i
].q
;
459 get_index(&top
->atoms
,ftp2fn_null(efNDX
,NFILE
,fnm
),ngrps
,ngx
,index
,grpname
);
461 if (dens_opt
[0][0] == 'e') {
462 nr_electrons
= get_electrons(&el_tab
,ftp2fn(efDAT
,NFILE
,fnm
));
463 fprintf(stderr
,"Read %d atomtypes from datafile\n", nr_electrons
);
465 calc_electron_density(ftp2fn(efTRX
,NFILE
,fnm
),index
, ngx
, &density
,
466 &nslices
, top
, ePBC
, axis
, ngrps
, &slWidth
, el_tab
,
467 nr_electrons
,bCenter
,oenv
);
469 calc_density(ftp2fn(efTRX
,NFILE
,fnm
),index
, ngx
, &density
, &nslices
, top
,
470 ePBC
, axis
, ngrps
, &slWidth
, bCenter
,oenv
);
472 plot_density(density
, opt2fn("-o",NFILE
,fnm
),
473 nslices
, ngrps
, grpname
, slWidth
, dens_opt
,
476 do_view(oenv
,opt2fn("-o",NFILE
,fnm
), "-nxy"); /* view xvgr file */