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-2007, 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 * Groningen Machine for Chemical Simulation
69 void add_rec(t_conect c[],atom_id i,atom_id j,real d2)
71 if (c[i].aa == NO_ATID) {
75 else if (c[i].ab == NO_ATID) {
79 else if (d2 < c[i].d2a) {
83 else if (d2 < c[i].d2b) {
87 /* Swap them if necessary: a must be larger than b */
88 if (c[i].d2a < c[i].d2b) {
98 void do_conect(const char *fn,int n,rvec x[])
106 fprintf(stderr,"Building CONECT records\n");
109 c[i].aa = c[i].ab = NO_ATID;
111 for(i=0; (i<n); i++) {
112 for(j=i+1; (j<n); j++) {
113 rvec_sub(x[i],x[j],dx);
120 for(i=0; (i<n); i++) {
121 if ((c[i].aa == NO_ATID) || (c[i].ab == NO_ATID))
122 fprintf(stderr,"Warning dot %d has no conections\n",i+1);
123 fprintf(fp,"CONECT%5d%5d%5d\n",i+1,c[i].aa+1,c[i].ab+1);
129 void connelly_plot(const char *fn,int ndots,real dots[],rvec x[],t_atoms *atoms,
130 t_symtab *symtab,int ePBC,matrix box,gmx_bool bSave)
132 static const char *atomnm="DOT";
133 static const char *resnm ="DOT";
134 static const char *title ="Connely Dot Surface Generated by g_sas";
143 srenew(atoms->atom,atoms->nr+ndots);
144 srenew(atoms->atomname,atoms->nr+ndots);
145 srenew(atoms->resinfo,r0+1);
146 atoms->atom[i0].resind = r0;
147 t_atoms_set_resinfo(atoms,i0,symtab,resnm,r0+1,' ',0,' ');
148 srenew(atoms->pdbinfo,atoms->nr+ndots);
149 snew(xnew,atoms->nr+ndots);
150 for(i=0; (i<atoms->nr); i++)
151 copy_rvec(x[i],xnew[i]);
152 for(i=k=0; (i<ndots); i++) {
154 atoms->atomname[ii0] = put_symtab(symtab,atomnm);
155 atoms->pdbinfo[ii0].type = epdbATOM;
156 atoms->pdbinfo[ii0].atomnr= ii0;
157 atoms->atom[ii0].resind = r0;
158 xnew[ii0][XX] = dots[k++];
159 xnew[ii0][YY] = dots[k++];
160 xnew[ii0][ZZ] = dots[k++];
161 atoms->pdbinfo[ii0].bfac = 0.0;
162 atoms->pdbinfo[ii0].occup = 0.0;
164 atoms->nr = i0+ndots;
166 write_sto_conf(fn,title,atoms,xnew,NULL,ePBC,box);
171 init_t_atoms(&aaa,ndots,TRUE);
172 aaa.atom[0].resind = 0;
173 t_atoms_set_resinfo(&aaa,0,symtab,resnm,1,' ',0,' ');
175 for(i=k=0; (i<ndots); i++) {
177 aaa.atomname[ii0] = put_symtab(symtab,atomnm);
178 aaa.pdbinfo[ii0].type = epdbATOM;
179 aaa.pdbinfo[ii0].atomnr= ii0;
180 aaa.atom[ii0].resind = 0;
181 xnew[ii0][XX] = dots[k++];
182 xnew[ii0][YY] = dots[k++];
183 xnew[ii0][ZZ] = dots[k++];
184 aaa.pdbinfo[ii0].bfac = 0.0;
185 aaa.pdbinfo[ii0].occup = 0.0;
188 write_sto_conf(fn,title,&aaa,xnew,NULL,ePBC,box);
189 do_conect(fn,ndots,xnew);
190 free_t_atoms(&aaa,FALSE);
195 real calc_radius(char *atom)
221 void sas_plot(int nfile,t_filenm fnm[],real solsize,int ndots,
222 real qcut,gmx_bool bSave,real minarea,gmx_bool bPBC,
223 real dgs_default,gmx_bool bFindex, const output_env_t oenv)
225 FILE *fp,*fp2,*fp3=NULL,*vp;
226 const char *flegend[] = { "Hydrophobic", "Hydrophilic",
227 "Total", "D Gsolv" };
228 const char *vlegend[] = { "Volume (nm\\S3\\N)", "Density (g/l)" };
231 gmx_atomprop_t aps=NULL;
232 gmx_rmpbc_t gpbc=NULL;
235 int i,j,ii,nfr,natoms,flag,nsurfacedots,res;
243 gmx_bool *bOut,*bPhobic;
245 gmx_bool bResAt,bITP,bDGsol;
246 real *radius,*dgs_factor=NULL,*area=NULL,*surfacedots=NULL;
247 real at_area,*atom_area=NULL,*atom_area2=NULL;
248 real *res_a=NULL,*res_area=NULL,*res_area2=NULL;
249 real totarea,totvolume,totmass=0,density,harea,tarea,fluc2;
250 atom_id **index,*findex;
251 int *nx,nphobic,npcheck,retval;
252 char **grpname,*fgrpname;
255 bITP = opt2bSet("-i",nfile,fnm);
256 bResAt = opt2bSet("-or",nfile,fnm) || opt2bSet("-oa",nfile,fnm) || bITP;
258 bTop = read_tps_conf(ftp2fn(efTPS,nfile,fnm),title,&top,&ePBC,
259 &xtop,NULL,topbox,FALSE);
260 atoms = &(top.atoms);
263 fprintf(stderr,"No tpr file, will not compute Delta G of solvation\n");
266 bDGsol = strcmp(*(atoms->atomtype[0]),"?") != 0;
268 fprintf(stderr,"Warning: your tpr file is too old, will not compute "
269 "Delta G of solvation\n");
271 printf("In case you use free energy of solvation predictions:\n");
272 please_cite(stdout,"Eisenberg86a");
276 aps = gmx_atomprop_init();
278 if ((natoms=read_first_x(oenv,&status,ftp2fn(efTRX,nfile,fnm),
280 gmx_fatal(FARGS,"Could not read coordinates from statusfile\n");
282 if ((ePBC != epbcXYZ) || (TRICLINIC(box))) {
283 fprintf(stderr,"\n\nWARNING: non-rectangular boxes may give erroneous results or crashes.\n"
284 "Analysis based on vacuum simulations (with the possibility of evaporation)\n"
285 "will certainly crash the analysis.\n\n");
290 fprintf(stderr,"Select a group for calculation of surface and a group for output:\n");
291 get_index(atoms,ftp2fn_null(efNDX,nfile,fnm),2,nx,index,grpname);
294 fprintf(stderr,"Select a group of hydrophobic atoms:\n");
295 get_index(atoms,ftp2fn_null(efNDX,nfile,fnm),1,&nphobic,&findex,&fgrpname);
298 for(i=0; i<nx[1]; i++)
299 bOut[index[1][i]] = TRUE;
301 /* Now compute atomic readii including solvent probe size */
305 snew(atom_area,nx[0]);
306 snew(atom_area2,nx[0]);
307 snew(res_a,atoms->nres);
308 snew(res_area,atoms->nres);
309 snew(res_area2,atoms->nres);
312 snew(dgs_factor,nx[0]);
314 /* Get a Van der Waals radius for each atom */
316 for(i=0; (i<natoms); i++) {
317 if (!gmx_atomprop_query(aps,epropVDW,
318 *(atoms->resinfo[atoms->atom[i].resind].name),
319 *(atoms->atomname[i]),&radius[i]))
321 /* radius[i] = calc_radius(*(top->atoms.atomname[i])); */
322 radius[i] += solsize;
325 fprintf(stderr,"WARNING: could not find a Van der Waals radius for %d atoms\n",ndefault);
326 /* Determine which atom is counted as hydrophobic */
329 for(i=0; (i<nx[0]); i++) {
331 for(j=0; (j<nphobic); j++) {
332 if (findex[j] == ii) {
339 if (npcheck != nphobic)
340 gmx_fatal(FARGS,"Consistency check failed: not all %d atoms in the hydrophobic index\n"
341 "found in the normal index selection (%d atoms)",nphobic,npcheck);
346 for(i=0; (i<nx[0]); i++) {
349 bPhobic[i] = fabs(atoms->atom[ii].q) <= qcut;
350 if (bPhobic[i] && bOut[ii])
354 if (!gmx_atomprop_query(aps,epropDGsol,
355 *(atoms->resinfo[atoms->atom[ii].resind].name),
356 *(atoms->atomtype[ii]),&(dgs_factor[i])))
357 dgs_factor[i] = dgs_default;
359 fprintf(debug,"Atom %5d %5s-%5s: q= %6.3f, r= %6.3f, dgsol= %6.3f, hydrophobic= %s\n",
360 ii+1,*(atoms->resinfo[atoms->atom[ii].resind].name),
361 *(atoms->atomname[ii]),
362 atoms->atom[ii].q,radius[ii]-solsize,dgs_factor[i],
365 fprintf(stderr,"%d out of %d atoms were classified as hydrophobic\n",
368 fp=xvgropen(opt2fn("-o",nfile,fnm),"Solvent Accessible Surface","Time (ps)",
369 "Area (nm\\S2\\N)",oenv);
370 xvgr_legend(fp,asize(flegend) - (bDGsol ? 0 : 1),flegend,oenv);
371 vfile = opt2fn_null("-tv",nfile,fnm);
374 gmx_fatal(FARGS,"Need a tpr file for option -tv");
376 vp=xvgropen(vfile,"Volume and Density","Time (ps)","",oenv);
377 xvgr_legend(vp,asize(vlegend),vlegend,oenv);
380 for(i=0; (i<nx[0]); i++) {
384 if (!query_atomprop(atomprop,epropMass,
385 *(top->atoms.resname[top->atoms.atom[ii].resnr]),
386 *(top->atoms.atomname[ii]),&mm))
390 totmass += atoms->atom[ii].m;
393 fprintf(stderr,"WARNING: Using %d default masses for density calculation, which most likely are inaccurate\n",ndefault);
398 gmx_atomprop_destroy(aps);
401 gpbc = gmx_rmpbc_init(&top.idef,ePBC,natoms,box);
406 gmx_rmpbc(gpbc,natoms,box,x);
408 bConnelly = (nfr==0 && opt2bSet("-q",nfile,fnm));
411 gmx_fatal(FARGS,"Need a tpr file for Connelly plot");
412 flag = FLAG_ATOM_AREA | FLAG_DOTS;
414 flag = FLAG_ATOM_AREA;
417 flag = flag | FLAG_VOLUME;
421 write_sto_conf("check.pdb","pbc check",atoms,x,NULL,ePBC,box);
423 retval = nsc_dclm_pbc(x,radius,nx[0],ndots,flag,&totarea,
424 &area,&totvolume,&surfacedots,&nsurfacedots,
425 index[0],ePBC,bPBC ? box : NULL);
427 gmx_fatal(FARGS,"Something wrong in nsc_dclm_pbc");
430 connelly_plot(ftp2fn(efPDB,nfile,fnm),
431 nsurfacedots,surfacedots,x,atoms,
432 &(top.symtab),ePBC,box,bSave);
437 for(i=0; i<atoms->nres; i++)
439 for(i=0; (i<nx[0]); i++) {
444 atom_area[i] += at_area;
445 atom_area2[i] += sqr(at_area);
446 res_a[atoms->atom[ii].resind] += at_area;
450 dgsolv += at_area*dgs_factor[i];
456 for(i=0; i<atoms->nres; i++) {
457 res_area[i] += res_a[i];
458 res_area2[i] += sqr(res_a[i]);
460 fprintf(fp,"%10g %10g %10g %10g",t,harea,tarea-harea,tarea);
462 fprintf(fp," %10g\n",dgsolv);
468 density = totmass*AMU/(totvolume*NANO*NANO*NANO);
469 fprintf(vp,"%12.5e %12.5e %12.5e\n",t,totvolume,density);
480 } while (read_next_x(oenv,status,&t,natoms,x,box));
483 gmx_rmpbc_done(gpbc);
485 fprintf(stderr,"\n");
491 /* if necessary, print areas per atom to file too: */
493 for(i=0; i<atoms->nres; i++) {
497 for(i=0; i<nx[0]; i++) {
499 atom_area2[i] /= nfr;
501 fprintf(stderr,"Printing out areas per atom\n");
502 fp = xvgropen(opt2fn("-or",nfile,fnm),"Area per residue","Residue",
503 "Area (nm\\S2\\N)",oenv);
504 fp2 = xvgropen(opt2fn("-oa",nfile,fnm),"Area per atom","Atom #",
505 "Area (nm\\S2\\N)",oenv);
507 fp3 = ftp2FILE(efITP,nfile,fnm,"w");
508 fprintf(fp3,"[ position_restraints ]\n"
512 "; Atom Type fx fy fz\n");
514 for(i=0; i<nx[0]; i++) {
516 res = atoms->atom[ii].resind;
517 if (i==nx[0]-1 || res!=atoms->atom[index[0][i+1]].resind) {
518 fluc2 = res_area2[res]-sqr(res_area[res]);
521 fprintf(fp,"%10d %10g %10g\n",
522 atoms->resinfo[res].nr,res_area[res],sqrt(fluc2));
524 fluc2 = atom_area2[i]-sqr(atom_area[i]);
527 fprintf(fp2,"%d %g %g\n",index[0][i]+1,atom_area[i],sqrt(fluc2));
528 if (bITP && (atom_area[i] > minarea))
529 fprintf(fp3,"%5d 1 FCX FCX FCZ\n",ii+1);
536 /* Be a good citizen, keep our memory free! */
562 int gmx_sas(int argc,char *argv[])
564 const char *desc[] = {
565 "g_sas computes hydrophobic, hydrophilic and total solvent accessible surface area.",
566 "As a side effect the Connolly surface can be generated as well in",
567 "a pdb file where the nodes are represented as atoms and the vertices",
568 "connecting the nearest nodes as CONECT records.",
569 "The program will ask for a group for the surface calculation",
570 "and a group for the output. The calculation group should always",
571 "consists of all the non-solvent atoms in the system.",
572 "The output group can be the whole or part of the calculation group.",
573 "The area can be plotted",
574 "per residue and atom as well (options [TT]-or[tt] and [TT]-oa[tt]).",
575 "In combination with the latter option an [TT]itp[tt] file can be",
576 "generated (option [TT]-i[tt])",
577 "which can be used to restrain surface atoms.[PAR]",
578 "By default, periodic boundary conditions are taken into account,",
579 "this can be turned off using the [TT]-nopbc[tt] option.[PAR]",
580 "With the [TT]-tv[tt] option the total volume and density of the molecule can be",
582 "Please consider whether the normal probe radius is appropriate",
583 "in this case or whether you would rather use e.g. 0. It is good",
584 "to keep in mind that the results for volume and density are very",
585 "approximate, in e.g. ice Ih one can easily fit water molecules in the",
586 "pores which would yield too low volume, too high surface area and too",
591 static real solsize = 0.14;
592 static int ndots = 24;
593 static real qcut = 0.2;
594 static real minarea = 0.5, dgs_default=0;
595 static gmx_bool bSave = TRUE,bPBC=TRUE,bFindex=FALSE;
597 { "-probe", FALSE, etREAL, {&solsize},
598 "Radius of the solvent probe (nm)" },
599 { "-ndots", FALSE, etINT, {&ndots},
600 "Number of dots per sphere, more dots means more accuracy" },
601 { "-qmax", FALSE, etREAL, {&qcut},
602 "The maximum charge (e, absolute value) of a hydrophobic atom" },
603 { "-f_index", FALSE, etBOOL, {&bFindex},
604 "Determine from a group in the index file what are the hydrophobic atoms rather than from the charge" },
605 { "-minarea", FALSE, etREAL, {&minarea},
606 "The minimum area (nm^2) to count an atom as a surface atom when writing a position restraint file (see help)" },
607 { "-pbc", FALSE, etBOOL, {&bPBC},
608 "Take periodicity into account" },
609 { "-prot", FALSE, etBOOL, {&bSave},
610 "Output the protein to the connelly pdb file too" },
611 { "-dgs", FALSE, etREAL, {&dgs_default},
612 "default value for solvation free energy per area (kJ/mol/nm^2)" }
615 { efTRX, "-f", NULL, ffREAD },
616 { efTPS, "-s", NULL, ffREAD },
617 { efXVG, "-o", "area", ffWRITE },
618 { efXVG, "-or", "resarea", ffOPTWR },
619 { efXVG, "-oa", "atomarea", ffOPTWR },
620 { efXVG, "-tv", "volume", ffOPTWR },
621 { efPDB, "-q", "connelly", ffOPTWR },
622 { efNDX, "-n", "index", ffOPTRD },
623 { efITP, "-i", "surfat", ffOPTWR }
625 #define NFILE asize(fnm)
627 CopyRight(stderr,argv[0]);
628 parse_common_args(&argc,argv,PCA_CAN_VIEW | PCA_CAN_TIME | PCA_BE_NICE,
629 NFILE,fnm,asize(pa),pa,asize(desc),desc,0,NULL,&oenv);
632 fprintf(stderr,"Probe size too small, setting it to %g\n",solsize);
636 fprintf(stderr,"Ndots too small, setting it to %d\n",ndots);
639 please_cite(stderr,"Eisenhaber95");
641 sas_plot(NFILE,fnm,solsize,ndots,qcut,bSave,minarea,bPBC,dgs_default,bFindex,
644 do_view(oenv,opt2fn("-o",NFILE,fnm),"-nxy");
645 do_view(oenv,opt2fn_null("-or",NFILE,fnm),"-nxy");
646 do_view(oenv,opt2fn_null("-oa",NFILE,fnm),"-nxy");