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 "types/commrec.h"
43 #include "gromacs/utility/smalloc.h"
48 #include "gromacs/fileio/futil.h"
49 #include "gromacs/essentialdynamics/edsam.h"
53 #include "mtop_util.h"
54 #include "gromacs/fileio/tpxio.h"
55 #include "gromacs/utility/cstringutil.h"
59 #include "gromacs/gmxpreprocess/readir.h"
61 /* information about scaling center */
63 rvec xmin
; /* smallest coordinates of all embedded molecules */
64 rvec xmax
; /* largest coordinates of all embedded molecules */
65 rvec
*geom_cent
; /* scaling center of each independent molecule to embed */
66 int pieces
; /* number of molecules to embed independently */
67 int *nidx
; /* n atoms for every independent embedded molecule (index in subindex) */
68 atom_id
**subindex
; /* atomids for independent molecule *
69 * atoms of piece i run from subindex[i][0] to subindex[i][nidx[i]] */
72 /* variables needed in do_md */
74 int it_xy
; /* number of iterations (steps) used to grow something in the xy-plane */
75 int it_z
; /* same, but for z */
76 real xy_step
; /* stepsize used during resize in xy-plane */
77 real z_step
; /* same, but in z */
78 rvec fac
; /* initial scaling of the molecule to grow into the membrane */
79 rvec
*r_ins
; /* final coordinates of the molecule to grow */
80 pos_ins_t
*pos_ins
; /* scaling center for each piece to embed */
83 /* membrane related variables */
85 char *name
; /* name of index group to embed molecule into (usually membrane) */
86 t_block mem_at
; /* list all atoms in membrane */
87 int nmol
; /* number of membrane molecules overlapping with the molecule to embed */
88 int *mol_id
; /* list of molecules in membrane that overlap with the molecule to embed */
89 real lip_area
; /* average area per lipid in membrane (only correct for homogeneous bilayers)*/
90 real zmin
; /* minimum z coordinate of membrane */
91 real zmax
; /* maximum z coordinate of membrane */
92 real zmed
; /* median z coordinate of membrane */
95 /* Lists all molecules in the membrane that overlap with the molecule to be embedded. *
96 * These will then be removed from the system */
98 int nr
; /* number of molecules to remove */
99 int *mol
; /* list of molecule ids to remove */
100 int *block
; /* id of the molblock that the molecule to remove is part of */
103 /* Get the global molecule id, and the corresponding molecule type and id of the *
104 * molblock from the global atom nr. */
105 static int get_mol_id(int at
, gmx_mtop_t
*mtop
, int *type
, int *block
)
110 gmx_mtop_atomlookup_t alook
;
112 alook
= gmx_mtop_atomlookup_settle_init(mtop
);
113 gmx_mtop_atomnr_to_molblock_ind(alook
, at
, block
, &mol_id
, &atnr_mol
);
114 for (i
= 0; i
< *block
; i
++)
116 mol_id
+= mtop
->molblock
[i
].nmol
;
118 *type
= mtop
->molblock
[*block
].type
;
120 gmx_mtop_atomlookup_destroy(alook
);
125 /* Get the id of the molblock from a global molecule id */
126 static int get_molblock(int mol_id
, int nmblock
, gmx_molblock_t
*mblock
)
131 for (i
= 0; i
< nmblock
; i
++)
133 nmol
+= mblock
[i
].nmol
;
140 gmx_fatal(FARGS
, "mol_id %d larger than total number of molecules %d.\n", mol_id
, nmol
);
145 static int get_tpr_version(const char *infile
)
148 int version
, generation
;
150 read_tpxheader(infile
, &header
, TRUE
, &version
, &generation
);
155 /* Get a list of all the molecule types that are present in a group of atoms. *
156 * Because all interaction within the group to embed are removed on the topology *
157 * level, if the same molecule type is found in another part of the system, these *
158 * would also be affected. Therefore we have to check if the embedded and rest group *
159 * share common molecule types. If so, membed will stop with an error. */
160 static int get_mtype_list(t_block
*at
, gmx_mtop_t
*mtop
, t_block
*tlist
)
162 int i
, j
, nr
, mol_id
;
163 int type
= 0, block
= 0;
167 snew(tlist
->index
, at
->nr
);
168 for (i
= 0; i
< at
->nr
; i
++)
171 mol_id
= get_mol_id(at
->index
[i
], mtop
, &type
, &block
);
172 for (j
= 0; j
< nr
; j
++)
174 if (tlist
->index
[j
] == type
)
182 tlist
->index
[nr
] = type
;
186 srenew(tlist
->index
, nr
);
190 /* Do the actual check of the molecule types between embedded and rest group */
191 static void check_types(t_block
*ins_at
, t_block
*rest_at
, gmx_mtop_t
*mtop
)
193 t_block
*ins_mtype
, *rest_mtype
;
198 ins_mtype
->nr
= get_mtype_list(ins_at
, mtop
, ins_mtype
);
199 rest_mtype
->nr
= get_mtype_list(rest_at
, mtop
, rest_mtype
);
201 for (i
= 0; i
< ins_mtype
->nr
; i
++)
203 for (j
= 0; j
< rest_mtype
->nr
; j
++)
205 if (ins_mtype
->index
[i
] == rest_mtype
->index
[j
])
207 gmx_fatal(FARGS
, "Moleculetype %s is found both in the group to insert and the rest of the system.\n"
208 "1. Your *.ndx and *.top do not match\n"
209 "2. You are inserting some molecules of type %s (for example xray-solvent), while\n"
210 "the same moleculetype is also used in the rest of the system (solvent box). Because\n"
211 "we need to exclude all interactions between the atoms in the group to\n"
212 "insert, the same moleculetype can not be used in both groups. Change the\n"
213 "moleculetype of the molecules %s in the inserted group. Do not forget to provide\n"
214 "an appropriate *.itp file", *(mtop
->moltype
[rest_mtype
->index
[j
]].name
),
215 *(mtop
->moltype
[rest_mtype
->index
[j
]].name
), *(mtop
->moltype
[rest_mtype
->index
[j
]].name
));
220 sfree(ins_mtype
->index
);
221 sfree(rest_mtype
->index
);
226 static void get_input(const char *membed_input
, real
*xy_fac
, real
*xy_max
, real
*z_fac
, real
*z_max
,
227 int *it_xy
, int *it_z
, real
*probe_rad
, int *low_up_rm
, int *maxwarn
,
228 int *pieces
, gmx_bool
*bALLOW_ASYMMETRY
)
234 wi
= init_warning(TRUE
, 0);
236 inp
= read_inpfile(membed_input
, &ninp
, wi
);
237 ITYPE ("nxy", *it_xy
, 1000);
238 ITYPE ("nz", *it_z
, 0);
239 RTYPE ("xyinit", *xy_fac
, 0.5);
240 RTYPE ("xyend", *xy_max
, 1.0);
241 RTYPE ("zinit", *z_fac
, 1.0);
242 RTYPE ("zend", *z_max
, 1.0);
243 RTYPE ("rad", *probe_rad
, 0.22);
244 ITYPE ("ndiff", *low_up_rm
, 0);
245 ITYPE ("maxwarn", *maxwarn
, 0);
246 ITYPE ("pieces", *pieces
, 1);
247 EETYPE("asymmetry", *bALLOW_ASYMMETRY
, yesno_names
);
249 write_inpfile(membed_input
, ninp
, inp
, FALSE
, wi
);
252 /* Obtain the maximum and minimum coordinates of the group to be embedded */
253 static int init_ins_at(t_block
*ins_at
, t_block
*rest_at
, t_state
*state
, pos_ins_t
*pos_ins
,
254 gmx_groups_t
*groups
, int ins_grp_id
, real xy_max
)
257 real x
, xmin
, xmax
, y
, ymin
, ymax
, z
, zmin
, zmax
;
258 const real min_memthick
= 6.0; /* minimum thickness of the bilayer that will be used to *
259 * determine the overlap between molecule to embed and membrane */
260 const real fac_inp_size
= 1.000001; /* scaling factor to obtain input_size + 0.000001 (comparing reals) */
261 snew(rest_at
->index
, state
->natoms
);
263 xmin
= xmax
= state
->x
[ins_at
->index
[0]][XX
];
264 ymin
= ymax
= state
->x
[ins_at
->index
[0]][YY
];
265 zmin
= zmax
= state
->x
[ins_at
->index
[0]][ZZ
];
267 for (i
= 0; i
< state
->natoms
; i
++)
269 gid
= groups
->grpnr
[egcFREEZE
][i
];
270 if (groups
->grps
[egcFREEZE
].nm_ind
[gid
] == ins_grp_id
)
302 rest_at
->index
[c
] = i
;
308 srenew(rest_at
->index
, c
);
310 if (xy_max
> fac_inp_size
)
312 pos_ins
->xmin
[XX
] = xmin
-((xmax
-xmin
)*xy_max
-(xmax
-xmin
))/2;
313 pos_ins
->xmin
[YY
] = ymin
-((ymax
-ymin
)*xy_max
-(ymax
-ymin
))/2;
315 pos_ins
->xmax
[XX
] = xmax
+((xmax
-xmin
)*xy_max
-(xmax
-xmin
))/2;
316 pos_ins
->xmax
[YY
] = ymax
+((ymax
-ymin
)*xy_max
-(ymax
-ymin
))/2;
320 pos_ins
->xmin
[XX
] = xmin
;
321 pos_ins
->xmin
[YY
] = ymin
;
323 pos_ins
->xmax
[XX
] = xmax
;
324 pos_ins
->xmax
[YY
] = ymax
;
327 if ( (zmax
-zmin
) < min_memthick
)
329 pos_ins
->xmin
[ZZ
] = zmin
+(zmax
-zmin
)/2.0-0.5*min_memthick
;
330 pos_ins
->xmax
[ZZ
] = zmin
+(zmax
-zmin
)/2.0+0.5*min_memthick
;
334 pos_ins
->xmin
[ZZ
] = zmin
;
335 pos_ins
->xmax
[ZZ
] = zmax
;
341 /* Estimate the area of the embedded molecule by projecting all coordinates on a grid in the *
342 * xy-plane and counting the number of occupied grid points */
343 static real
est_prot_area(pos_ins_t
*pos_ins
, rvec
*r
, t_block
*ins_at
, mem_t
*mem_p
)
345 real x
, y
, dx
= 0.15, dy
= 0.15, area
= 0.0;
346 real add
, memmin
, memmax
;
349 /* min and max membrane coordinate are altered to reduce the influence of the *
351 memmin
= mem_p
->zmin
+0.1*(mem_p
->zmax
-mem_p
->zmin
);
352 memmax
= mem_p
->zmax
-0.1*(mem_p
->zmax
-mem_p
->zmin
);
354 for (x
= pos_ins
->xmin
[XX
]; x
< pos_ins
->xmax
[XX
]; x
+= dx
)
356 for (y
= pos_ins
->xmin
[YY
]; y
< pos_ins
->xmax
[YY
]; y
+= dy
)
362 at
= ins_at
->index
[c
];
363 if ( (r
[at
][XX
] >= x
) && (r
[at
][XX
] < x
+dx
) &&
364 (r
[at
][YY
] >= y
) && (r
[at
][YY
] < y
+dy
) &&
365 (r
[at
][ZZ
] > memmin
) && (r
[at
][ZZ
] < memmax
) )
371 while ( (c
< ins_at
->nr
) && (add
< 0.5) );
380 static int init_mem_at(mem_t
*mem_p
, gmx_mtop_t
*mtop
, rvec
*r
, matrix box
, pos_ins_t
*pos_ins
)
382 int i
, j
, at
, mol
, nmol
, nmolbox
, count
;
384 real z
, zmin
, zmax
, mem_area
;
387 int type
= 0, block
= 0;
390 mem_a
= &(mem_p
->mem_at
);
391 snew(mol_id
, mem_a
->nr
);
392 zmin
= pos_ins
->xmax
[ZZ
];
393 zmax
= pos_ins
->xmin
[ZZ
];
394 for (i
= 0; i
< mem_a
->nr
; i
++)
396 at
= mem_a
->index
[i
];
397 if ( (r
[at
][XX
] > pos_ins
->xmin
[XX
]) && (r
[at
][XX
] < pos_ins
->xmax
[XX
]) &&
398 (r
[at
][YY
] > pos_ins
->xmin
[YY
]) && (r
[at
][YY
] < pos_ins
->xmax
[YY
]) &&
399 (r
[at
][ZZ
] > pos_ins
->xmin
[ZZ
]) && (r
[at
][ZZ
] < pos_ins
->xmax
[ZZ
]) )
401 mol
= get_mol_id(at
, mtop
, &type
, &block
);
403 for (j
= 0; j
< nmol
; j
++)
405 if (mol
== mol_id
[j
])
433 srenew(mol_id
, nmol
);
434 mem_p
->mol_id
= mol_id
;
436 if ((zmax
-zmin
) > (box
[ZZ
][ZZ
]-0.5))
438 gmx_fatal(FARGS
, "Something is wrong with your membrane. Max and min z values are %f and %f.\n"
439 "Maybe your membrane is not centered in the box, but located at the box edge in the z-direction,\n"
440 "so that one membrane is distributed over two periodic box images. Another possibility is that\n"
441 "your water layer is not thick enough.\n", zmax
, zmin
);
445 mem_p
->zmed
= (zmax
-zmin
)/2+zmin
;
447 /*number of membrane molecules in protein box*/
448 nmolbox
= count
/mtop
->molblock
[block
].natoms_mol
;
449 /*membrane area within the box defined by the min and max coordinates of the embedded molecule*/
450 mem_area
= (pos_ins
->xmax
[XX
]-pos_ins
->xmin
[XX
])*(pos_ins
->xmax
[YY
]-pos_ins
->xmin
[YY
]);
451 /*rough estimate of area per lipid, assuming there is only one type of lipid in the membrane*/
452 mem_p
->lip_area
= 2.0*mem_area
/(double)nmolbox
;
454 return mem_p
->mem_at
.nr
;
457 static void init_resize(t_block
*ins_at
, rvec
*r_ins
, pos_ins_t
*pos_ins
, mem_t
*mem_p
, rvec
*r
,
458 gmx_bool bALLOW_ASYMMETRY
)
460 int i
, j
, at
, c
, outsidesum
, gctr
= 0;
464 for (i
= 0; i
< pos_ins
->pieces
; i
++)
466 idxsum
+= pos_ins
->nidx
[i
];
469 if (idxsum
!= ins_at
->nr
)
471 gmx_fatal(FARGS
, "Piecewise sum of inserted atoms not same as size of group selected to insert.");
474 snew(pos_ins
->geom_cent
, pos_ins
->pieces
);
475 for (i
= 0; i
< pos_ins
->pieces
; i
++)
479 for (j
= 0; j
< DIM
; j
++)
481 pos_ins
->geom_cent
[i
][j
] = 0;
484 for (j
= 0; j
< pos_ins
->nidx
[i
]; j
++)
486 at
= pos_ins
->subindex
[i
][j
];
487 copy_rvec(r
[at
], r_ins
[gctr
]);
488 if ( (r_ins
[gctr
][ZZ
] < mem_p
->zmax
) && (r_ins
[gctr
][ZZ
] > mem_p
->zmin
) )
490 rvec_inc(pos_ins
->geom_cent
[i
], r_ins
[gctr
]);
502 svmul(1/(double)c
, pos_ins
->geom_cent
[i
], pos_ins
->geom_cent
[i
]);
505 if (!bALLOW_ASYMMETRY
)
507 pos_ins
->geom_cent
[i
][ZZ
] = mem_p
->zmed
;
510 fprintf(stderr
, "Embedding piece %d with center of geometry: %f %f %f\n",
511 i
, pos_ins
->geom_cent
[i
][XX
], pos_ins
->geom_cent
[i
][YY
], pos_ins
->geom_cent
[i
][ZZ
]);
513 fprintf(stderr
, "\n");
516 /* resize performed in the md loop */
517 static void resize(rvec
*r_ins
, rvec
*r
, pos_ins_t
*pos_ins
, rvec fac
)
519 int i
, j
, k
, at
, c
= 0;
520 for (k
= 0; k
< pos_ins
->pieces
; k
++)
522 for (i
= 0; i
< pos_ins
->nidx
[k
]; i
++)
524 at
= pos_ins
->subindex
[k
][i
];
525 for (j
= 0; j
< DIM
; j
++)
527 r
[at
][j
] = pos_ins
->geom_cent
[k
][j
]+fac
[j
]*(r_ins
[c
][j
]-pos_ins
->geom_cent
[k
][j
]);
534 /* generate the list of membrane molecules that overlap with the molecule to be embedded. *
535 * The molecule to be embedded is already reduced in size. */
536 static int gen_rm_list(rm_t
*rm_p
, t_block
*ins_at
, t_block
*rest_at
, t_pbc
*pbc
, gmx_mtop_t
*mtop
,
537 rvec
*r
, mem_t
*mem_p
, pos_ins_t
*pos_ins
, real probe_rad
,
538 int low_up_rm
, gmx_bool bALLOW_ASYMMETRY
)
540 int i
, j
, k
, l
, at
, at2
, mol_id
;
541 int type
= 0, block
= 0;
542 int nrm
, nupper
, nlower
;
543 real r_min_rad
, z_lip
, min_norm
;
549 r_min_rad
= probe_rad
*probe_rad
;
550 snew(rm_p
->mol
, mtop
->mols
.nr
);
551 snew(rm_p
->block
, mtop
->mols
.nr
);
554 for (i
= 0; i
< ins_at
->nr
; i
++)
556 at
= ins_at
->index
[i
];
557 for (j
= 0; j
< rest_at
->nr
; j
++)
559 at2
= rest_at
->index
[j
];
560 pbc_dx(pbc
, r
[at
], r
[at2
], dr
);
562 if (norm2(dr
) < r_min_rad
)
564 mol_id
= get_mol_id(at2
, mtop
, &type
, &block
);
566 for (l
= 0; l
< nrm
; l
++)
568 if (rm_p
->mol
[l
] == mol_id
)
576 rm_p
->mol
[nrm
] = mol_id
;
577 rm_p
->block
[nrm
] = block
;
580 for (l
= 0; l
< mem_p
->nmol
; l
++)
582 if (mol_id
== mem_p
->mol_id
[l
])
584 for (k
= mtop
->mols
.index
[mol_id
]; k
< mtop
->mols
.index
[mol_id
+1]; k
++)
588 z_lip
/= mtop
->molblock
[block
].natoms_mol
;
589 if (z_lip
< mem_p
->zmed
)
604 /*make sure equal number of lipids from upper and lower layer are removed */
605 if ( (nupper
!= nlower
) && (!bALLOW_ASYMMETRY
) )
607 snew(dist
, mem_p
->nmol
);
608 snew(order
, mem_p
->nmol
);
609 for (i
= 0; i
< mem_p
->nmol
; i
++)
611 at
= mtop
->mols
.index
[mem_p
->mol_id
[i
]];
612 pbc_dx(pbc
, r
[at
], pos_ins
->geom_cent
[0], dr
);
613 if (pos_ins
->pieces
> 1)
616 min_norm
= norm2(dr
);
617 for (k
= 1; k
< pos_ins
->pieces
; k
++)
619 pbc_dx(pbc
, r
[at
], pos_ins
->geom_cent
[k
], dr_tmp
);
620 if (norm2(dr_tmp
) < min_norm
)
622 min_norm
= norm2(dr_tmp
);
623 copy_rvec(dr_tmp
, dr
);
627 dist
[i
] = dr
[XX
]*dr
[XX
]+dr
[YY
]*dr
[YY
];
629 while (j
>= 0 && dist
[i
] < dist
[order
[j
]])
631 order
[j
+1] = order
[j
];
638 while (nupper
!= nlower
)
640 mol_id
= mem_p
->mol_id
[order
[i
]];
641 block
= get_molblock(mol_id
, mtop
->nmolblock
, mtop
->molblock
);
643 for (l
= 0; l
< nrm
; l
++)
645 if (rm_p
->mol
[l
] == mol_id
)
654 for (k
= mtop
->mols
.index
[mol_id
]; k
< mtop
->mols
.index
[mol_id
+1]; k
++)
658 z_lip
/= mtop
->molblock
[block
].natoms_mol
;
659 if (nupper
> nlower
&& z_lip
< mem_p
->zmed
)
661 rm_p
->mol
[nrm
] = mol_id
;
662 rm_p
->block
[nrm
] = block
;
666 else if (nupper
< nlower
&& z_lip
> mem_p
->zmed
)
668 rm_p
->mol
[nrm
] = mol_id
;
669 rm_p
->block
[nrm
] = block
;
678 gmx_fatal(FARGS
, "Trying to remove more lipid molecules than there are in the membrane");
686 srenew(rm_p
->mol
, nrm
);
687 srenew(rm_p
->block
, nrm
);
689 return nupper
+nlower
;
692 /*remove all lipids and waters overlapping and update all important structures (e.g. state and mtop)*/
693 static void rm_group(gmx_groups_t
*groups
, gmx_mtop_t
*mtop
, rm_t
*rm_p
, t_state
*state
,
694 t_block
*ins_at
, pos_ins_t
*pos_ins
)
696 int i
, j
, k
, n
, rm
, mol_id
, at
, block
;
698 atom_id
*list
, *new_mols
;
699 unsigned char *new_egrp
[egcNR
];
703 snew(list
, state
->natoms
);
705 for (i
= 0; i
< rm_p
->nr
; i
++)
707 mol_id
= rm_p
->mol
[i
];
708 at
= mtop
->mols
.index
[mol_id
];
709 block
= rm_p
->block
[i
];
710 mtop
->molblock
[block
].nmol
--;
711 for (j
= 0; j
< mtop
->molblock
[block
].natoms_mol
; j
++)
716 mtop
->mols
.index
[mol_id
] = -1;
719 mtop
->mols
.nr
-= rm_p
->nr
;
720 mtop
->mols
.nalloc_index
-= rm_p
->nr
;
721 snew(new_mols
, mtop
->mols
.nr
);
722 for (i
= 0; i
< mtop
->mols
.nr
+rm_p
->nr
; i
++)
725 if (mtop
->mols
.index
[i
] != -1)
727 new_mols
[j
] = mtop
->mols
.index
[i
];
731 sfree(mtop
->mols
.index
);
732 mtop
->mols
.index
= new_mols
;
735 state
->nalloc
= state
->natoms
;
736 snew(x_tmp
, state
->nalloc
);
737 snew(v_tmp
, state
->nalloc
);
739 for (i
= 0; i
< egcNR
; i
++)
741 if (groups
->grpnr
[i
] != NULL
)
743 groups
->ngrpnr
[i
] = state
->natoms
;
744 snew(new_egrp
[i
], state
->natoms
);
749 for (i
= 0; i
< state
->natoms
+n
; i
++)
752 for (j
= 0; j
< n
; j
++)
763 for (j
= 0; j
< egcNR
; j
++)
765 if (groups
->grpnr
[j
] != NULL
)
767 new_egrp
[j
][i
-rm
] = groups
->grpnr
[j
][i
];
770 copy_rvec(state
->x
[i
], x_tmp
[i
-rm
]);
771 copy_rvec(state
->v
[i
], v_tmp
[i
-rm
]);
772 for (j
= 0; j
< ins_at
->nr
; j
++)
774 if (i
== ins_at
->index
[j
])
776 ins_at
->index
[j
] = i
-rm
;
780 for (j
= 0; j
< pos_ins
->pieces
; j
++)
782 for (k
= 0; k
< pos_ins
->nidx
[j
]; k
++)
784 if (i
== pos_ins
->subindex
[j
][k
])
786 pos_ins
->subindex
[j
][k
] = i
-rm
;
797 for (i
= 0; i
< egcNR
; i
++)
799 if (groups
->grpnr
[i
] != NULL
)
801 sfree(groups
->grpnr
[i
]);
802 groups
->grpnr
[i
] = new_egrp
[i
];
806 /* remove empty molblocks */
808 for (i
= 0; i
< mtop
->nmolblock
; i
++)
810 if (mtop
->molblock
[i
].nmol
== 0)
816 mtop
->molblock
[i
-RMmolblock
] = mtop
->molblock
[i
];
819 mtop
->nmolblock
-= RMmolblock
;
822 /* remove al bonded interactions from mtop for the molecule to be embedded */
823 int rm_bonded(t_block
*ins_at
, gmx_mtop_t
*mtop
)
826 int type
, natom
, nmol
, at
, atom1
= 0, rm_at
= 0;
828 /*this routine lives dangerously by assuming that all molecules of a given type are in order in the structure*/
829 /*this routine does not live as dangerously as it seems. There is namely a check in init_membed to make *
830 * sure that g_membed exits with a warning when there are molecules of the same type not in the *
831 * ins_at index group. MGWolf 050710 */
834 snew(bRM
, mtop
->nmoltype
);
835 for (i
= 0; i
< mtop
->nmoltype
; i
++)
840 for (i
= 0; i
< mtop
->nmolblock
; i
++)
842 /*loop over molecule blocks*/
843 type
= mtop
->molblock
[i
].type
;
844 natom
= mtop
->molblock
[i
].natoms_mol
;
845 nmol
= mtop
->molblock
[i
].nmol
;
847 for (j
= 0; j
< natom
*nmol
&& bRM
[type
] == TRUE
; j
++)
849 /*loop over atoms in the block*/
850 at
= j
+atom1
; /*atom index = block index + offset*/
853 for (m
= 0; (m
< ins_at
->nr
) && (bINS
== FALSE
); m
++)
855 /*loop over atoms in insertion index group to determine if we're inserting one*/
856 if (at
== ins_at
->index
[m
])
863 atom1
+= natom
*nmol
; /*update offset*/
866 rm_at
+= natom
*nmol
; /*increment bonded removal counter by # atoms in block*/
870 for (i
= 0; i
< mtop
->nmoltype
; i
++)
874 for (j
= 0; j
< F_LJ
; j
++)
876 mtop
->moltype
[i
].ilist
[j
].nr
= 0;
879 for (j
= F_POSRES
; j
<= F_VSITEN
; j
++)
881 mtop
->moltype
[i
].ilist
[j
].nr
= 0;
890 /* Write a topology where the number of molecules is correct for the system after embedding */
891 static void top_update(const char *topfile
, rm_t
*rm_p
, gmx_mtop_t
*mtop
)
895 char buf
[STRLEN
], buf2
[STRLEN
], *temp
;
896 int i
, *nmol_rm
, nmol
, line
;
897 char temporary_filename
[STRLEN
];
899 fpin
= gmx_ffopen(topfile
, "r");
900 strncpy(temporary_filename
, "temp.topXXXXXX", STRLEN
);
901 gmx_tmpnam(temporary_filename
);
902 fpout
= gmx_ffopen(temporary_filename
, "w");
904 snew(nmol_rm
, mtop
->nmoltype
);
905 for (i
= 0; i
< rm_p
->nr
; i
++)
907 nmol_rm
[rm_p
->block
[i
]]++;
911 while (fgets(buf
, STRLEN
, fpin
))
917 if ((temp
= strchr(buf2
, '\n')) != NULL
)
925 if ((temp
= strchr(buf2
, '\n')) != NULL
)
930 if (buf2
[strlen(buf2
)-1] == ']')
932 buf2
[strlen(buf2
)-1] = '\0';
935 if (gmx_strcasecmp(buf2
, "molecules") == 0)
940 fprintf(fpout
, "%s", buf
);
942 else if (bMolecules
== 1)
944 for (i
= 0; i
< mtop
->nmolblock
; i
++)
946 nmol
= mtop
->molblock
[i
].nmol
;
947 sprintf(buf
, "%-15s %5d\n", *(mtop
->moltype
[mtop
->molblock
[i
].type
].name
), nmol
);
948 fprintf(fpout
, "%s", buf
);
952 else if (bMolecules
== 2)
958 fprintf(fpout
, "%s", buf
);
963 fprintf(fpout
, "%s", buf
);
968 /* use gmx_ffopen to generate backup of topinout */
969 fpout
= gmx_ffopen(topfile
, "w");
971 rename(temporary_filename
, topfile
);
974 void rescale_membed(int step_rel
, gmx_membed_t membed
, rvec
*x
)
976 /* Set new positions for the group to embed */
977 if (step_rel
<= membed
->it_xy
)
979 membed
->fac
[0] += membed
->xy_step
;
980 membed
->fac
[1] += membed
->xy_step
;
982 else if (step_rel
<= (membed
->it_xy
+membed
->it_z
))
984 membed
->fac
[2] += membed
->z_step
;
986 resize(membed
->r_ins
, x
, membed
->pos_ins
, membed
->fac
);
989 gmx_membed_t
init_membed(FILE *fplog
, int nfile
, const t_filenm fnm
[], gmx_mtop_t
*mtop
,
990 t_inputrec
*inputrec
, t_state
*state
, t_commrec
*cr
, real
*cpt
)
993 int i
, rm_bonded_at
, fr_id
, fr_i
= 0, tmp_id
, warn
= 0;
994 int ng
, j
, max_lip_rm
, ins_grp_id
, ins_nat
, mem_nat
, ntype
, lip_rm
, tpr_version
;
997 t_block
*ins_at
, *rest_at
;
1001 gmx_groups_t
*groups
;
1002 gmx_bool bExcl
= FALSE
;
1005 char **piecename
= NULL
;
1006 gmx_membed_t membed
= NULL
;
1008 /* input variables */
1009 const char *membed_input
;
1016 real probe_rad
= 0.22;
1020 gmx_bool bALLOW_ASYMMETRY
= FALSE
;
1022 /* sanity check constants */ /* Issue a warning when: */
1023 const int membed_version
= 58; /* tpr version is smaller */
1024 const real min_probe_rad
= 0.2199999; /* A probe radius for overlap between embedded molecule *
1025 * and rest smaller than this value is probably too small */
1026 const real min_xy_init
= 0.0999999; /* the initial shrinking of the molecule to embed is smaller */
1027 const int min_it_xy
= 1000; /* the number of steps to embed in xy-plane is smaller */
1028 const int min_it_z
= 100; /* the number of steps to embed in z is smaller */
1029 const real prot_vs_box
= 7.5; /* molecule to embed is large (more then prot_vs_box) with respect */
1030 const real box_vs_prot
= 50; /* to the box size (less than box_vs_prot) */
1038 /* get input data out membed file */
1039 membed_input
= opt2fn("-membed", nfile
, fnm
);
1040 get_input(membed_input
, &xy_fac
, &xy_max
, &z_fac
, &z_max
, &it_xy
, &it_z
, &probe_rad
, &low_up_rm
,
1041 &maxwarn
, &pieces
, &bALLOW_ASYMMETRY
);
1043 tpr_version
= get_tpr_version(ftp2fn(efTPX
, nfile
, fnm
));
1044 if (tpr_version
< membed_version
)
1046 gmx_fatal(FARGS
, "Version of *.tpr file to old (%d). "
1047 "Rerun grompp with GROMACS version 4.0.3 or newer.\n", tpr_version
);
1050 if (!EI_DYNAMICS(inputrec
->eI
) )
1052 gmx_input("Change integrator to a dynamics integrator in mdp file (e.g. md or sd).");
1057 gmx_input("Sorry, parallel g_membed is not yet fully functional.");
1062 fprintf(stderr
, "\nSetting -cpt to -1, because embedding cannot be restarted from cpt-files.\n");
1065 groups
= &(mtop
->groups
);
1066 snew(gnames
, groups
->ngrpname
);
1067 for (i
= 0; i
< groups
->ngrpname
; i
++)
1069 gnames
[i
] = *(groups
->grpname
[i
]);
1072 atoms
= gmx_mtop_global_atoms(mtop
);
1074 fprintf(stderr
, "\nSelect a group to embed in the membrane:\n");
1075 get_index(&atoms
, opt2fn_null("-mn", nfile
, fnm
), 1, &(ins_at
->nr
), &(ins_at
->index
), &ins
);
1076 ins_grp_id
= search_string(ins
, groups
->ngrpname
, gnames
);
1077 fprintf(stderr
, "\nSelect a group to embed %s into (e.g. the membrane):\n", ins
);
1078 get_index(&atoms
, opt2fn_null("-mn", nfile
, fnm
), 1, &(mem_p
->mem_at
.nr
), &(mem_p
->mem_at
.index
), &(mem_p
->name
));
1080 pos_ins
->pieces
= pieces
;
1081 snew(pos_ins
->nidx
, pieces
);
1082 snew(pos_ins
->subindex
, pieces
);
1083 snew(piecename
, pieces
);
1086 fprintf(stderr
, "\nSelect pieces to embed:\n");
1087 get_index(&atoms
, opt2fn_null("-mn", nfile
, fnm
), pieces
, pos_ins
->nidx
, pos_ins
->subindex
, piecename
);
1091 /*use whole embedded group*/
1092 snew(pos_ins
->nidx
, 1);
1093 snew(pos_ins
->subindex
, 1);
1094 pos_ins
->nidx
[0] = ins_at
->nr
;
1095 pos_ins
->subindex
[0] = ins_at
->index
;
1098 if (probe_rad
< min_probe_rad
)
1101 fprintf(stderr
, "\nWarning %d:\nA probe radius (-rad) smaller than 0.2 nm can result "
1102 "in overlap between waters and the group to embed, which will result "
1103 "in Lincs errors etc.\n\n", warn
);
1106 if (xy_fac
< min_xy_init
)
1109 fprintf(stderr
, "\nWarning %d:\nThe initial size of %s is probably too smal.\n\n", warn
, ins
);
1112 if (it_xy
< min_it_xy
)
1115 fprintf(stderr
, "\nWarning %d;\nThe number of steps used to grow the xy-coordinates of %s (%d)"
1116 " is probably too small.\nIncrease -nxy or.\n\n", warn
, ins
, it_xy
);
1119 if ( (it_z
< min_it_z
) && ( z_fac
< 0.99999999 || z_fac
> 1.0000001) )
1122 fprintf(stderr
, "\nWarning %d;\nThe number of steps used to grow the z-coordinate of %s (%d)"
1123 " is probably too small.\nIncrease -nz or maxwarn.\n\n", warn
, ins
, it_z
);
1126 if (it_xy
+it_z
> inputrec
->nsteps
)
1129 fprintf(stderr
, "\nWarning %d:\nThe number of growth steps (-nxy + -nz) is larger than the "
1130 "number of steps in the tpr.\n\n", warn
);
1134 if (inputrec
->opts
.ngfrz
== 1)
1136 gmx_fatal(FARGS
, "You did not specify \"%s\" as a freezegroup.", ins
);
1139 for (i
= 0; i
< inputrec
->opts
.ngfrz
; i
++)
1141 tmp_id
= mtop
->groups
.grps
[egcFREEZE
].nm_ind
[i
];
1142 if (ins_grp_id
== tmp_id
)
1151 gmx_fatal(FARGS
, "\"%s\" not as freezegroup defined in the mdp-file.", ins
);
1154 for (i
= 0; i
< DIM
; i
++)
1156 if (inputrec
->opts
.nFreeze
[fr_i
][i
] != 1)
1158 gmx_fatal(FARGS
, "freeze dimensions for %s are not Y Y Y\n", ins
);
1162 ng
= groups
->grps
[egcENER
].nr
;
1165 gmx_input("No energy groups defined. This is necessary for energy exclusion in the freeze group");
1168 for (i
= 0; i
< ng
; i
++)
1170 for (j
= 0; j
< ng
; j
++)
1172 if (inputrec
->opts
.egp_flags
[ng
*i
+j
] == EGP_EXCL
)
1175 if ( (groups
->grps
[egcENER
].nm_ind
[i
] != ins_grp_id
) ||
1176 (groups
->grps
[egcENER
].nm_ind
[j
] != ins_grp_id
) )
1178 gmx_fatal(FARGS
, "Energy exclusions \"%s\" and \"%s\" do not match the group "
1179 "to embed \"%s\"", *groups
->grpname
[groups
->grps
[egcENER
].nm_ind
[i
]],
1180 *groups
->grpname
[groups
->grps
[egcENER
].nm_ind
[j
]], ins
);
1188 gmx_input("No energy exclusion groups defined. This is necessary for energy exclusion in "
1189 "the freeze group");
1192 /* Obtain the maximum and minimum coordinates of the group to be embedded */
1194 ins_nat
= init_ins_at(ins_at
, rest_at
, state
, pos_ins
, groups
, ins_grp_id
, xy_max
);
1195 /* Check that moleculetypes in insertion group are not part of the rest of the system */
1196 check_types(ins_at
, rest_at
, mtop
);
1198 mem_nat
= init_mem_at(mem_p
, mtop
, state
->x
, state
->box
, pos_ins
);
1200 prot_area
= est_prot_area(pos_ins
, state
->x
, ins_at
, mem_p
);
1201 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
) )
1204 fprintf(stderr
, "\nWarning %d:\nThe xy-area is very small compared to the area of the protein.\n"
1205 "This might cause pressure problems during the growth phase. Just try with\n"
1206 "current setup (-maxwarn + 1), but if pressure problems occur, lower the\n"
1207 "compressibility in the mdp-file or use no pressure coupling at all.\n\n", warn
);
1212 gmx_fatal(FARGS
, "Too many warnings.\n");
1215 printf("The estimated area of the protein in the membrane is %.3f nm^2\n", prot_area
);
1216 printf("\nThere are %d lipids in the membrane part that overlaps the protein.\n"
1217 "The area per lipid is %.4f nm^2.\n", mem_p
->nmol
, mem_p
->lip_area
);
1219 /* Maximum number of lipids to be removed*/
1220 max_lip_rm
= (int)(2*prot_area
/mem_p
->lip_area
);
1221 printf("Maximum number of lipids that will be removed is %d.\n", max_lip_rm
);
1223 printf("\nWill resize the protein by a factor of %.3f in the xy plane and %.3f in the z direction.\n"
1224 "This resizing will be done with respect to the geometrical center of all protein atoms\n"
1225 "that span the membrane region, i.e. z between %.3f and %.3f\n\n",
1226 xy_fac
, z_fac
, mem_p
->zmin
, mem_p
->zmax
);
1228 /* resize the protein by xy and by z if necessary*/
1229 snew(r_ins
, ins_at
->nr
);
1230 init_resize(ins_at
, r_ins
, pos_ins
, mem_p
, state
->x
, bALLOW_ASYMMETRY
);
1231 membed
->fac
[0] = membed
->fac
[1] = xy_fac
;
1232 membed
->fac
[2] = z_fac
;
1234 membed
->xy_step
= (xy_max
-xy_fac
)/(double)(it_xy
);
1235 membed
->z_step
= (z_max
-z_fac
)/(double)(it_z
-1);
1237 resize(r_ins
, state
->x
, pos_ins
, membed
->fac
);
1239 /* remove overlapping lipids and water from the membrane box*/
1240 /*mark molecules to be removed*/
1242 set_pbc(pbc
, inputrec
->ePBC
, state
->box
);
1245 lip_rm
= gen_rm_list(rm_p
, ins_at
, rest_at
, pbc
, mtop
, state
->x
, mem_p
, pos_ins
,
1246 probe_rad
, low_up_rm
, bALLOW_ASYMMETRY
);
1247 lip_rm
-= low_up_rm
;
1251 for (i
= 0; i
< rm_p
->nr
; i
++)
1253 fprintf(fplog
, "rm mol %d\n", rm_p
->mol
[i
]);
1257 for (i
= 0; i
< mtop
->nmolblock
; i
++)
1260 for (j
= 0; j
< rm_p
->nr
; j
++)
1262 if (rm_p
->block
[j
] == i
)
1267 printf("Will remove %d %s molecules\n", ntype
, *(mtop
->moltype
[mtop
->molblock
[i
].type
].name
));
1270 if (lip_rm
> max_lip_rm
)
1273 fprintf(stderr
, "\nWarning %d:\nTrying to remove a larger lipid area than the estimated "
1274 "protein area\nTry making the -xyinit resize factor smaller or increase "
1275 "maxwarn.\n\n", warn
);
1278 /*remove all lipids and waters overlapping and update all important structures*/
1279 rm_group(groups
, mtop
, rm_p
, state
, ins_at
, pos_ins
);
1281 rm_bonded_at
= rm_bonded(ins_at
, mtop
);
1282 if (rm_bonded_at
!= ins_at
->nr
)
1284 fprintf(stderr
, "Warning: The number of atoms for which the bonded interactions are removed is %d, "
1285 "while %d atoms are embedded. Make sure that the atoms to be embedded are not in the same"
1286 "molecule type as atoms that are not to be embedded.\n", rm_bonded_at
, ins_at
->nr
);
1291 gmx_fatal(FARGS
, "Too many warnings.\nIf you are sure these warnings are harmless, "
1292 "you can increase -maxwarn");
1295 if (ftp2bSet(efTOP
, nfile
, fnm
))
1297 top_update(opt2fn("-mp", nfile
, fnm
), rm_p
, mtop
);
1307 membed
->it_xy
= it_xy
;
1308 membed
->it_z
= it_z
;
1309 membed
->pos_ins
= pos_ins
;
1310 membed
->r_ins
= r_ins
;