4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
12 * Copyright (c) 1991-1999
13 * BIOSON Research Institute, Dept. of Biophysical Chemistry
14 * University of Groningen, The Netherlands
17 * GROMACS: A message-passing parallel molecular dynamics implementation
18 * H.J.C. Berendsen, D. van der Spoel and R. van Drunen
19 * Comp. Phys. Comm. 91, 43-56 (1995)
21 * Also check out our WWW page:
22 * http://md.chem.rug.nl/~gmx
27 * Great Red Oystrich Makes All Chemists Sane
29 static char *SRCID_genion_c
= "$Id$";
53 static void insert_ion(int nsa
,int *nwater
,
54 bool bSet
[],int repl
[],atom_id index
[],
56 int sign
,real q
,char *ionname
,
58 real rmin
,bool bRandom
,int *seed
)
60 int i
,ii
,ei
,owater
,wlast
,m
,nw
;
61 real extr_e
,poti
,rmin2
;
73 } while (bSet
[ei
] && (maxrand
> 0));
77 for(i
=0; (i
<nw
); i
++) {
82 if ((poti
<= extr_e
) || !bSub
) {
89 if ((poti
>= extr_e
) || !bSub
) {
99 fatal_error(0,"No more replaceable solvent!");
100 fprintf(stderr
,"Replacing solvent molecule %d (atom %d) with %s\n",
101 ei
,index
[nsa
*ei
],ionname
);
103 /* Replace solvent molecule charges with ion charge */
106 mdatoms
->chargeA
[index
[nsa
*ei
]] = q
;
108 mdatoms
->chargeA
[index
[nsa
*ei
+i
]] = 0;
110 /* Mark all solvent molecules within rmin as unavailable for substitution */
113 for(i
=0; (i
<nw
); i
++) {
115 pbc_dx(x
[index
[nsa
*ei
]],x
[index
[nsa
*i
]],dx
);
116 if (iprod(dx
,dx
) < rmin2
)
123 static char *aname(char *mname
)
130 while (i
>1 && (isdigit(str
[i
]) || (str
[i
]=='+') || (str
[i
]=='-'))) {
138 void sort_ions(int nsa
,int nw
,int repl
[],atom_id index
[],
139 t_atoms
*atoms
,rvec x
[],
140 char *p_name
,char *n_name
)
142 int i
,j
,k
,r
,np
,nn
,starta
,startr
,npi
,nni
;
144 char **pptr
=NULL
,**nptr
=NULL
,**paptr
=NULL
,**naptr
=NULL
;
148 /* Put all the solvent in front and count the added ions */
152 for(i
=0; i
<nw
; i
++) {
156 copy_rvec(x
[index
[nsa
*i
+k
]],xt
[j
++]);
164 /* Put the positive and negative ions at the end */
165 starta
= index
[nsa
*(nw
- np
- nn
)];
166 startr
= atoms
->atom
[starta
].resnr
;
172 paptr
[0] = aname(p_name
);
178 naptr
[0] = aname(n_name
);
182 for(i
=0; i
<nw
; i
++) {
187 copy_rvec(x
[index
[nsa
*i
]],xt
[j
]);
188 atoms
->atomname
[j
] = paptr
;
189 atoms
->atom
[j
].resnr
= k
;
190 atoms
->resname
[k
] = pptr
;
195 copy_rvec(x
[index
[nsa
*i
]],xt
[j
]);
196 atoms
->atomname
[j
] = naptr
;
197 atoms
->atom
[j
].resnr
= k
;
198 atoms
->resname
[k
] = nptr
;
202 for(i
=index
[nsa
*nw
-1]+1; i
<atoms
->nr
; i
++) {
203 j
= i
-(nsa
-1)*(np
+nn
);
204 atoms
->atomname
[j
] = atoms
->atomname
[i
];
205 atoms
->atom
[j
] = atoms
->atom
[i
];
206 copy_rvec(x
[i
],xt
[j
]);
208 atoms
->nr
-= (nsa
-1)*(np
+nn
);
210 /* Copy the new positions back */
211 for(i
=index
[0]; i
<atoms
->nr
; i
++)
212 copy_rvec(xt
[i
],x
[i
]);
217 int main(int argc
, char *argv
[])
219 static char *desc
[] = {
220 "genion replaces solvent molecules by monoatomic ions at",
221 "the position of the first atoms with the most favorable electrostatic",
222 "potential or at random. The potential is calculated on all atoms, using",
223 "normal GROMACS particle based methods (in contrast to other methods",
224 "based on solving the Poisson-Boltzmann equation).",
225 "The potential is recalculated after every ion insertion.",
226 "If specified in the run input file, a reaction field or shift function",
228 "The group of solvent molecules should be continuous and all molecules",
229 "should have the same number of atoms.",
230 "The user should add the ion molecules to the topology file and include",
231 "the file [TT]ions.itp[tt].",
232 "Ion names for Gromos96 should include the charge.[PAR]",
233 "The potential can be written as B-factors",
234 "in a pdb file (for visualisation using e.g. rasmol)[PAR]"
235 "For larger ions, e.g. sulfate we recommended to use genbox."
237 static int p_num
=0,n_num
=0;
238 static char *p_name
="Na",*n_name
="Cl";
239 static real p_q
=1,n_q
=-1,rmin
=0.6;
240 static int seed
=1993;
241 static bool bRandom
=FALSE
;
242 static t_pargs pa
[] = {
243 { "-np", FALSE
, etINT
, {&p_num
}, "Number of positive ions" },
244 { "-pname", FALSE
, etSTR
, {&p_name
},"Name of the positive ion" },
245 { "-pq", FALSE
, etREAL
, {&p_q
}, "Charge of the positive ion" },
246 { "-nn", FALSE
, etINT
, {&n_num
}, "Number of negative ions" },
247 { "-nname", FALSE
, etSTR
, {&n_name
},"Name of the negative ion" },
248 { "-nq", FALSE
, etREAL
, {&n_q
}, "Charge of the negative ion" },
249 { "-rmin", FALSE
, etREAL
, {&rmin
}, "Minimum distance between ions" },
250 { "-random",FALSE
,etBOOL
, {&bRandom
},"Use random placement of ions instead of based on potential. The rmin option should still work" },
251 { "-seed", FALSE
, etINT
, {&seed
}, "Seed for random number generator" }
270 { efTPX
, NULL
, NULL
, ffREAD
},
271 { efNDX
, NULL
, NULL
, ffOPTRD
},
272 { efSTO
, "-o", NULL
, ffWRITE
},
273 { efLOG
, "-g", "genion", ffWRITE
},
274 { efPDB
, "-pot", "pot", ffOPTWR
}
276 #define NFILE asize(fnm)
278 CopyRight(stdout
,argv
[0]);
279 parse_common_args(&argc
,argv
,0,TRUE
,NFILE
,fnm
,asize(pa
),pa
,asize(desc
),desc
,
281 bPDB
= ftp2bSet(efPDB
,NFILE
,fnm
);
282 if (bRandom
&& bPDB
) {
283 fprintf(stderr
,"Not computing potential with random option!\n");
287 /* Check input for something sensible */
288 if ((p_num
<0) || (n_num
<0))
289 fatal_error(0,"Negative number of ions to add?");
292 init_calcpot(NFILE
,fnm
,top
,&x
,&parm
,&cr
,
293 &graph
,&mdatoms
,&nsb
,&grps
,&fr
,&pot
,box
);
295 if ((p_num
== 0) && (n_num
== 0)) {
297 fprintf(stderr
,"No ions to add and no potential to calculate.\n");
302 printf("Select a continuous group of solvent molecules\n");
303 get_index(&top
->atoms
,ftp2fn_null(efNDX
,NFILE
,fnm
),1,&nwa
,&index
,&grpname
);
305 if (index
[i
] != index
[i
-1]+1)
306 fatal_error(0,"The solvent group is not continuous: index[%d]=%d, "
307 "index[%d]=%d",i
,index
[i
-1]+1,i
+1,index
[i
]+1);
310 (top
->atoms
.atom
[index
[nsa
]].resnr
==
311 top
->atoms
.atom
[index
[nsa
-1]].resnr
))
314 fatal_error(0,"Your solvent group size (%d) is not a multiple of %d",
317 fprintf(stderr
,"Number of (%d-atomic) solvent molecules: %d\n",nsa
,nw
);
318 if (p_num
+n_num
> nw
)
319 fatal_error(0,"Not enough solvent for adding ions");
324 snew(v
,top
->atoms
.nr
);
325 snew(top
->atoms
.pdbinfo
,top
->atoms
.nr
);
327 /* Now loop over the ions that have to be placed */
330 calc_pot(stdlog
,&nsb
,&cr
,&grps
,&parm
,top
,x
,fr
,mdatoms
,pot
);
335 sprintf(buf
,"%d_%s",p_num
+n_num
,ftp2fn(efPDB
,NFILE
,fnm
));
337 strcpy(buf
,ftp2fn(efPDB
,NFILE
,fnm
));
338 for(i
=0; (i
<top
->atoms
.nr
); i
++)
339 top
->atoms
.pdbinfo
[i
].bfac
= pot
[i
]*0.001;
340 write_sto_conf(buf
,"Potential calculated by genion",
341 &top
->atoms
,x
,v
,box
);
345 if ((p_num
> 0) && (p_num
>= n_num
)) {
346 insert_ion(nsa
,&nw
,bSet
,repl
,index
,pot
,x
,
347 1,p_q
,p_name
,mdatoms
,rmin
,bRandom
,&seed
);
350 else if (n_num
> 0) {
351 insert_ion(nsa
,&nw
,bSet
,repl
,index
,pot
,x
,
352 -1,n_q
,n_name
,mdatoms
,rmin
,bRandom
,&seed
);
355 } while (p_num
+n_num
> 0);
356 fprintf(stderr
,"\n");
359 sort_ions(nsa
,nw
,repl
,index
,&top
->atoms
,x
,p_name
,n_name
);
361 sfree(top
->atoms
.pdbinfo
);
362 top
->atoms
.pdbinfo
= NULL
;
363 write_sto_conf(ftp2fn(efSTO
,NFILE
,fnm
),*top
->name
,&top
->atoms
,x
,NULL
,box
);