Enforced rotation: fixed torque calculation for FLEX potential when using mass-weighting
[gromacs/adressmacs.git] / src / tools / gmx_density.c
blob545dcb154bba99b8b2dfa377514d39edfbf87ec2
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
38 #include <math.h>
39 #include <ctype.h>
41 #include "sysstuff.h"
42 #include "string.h"
43 #include "string2.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 "physics.h"
57 #include "gmx_ana.h"
59 typedef struct {
60 char *atomname;
61 int nr_el;
62 } t_electron;
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 */
82 int tempnr;
84 FILE *in;
85 int nr; /* number of atomstypes to read */
86 int i;
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");
99 snew(*eltab,nr);
101 for (i=0;i<nr;i++) {
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);
109 ffclose(in);
111 /* sort the list */
112 fprintf(stderr,"Sorting list..\n");
113 qsort ((void*)*eltab, nr, sizeof(t_electron),
114 (int(*)(const void*, const void*))compare);
116 return nr;
119 void center_coords(t_atoms *atoms,matrix box,rvec x0[],int axis)
121 int i,m;
122 real tmass,mm;
123 rvec com,shift,box_center;
125 tmass = 0;
126 clear_rvec(com);
127 for(i=0; (i<atoms->nr); i++) {
128 mm = atoms->atom[i].m;
129 tmass += mm;
130 for(m=0; (m<DIM); m++)
131 com[m] += mm*x0[i][m];
133 for(m=0; (m<DIM); m++)
134 com[m] /= tmass;
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,
145 int ePBC,
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) */
152 double invvol;
153 int natoms; /* nr. atoms in trj */
154 t_trxstatus *status;
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;
162 real t,
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");
172 if (! *nslices)
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 ***********/
182 do {
183 gmx_rmpbc(gpbc,natoms,box,x0);
185 if (bCenter)
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];
194 while (z < 0)
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));
201 sought.nr_el = 0;
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);
210 if (found == NULL)
211 fprintf(stderr,"Couldn't find %s. Add it to the .dat file\n",
212 *(top->atoms.atomname[index[n][i]]));
213 else
214 (*slDensity)[n][slice] += (found->nr_el -
215 top->atoms.atom[index[n][i]].q)*invvol;
216 free(sought.atomname);
219 nr_frames++;
220 } while (read_next_x(oenv,status,&t,natoms,x0,box));
221 gmx_rmpbc_done(gpbc);
223 /*********** done with status file **********/
224 close_trj(status);
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",
231 nr_frames);
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) */
248 double invvol;
249 int natoms; /* nr. atoms in trj */
250 t_trxstatus *status;
251 int **slCount, /* nr. of atoms in one slice for a group */
252 i,j,n, /* loop indices */
253 teller = 0,
254 ax1=0, ax2=0,
255 nr_frames = 0, /* number of frames */
256 slice; /* current slice */
257 real t,
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");
269 if (! *nslices) {
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 ***********/
280 do {
281 gmx_rmpbc(gpbc,natoms,box,x0);
283 if (bCenter)
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]);
288 teller++;
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];
293 while (z < 0)
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;
303 nr_frames++;
304 } while (read_next_x(oenv,status,&t,natoms,x0,box));
305 gmx_rmpbc_done(gpbc);
307 /*********** done with status file **********/
308 close_trj(status);
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",
315 nr_frames);
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)
331 FILE *den;
332 const char *ylabel=NULL;
333 int slice, n;
334 real ddd;
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++) {
350 if (bSymmetrize)
351 ddd = (slDensity[n][slice]+slDensity[n][nslices-slice-1])*0.5;
352 else
353 ddd = slDensity[n][slice];
354 if (dens_opt[0][0] == 'm')
355 fprintf(den," %12g", ddd*AMU/(NANO*NANO*NANO));
356 else
357 fprintf(den," %12g", ddd);
359 fprintf(den,"\n");
362 ffclose(den);
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.",
370 "[PAR]",
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]",
375 " 2[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",
381 "partial charge."
384 output_env_t oenv;
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;
393 t_pargs pa[] = {
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},
399 "Density"},
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 */
419 int ePBC;
420 atom_id **index; /* indices for all groups */
421 int i;
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,
437 &oenv);
439 if (bSymmetrize && !bCenter) {
440 fprintf(stderr,"Can not symmetrize without centering. Turning on -center\n");
441 bCenter = TRUE;
443 /* Calculate axis */
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;
455 snew(grpname,ngrps);
456 snew(index,ngrps);
457 snew(ngx,ngrps);
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);
468 } else
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,
474 bSymmetrize,oenv);
476 do_view(oenv,opt2fn("-o",NFILE,fnm), "-nxy"); /* view xvgr file */
477 thanx(stderr);
478 return 0;