Reduce hwloc & cpuid test requirements
[gromacs.git] / src / programs / mdrun / membed.cpp
blobf7f47d9b936e5dd3d0b30a165fd539681df71bb8
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
35 #include "gmxpre.h"
37 #include "membed.h"
39 #include <signal.h>
40 #include <stdlib.h>
42 #include "gromacs/commandline/filenm.h"
43 #include "gromacs/essentialdynamics/edsam.h"
44 #include "gromacs/fileio/readinp.h"
45 #include "gromacs/gmxlib/network.h"
46 #include "gromacs/math/vec.h"
47 #include "gromacs/mdtypes/commrec.h"
48 #include "gromacs/mdtypes/inputrec.h"
49 #include "gromacs/mdtypes/md_enums.h"
50 #include "gromacs/mdtypes/state.h"
51 #include "gromacs/pbcutil/pbc.h"
52 #include "gromacs/topology/index.h"
53 #include "gromacs/topology/mtop_util.h"
54 #include "gromacs/topology/topology.h"
55 #include "gromacs/utility/cstringutil.h"
56 #include "gromacs/utility/fatalerror.h"
57 #include "gromacs/utility/futil.h"
58 #include "gromacs/utility/smalloc.h"
60 /* information about scaling center */
61 typedef struct {
62 rvec xmin; /* smallest coordinates of all embedded molecules */
63 rvec xmax; /* largest coordinates of all embedded molecules */
64 rvec *geom_cent; /* scaling center of each independent molecule to embed */
65 int pieces; /* number of molecules to embed independently */
66 int *nidx; /* n atoms for every independent embedded molecule (index in subindex) */
67 int **subindex; /* atomids for independent molecule *
68 * atoms of piece i run from subindex[i][0] to subindex[i][nidx[i]] */
69 } pos_ins_t;
71 /* variables needed in do_md */
72 struct gmx_membed_t {
73 int it_xy; /* number of iterations (steps) used to grow something in the xy-plane */
74 int it_z; /* same, but for z */
75 real xy_step; /* stepsize used during resize in xy-plane */
76 real z_step; /* same, but in z */
77 rvec fac; /* initial scaling of the molecule to grow into the membrane */
78 rvec *r_ins; /* final coordinates of the molecule to grow */
79 pos_ins_t *pos_ins; /* scaling center for each piece to embed */
82 /* membrane related variables */
83 typedef struct {
84 char *name; /* name of index group to embed molecule into (usually membrane) */
85 t_block mem_at; /* list all atoms in membrane */
86 int nmol; /* number of membrane molecules overlapping with the molecule to embed */
87 int *mol_id; /* list of molecules in membrane that overlap with the molecule to embed */
88 real lip_area; /* average area per lipid in membrane (only correct for homogeneous bilayers)*/
89 real zmin; /* minimum z coordinate of membrane */
90 real zmax; /* maximum z coordinate of membrane */
91 real zmed; /* median z coordinate of membrane */
92 } mem_t;
94 /* Lists all molecules in the membrane that overlap with the molecule to be embedded. *
95 * These will then be removed from the system */
96 typedef struct {
97 int nr; /* number of molecules to remove */
98 int *mol; /* list of molecule ids to remove */
99 int *block; /* id of the molblock that the molecule to remove is part of */
100 } rm_t;
102 /* Get the global molecule id, and the corresponding molecule type and id of the *
103 * molblock from the global atom nr. */
104 static int get_mol_id(int at, gmx_mtop_t *mtop, int *type, int *block)
106 int mol_id = 0;
107 int i;
108 int atnr_mol;
109 gmx_mtop_atomlookup_t alook;
111 alook = gmx_mtop_atomlookup_settle_init(mtop);
112 gmx_mtop_atomnr_to_molblock_ind(alook, at, block, &mol_id, &atnr_mol);
113 for (i = 0; i < *block; i++)
115 mol_id += mtop->molblock[i].nmol;
117 *type = mtop->molblock[*block].type;
119 gmx_mtop_atomlookup_destroy(alook);
121 return mol_id;
124 /* Get the id of the molblock from a global molecule id */
125 static int get_molblock(int mol_id, int nmblock, gmx_molblock_t *mblock)
127 int i;
128 int nmol = 0;
130 for (i = 0; i < nmblock; i++)
132 nmol += mblock[i].nmol;
133 if (mol_id < nmol)
135 return i;
139 gmx_fatal(FARGS, "mol_id %d larger than total number of molecules %d.\n", mol_id, nmol);
141 return -1;
144 /* Get a list of all the molecule types that are present in a group of atoms. *
145 * Because all interaction within the group to embed are removed on the topology *
146 * level, if the same molecule type is found in another part of the system, these *
147 * would also be affected. Therefore we have to check if the embedded and rest group *
148 * share common molecule types. If so, membed will stop with an error. */
149 static int get_mtype_list(t_block *at, gmx_mtop_t *mtop, t_block *tlist)
151 int i, j, nr;
152 int type = 0, block = 0;
153 gmx_bool bNEW;
155 nr = 0;
156 snew(tlist->index, at->nr);
157 for (i = 0; i < at->nr; i++)
159 bNEW = TRUE;
160 get_mol_id(at->index[i], mtop, &type, &block);
161 for (j = 0; j < nr; j++)
163 if (tlist->index[j] == type)
165 bNEW = FALSE;
169 if (bNEW == TRUE)
171 tlist->index[nr] = type;
172 nr++;
175 srenew(tlist->index, nr);
176 return nr;
179 /* Do the actual check of the molecule types between embedded and rest group */
180 static void check_types(t_block *ins_at, t_block *rest_at, gmx_mtop_t *mtop)
182 t_block *ins_mtype, *rest_mtype;
183 int i, j;
185 snew(ins_mtype, 1);
186 snew(rest_mtype, 1);
187 ins_mtype->nr = get_mtype_list(ins_at, mtop, ins_mtype );
188 rest_mtype->nr = get_mtype_list(rest_at, mtop, rest_mtype);
190 for (i = 0; i < ins_mtype->nr; i++)
192 for (j = 0; j < rest_mtype->nr; j++)
194 if (ins_mtype->index[i] == rest_mtype->index[j])
196 gmx_fatal(FARGS, "Moleculetype %s is found both in the group to insert and the rest of the system.\n"
197 "1. Your *.ndx and *.top do not match\n"
198 "2. You are inserting some molecules of type %s (for example xray-solvent), while\n"
199 "the same moleculetype is also used in the rest of the system (solvent box). Because\n"
200 "we need to exclude all interactions between the atoms in the group to\n"
201 "insert, the same moleculetype can not be used in both groups. Change the\n"
202 "moleculetype of the molecules %s in the inserted group. Do not forget to provide\n"
203 "an appropriate *.itp file", *(mtop->moltype[rest_mtype->index[j]].name),
204 *(mtop->moltype[rest_mtype->index[j]].name), *(mtop->moltype[rest_mtype->index[j]].name));
209 sfree(ins_mtype->index);
210 sfree(rest_mtype->index);
211 sfree(ins_mtype);
212 sfree(rest_mtype);
215 static void get_input(const char *membed_input, real *xy_fac, real *xy_max, real *z_fac, real *z_max,
216 int *it_xy, int *it_z, real *probe_rad, int *low_up_rm, int *maxwarn,
217 int *pieces, gmx_bool *bALLOW_ASYMMETRY)
219 warninp_t wi;
220 t_inpfile *inp;
221 int ninp;
223 wi = init_warning(TRUE, 0);
225 inp = read_inpfile(membed_input, &ninp, wi);
226 ITYPE ("nxy", *it_xy, 1000);
227 ITYPE ("nz", *it_z, 0);
228 RTYPE ("xyinit", *xy_fac, 0.5);
229 RTYPE ("xyend", *xy_max, 1.0);
230 RTYPE ("zinit", *z_fac, 1.0);
231 RTYPE ("zend", *z_max, 1.0);
232 RTYPE ("rad", *probe_rad, 0.22);
233 ITYPE ("ndiff", *low_up_rm, 0);
234 ITYPE ("maxwarn", *maxwarn, 0);
235 ITYPE ("pieces", *pieces, 1);
236 EETYPE("asymmetry", *bALLOW_ASYMMETRY, yesno_names);
238 write_inpfile(membed_input, ninp, inp, FALSE, wi);
241 /* Obtain the maximum and minimum coordinates of the group to be embedded */
242 static int init_ins_at(t_block *ins_at, t_block *rest_at, t_state *state, pos_ins_t *pos_ins,
243 gmx_groups_t *groups, int ins_grp_id, real xy_max)
245 int i, gid, c = 0;
246 real x, xmin, xmax, y, ymin, ymax, z, zmin, zmax;
247 const real min_memthick = 6.0; /* minimum thickness of the bilayer that will be used to *
248 * determine the overlap between molecule to embed and membrane */
249 const real fac_inp_size = 1.000001; /* scaling factor to obtain input_size + 0.000001 (comparing reals) */
250 snew(rest_at->index, state->natoms);
252 xmin = xmax = state->x[ins_at->index[0]][XX];
253 ymin = ymax = state->x[ins_at->index[0]][YY];
254 zmin = zmax = state->x[ins_at->index[0]][ZZ];
256 for (i = 0; i < state->natoms; i++)
258 gid = groups->grpnr[egcFREEZE][i];
259 if (groups->grps[egcFREEZE].nm_ind[gid] == ins_grp_id)
261 x = state->x[i][XX];
262 if (x < xmin)
264 xmin = x;
266 if (x > xmax)
268 xmax = x;
270 y = state->x[i][YY];
271 if (y < ymin)
273 ymin = y;
275 if (y > ymax)
277 ymax = y;
279 z = state->x[i][ZZ];
280 if (z < zmin)
282 zmin = z;
284 if (z > zmax)
286 zmax = z;
289 else
291 rest_at->index[c] = i;
292 c++;
296 rest_at->nr = c;
297 srenew(rest_at->index, c);
299 if (xy_max > fac_inp_size)
301 pos_ins->xmin[XX] = xmin-((xmax-xmin)*xy_max-(xmax-xmin))/2;
302 pos_ins->xmin[YY] = ymin-((ymax-ymin)*xy_max-(ymax-ymin))/2;
304 pos_ins->xmax[XX] = xmax+((xmax-xmin)*xy_max-(xmax-xmin))/2;
305 pos_ins->xmax[YY] = ymax+((ymax-ymin)*xy_max-(ymax-ymin))/2;
307 else
309 pos_ins->xmin[XX] = xmin;
310 pos_ins->xmin[YY] = ymin;
312 pos_ins->xmax[XX] = xmax;
313 pos_ins->xmax[YY] = ymax;
316 if ( (zmax-zmin) < min_memthick)
318 pos_ins->xmin[ZZ] = zmin+(zmax-zmin)/2.0-0.5*min_memthick;
319 pos_ins->xmax[ZZ] = zmin+(zmax-zmin)/2.0+0.5*min_memthick;
321 else
323 pos_ins->xmin[ZZ] = zmin;
324 pos_ins->xmax[ZZ] = zmax;
327 return c;
330 /* Estimate the area of the embedded molecule by projecting all coordinates on a grid in the *
331 * xy-plane and counting the number of occupied grid points */
332 static real est_prot_area(pos_ins_t *pos_ins, rvec *r, t_block *ins_at, mem_t *mem_p)
334 real x, y, dx = 0.15, dy = 0.15, area = 0.0;
335 real add, memmin, memmax;
336 int c, at;
338 /* min and max membrane coordinate are altered to reduce the influence of the *
339 * boundary region */
340 memmin = mem_p->zmin+0.1*(mem_p->zmax-mem_p->zmin);
341 memmax = mem_p->zmax-0.1*(mem_p->zmax-mem_p->zmin);
343 for (x = pos_ins->xmin[XX]; x < pos_ins->xmax[XX]; x += dx)
345 for (y = pos_ins->xmin[YY]; y < pos_ins->xmax[YY]; y += dy)
347 c = 0;
348 add = 0.0;
351 at = ins_at->index[c];
352 if ( (r[at][XX] >= x) && (r[at][XX] < x+dx) &&
353 (r[at][YY] >= y) && (r[at][YY] < y+dy) &&
354 (r[at][ZZ] > memmin) && (r[at][ZZ] < memmax) )
356 add = 1.0;
358 c++;
360 while ( (c < ins_at->nr) && (add < 0.5) );
361 area += add;
364 area = area*dx*dy;
366 return area;
369 static int init_mem_at(mem_t *mem_p, gmx_mtop_t *mtop, rvec *r, matrix box, pos_ins_t *pos_ins)
371 int i, j, at, mol, nmol, nmolbox, count;
372 t_block *mem_a;
373 real z, zmin, zmax, mem_area;
374 gmx_bool bNew;
375 int *mol_id;
376 int type = 0, block = 0;
378 nmol = count = 0;
379 mem_a = &(mem_p->mem_at);
380 snew(mol_id, mem_a->nr);
381 zmin = pos_ins->xmax[ZZ];
382 zmax = pos_ins->xmin[ZZ];
383 for (i = 0; i < mem_a->nr; i++)
385 at = mem_a->index[i];
386 if ( (r[at][XX] > pos_ins->xmin[XX]) && (r[at][XX] < pos_ins->xmax[XX]) &&
387 (r[at][YY] > pos_ins->xmin[YY]) && (r[at][YY] < pos_ins->xmax[YY]) &&
388 (r[at][ZZ] > pos_ins->xmin[ZZ]) && (r[at][ZZ] < pos_ins->xmax[ZZ]) )
390 mol = get_mol_id(at, mtop, &type, &block);
391 bNew = TRUE;
392 for (j = 0; j < nmol; j++)
394 if (mol == mol_id[j])
396 bNew = FALSE;
400 if (bNew)
402 mol_id[nmol] = mol;
403 nmol++;
406 z = r[at][ZZ];
407 if (z < zmin)
409 zmin = z;
412 if (z > zmax)
414 zmax = z;
417 count++;
421 mem_p->nmol = nmol;
422 srenew(mol_id, nmol);
423 mem_p->mol_id = mol_id;
425 if ((zmax-zmin) > (box[ZZ][ZZ]-0.5))
427 gmx_fatal(FARGS, "Something is wrong with your membrane. Max and min z values are %f and %f.\n"
428 "Maybe your membrane is not centered in the box, but located at the box edge in the z-direction,\n"
429 "so that one membrane is distributed over two periodic box images. Another possibility is that\n"
430 "your water layer is not thick enough.\n", zmax, zmin);
432 mem_p->zmin = zmin;
433 mem_p->zmax = zmax;
434 mem_p->zmed = (zmax-zmin)/2+zmin;
436 /*number of membrane molecules in protein box*/
437 nmolbox = count/mtop->molblock[block].natoms_mol;
438 /*membrane area within the box defined by the min and max coordinates of the embedded molecule*/
439 mem_area = (pos_ins->xmax[XX]-pos_ins->xmin[XX])*(pos_ins->xmax[YY]-pos_ins->xmin[YY]);
440 /*rough estimate of area per lipid, assuming there is only one type of lipid in the membrane*/
441 mem_p->lip_area = 2.0*mem_area/(double)nmolbox;
443 return mem_p->mem_at.nr;
446 static void init_resize(t_block *ins_at, rvec *r_ins, pos_ins_t *pos_ins, mem_t *mem_p, rvec *r,
447 gmx_bool bALLOW_ASYMMETRY)
449 int i, j, at, c, outsidesum, gctr = 0;
450 int idxsum = 0;
452 /*sanity check*/
453 for (i = 0; i < pos_ins->pieces; i++)
455 idxsum += pos_ins->nidx[i];
458 if (idxsum != ins_at->nr)
460 gmx_fatal(FARGS, "Piecewise sum of inserted atoms not same as size of group selected to insert.");
463 snew(pos_ins->geom_cent, pos_ins->pieces);
464 for (i = 0; i < pos_ins->pieces; i++)
466 c = 0;
467 outsidesum = 0;
468 for (j = 0; j < DIM; j++)
470 pos_ins->geom_cent[i][j] = 0;
473 for (j = 0; j < pos_ins->nidx[i]; j++)
475 at = pos_ins->subindex[i][j];
476 copy_rvec(r[at], r_ins[gctr]);
477 if ( (r_ins[gctr][ZZ] < mem_p->zmax) && (r_ins[gctr][ZZ] > mem_p->zmin) )
479 rvec_inc(pos_ins->geom_cent[i], r_ins[gctr]);
480 c++;
482 else
484 outsidesum++;
486 gctr++;
489 if (c > 0)
491 svmul(1/(double)c, pos_ins->geom_cent[i], pos_ins->geom_cent[i]);
494 if (!bALLOW_ASYMMETRY)
496 pos_ins->geom_cent[i][ZZ] = mem_p->zmed;
499 fprintf(stderr, "Embedding piece %d with center of geometry: %f %f %f\n",
500 i, pos_ins->geom_cent[i][XX], pos_ins->geom_cent[i][YY], pos_ins->geom_cent[i][ZZ]);
502 fprintf(stderr, "\n");
505 /* resize performed in the md loop */
506 static void resize(rvec *r_ins, rvec *r, pos_ins_t *pos_ins, rvec fac)
508 int i, j, k, at, c = 0;
509 for (k = 0; k < pos_ins->pieces; k++)
511 for (i = 0; i < pos_ins->nidx[k]; i++)
513 at = pos_ins->subindex[k][i];
514 for (j = 0; j < DIM; j++)
516 r[at][j] = pos_ins->geom_cent[k][j]+fac[j]*(r_ins[c][j]-pos_ins->geom_cent[k][j]);
518 c++;
523 /* generate the list of membrane molecules that overlap with the molecule to be embedded. *
524 * The molecule to be embedded is already reduced in size. */
525 static int gen_rm_list(rm_t *rm_p, t_block *ins_at, t_block *rest_at, t_pbc *pbc, gmx_mtop_t *mtop,
526 rvec *r, mem_t *mem_p, pos_ins_t *pos_ins, real probe_rad,
527 int low_up_rm, gmx_bool bALLOW_ASYMMETRY)
529 int i, j, k, l, at, at2, mol_id;
530 int type = 0, block = 0;
531 int nrm, nupper, nlower;
532 real r_min_rad, z_lip, min_norm;
533 gmx_bool bRM;
534 rvec dr, dr_tmp;
535 real *dist;
536 int *order;
538 r_min_rad = probe_rad*probe_rad;
539 snew(rm_p->mol, mtop->mols.nr);
540 snew(rm_p->block, mtop->mols.nr);
541 nrm = nupper = 0;
542 nlower = low_up_rm;
543 for (i = 0; i < ins_at->nr; i++)
545 at = ins_at->index[i];
546 for (j = 0; j < rest_at->nr; j++)
548 at2 = rest_at->index[j];
549 pbc_dx(pbc, r[at], r[at2], dr);
551 if (norm2(dr) < r_min_rad)
553 mol_id = get_mol_id(at2, mtop, &type, &block);
554 bRM = TRUE;
555 for (l = 0; l < nrm; l++)
557 if (rm_p->mol[l] == mol_id)
559 bRM = FALSE;
563 if (bRM)
565 rm_p->mol[nrm] = mol_id;
566 rm_p->block[nrm] = block;
567 nrm++;
568 z_lip = 0.0;
569 for (l = 0; l < mem_p->nmol; l++)
571 if (mol_id == mem_p->mol_id[l])
573 for (k = mtop->mols.index[mol_id]; k < mtop->mols.index[mol_id+1]; k++)
575 z_lip += r[k][ZZ];
577 z_lip /= mtop->molblock[block].natoms_mol;
578 if (z_lip < mem_p->zmed)
580 nlower++;
582 else
584 nupper++;
593 /*make sure equal number of lipids from upper and lower layer are removed */
594 if ( (nupper != nlower) && (!bALLOW_ASYMMETRY) )
596 snew(dist, mem_p->nmol);
597 snew(order, mem_p->nmol);
598 for (i = 0; i < mem_p->nmol; i++)
600 at = mtop->mols.index[mem_p->mol_id[i]];
601 pbc_dx(pbc, r[at], pos_ins->geom_cent[0], dr);
602 if (pos_ins->pieces > 1)
604 /*minimum dr value*/
605 min_norm = norm2(dr);
606 for (k = 1; k < pos_ins->pieces; k++)
608 pbc_dx(pbc, r[at], pos_ins->geom_cent[k], dr_tmp);
609 if (norm2(dr_tmp) < min_norm)
611 min_norm = norm2(dr_tmp);
612 copy_rvec(dr_tmp, dr);
616 dist[i] = dr[XX]*dr[XX]+dr[YY]*dr[YY];
617 j = i-1;
618 while (j >= 0 && dist[i] < dist[order[j]])
620 order[j+1] = order[j];
621 j--;
623 order[j+1] = i;
626 i = 0;
627 while (nupper != nlower)
629 mol_id = mem_p->mol_id[order[i]];
630 block = get_molblock(mol_id, mtop->nmolblock, mtop->molblock);
631 bRM = TRUE;
632 for (l = 0; l < nrm; l++)
634 if (rm_p->mol[l] == mol_id)
636 bRM = FALSE;
640 if (bRM)
642 z_lip = 0;
643 for (k = mtop->mols.index[mol_id]; k < mtop->mols.index[mol_id+1]; k++)
645 z_lip += r[k][ZZ];
647 z_lip /= mtop->molblock[block].natoms_mol;
648 if (nupper > nlower && z_lip < mem_p->zmed)
650 rm_p->mol[nrm] = mol_id;
651 rm_p->block[nrm] = block;
652 nrm++;
653 nlower++;
655 else if (nupper < nlower && z_lip > mem_p->zmed)
657 rm_p->mol[nrm] = mol_id;
658 rm_p->block[nrm] = block;
659 nrm++;
660 nupper++;
663 i++;
665 if (i > mem_p->nmol)
667 gmx_fatal(FARGS, "Trying to remove more lipid molecules than there are in the membrane");
670 sfree(dist);
671 sfree(order);
674 rm_p->nr = nrm;
675 srenew(rm_p->mol, nrm);
676 srenew(rm_p->block, nrm);
678 return nupper+nlower;
681 /*remove all lipids and waters overlapping and update all important structures (e.g. state and mtop)*/
682 static void rm_group(gmx_groups_t *groups, gmx_mtop_t *mtop, rm_t *rm_p, t_state *state,
683 t_block *ins_at, pos_ins_t *pos_ins)
685 int i, j, k, n, rm, mol_id, at, block;
686 rvec *x_tmp, *v_tmp;
687 int *list, *new_mols;
688 unsigned char *new_egrp[egcNR];
689 gmx_bool bRM;
690 int RMmolblock;
692 snew(list, state->natoms);
693 n = 0;
694 for (i = 0; i < rm_p->nr; i++)
696 mol_id = rm_p->mol[i];
697 at = mtop->mols.index[mol_id];
698 block = rm_p->block[i];
699 mtop->molblock[block].nmol--;
700 for (j = 0; j < mtop->molblock[block].natoms_mol; j++)
702 list[n] = at+j;
703 n++;
705 mtop->mols.index[mol_id] = -1;
708 mtop->mols.nr -= rm_p->nr;
709 mtop->mols.nalloc_index -= rm_p->nr;
710 snew(new_mols, mtop->mols.nr);
711 for (i = 0; i < mtop->mols.nr+rm_p->nr; i++)
713 j = 0;
714 if (mtop->mols.index[i] != -1)
716 new_mols[j] = mtop->mols.index[i];
717 j++;
720 sfree(mtop->mols.index);
721 mtop->mols.index = new_mols;
722 mtop->natoms -= n;
723 state->natoms -= n;
724 state->nalloc = state->natoms;
725 snew(x_tmp, state->nalloc);
726 snew(v_tmp, state->nalloc);
728 for (i = 0; i < egcNR; i++)
730 if (groups->grpnr[i] != NULL)
732 groups->ngrpnr[i] = state->natoms;
733 snew(new_egrp[i], state->natoms);
737 rm = 0;
738 for (i = 0; i < state->natoms+n; i++)
740 bRM = FALSE;
741 for (j = 0; j < n; j++)
743 if (i == list[j])
745 bRM = TRUE;
746 rm++;
750 if (!bRM)
752 for (j = 0; j < egcNR; j++)
754 if (groups->grpnr[j] != NULL)
756 new_egrp[j][i-rm] = groups->grpnr[j][i];
759 copy_rvec(state->x[i], x_tmp[i-rm]);
760 copy_rvec(state->v[i], v_tmp[i-rm]);
761 for (j = 0; j < ins_at->nr; j++)
763 if (i == ins_at->index[j])
765 ins_at->index[j] = i-rm;
769 for (j = 0; j < pos_ins->pieces; j++)
771 for (k = 0; k < pos_ins->nidx[j]; k++)
773 if (i == pos_ins->subindex[j][k])
775 pos_ins->subindex[j][k] = i-rm;
781 sfree(state->x);
782 state->x = x_tmp;
783 sfree(state->v);
784 state->v = v_tmp;
786 for (i = 0; i < egcNR; i++)
788 if (groups->grpnr[i] != NULL)
790 sfree(groups->grpnr[i]);
791 groups->grpnr[i] = new_egrp[i];
795 /* remove empty molblocks */
796 RMmolblock = 0;
797 for (i = 0; i < mtop->nmolblock; i++)
799 if (mtop->molblock[i].nmol == 0)
801 RMmolblock++;
803 else
805 mtop->molblock[i-RMmolblock] = mtop->molblock[i];
808 mtop->nmolblock -= RMmolblock;
811 /* remove al bonded interactions from mtop for the molecule to be embedded */
812 int rm_bonded(t_block *ins_at, gmx_mtop_t *mtop)
814 int i, j, m;
815 int type, natom, nmol, at, atom1 = 0, rm_at = 0;
816 gmx_bool *bRM, bINS;
817 /*this routine lives dangerously by assuming that all molecules of a given type are in order in the structure*/
818 /*this routine does not live as dangerously as it seems. There is namely a check in init_membed to make *
819 * sure that g_membed exits with a warning when there are molecules of the same type not in the *
820 * ins_at index group. MGWolf 050710 */
823 snew(bRM, mtop->nmoltype);
824 for (i = 0; i < mtop->nmoltype; i++)
826 bRM[i] = TRUE;
829 for (i = 0; i < mtop->nmolblock; i++)
831 /*loop over molecule blocks*/
832 type = mtop->molblock[i].type;
833 natom = mtop->molblock[i].natoms_mol;
834 nmol = mtop->molblock[i].nmol;
836 for (j = 0; j < natom*nmol && bRM[type] == TRUE; j++)
838 /*loop over atoms in the block*/
839 at = j+atom1; /*atom index = block index + offset*/
840 bINS = FALSE;
842 for (m = 0; (m < ins_at->nr) && (bINS == FALSE); m++)
844 /*loop over atoms in insertion index group to determine if we're inserting one*/
845 if (at == ins_at->index[m])
847 bINS = TRUE;
850 bRM[type] = bINS;
852 atom1 += natom*nmol; /*update offset*/
853 if (bRM[type])
855 rm_at += natom*nmol; /*increment bonded removal counter by # atoms in block*/
859 for (i = 0; i < mtop->nmoltype; i++)
861 if (bRM[i])
863 for (j = 0; j < F_LJ; j++)
865 mtop->moltype[i].ilist[j].nr = 0;
868 for (j = F_POSRES; j <= F_VSITEN; j++)
870 mtop->moltype[i].ilist[j].nr = 0;
874 sfree(bRM);
876 return rm_at;
879 /* Write a topology where the number of molecules is correct for the system after embedding */
880 static void top_update(const char *topfile, rm_t *rm_p, gmx_mtop_t *mtop)
882 int bMolecules = 0;
883 FILE *fpin, *fpout;
884 char buf[STRLEN], buf2[STRLEN], *temp;
885 int i, *nmol_rm, nmol, line;
886 char temporary_filename[STRLEN];
888 fpin = gmx_ffopen(topfile, "r");
889 strncpy(temporary_filename, "temp.topXXXXXX", STRLEN);
890 gmx_tmpnam(temporary_filename);
891 fpout = gmx_ffopen(temporary_filename, "w");
893 snew(nmol_rm, mtop->nmoltype);
894 for (i = 0; i < rm_p->nr; i++)
896 nmol_rm[rm_p->block[i]]++;
899 line = 0;
900 while (fgets(buf, STRLEN, fpin))
902 line++;
903 if (buf[0] != ';')
905 strcpy(buf2, buf);
906 if ((temp = strchr(buf2, '\n')) != NULL)
908 temp[0] = '\0';
910 ltrim(buf2);
911 if (buf2[0] == '[')
913 buf2[0] = ' ';
914 if ((temp = strchr(buf2, '\n')) != NULL)
916 temp[0] = '\0';
918 rtrim(buf2);
919 if (buf2[strlen(buf2)-1] == ']')
921 buf2[strlen(buf2)-1] = '\0';
922 ltrim(buf2);
923 rtrim(buf2);
924 if (gmx_strcasecmp(buf2, "molecules") == 0)
926 bMolecules = 1;
929 fprintf(fpout, "%s", buf);
931 else if (bMolecules == 1)
933 for (i = 0; i < mtop->nmolblock; i++)
935 nmol = mtop->molblock[i].nmol;
936 sprintf(buf, "%-15s %5d\n", *(mtop->moltype[mtop->molblock[i].type].name), nmol);
937 fprintf(fpout, "%s", buf);
939 bMolecules = 2;
941 else if (bMolecules == 2)
943 /* print nothing */
945 else
947 fprintf(fpout, "%s", buf);
950 else
952 fprintf(fpout, "%s", buf);
956 gmx_ffclose(fpout);
957 /* use gmx_ffopen to generate backup of topinout */
958 fpout = gmx_ffopen(topfile, "w");
959 gmx_ffclose(fpout);
960 rename(temporary_filename, topfile);
963 void rescale_membed(int step_rel, gmx_membed_t *membed, rvec *x)
965 /* Set new positions for the group to embed */
966 if (step_rel <= membed->it_xy)
968 membed->fac[0] += membed->xy_step;
969 membed->fac[1] += membed->xy_step;
971 else if (step_rel <= (membed->it_xy+membed->it_z))
973 membed->fac[2] += membed->z_step;
975 resize(membed->r_ins, x, membed->pos_ins, membed->fac);
978 /* We would like gn to be const as well, but C doesn't allow this */
979 /* TODO this is utility functionality (search for the index of a
980 string in a collection), so should be refactored and located more
981 centrally. Also, it nearly duplicates the same string in readir.c */
982 static int search_string(const char *s, int ng, char *gn[])
984 int i;
986 for (i = 0; (i < ng); i++)
988 if (gmx_strcasecmp(s, gn[i]) == 0)
990 return i;
994 gmx_fatal(FARGS,
995 "Group %s selected for embedding was not found in the index file.\n"
996 "Group names must match either [moleculetype] names or custom index group\n"
997 "names, in which case you must supply an index file to the '-n' option\n"
998 "of grompp.",
1001 return -1;
1004 gmx_membed_t *init_membed(FILE *fplog, int nfile, const t_filenm fnm[], gmx_mtop_t *mtop,
1005 t_inputrec *inputrec, t_state *state, t_commrec *cr, real *cpt)
1007 char *ins, **gnames;
1008 int i, rm_bonded_at, fr_id, fr_i = 0, tmp_id, warn = 0;
1009 int ng, j, max_lip_rm, ins_grp_id, ntype, lip_rm;
1010 real prot_area;
1011 rvec *r_ins = NULL;
1012 t_block *ins_at, *rest_at;
1013 pos_ins_t *pos_ins;
1014 mem_t *mem_p;
1015 rm_t *rm_p;
1016 gmx_groups_t *groups;
1017 gmx_bool bExcl = FALSE;
1018 t_atoms atoms;
1019 t_pbc *pbc;
1020 char **piecename = NULL;
1021 gmx_membed_t *membed = NULL;
1023 /* input variables */
1024 const char *membed_input;
1025 real xy_fac = 0.5;
1026 real xy_max = 1.0;
1027 real z_fac = 1.0;
1028 real z_max = 1.0;
1029 int it_xy = 1000;
1030 int it_z = 0;
1031 real probe_rad = 0.22;
1032 int low_up_rm = 0;
1033 int maxwarn = 0;
1034 int pieces = 1;
1035 gmx_bool bALLOW_ASYMMETRY = FALSE;
1037 /* sanity check constants */ /* Issue a warning when: */
1038 const real min_probe_rad = 0.2199999; /* A probe radius for overlap between embedded molecule *
1039 * and rest smaller than this value is probably too small */
1040 const real min_xy_init = 0.0999999; /* the initial shrinking of the molecule to embed is smaller */
1041 const int min_it_xy = 1000; /* the number of steps to embed in xy-plane is smaller */
1042 const int min_it_z = 100; /* the number of steps to embed in z is smaller */
1043 const real prot_vs_box = 7.5; /* molecule to embed is large (more then prot_vs_box) with respect */
1044 const real box_vs_prot = 50; /* to the box size (less than box_vs_prot) */
1046 snew(membed, 1);
1047 snew(ins_at, 1);
1048 snew(pos_ins, 1);
1050 if (MASTER(cr))
1052 /* get input data out membed file */
1053 membed_input = opt2fn("-membed", nfile, fnm);
1054 get_input(membed_input, &xy_fac, &xy_max, &z_fac, &z_max, &it_xy, &it_z, &probe_rad, &low_up_rm,
1055 &maxwarn, &pieces, &bALLOW_ASYMMETRY);
1057 if (!EI_DYNAMICS(inputrec->eI) )
1059 gmx_input("Change integrator to a dynamics integrator in mdp file (e.g. md or sd).");
1062 if (PAR(cr))
1064 gmx_input("Sorry, parallel g_membed is not yet fully functional.");
1067 if (*cpt >= 0)
1069 fprintf(stderr, "\nSetting -cpt to -1, because embedding cannot be restarted from cpt-files.\n");
1070 *cpt = -1;
1072 groups = &(mtop->groups);
1073 snew(gnames, groups->ngrpname);
1074 for (i = 0; i < groups->ngrpname; i++)
1076 gnames[i] = *(groups->grpname[i]);
1079 atoms = gmx_mtop_global_atoms(mtop);
1080 snew(mem_p, 1);
1081 fprintf(stderr, "\nSelect a group to embed in the membrane:\n");
1082 get_index(&atoms, opt2fn_null("-mn", nfile, fnm), 1, &(ins_at->nr), &(ins_at->index), &ins);
1083 ins_grp_id = search_string(ins, groups->ngrpname, gnames);
1084 fprintf(stderr, "\nSelect a group to embed %s into (e.g. the membrane):\n", ins);
1085 get_index(&atoms, opt2fn_null("-mn", nfile, fnm), 1, &(mem_p->mem_at.nr), &(mem_p->mem_at.index), &(mem_p->name));
1087 pos_ins->pieces = pieces;
1088 snew(pos_ins->nidx, pieces);
1089 snew(pos_ins->subindex, pieces);
1090 snew(piecename, pieces);
1091 if (pieces > 1)
1093 fprintf(stderr, "\nSelect pieces to embed:\n");
1094 get_index(&atoms, opt2fn_null("-mn", nfile, fnm), pieces, pos_ins->nidx, pos_ins->subindex, piecename);
1096 else
1098 /*use whole embedded group*/
1099 snew(pos_ins->nidx, 1);
1100 snew(pos_ins->subindex, 1);
1101 pos_ins->nidx[0] = ins_at->nr;
1102 pos_ins->subindex[0] = ins_at->index;
1105 if (probe_rad < min_probe_rad)
1107 warn++;
1108 fprintf(stderr, "\nWarning %d:\nA probe radius (-rad) smaller than 0.2 nm can result "
1109 "in overlap between waters and the group to embed, which will result "
1110 "in Lincs errors etc.\n\n", warn);
1113 if (xy_fac < min_xy_init)
1115 warn++;
1116 fprintf(stderr, "\nWarning %d:\nThe initial size of %s is probably too smal.\n\n", warn, ins);
1119 if (it_xy < min_it_xy)
1121 warn++;
1122 fprintf(stderr, "\nWarning %d;\nThe number of steps used to grow the xy-coordinates of %s (%d)"
1123 " is probably too small.\nIncrease -nxy or.\n\n", warn, ins, it_xy);
1126 if ( (it_z < min_it_z) && ( z_fac < 0.99999999 || z_fac > 1.0000001) )
1128 warn++;
1129 fprintf(stderr, "\nWarning %d;\nThe number of steps used to grow the z-coordinate of %s (%d)"
1130 " is probably too small.\nIncrease -nz or the maxwarn setting in the membed input file.\n\n", warn, ins, it_z);
1133 if (it_xy+it_z > inputrec->nsteps)
1135 warn++;
1136 fprintf(stderr, "\nWarning %d:\nThe number of growth steps (-nxy + -nz) is larger than the "
1137 "number of steps in the tpr.\n"
1138 "(increase maxwarn in the membed input file to override)\n\n", warn);
1141 fr_id = -1;
1142 if (inputrec->opts.ngfrz == 1)
1144 gmx_fatal(FARGS, "You did not specify \"%s\" as a freezegroup.", ins);
1147 for (i = 0; i < inputrec->opts.ngfrz; i++)
1149 tmp_id = mtop->groups.grps[egcFREEZE].nm_ind[i];
1150 if (ins_grp_id == tmp_id)
1152 fr_id = tmp_id;
1153 fr_i = i;
1157 if (fr_id == -1)
1159 gmx_fatal(FARGS, "\"%s\" not as freezegroup defined in the mdp-file.", ins);
1162 for (i = 0; i < DIM; i++)
1164 if (inputrec->opts.nFreeze[fr_i][i] != 1)
1166 gmx_fatal(FARGS, "freeze dimensions for %s are not Y Y Y\n", ins);
1170 ng = groups->grps[egcENER].nr;
1171 if (ng == 1)
1173 gmx_input("No energy groups defined. This is necessary for energy exclusion in the freeze group");
1176 for (i = 0; i < ng; i++)
1178 for (j = 0; j < ng; j++)
1180 if (inputrec->opts.egp_flags[ng*i+j] == EGP_EXCL)
1182 bExcl = TRUE;
1183 if ( (groups->grps[egcENER].nm_ind[i] != ins_grp_id) ||
1184 (groups->grps[egcENER].nm_ind[j] != ins_grp_id) )
1186 gmx_fatal(FARGS, "Energy exclusions \"%s\" and \"%s\" do not match the group "
1187 "to embed \"%s\"", *groups->grpname[groups->grps[egcENER].nm_ind[i]],
1188 *groups->grpname[groups->grps[egcENER].nm_ind[j]], ins);
1194 if (!bExcl)
1196 gmx_input("No energy exclusion groups defined. This is necessary for energy exclusion in "
1197 "the freeze group");
1200 /* Obtain the maximum and minimum coordinates of the group to be embedded */
1201 snew(rest_at, 1);
1202 init_ins_at(ins_at, rest_at, state, pos_ins, groups, ins_grp_id, xy_max);
1203 /* Check that moleculetypes in insertion group are not part of the rest of the system */
1204 check_types(ins_at, rest_at, mtop);
1206 init_mem_at(mem_p, mtop, state->x, state->box, pos_ins);
1208 prot_area = est_prot_area(pos_ins, state->x, ins_at, mem_p);
1209 if ( (prot_area > prot_vs_box) && ( (state->box[XX][XX]*state->box[YY][YY]-state->box[XX][YY]*state->box[YY][XX]) < box_vs_prot) )
1211 warn++;
1212 fprintf(stderr, "\nWarning %d:\nThe xy-area is very small compared to the area of the protein.\n"
1213 "This might cause pressure problems during the growth phase. Just try with\n"
1214 "current setup and increase 'maxwarn' in your membed settings file, but lower the\n"
1215 "compressibility in the mdp-file or disable pressure coupling if problems occur.\n\n", warn);
1218 if (warn > maxwarn)
1220 gmx_fatal(FARGS, "Too many warnings (override by setting maxwarn in the membed input file)\n");
1223 printf("The estimated area of the protein in the membrane is %.3f nm^2\n", prot_area);
1224 printf("\nThere are %d lipids in the membrane part that overlaps the protein.\n"
1225 "The area per lipid is %.4f nm^2.\n", mem_p->nmol, mem_p->lip_area);
1227 /* Maximum number of lipids to be removed*/
1228 max_lip_rm = (int)(2*prot_area/mem_p->lip_area);
1229 printf("Maximum number of lipids that will be removed is %d.\n", max_lip_rm);
1231 printf("\nWill resize the protein by a factor of %.3f in the xy plane and %.3f in the z direction.\n"
1232 "This resizing will be done with respect to the geometrical center of all protein atoms\n"
1233 "that span the membrane region, i.e. z between %.3f and %.3f\n\n",
1234 xy_fac, z_fac, mem_p->zmin, mem_p->zmax);
1236 /* resize the protein by xy and by z if necessary*/
1237 snew(r_ins, ins_at->nr);
1238 init_resize(ins_at, r_ins, pos_ins, mem_p, state->x, bALLOW_ASYMMETRY);
1239 membed->fac[0] = membed->fac[1] = xy_fac;
1240 membed->fac[2] = z_fac;
1242 membed->xy_step = (xy_max-xy_fac)/(double)(it_xy);
1243 membed->z_step = (z_max-z_fac)/(double)(it_z-1);
1245 resize(r_ins, state->x, pos_ins, membed->fac);
1247 /* remove overlapping lipids and water from the membrane box*/
1248 /*mark molecules to be removed*/
1249 snew(pbc, 1);
1250 set_pbc(pbc, inputrec->ePBC, state->box);
1252 snew(rm_p, 1);
1253 lip_rm = gen_rm_list(rm_p, ins_at, rest_at, pbc, mtop, state->x, mem_p, pos_ins,
1254 probe_rad, low_up_rm, bALLOW_ASYMMETRY);
1255 lip_rm -= low_up_rm;
1257 if (fplog)
1259 for (i = 0; i < rm_p->nr; i++)
1261 fprintf(fplog, "rm mol %d\n", rm_p->mol[i]);
1265 for (i = 0; i < mtop->nmolblock; i++)
1267 ntype = 0;
1268 for (j = 0; j < rm_p->nr; j++)
1270 if (rm_p->block[j] == i)
1272 ntype++;
1275 printf("Will remove %d %s molecules\n", ntype, *(mtop->moltype[mtop->molblock[i].type].name));
1278 if (lip_rm > max_lip_rm)
1280 warn++;
1281 fprintf(stderr, "\nWarning %d:\nTrying to remove a larger lipid area than the estimated "
1282 "protein area\nTry making the -xyinit resize factor smaller or increase "
1283 "maxwarn in the membed input file.\n\n", warn);
1286 /*remove all lipids and waters overlapping and update all important structures*/
1287 rm_group(groups, mtop, rm_p, state, ins_at, pos_ins);
1289 rm_bonded_at = rm_bonded(ins_at, mtop);
1290 if (rm_bonded_at != ins_at->nr)
1292 fprintf(stderr, "Warning: The number of atoms for which the bonded interactions are removed is %d, "
1293 "while %d atoms are embedded. Make sure that the atoms to be embedded are not in the same"
1294 "molecule type as atoms that are not to be embedded.\n", rm_bonded_at, ins_at->nr);
1297 if (warn > maxwarn)
1299 gmx_fatal(FARGS, "Too many warnings.\nIf you are sure these warnings are harmless,\n"
1300 "you can increase the maxwarn setting in the membed input file.");
1303 if (ftp2bSet(efTOP, nfile, fnm))
1305 top_update(opt2fn("-mp", nfile, fnm), rm_p, mtop);
1308 sfree(pbc);
1309 sfree(rest_at);
1310 if (pieces > 1)
1312 sfree(piecename);
1315 membed->it_xy = it_xy;
1316 membed->it_z = it_z;
1317 membed->pos_ins = pos_ins;
1318 membed->r_ins = r_ins;
1321 return membed;
1324 void free_membed(gmx_membed_t *membed)
1326 sfree(membed);