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