c5647569662da57914c28b51ca99521c33820c4d
[alexxy/gromacs.git] / src / gromacs / mdlib / membed.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2010,2011,2012,2013,2014,2015,2016,2017,2018, 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.
8  *
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.
13  *
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.
18  *
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.
23  *
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.
31  *
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.
34  */
35 #include "gmxpre.h"
36
37 #include "membed.h"
38
39 #include <csignal>
40 #include <cstdlib>
41
42 #include "gromacs/commandline/filenm.h"
43 #include "gromacs/fileio/readinp.h"
44 #include "gromacs/fileio/warninp.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_lookup.h"
54 #include "gromacs/topology/mtop_util.h"
55 #include "gromacs/topology/topology.h"
56 #include "gromacs/utility/cstringutil.h"
57 #include "gromacs/utility/exceptions.h"
58 #include "gromacs/utility/fatalerror.h"
59 #include "gromacs/utility/filestream.h"
60 #include "gromacs/utility/futil.h"
61 #include "gromacs/utility/smalloc.h"
62
63 /* information about scaling center */
64 typedef struct {
65     rvec      xmin;      /* smallest coordinates of all embedded molecules */
66     rvec      xmax;      /* largest coordinates of all embedded molecules */
67     rvec     *geom_cent; /* scaling center of each independent molecule to embed */
68     int       pieces;    /* number of molecules to embed independently */
69     int      *nidx;      /* n atoms for every independent embedded molecule (index in subindex) */
70     int     **subindex;  /* atomids for independent molecule *
71                           * atoms of piece i run from subindex[i][0] to subindex[i][nidx[i]] */
72 } pos_ins_t;
73
74 /* variables needed in do_md */
75 struct gmx_membed_t {
76     int        it_xy;     /* number of iterations (steps) used to grow something in the xy-plane */
77     int        it_z;      /* same, but for z */
78     real       xy_step;   /* stepsize used during resize in xy-plane */
79     real       z_step;    /* same, but in z */
80     rvec       fac;       /* initial scaling of the molecule to grow into the membrane */
81     rvec      *r_ins;     /* final coordinates of the molecule to grow  */
82     pos_ins_t *pos_ins;   /* scaling center for each piece to embed */
83 };
84
85 /* membrane related variables */
86 typedef struct {
87     char      *name;     /* name of index group to embed molecule into (usually membrane) */
88     t_block    mem_at;   /* list all atoms in membrane */
89     int        nmol;     /* number of membrane molecules overlapping with the molecule to embed */
90     int       *mol_id;   /* list of molecules in membrane that overlap with the molecule to embed */
91     real       lip_area; /* average area per lipid in membrane (only correct for homogeneous bilayers)*/
92     real       zmin;     /* minimum z coordinate of membrane */
93     real       zmax;     /* maximum z coordinate of membrane */
94     real       zmed;     /* median z coordinate of membrane */
95 } mem_t;
96
97 /* Lists all molecules in the membrane that overlap with the molecule to be embedded. *
98  * These will then be removed from the system */
99 typedef struct {
100     int   nr;     /* number of molecules to remove */
101     int  *mol;    /* list of molecule ids to remove */
102     int  *block;  /* id of the molblock that the molecule to remove is part of */
103 } rm_t;
104
105 /* Get the global molecule id, and the corresponding molecule type and id of the *
106  * molblock from the global atom nr. */
107 static int get_mol_id(int at, gmx_mtop_t  *mtop, int *type, int *block)
108 {
109     int                   mol_id = 0;
110     int                   i;
111     int                   atnr_mol;
112
113     *block = 0;
114     mtopGetMolblockIndex(mtop, at, block, &mol_id, &atnr_mol);
115     for (i = 0; i < *block; i++)
116     {
117         mol_id += mtop->molblock[i].nmol;
118     }
119     *type = mtop->molblock[*block].type;
120
121     return mol_id;
122 }
123
124 /* Get the id of the molblock from a global molecule id */
125 static int get_molblock(int mol_id, const std::vector<gmx_molblock_t> &mblock)
126 {
127     int nmol = 0;
128
129     for (size_t i = 0; i < mblock.size(); i++)
130     {
131         nmol += mblock[i].nmol;
132         if (mol_id < nmol)
133         {
134             return i;
135         }
136     }
137
138     gmx_fatal(FARGS, "mol_id %d larger than total number of molecules %d.\n", mol_id, nmol);
139 }
140
141 /* Get a list of all the molecule types that are present in a group of atoms. *
142  * Because all interaction within the group to embed are removed on the topology *
143  * level, if the same molecule type is found in another part of the system, these *
144  * would also be affected. Therefore we have to check if the embedded and rest group *
145  * share common molecule types. If so, membed will stop with an error. */
146 static int get_mtype_list(t_block *at, gmx_mtop_t *mtop, t_block *tlist)
147 {
148     int      i, j, nr;
149     int      type = 0, block = 0;
150     gmx_bool bNEW;
151
152     nr = 0;
153     snew(tlist->index, at->nr);
154     for (i = 0; i < at->nr; i++)
155     {
156         bNEW   = TRUE;
157         get_mol_id(at->index[i], mtop, &type, &block);
158         for (j = 0; j < nr; j++)
159         {
160             if (tlist->index[j] == type)
161             {
162                 bNEW = FALSE;
163             }
164         }
165
166         if (bNEW)
167         {
168             tlist->index[nr] = type;
169             nr++;
170         }
171     }
172     srenew(tlist->index, nr);
173     return nr;
174 }
175
176 /* Do the actual check of the molecule types between embedded and rest group */
177 static void check_types(t_block *ins_at, t_block *rest_at, gmx_mtop_t *mtop)
178 {
179     t_block        *ins_mtype, *rest_mtype;
180     int             i, j;
181
182     snew(ins_mtype, 1);
183     snew(rest_mtype, 1);
184     ins_mtype->nr  = get_mtype_list(ins_at, mtop, ins_mtype );
185     rest_mtype->nr = get_mtype_list(rest_at, mtop, rest_mtype);
186
187     for (i = 0; i < ins_mtype->nr; i++)
188     {
189         for (j = 0; j < rest_mtype->nr; j++)
190         {
191             if (ins_mtype->index[i] == rest_mtype->index[j])
192             {
193                 gmx_fatal(FARGS, "Moleculetype %s is found both in the group to insert and the rest of the system.\n"
194                           "1. Your *.ndx and *.top do not match\n"
195                           "2. You are inserting some molecules of type %s (for example xray-solvent), while\n"
196                           "the same moleculetype is also used in the rest of the system (solvent box). Because\n"
197                           "we need to exclude all interactions between the atoms in the group to\n"
198                           "insert, the same moleculetype can not be used in both groups. Change the\n"
199                           "moleculetype of the molecules %s in the inserted group. Do not forget to provide\n"
200                           "an appropriate *.itp file", *(mtop->moltype[rest_mtype->index[j]].name),
201                           *(mtop->moltype[rest_mtype->index[j]].name), *(mtop->moltype[rest_mtype->index[j]].name));
202             }
203         }
204     }
205
206     done_block(ins_mtype);
207     done_block(rest_mtype);
208     sfree(ins_mtype);
209     sfree(rest_mtype);
210 }
211
212 static void get_input(const char *membed_input, real *xy_fac, real *xy_max, real *z_fac, real *z_max,
213                       int *it_xy, int *it_z, real *probe_rad, int *low_up_rm, int *maxwarn,
214                       int *pieces, gmx_bool *bALLOW_ASYMMETRY)
215 {
216     warninp_t               wi;
217     std::vector <t_inpfile> inp;
218
219     wi = init_warning(TRUE, 0);
220
221     {
222         gmx::TextInputFile stream(membed_input);
223         inp = read_inpfile(&stream, membed_input, wi);
224         stream.close();
225     }
226     *it_xy            = get_eint(&inp, "nxy", 1000, wi);
227     *it_z             = get_eint(&inp, "nz", 0, wi);
228     *xy_fac           = get_ereal(&inp, "xyinit", 0.5, wi);
229     *xy_max           = get_ereal(&inp, "xyend", 1.0, wi);
230     *z_fac            = get_ereal(&inp, "zinit", 1.0, wi);
231     *z_max            = get_ereal(&inp, "zend", 1.0, wi);
232     *probe_rad        = get_ereal(&inp, "rad", 0.22, wi);
233     *low_up_rm        = get_eint(&inp, "ndiff", 0, wi);
234     *maxwarn          = get_eint(&inp, "maxwarn", 0, wi);
235     *pieces           = get_eint(&inp, "pieces", 1, wi);
236     const char *yesno_names[BOOL_NR+1] =
237     {
238         "no", "yes", nullptr
239     };
240     *bALLOW_ASYMMETRY = (get_eeenum(&inp, "asymmetry", yesno_names, wi) != 0);
241
242     check_warning_error(wi, FARGS);
243     {
244         gmx::TextOutputFile stream(membed_input);
245         write_inpfile(&stream, membed_input, &inp, FALSE, WriteMdpHeader::yes, wi);
246         stream.close();
247     }
248     done_warning(wi, FARGS);
249 }
250
251 /* Obtain the maximum and minimum coordinates of the group to be embedded */
252 static int init_ins_at(t_block *ins_at, t_block *rest_at, t_state *state, pos_ins_t *pos_ins,
253                        gmx_groups_t *groups, int ins_grp_id, real xy_max)
254 {
255     int        i, gid, c = 0;
256     real       xmin, xmax, ymin, ymax, zmin, zmax;
257     const real min_memthick = 6.0;      /* minimum thickness of the bilayer that will be used to *
258                                          * determine the overlap between molecule to embed and membrane */
259     const real fac_inp_size = 1.000001; /* scaling factor to obtain input_size + 0.000001 (comparing reals) */
260     snew(rest_at->index, state->natoms);
261     auto       x = makeArrayRef(state->x);
262
263     xmin = xmax = x[ins_at->index[0]][XX];
264     ymin = ymax = x[ins_at->index[0]][YY];
265     zmin = zmax = x[ins_at->index[0]][ZZ];
266
267     for (i = 0; i < state->natoms; i++)
268     {
269         gid = groups->grpnr[egcFREEZE][i];
270         if (groups->grps[egcFREEZE].nm_ind[gid] == ins_grp_id)
271         {
272             xmin = std::min(xmin, x[i][XX]);
273             xmax = std::max(xmax, x[i][XX]);
274             ymin = std::min(ymin, x[i][YY]);
275             ymax = std::max(ymax, x[i][YY]);
276             zmin = std::min(zmin, x[i][ZZ]);
277             zmax = std::max(zmax, x[i][ZZ]);
278         }
279         else
280         {
281             rest_at->index[c] = i;
282             c++;
283         }
284     }
285
286     rest_at->nr = c;
287     srenew(rest_at->index, c);
288
289     if (xy_max > fac_inp_size)
290     {
291         pos_ins->xmin[XX] = xmin-((xmax-xmin)*xy_max-(xmax-xmin))/2;
292         pos_ins->xmin[YY] = ymin-((ymax-ymin)*xy_max-(ymax-ymin))/2;
293
294         pos_ins->xmax[XX] = xmax+((xmax-xmin)*xy_max-(xmax-xmin))/2;
295         pos_ins->xmax[YY] = ymax+((ymax-ymin)*xy_max-(ymax-ymin))/2;
296     }
297     else
298     {
299         pos_ins->xmin[XX] = xmin;
300         pos_ins->xmin[YY] = ymin;
301
302         pos_ins->xmax[XX] = xmax;
303         pos_ins->xmax[YY] = ymax;
304     }
305
306     if ( (zmax-zmin) < min_memthick)
307     {
308         pos_ins->xmin[ZZ] = zmin+(zmax-zmin)/2.0-0.5*min_memthick;
309         pos_ins->xmax[ZZ] = zmin+(zmax-zmin)/2.0+0.5*min_memthick;
310     }
311     else
312     {
313         pos_ins->xmin[ZZ] = zmin;
314         pos_ins->xmax[ZZ] = zmax;
315     }
316
317     return c;
318 }
319
320 /* Estimate the area of the embedded molecule by projecting all coordinates on a grid in the *
321  * xy-plane and counting the number of occupied grid points */
322 static real est_prot_area(pos_ins_t *pos_ins, rvec *r, t_block *ins_at, mem_t *mem_p)
323 {
324     real x, y, dx = 0.15, dy = 0.15, area = 0.0;
325     real add, memmin, memmax;
326     int  c, at;
327
328     /* min and max membrane coordinate are altered to reduce the influence of the *
329      * boundary region */
330     memmin = mem_p->zmin+0.1*(mem_p->zmax-mem_p->zmin);
331     memmax = mem_p->zmax-0.1*(mem_p->zmax-mem_p->zmin);
332
333     //NOLINTNEXTLINE(clang-analyzer-security.FloatLoopCounter)
334     for (x = pos_ins->xmin[XX]; x < pos_ins->xmax[XX]; x += dx)
335     {
336         //NOLINTNEXTLINE(clang-analyzer-security.FloatLoopCounter)
337         for (y = pos_ins->xmin[YY]; y < pos_ins->xmax[YY]; y += dy)
338         {
339             c   = 0;
340             add = 0.0;
341             do
342             {
343                 at = ins_at->index[c];
344                 if ( (r[at][XX] >= x) && (r[at][XX] < x+dx) &&
345                      (r[at][YY] >= y) && (r[at][YY] < y+dy) &&
346                      (r[at][ZZ] > memmin) && (r[at][ZZ] < memmax) )
347                 {
348                     add = 1.0;
349                 }
350                 c++;
351             }
352             while ( (c < ins_at->nr) && (add < 0.5) );
353             area += add;
354         }
355     }
356     area = area*dx*dy;
357
358     return area;
359 }
360
361 static int init_mem_at(mem_t *mem_p, gmx_mtop_t *mtop, rvec *r, matrix box, pos_ins_t *pos_ins)
362 {
363     int      i, j, at, mol, nmol, nmolbox, count;
364     t_block *mem_a;
365     real     z, zmin, zmax, mem_area;
366     gmx_bool bNew;
367     int     *mol_id;
368     int      type = 0, block = 0;
369
370     nmol  = count = 0;
371     mem_a = &(mem_p->mem_at);
372     snew(mol_id, mem_a->nr);
373     zmin = pos_ins->xmax[ZZ];
374     zmax = pos_ins->xmin[ZZ];
375     for (i = 0; i < mem_a->nr; i++)
376     {
377         at = mem_a->index[i];
378         if ( (r[at][XX] > pos_ins->xmin[XX]) && (r[at][XX] < pos_ins->xmax[XX]) &&
379              (r[at][YY] > pos_ins->xmin[YY]) && (r[at][YY] < pos_ins->xmax[YY]) &&
380              (r[at][ZZ] > pos_ins->xmin[ZZ]) && (r[at][ZZ] < pos_ins->xmax[ZZ]) )
381         {
382             mol  = get_mol_id(at, mtop, &type, &block);
383             bNew = TRUE;
384             for (j = 0; j < nmol; j++)
385             {
386                 if (mol == mol_id[j])
387                 {
388                     bNew = FALSE;
389                 }
390             }
391
392             if (bNew)
393             {
394                 mol_id[nmol] = mol;
395                 nmol++;
396             }
397
398             z = r[at][ZZ];
399             if (z < zmin)
400             {
401                 zmin = z;
402             }
403
404             if (z > zmax)
405             {
406                 zmax = z;
407             }
408
409             count++;
410         }
411     }
412
413     mem_p->nmol = nmol;
414     srenew(mol_id, nmol);
415     mem_p->mol_id = mol_id;
416
417     if ((zmax-zmin) > (box[ZZ][ZZ]-0.5))
418     {
419         gmx_fatal(FARGS, "Something is wrong with your membrane. Max and min z values are %f and %f.\n"
420                   "Maybe your membrane is not centered in the box, but located at the box edge in the z-direction,\n"
421                   "so that one membrane is distributed over two periodic box images. Another possibility is that\n"
422                   "your water layer is not thick enough.\n", zmax, zmin);
423     }
424     mem_p->zmin = zmin;
425     mem_p->zmax = zmax;
426     mem_p->zmed = (zmax-zmin)/2+zmin;
427
428     /*number of membrane molecules in protein box*/
429     nmolbox = count/mtop->moltype[mtop->molblock[block].type].atoms.nr;
430     /*membrane area within the box defined by the min and max coordinates of the embedded molecule*/
431     mem_area = (pos_ins->xmax[XX]-pos_ins->xmin[XX])*(pos_ins->xmax[YY]-pos_ins->xmin[YY]);
432     /*rough estimate of area per lipid, assuming there is only one type of lipid in the membrane*/
433     mem_p->lip_area = 2.0*mem_area/static_cast<double>(nmolbox);
434
435     return mem_p->mem_at.nr;
436 }
437
438 static void init_resize(t_block *ins_at, rvec *r_ins, pos_ins_t *pos_ins, mem_t *mem_p, rvec *r,
439                         gmx_bool bALLOW_ASYMMETRY)
440 {
441     int i, j, at, c, outsidesum, gctr = 0;
442     int idxsum = 0;
443
444     /*sanity check*/
445     for (i = 0; i < pos_ins->pieces; i++)
446     {
447         idxsum += pos_ins->nidx[i];
448     }
449
450     if (idxsum != ins_at->nr)
451     {
452         gmx_fatal(FARGS, "Piecewise sum of inserted atoms not same as size of group selected to insert.");
453     }
454
455     snew(pos_ins->geom_cent, pos_ins->pieces);
456     for (i = 0; i < pos_ins->pieces; i++)
457     {
458         c          = 0;
459         outsidesum = 0;
460         for (j = 0; j < DIM; j++)
461         {
462             pos_ins->geom_cent[i][j] = 0;
463         }
464
465         for (j = 0; j < pos_ins->nidx[i]; j++)
466         {
467             at = pos_ins->subindex[i][j];
468             copy_rvec(r[at], r_ins[gctr]);
469             if ( (r_ins[gctr][ZZ] < mem_p->zmax) && (r_ins[gctr][ZZ] > mem_p->zmin) )
470             {
471                 rvec_inc(pos_ins->geom_cent[i], r_ins[gctr]);
472                 c++;
473             }
474             else
475             {
476                 outsidesum++;
477             }
478             gctr++;
479         }
480
481         if (c > 0)
482         {
483             svmul(1/static_cast<double>(c), pos_ins->geom_cent[i], pos_ins->geom_cent[i]);
484         }
485
486         if (!bALLOW_ASYMMETRY)
487         {
488             pos_ins->geom_cent[i][ZZ] = mem_p->zmed;
489         }
490
491         fprintf(stderr, "Embedding piece %d with center of geometry: %f %f %f\n",
492                 i, pos_ins->geom_cent[i][XX], pos_ins->geom_cent[i][YY], pos_ins->geom_cent[i][ZZ]);
493     }
494     fprintf(stderr, "\n");
495 }
496
497 /* resize performed in the md loop */
498 static void resize(rvec *r_ins, rvec *r, pos_ins_t *pos_ins, const rvec fac)
499 {
500     int i, j, k, at, c = 0;
501     for (k = 0; k < pos_ins->pieces; k++)
502     {
503         for (i = 0; i < pos_ins->nidx[k]; i++)
504         {
505             at = pos_ins->subindex[k][i];
506             for (j = 0; j < DIM; j++)
507             {
508                 r[at][j] = pos_ins->geom_cent[k][j]+fac[j]*(r_ins[c][j]-pos_ins->geom_cent[k][j]);
509             }
510             c++;
511         }
512     }
513 }
514
515 /* generate the list of membrane molecules that overlap with the molecule to be embedded. *
516  * The molecule to be embedded is already reduced in size. */
517 static int gen_rm_list(rm_t *rm_p, t_block *ins_at, t_block *rest_at, t_pbc *pbc, gmx_mtop_t *mtop,
518                        rvec *r, mem_t *mem_p, pos_ins_t *pos_ins, real probe_rad,
519                        int low_up_rm, gmx_bool bALLOW_ASYMMETRY)
520 {
521     int      i, j, k, l, at, at2, mol_id;
522     int      type = 0, block = 0;
523     int      nrm, nupper, nlower;
524     real     r_min_rad, z_lip, min_norm;
525     gmx_bool bRM;
526     rvec     dr, dr_tmp;
527     real    *dist;
528     int     *order;
529
530     r_min_rad = probe_rad*probe_rad;
531     gmx::RangePartitioning molecules = gmx_mtop_molecules(*mtop);
532     snew(rm_p->block, molecules.numBlocks());
533     nrm    = nupper = 0;
534     nlower = low_up_rm;
535     for (i = 0; i < ins_at->nr; i++)
536     {
537         at = ins_at->index[i];
538         for (j = 0; j < rest_at->nr; j++)
539         {
540             at2 = rest_at->index[j];
541             pbc_dx(pbc, r[at], r[at2], dr);
542
543             if (norm2(dr) < r_min_rad)
544             {
545                 mol_id = get_mol_id(at2, mtop, &type, &block);
546                 bRM    = TRUE;
547                 for (l = 0; l < nrm; l++)
548                 {
549                     if (rm_p->mol[l] == mol_id)
550                     {
551                         bRM = FALSE;
552                     }
553                 }
554
555                 if (bRM)
556                 {
557                     rm_p->mol[nrm]   = mol_id;
558                     rm_p->block[nrm] = block;
559                     nrm++;
560                     z_lip = 0.0;
561                     for (l = 0; l < mem_p->nmol; l++)
562                     {
563                         if (mol_id == mem_p->mol_id[l])
564                         {
565                             for (int k : molecules.block(mol_id))
566                             {
567                                 z_lip += r[k][ZZ];
568                             }
569                             z_lip /= molecules.block(mol_id).size();
570                             if (z_lip < mem_p->zmed)
571                             {
572                                 nlower++;
573                             }
574                             else
575                             {
576                                 nupper++;
577                             }
578                         }
579                     }
580                 }
581             }
582         }
583     }
584
585     /*make sure equal number of lipids from upper and lower layer are removed */
586     if ( (nupper != nlower) && (!bALLOW_ASYMMETRY) )
587     {
588         snew(dist, mem_p->nmol);
589         snew(order, mem_p->nmol);
590         for (i = 0; i < mem_p->nmol; i++)
591         {
592             at = molecules.block(mem_p->mol_id[i]).begin();
593             pbc_dx(pbc, r[at], pos_ins->geom_cent[0], dr);
594             if (pos_ins->pieces > 1)
595             {
596                 /*minimum dr value*/
597                 min_norm = norm2(dr);
598                 for (k = 1; k < pos_ins->pieces; k++)
599                 {
600                     pbc_dx(pbc, r[at], pos_ins->geom_cent[k], dr_tmp);
601                     if (norm2(dr_tmp) < min_norm)
602                     {
603                         min_norm = norm2(dr_tmp);
604                         copy_rvec(dr_tmp, dr);
605                     }
606                 }
607             }
608             dist[i] = dr[XX]*dr[XX]+dr[YY]*dr[YY];
609             j       = i-1;
610             while (j >= 0 && dist[i] < dist[order[j]])
611             {
612                 order[j+1] = order[j];
613                 j--;
614             }
615             order[j+1] = i;
616         }
617
618         i = 0;
619         while (nupper != nlower)
620         {
621             mol_id = mem_p->mol_id[order[i]];
622             block  = get_molblock(mol_id, mtop->molblock);
623             bRM    = TRUE;
624             for (l = 0; l < nrm; l++)
625             {
626                 if (rm_p->mol[l] == mol_id)
627                 {
628                     bRM = FALSE;
629                 }
630             }
631
632             if (bRM)
633             {
634                 z_lip = 0;
635                 for (int k : molecules.block(mol_id))
636                 {
637                     z_lip += r[k][ZZ];
638                 }
639                 z_lip /= molecules.block(mol_id).size();
640                 if (nupper > nlower && z_lip < mem_p->zmed)
641                 {
642                     rm_p->mol[nrm]   = mol_id;
643                     rm_p->block[nrm] = block;
644                     nrm++;
645                     nlower++;
646                 }
647                 else if (nupper < nlower && z_lip > mem_p->zmed)
648                 {
649                     rm_p->mol[nrm]   = mol_id;
650                     rm_p->block[nrm] = block;
651                     nrm++;
652                     nupper++;
653                 }
654             }
655             i++;
656
657             if (i > mem_p->nmol)
658             {
659                 gmx_fatal(FARGS, "Trying to remove more lipid molecules than there are in the membrane");
660             }
661         }
662         sfree(dist);
663         sfree(order);
664     }
665
666     rm_p->nr = nrm;
667     srenew(rm_p->mol, nrm);
668     srenew(rm_p->block, nrm);
669
670     return nupper+nlower;
671 }
672
673 /*remove all lipids and waters overlapping and update all important structures (e.g. state and mtop)*/
674 static void rm_group(gmx_groups_t *groups, gmx_mtop_t *mtop, rm_t *rm_p, t_state *state,
675                      t_block *ins_at, pos_ins_t *pos_ins)
676 {
677     int             j, k, n, rm, mol_id, at, block;
678     rvec           *x_tmp, *v_tmp;
679     int            *list;
680     unsigned char  *new_egrp[egcNR];
681     gmx_bool        bRM;
682     int             RMmolblock;
683
684     /* Construct the molecule range information */
685     gmx::RangePartitioning molecules = gmx_mtop_molecules(*mtop);
686
687     snew(list, state->natoms);
688     n = 0;
689     for (int i = 0; i < rm_p->nr; i++)
690     {
691         mol_id = rm_p->mol[i];
692         at     = molecules.block(mol_id).size();
693         block  = rm_p->block[i];
694         mtop->molblock[block].nmol--;
695         for (j = 0; j < mtop->moltype[mtop->molblock[block].type].atoms.nr; j++)
696         {
697             list[n] = at+j;
698             n++;
699         }
700     }
701
702     mtop->natoms    -= n;
703     state_change_natoms(state, state->natoms - n);
704     snew(x_tmp, state->natoms);
705     snew(v_tmp, state->natoms);
706
707     for (int i = 0; i < egcNR; i++)
708     {
709         if (groups->grpnr[i] != nullptr)
710         {
711             groups->ngrpnr[i] = state->natoms;
712             snew(new_egrp[i], state->natoms);
713         }
714     }
715
716     auto x = makeArrayRef(state->x);
717     auto v = makeArrayRef(state->v);
718     rm = 0;
719     for (int i = 0; i < state->natoms+n; i++)
720     {
721         bRM = FALSE;
722         for (j = 0; j < n; j++)
723         {
724             if (i == list[j])
725             {
726                 bRM = TRUE;
727                 rm++;
728             }
729         }
730
731         if (!bRM)
732         {
733             for (j = 0; j < egcNR; j++)
734             {
735                 if (groups->grpnr[j] != nullptr)
736                 {
737                     new_egrp[j][i-rm] = groups->grpnr[j][i];
738                 }
739             }
740             copy_rvec(x[i], x_tmp[i-rm]);
741             copy_rvec(v[i], v_tmp[i-rm]);
742             for (j = 0; j < ins_at->nr; j++)
743             {
744                 if (i == ins_at->index[j])
745                 {
746                     ins_at->index[j] = i-rm;
747                 }
748             }
749
750             for (j = 0; j < pos_ins->pieces; j++)
751             {
752                 for (k = 0; k < pos_ins->nidx[j]; k++)
753                 {
754                     if (i == pos_ins->subindex[j][k])
755                     {
756                         pos_ins->subindex[j][k] = i-rm;
757                     }
758                 }
759             }
760         }
761     }
762     for (int i = 0; i < state->natoms; i++)
763     {
764         copy_rvec(x_tmp[i], x[i]);
765     }
766     sfree(x_tmp);
767     for (int i = 0; i < state->natoms; i++)
768     {
769         copy_rvec(v_tmp[i], v[i]);
770     }
771     sfree(v_tmp);
772
773     for (int i = 0; i < egcNR; i++)
774     {
775         if (groups->grpnr[i] != nullptr)
776         {
777             sfree(groups->grpnr[i]);
778             groups->grpnr[i] = new_egrp[i];
779         }
780     }
781
782     /* remove empty molblocks */
783     RMmolblock = 0;
784     for (size_t i = 0; i < mtop->molblock.size(); i++)
785     {
786         if (mtop->molblock[i].nmol == 0)
787         {
788             RMmolblock++;
789         }
790         else
791         {
792             mtop->molblock[i-RMmolblock] = mtop->molblock[i];
793         }
794     }
795     mtop->molblock.resize(mtop->molblock.size() - RMmolblock);
796 }
797
798 /* remove al bonded interactions from mtop for the molecule to be embedded */
799 static int rm_bonded(t_block *ins_at, gmx_mtop_t *mtop)
800 {
801     int       j, m;
802     int       type, natom, nmol, at, atom1 = 0, rm_at = 0;
803     gmx_bool *bRM, bINS;
804     /*this routine lives dangerously by assuming that all molecules of a given type are in order in the structure*/
805     /*this routine does not live as dangerously as it seems. There is namely a check in init_membed to make *
806      * sure that g_membed exits with a warning when there are molecules of the same type not in the *
807      * ins_at index group. MGWolf 050710 */
808
809
810     snew(bRM, mtop->moltype.size());
811     for (size_t i = 0; i < mtop->moltype.size(); i++)
812     {
813         bRM[i] = TRUE;
814     }
815
816     for (size_t i = 0; i < mtop->molblock.size(); i++)
817     {
818         /*loop over molecule blocks*/
819         type         = mtop->molblock[i].type;
820         natom        = mtop->moltype[type].atoms.nr;
821         nmol         = mtop->molblock[i].nmol;
822
823         for (j = 0; j < natom*nmol && bRM[type]; j++)
824         {
825             /*loop over atoms in the block*/
826             at   = j+atom1; /*atom index = block index + offset*/
827             bINS = FALSE;
828
829             for (m = 0; (m < ins_at->nr) && (!bINS); m++)
830             {
831                 /*loop over atoms in insertion index group to determine if we're inserting one*/
832                 if (at == ins_at->index[m])
833                 {
834                     bINS = TRUE;
835                 }
836             }
837             bRM[type] = bINS;
838         }
839         atom1 += natom*nmol; /*update offset*/
840         if (bRM[type])
841         {
842             rm_at += natom*nmol; /*increment bonded removal counter by # atoms in block*/
843         }
844     }
845
846     for (size_t i = 0; i < mtop->moltype.size(); i++)
847     {
848         if (bRM[i])
849         {
850             for (j = 0; j < F_LJ; j++)
851             {
852                 mtop->moltype[i].ilist[j].iatoms.clear();
853             }
854
855             for (j = F_POSRES; j <= F_VSITEN; j++)
856             {
857                 mtop->moltype[i].ilist[j].iatoms.clear();
858             }
859         }
860     }
861     sfree(bRM);
862
863     return rm_at;
864 }
865
866 /* Write a topology where the number of molecules is correct for the system after embedding */
867 static void top_update(const char *topfile, rm_t *rm_p, gmx_mtop_t *mtop)
868 {
869     int        bMolecules         = 0;
870     FILE      *fpin, *fpout;
871     char       buf[STRLEN], buf2[STRLEN], *temp;
872     int        i, *nmol_rm, nmol, line;
873     char       temporary_filename[STRLEN];
874
875     fpin  = gmx_ffopen(topfile, "r");
876     strncpy(temporary_filename, "temp.topXXXXXX", STRLEN);
877     gmx_tmpnam(temporary_filename);
878     fpout = gmx_ffopen(temporary_filename, "w");
879
880     snew(nmol_rm, mtop->moltype.size());
881     for (i = 0; i < rm_p->nr; i++)
882     {
883         nmol_rm[rm_p->block[i]]++;
884     }
885
886     line = 0;
887     while (fgets(buf, STRLEN, fpin))
888     {
889         line++;
890         if (buf[0] != ';')
891         {
892             strcpy(buf2, buf);
893             if ((temp = strchr(buf2, '\n')) != nullptr)
894             {
895                 temp[0] = '\0';
896             }
897             ltrim(buf2);
898             if (buf2[0] == '[')
899             {
900                 buf2[0] = ' ';
901                 if ((temp = strchr(buf2, '\n')) != nullptr)
902                 {
903                     temp[0] = '\0';
904                 }
905                 rtrim(buf2);
906                 if (buf2[strlen(buf2)-1] == ']')
907                 {
908                     buf2[strlen(buf2)-1] = '\0';
909                     ltrim(buf2);
910                     rtrim(buf2);
911                     if (gmx_strcasecmp(buf2, "molecules") == 0)
912                     {
913                         bMolecules = 1;
914                     }
915                 }
916                 fprintf(fpout, "%s", buf);
917             }
918             else if (bMolecules == 1)
919             {
920                 for (size_t i = 0; i < mtop->molblock.size(); i++)
921                 {
922                     nmol = mtop->molblock[i].nmol;
923                     sprintf(buf, "%-15s %5d\n", *(mtop->moltype[mtop->molblock[i].type].name), nmol);
924                     fprintf(fpout, "%s", buf);
925                 }
926                 bMolecules = 2;
927             }
928             else if (bMolecules == 2)
929             {
930                 /* print nothing */
931             }
932             else
933             {
934                 fprintf(fpout, "%s", buf);
935             }
936         }
937         else
938         {
939             fprintf(fpout, "%s", buf);
940         }
941     }
942
943     gmx_ffclose(fpout);
944     /* use gmx_ffopen to generate backup of topinout */
945     fpout = gmx_ffopen(topfile, "w");
946     gmx_ffclose(fpout);
947     rename(temporary_filename, topfile);
948 }
949
950 void rescale_membed(int step_rel, gmx_membed_t *membed, rvec *x)
951 {
952     /* Set new positions for the group to embed */
953     if (step_rel <= membed->it_xy)
954     {
955         membed->fac[0] += membed->xy_step;
956         membed->fac[1] += membed->xy_step;
957     }
958     else if (step_rel <= (membed->it_xy+membed->it_z))
959     {
960         membed->fac[2] += membed->z_step;
961     }
962     resize(membed->r_ins, x, membed->pos_ins, membed->fac);
963 }
964
965 /* We would like gn to be const as well, but C doesn't allow this */
966 /* TODO this is utility functionality (search for the index of a
967    string in a collection), so should be refactored and located more
968    centrally. Also, it nearly duplicates the same string in readir.c */
969 static int search_string(const char *s, int ng, char *gn[])
970 {
971     int i;
972
973     for (i = 0; (i < ng); i++)
974     {
975         if (gmx_strcasecmp(s, gn[i]) == 0)
976         {
977             return i;
978         }
979     }
980
981     gmx_fatal(FARGS,
982               "Group %s selected for embedding was not found in the index file.\n"
983               "Group names must match either [moleculetype] names or custom index group\n"
984               "names, in which case you must supply an index file to the '-n' option\n"
985               "of grompp.",
986               s);
987 }
988
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)
991 {
992     char                     *ins, **gnames;
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, ntype, lip_rm;
995     real                      prot_area;
996     rvec                     *r_ins = nullptr;
997     t_block                  *ins_at, *rest_at;
998     pos_ins_t                *pos_ins;
999     mem_t                    *mem_p;
1000     rm_t                     *rm_p;
1001     gmx_groups_t             *groups;
1002     gmx_bool                  bExcl = FALSE;
1003     t_atoms                   atoms;
1004     t_pbc                    *pbc;
1005     char                    **piecename = nullptr;
1006     gmx_membed_t             *membed    = nullptr;
1007
1008     /* input variables */
1009     real        xy_fac           = 0.5;
1010     real        xy_max           = 1.0;
1011     real        z_fac            = 1.0;
1012     real        z_max            = 1.0;
1013     int         it_xy            = 1000;
1014     int         it_z             = 0;
1015     real        probe_rad        = 0.22;
1016     int         low_up_rm        = 0;
1017     int         maxwarn          = 0;
1018     int         pieces           = 1;
1019     gmx_bool    bALLOW_ASYMMETRY = FALSE;
1020
1021     /* sanity check constants */         /* Issue a warning when: */
1022     const real min_probe_rad  = 0.2199999; /* A probe radius for overlap between embedded molecule *
1023                                             * and rest smaller than this value is probably too small */
1024     const real min_xy_init    = 0.0999999; /* the initial shrinking of the molecule to embed is smaller */
1025     const int  min_it_xy      = 1000;      /* the number of steps to embed in xy-plane is smaller */
1026     const int  min_it_z       = 100;       /* the number of steps to embed in z is smaller */
1027     const real prot_vs_box    = 7.5;       /* molecule to embed is large (more then prot_vs_box) with respect */
1028     const real box_vs_prot    = 50;        /* to the box size (less than box_vs_prot) */
1029
1030     snew(membed, 1);
1031     snew(ins_at, 1);
1032     snew(pos_ins, 1);
1033
1034     if (MASTER(cr))
1035     {
1036         fprintf(fplog, "Note: it is expected that in future gmx mdrun -membed will not be the "
1037                 "way to access this feature, perhaps changing to e.g. gmx membed.");
1038         /* get input data out membed file */
1039         try
1040         {
1041             get_input(opt2fn("-membed", nfile, fnm),
1042                       &xy_fac, &xy_max, &z_fac, &z_max, &it_xy, &it_z, &probe_rad, &low_up_rm,
1043                       &maxwarn, &pieces, &bALLOW_ASYMMETRY);
1044         }
1045         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
1046
1047         if (!EI_DYNAMICS(inputrec->eI) )
1048         {
1049             gmx_input("Change integrator to a dynamics integrator in mdp file (e.g. md or sd).");
1050         }
1051
1052         if (PAR(cr))
1053         {
1054             gmx_input("Sorry, parallel membed is not yet fully functional.");
1055         }
1056
1057         if (*cpt >= 0)
1058         {
1059             fprintf(stderr, "\nSetting -cpt to -1, because embedding cannot be restarted from cpt-files.\n");
1060             *cpt = -1;
1061         }
1062         groups = &(mtop->groups);
1063         snew(gnames, groups->ngrpname);
1064         for (i = 0; i < groups->ngrpname; i++)
1065         {
1066             gnames[i] = *(groups->grpname[i]);
1067         }
1068
1069         atoms = gmx_mtop_global_atoms(mtop);
1070         snew(mem_p, 1);
1071         fprintf(stderr, "\nSelect a group to embed in the membrane:\n");
1072         get_index(&atoms, opt2fn_null("-mn", nfile, fnm), 1, &(ins_at->nr), &(ins_at->index), &ins);
1073         ins_grp_id = search_string(ins, groups->ngrpname, gnames);
1074         fprintf(stderr, "\nSelect a group to embed %s into (e.g. the membrane):\n", ins);
1075         get_index(&atoms, opt2fn_null("-mn", nfile, fnm), 1, &(mem_p->mem_at.nr), &(mem_p->mem_at.index), &(mem_p->name));
1076
1077         pos_ins->pieces = pieces;
1078         snew(pos_ins->nidx, pieces);
1079         snew(pos_ins->subindex, pieces);
1080         snew(piecename, pieces);
1081         if (pieces > 1)
1082         {
1083             fprintf(stderr, "\nSelect pieces to embed:\n");
1084             get_index(&atoms, opt2fn_null("-mn", nfile, fnm), pieces, pos_ins->nidx, pos_ins->subindex, piecename);
1085         }
1086         else
1087         {
1088             /*use whole embedded group*/
1089             snew(pos_ins->nidx, 1);
1090             snew(pos_ins->subindex, 1);
1091             pos_ins->nidx[0]     = ins_at->nr;
1092             pos_ins->subindex[0] = ins_at->index;
1093         }
1094
1095         if (probe_rad < min_probe_rad)
1096         {
1097             warn++;
1098             fprintf(stderr, "\nWarning %d:\nA probe radius (-rad) smaller than 0.2 nm can result "
1099                     "in overlap between waters and the group to embed, which will result "
1100                     "in Lincs errors etc.\n\n", warn);
1101         }
1102
1103         if (xy_fac < min_xy_init)
1104         {
1105             warn++;
1106             fprintf(stderr, "\nWarning %d:\nThe initial size of %s is probably too small.\n\n", warn, ins);
1107         }
1108
1109         if (it_xy < min_it_xy)
1110         {
1111             warn++;
1112             fprintf(stderr, "\nWarning %d;\nThe number of steps used to grow the xy-coordinates of %s (%d)"
1113                     " is probably too small.\nIncrease -nxy or.\n\n", warn, ins, it_xy);
1114         }
1115
1116         if ( (it_z < min_it_z) && ( z_fac < 0.99999999 || z_fac > 1.0000001) )
1117         {
1118             warn++;
1119             fprintf(stderr, "\nWarning %d;\nThe number of steps used to grow the z-coordinate of %s (%d)"
1120                     " is probably too small.\nIncrease -nz or the maxwarn setting in the membed input file.\n\n", warn, ins, it_z);
1121         }
1122
1123         if (it_xy+it_z > inputrec->nsteps)
1124         {
1125             warn++;
1126             fprintf(stderr, "\nWarning %d:\nThe number of growth steps (-nxy + -nz) is larger than the "
1127                     "number of steps in the tpr.\n"
1128                     "(increase maxwarn in the membed input file to override)\n\n", warn);
1129         }
1130
1131         fr_id = -1;
1132         if (inputrec->opts.ngfrz == 1)
1133         {
1134             gmx_fatal(FARGS, "You did not specify \"%s\" as a freezegroup.", ins);
1135         }
1136
1137         for (i = 0; i < inputrec->opts.ngfrz; i++)
1138         {
1139             tmp_id = mtop->groups.grps[egcFREEZE].nm_ind[i];
1140             if (ins_grp_id == tmp_id)
1141             {
1142                 fr_id = tmp_id;
1143                 fr_i  = i;
1144             }
1145         }
1146
1147         if (fr_id == -1)
1148         {
1149             gmx_fatal(FARGS, "\"%s\" not as freezegroup defined in the mdp-file.", ins);
1150         }
1151
1152         for (i = 0; i < DIM; i++)
1153         {
1154             if (inputrec->opts.nFreeze[fr_i][i] != 1)
1155             {
1156                 gmx_fatal(FARGS, "freeze dimensions for %s are not Y Y Y\n", ins);
1157             }
1158         }
1159
1160         ng = groups->grps[egcENER].nr;
1161         if (ng == 1)
1162         {
1163             gmx_input("No energy groups defined. This is necessary for energy exclusion in the freeze group");
1164         }
1165
1166         for (i = 0; i < ng; i++)
1167         {
1168             for (j = 0; j < ng; j++)
1169             {
1170                 if (inputrec->opts.egp_flags[ng*i+j] == EGP_EXCL)
1171                 {
1172                     bExcl = TRUE;
1173                     if ( (groups->grps[egcENER].nm_ind[i] != ins_grp_id) ||
1174                          (groups->grps[egcENER].nm_ind[j] != ins_grp_id) )
1175                     {
1176                         gmx_fatal(FARGS, "Energy exclusions \"%s\" and  \"%s\" do not match the group "
1177                                   "to embed \"%s\"", *groups->grpname[groups->grps[egcENER].nm_ind[i]],
1178                                   *groups->grpname[groups->grps[egcENER].nm_ind[j]], ins);
1179                     }
1180                 }
1181             }
1182         }
1183
1184         if (!bExcl)
1185         {
1186             gmx_input("No energy exclusion groups defined. This is necessary for energy exclusion in "
1187                       "the freeze group");
1188         }
1189
1190         /* Obtain the maximum and minimum coordinates of the group to be embedded */
1191         snew(rest_at, 1);
1192         init_ins_at(ins_at, rest_at, state, pos_ins, groups, ins_grp_id, xy_max);
1193         /* Check that moleculetypes in insertion group are not part of the rest of the system */
1194         check_types(ins_at, rest_at, mtop);
1195
1196         init_mem_at(mem_p, mtop, state->x.rvec_array(), state->box, pos_ins);
1197
1198         prot_area = est_prot_area(pos_ins, state->x.rvec_array(), ins_at, mem_p);
1199         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) )
1200         {
1201             warn++;
1202             fprintf(stderr, "\nWarning %d:\nThe xy-area is very small compared to the area of the protein.\n"
1203                     "This might cause pressure problems during the growth phase. Just try with\n"
1204                     "current setup and increase 'maxwarn' in your membed settings file, but lower the\n"
1205                     "compressibility in the mdp-file or disable pressure coupling if problems occur.\n\n", warn);
1206         }
1207
1208         if (warn > maxwarn)
1209         {
1210             gmx_fatal(FARGS, "Too many warnings (override by setting maxwarn in the membed input file)\n");
1211         }
1212
1213         printf("The estimated area of the protein in the membrane is %.3f nm^2\n", prot_area);
1214         printf("\nThere are %d lipids in the membrane part that overlaps the protein.\n"
1215                "The area per lipid is %.4f nm^2.\n", mem_p->nmol, mem_p->lip_area);
1216
1217         /* Maximum number of lipids to be removed*/
1218         max_lip_rm = static_cast<int>(2*prot_area/mem_p->lip_area);
1219         printf("Maximum number of lipids that will be removed is %d.\n", max_lip_rm);
1220
1221         printf("\nWill resize the protein by a factor of %.3f in the xy plane and %.3f in the z direction.\n"
1222                "This resizing will be done with respect to the geometrical center of all protein atoms\n"
1223                "that span the membrane region, i.e. z between %.3f and %.3f\n\n",
1224                xy_fac, z_fac, mem_p->zmin, mem_p->zmax);
1225
1226         /* resize the protein by xy and by z if necessary*/
1227         snew(r_ins, ins_at->nr);
1228         init_resize(ins_at, r_ins, pos_ins, mem_p, state->x.rvec_array(), bALLOW_ASYMMETRY);
1229         membed->fac[0] = membed->fac[1] = xy_fac;
1230         membed->fac[2] = z_fac;
1231
1232         membed->xy_step = (xy_max-xy_fac)/static_cast<double>(it_xy);
1233         membed->z_step  = (z_max-z_fac)/static_cast<double>(it_z-1);
1234
1235         resize(r_ins, state->x.rvec_array(), pos_ins, membed->fac);
1236
1237         /* remove overlapping lipids and water from the membrane box*/
1238         /*mark molecules to be removed*/
1239         snew(pbc, 1);
1240         set_pbc(pbc, inputrec->ePBC, state->box);
1241
1242         snew(rm_p, 1);
1243         lip_rm = gen_rm_list(rm_p, ins_at, rest_at, pbc, mtop, state->x.rvec_array(), mem_p, pos_ins,
1244                              probe_rad, low_up_rm, bALLOW_ASYMMETRY);
1245         lip_rm -= low_up_rm;
1246
1247         if (fplog)
1248         {
1249             for (i = 0; i < rm_p->nr; i++)
1250             {
1251                 fprintf(fplog, "rm mol %d\n", rm_p->mol[i]);
1252             }
1253         }
1254
1255         for (size_t i = 0; i < mtop->molblock.size(); i++)
1256         {
1257             ntype = 0;
1258             for (j = 0; j < rm_p->nr; j++)
1259             {
1260                 if (rm_p->block[j] == static_cast<int>(i))
1261                 {
1262                     ntype++;
1263                 }
1264             }
1265             printf("Will remove %d %s molecules\n", ntype, *(mtop->moltype[mtop->molblock[i].type].name));
1266         }
1267
1268         if (lip_rm > max_lip_rm)
1269         {
1270             warn++;
1271             fprintf(stderr, "\nWarning %d:\nTrying to remove a larger lipid area than the estimated "
1272                     "protein area\nTry making the -xyinit resize factor smaller or increase "
1273                     "maxwarn in the membed input file.\n\n", warn);
1274         }
1275
1276         /*remove all lipids and waters overlapping and update all important structures*/
1277         rm_group(groups, mtop, rm_p, state, ins_at, pos_ins);
1278
1279         rm_bonded_at = rm_bonded(ins_at, mtop);
1280         if (rm_bonded_at != ins_at->nr)
1281         {
1282             fprintf(stderr, "Warning: The number of atoms for which the bonded interactions are removed is %d, "
1283                     "while %d atoms are embedded. Make sure that the atoms to be embedded are not in the same"
1284                     "molecule type as atoms that are not to be embedded.\n", rm_bonded_at, ins_at->nr);
1285         }
1286
1287         if (warn > maxwarn)
1288         {
1289             gmx_fatal(FARGS, "Too many warnings.\nIf you are sure these warnings are harmless,\n"
1290                       "you can increase the maxwarn setting in the membed input file.");
1291         }
1292
1293         // Re-establish the invariants of the derived values within
1294         // mtop.
1295         gmx_mtop_finalize(mtop);
1296
1297         if (ftp2bSet(efTOP, nfile, fnm))
1298         {
1299             top_update(opt2fn("-mp", nfile, fnm), rm_p, mtop);
1300         }
1301
1302         sfree(pbc);
1303         sfree(rest_at);
1304         if (pieces > 1)
1305         {
1306             sfree(piecename);
1307         }
1308
1309         membed->it_xy   = it_xy;
1310         membed->it_z    = it_z;
1311         membed->pos_ins = pos_ins;
1312         membed->r_ins   = r_ins;
1313     }
1314
1315     return membed;
1316 }
1317
1318 void free_membed(gmx_membed_t *membed)
1319 {
1320     sfree(membed);
1321 }