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