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.
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 */
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]] */
71 /* variables needed in do_md */
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 */
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 */
94 /* Lists all molecules in the membrane that overlap with the molecule to be embedded. *
95 * These will then be removed from the system */
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 */
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
)
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
);
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
)
130 for (i
= 0; i
< nmblock
; i
++)
132 nmol
+= mblock
[i
].nmol
;
139 gmx_fatal(FARGS
, "mol_id %d larger than total number of molecules %d.\n", mol_id
, nmol
);
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
)
152 int type
= 0, block
= 0;
156 snew(tlist
->index
, at
->nr
);
157 for (i
= 0; i
< at
->nr
; i
++)
160 get_mol_id(at
->index
[i
], mtop
, &type
, &block
);
161 for (j
= 0; j
< nr
; j
++)
163 if (tlist
->index
[j
] == type
)
171 tlist
->index
[nr
] = type
;
175 srenew(tlist
->index
, 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
;
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
);
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
)
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
)
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
)
291 rest_at
->index
[c
] = i
;
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;
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
;
323 pos_ins
->xmin
[ZZ
] = zmin
;
324 pos_ins
->xmax
[ZZ
] = zmax
;
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
;
338 /* min and max membrane coordinate are altered to reduce the influence of the *
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
)
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
) )
360 while ( (c
< ins_at
->nr
) && (add
< 0.5) );
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
;
373 real z
, zmin
, zmax
, mem_area
;
376 int type
= 0, block
= 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
);
392 for (j
= 0; j
< nmol
; j
++)
394 if (mol
== mol_id
[j
])
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
);
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;
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
++)
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
]);
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
]);
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
;
538 r_min_rad
= probe_rad
*probe_rad
;
539 snew(rm_p
->mol
, mtop
->mols
.nr
);
540 snew(rm_p
->block
, mtop
->mols
.nr
);
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
);
555 for (l
= 0; l
< nrm
; l
++)
557 if (rm_p
->mol
[l
] == mol_id
)
565 rm_p
->mol
[nrm
] = mol_id
;
566 rm_p
->block
[nrm
] = block
;
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
++)
577 z_lip
/= mtop
->molblock
[block
].natoms_mol
;
578 if (z_lip
< mem_p
->zmed
)
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)
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
];
618 while (j
>= 0 && dist
[i
] < dist
[order
[j
]])
620 order
[j
+1] = order
[j
];
627 while (nupper
!= nlower
)
629 mol_id
= mem_p
->mol_id
[order
[i
]];
630 block
= get_molblock(mol_id
, mtop
->nmolblock
, mtop
->molblock
);
632 for (l
= 0; l
< nrm
; l
++)
634 if (rm_p
->mol
[l
] == mol_id
)
643 for (k
= mtop
->mols
.index
[mol_id
]; k
< mtop
->mols
.index
[mol_id
+1]; k
++)
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
;
655 else if (nupper
< nlower
&& z_lip
> mem_p
->zmed
)
657 rm_p
->mol
[nrm
] = mol_id
;
658 rm_p
->block
[nrm
] = block
;
667 gmx_fatal(FARGS
, "Trying to remove more lipid molecules than there are in the membrane");
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
;
687 int *list
, *new_mols
;
688 unsigned char *new_egrp
[egcNR
];
692 snew(list
, state
->natoms
);
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
++)
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
++)
714 if (mtop
->mols
.index
[i
] != -1)
716 new_mols
[j
] = mtop
->mols
.index
[i
];
720 sfree(mtop
->mols
.index
);
721 mtop
->mols
.index
= new_mols
;
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
);
738 for (i
= 0; i
< state
->natoms
+n
; i
++)
741 for (j
= 0; j
< n
; j
++)
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
;
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 */
797 for (i
= 0; i
< mtop
->nmolblock
; i
++)
799 if (mtop
->molblock
[i
].nmol
== 0)
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
)
815 int type
, natom
, nmol
, at
, atom1
= 0, rm_at
= 0;
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
++)
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*/
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
])
852 atom1
+= natom
*nmol
; /*update offset*/
855 rm_at
+= natom
*nmol
; /*increment bonded removal counter by # atoms in block*/
859 for (i
= 0; i
< mtop
->nmoltype
; 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;
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
)
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
]]++;
900 while (fgets(buf
, STRLEN
, fpin
))
906 if ((temp
= strchr(buf2
, '\n')) != NULL
)
914 if ((temp
= strchr(buf2
, '\n')) != NULL
)
919 if (buf2
[strlen(buf2
)-1] == ']')
921 buf2
[strlen(buf2
)-1] = '\0';
924 if (gmx_strcasecmp(buf2
, "molecules") == 0)
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
);
941 else if (bMolecules
== 2)
947 fprintf(fpout
, "%s", buf
);
952 fprintf(fpout
, "%s", buf
);
957 /* use gmx_ffopen to generate backup of topinout */
958 fpout
= gmx_ffopen(topfile
, "w");
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
[])
986 for (i
= 0; (i
< ng
); i
++)
988 if (gmx_strcasecmp(s
, gn
[i
]) == 0)
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"
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
;
1012 t_block
*ins_at
, *rest_at
;
1016 gmx_groups_t
*groups
;
1017 gmx_bool bExcl
= FALSE
;
1020 char **piecename
= NULL
;
1021 gmx_membed_t
*membed
= NULL
;
1023 /* input variables */
1024 const char *membed_input
;
1031 real probe_rad
= 0.22;
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) */
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).");
1064 gmx_input("Sorry, parallel g_membed is not yet fully functional.");
1069 fprintf(stderr
, "\nSetting -cpt to -1, because embedding cannot be restarted from cpt-files.\n");
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
);
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
);
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
);
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
)
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
)
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
)
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) )
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
)
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
);
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
)
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
;
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
)
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
);
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 */
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
) )
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
);
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*/
1250 set_pbc(pbc
, inputrec
->ePBC
, state
->box
);
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
;
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
++)
1268 for (j
= 0; j
< rm_p
->nr
; j
++)
1270 if (rm_p
->block
[j
] == i
)
1275 printf("Will remove %d %s molecules\n", ntype
, *(mtop
->moltype
[mtop
->molblock
[i
].type
].name
));
1278 if (lip_rm
> max_lip_rm
)
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
);
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
);
1315 membed
->it_xy
= it_xy
;
1316 membed
->it_z
= it_z
;
1317 membed
->pos_ins
= pos_ins
;
1318 membed
->r_ins
= r_ins
;
1324 void free_membed(gmx_membed_t
*membed
)