コード例 #1
0
CorrelationDataSet::CorrelationDataSet(const std::string &fileName)
{
    std::string fileNm = gmx::test::TestFileManager::getInputFilePath(fileName.c_str());
    nrLines_    = read_xvg(fileNm.c_str(), &tempValues_, &nrColumns_);

    dt_         = tempValues_[0][1] - tempValues_[0][0];
    startTime_  = tempValues_[0][0];
    endTime_    = tempValues_[0][nrLines_-1];
}
コード例 #2
0
ファイル: gmx_make_edi.c プロジェクト: drmaruyama/gromacs
void read_eigenvalues(int vecs[], const char *eigfile, real values[],
                      gmx_bool bHesse, real kT)
{
    int      neig, nrow, i;
    double **eigval;

    neig = read_xvg(eigfile, &eigval, &nrow);

    fprintf(stderr, "Read %d eigenvalues\n", neig);
    for (i = bHesse ? 6 : 0; i < neig; i++)
    {
        if (eigval[1][i] < -0.001 && bHesse)
        {
            fprintf(stderr,
                    "WARNING: The Hessian Matrix has negative eigenvalue %f, we set it to zero (no flooding in this direction)\n\n", eigval[1][i]);
        }

        if (eigval[1][i] < 0)
        {
            eigval[1][i] = 0;
        }
    }
    if (bHesse)
    {
        for (i = 0; vecs[i]; i++)
        {
            if (vecs[i] < 7)
            {
                gmx_fatal(FARGS, "ERROR: You have chosen one of the first 6 eigenvectors of the HESSE Matrix. That does not make sense, since they correspond to the 6 rotational and translational degrees of freedom.\n\n");
            }
            values[i] = eigval[1][vecs[i]-1]/kT;
        }
    }
    else
    {
        for (i = 0; vecs[i]; i++)
        {
            if (vecs[i] > (neig-6))
            {
                gmx_fatal(FARGS, "ERROR: You have chosen one of the last 6 eigenvectors of the COVARIANCE Matrix. That does not make sense, since they correspond to the 6 rotational and translational degrees of freedom.\n\n");
            }
            values[i] = 1/eigval[1][vecs[i]-1];
        }
    }
    /* free memory */
    for (i = 0; i < nrow; i++)
    {
        sfree(eigval[i]);
    }
    sfree(eigval);
}
コード例 #3
0
ファイル: tables.c プロジェクト: Chadi-akel/cere
static void read_tables(FILE *fp,char *fn,t_tabledata td[])
{
  char *libfn;
  real **yy=NULL;
  int  k,i,nx,nx0,ny,nny;
  bool bCont;
  real tabscale;

  nny = 2*etiNR+1;  
  libfn = low_libfn(fn,TRUE);
  nx  = read_xvg(libfn,&yy,&ny);
  if (ny != nny)
    fatal_error(0,"Trying to read file %s, but nr columns = %d, should be %d",
		libfn,ny,nny);
  bCont = TRUE;
  for(nx0=0; bCont && (nx0 < nx); nx0++)
    for(k=1; (k<ny); k++)
      if (fabs(yy[k][nx0]) > GMX_REAL_MIN)
	bCont = FALSE;
  if (nx0 == nx)
    fatal_error(0,"All elements in table %s are zero!\n",libfn);
    
  tabscale = (nx-1)/(yy[0][nx-1] - yy[0][0]);
  for(k=0; (k<etiNR); k++) {
    init_table(fp,nx,nx0,etabUSER,tabscale,&(td[k]),TRUE);
    for(i=0; (i<nx); i++) {
      td[k].x[i]  = yy[0][i];
      td[k].v[i]  = yy[2*k+1][i];
      td[k].v2[i] = yy[2*k+2][i];
    }
  }
  for(i=0; (i<ny); i++)
    sfree(yy[i]);
  sfree(yy);
  
  if (fp) 
    fprintf(fp,"Read user tables from %s with %d data points.\n"
	    "Tabscale = %g points/nm\n",libfn,nx,tabscale);
}
コード例 #4
0
ファイル: gmx_dielectric.c プロジェクト: exianshine/gromacs
int gmx_dielectric(int argc, char *argv[])
{
    const char  *desc[] = {
        "[THISMODULE] calculates frequency dependent dielectric constants",
        "from the autocorrelation function of the total dipole moment in",
        "your simulation. This ACF can be generated by [gmx-dipoles].",
        "The functional forms of the available functions are:[PAR]",
        "One parameter:    y = [EXP]-a[SUB]1[sub] x[exp],[BR]",
        "Two parameters:   y = a[SUB]2[sub] [EXP]-a[SUB]1[sub] x[exp],[BR]",
        "Three parameters: y = a[SUB]2[sub] [EXP]-a[SUB]1[sub] x[exp] + (1 - a[SUB]2[sub]) [EXP]-a[SUB]3[sub] x[exp].[BR]",
        "Start values for the fit procedure can be given on the command line.",
        "It is also possible to fix parameters at their start value, use [TT]-fix[tt]",
        "with the number of the parameter you want to fix.",
        "[PAR]",
        "Three output files are generated, the first contains the ACF,",
        "an exponential fit to it with 1, 2 or 3 parameters, and the",
        "numerical derivative of the combination data/fit.",
        "The second file contains the real and imaginary parts of the",
        "frequency-dependent dielectric constant, the last gives a plot",
        "known as the Cole-Cole plot, in which the imaginary",
        "component is plotted as a function of the real component.",
        "For a pure exponential relaxation (Debye relaxation) the latter",
        "plot should be one half of a circle."
    };
    t_filenm     fnm[] = {
        { efXVG, "-f", "dipcorr", ffREAD  },
        { efXVG, "-d", "deriv",  ffWRITE },
        { efXVG, "-o", "epsw",   ffWRITE },
        { efXVG, "-c", "cole",   ffWRITE }
    };
#define NFILE asize(fnm)
    output_env_t oenv;
    int          i, j, nx, ny, nxtail, eFitFn, nfitparm;
    real         dt, integral, fitintegral, *fitparms, fac, rffac;
    double     **yd;
    real       **y;
    const char  *legend[] = { "Correlation", "Std. Dev.", "Fit", "Combined", "Derivative" };
    static int   fix      = 0, bFour = 0, bX = 1, nsmooth = 3;
    static real  tendInt  = 5.0, tbegin = 5.0, tend = 500.0;
    static real  A        = 0.5, tau1 = 10.0, tau2 = 1.0, eps0 = 80, epsRF = 78.5, tail = 500.0;
    real         lambda;
    t_pargs      pa[] = {
        { "-fft", FALSE, etBOOL, {&bFour},
          "use fast fourier transform for correlation function" },
        { "-x1",  FALSE, etBOOL, {&bX},
          "use first column as [IT]x[it]-axis rather than first data set" },
        { "-eint", FALSE, etREAL, {&tendInt},
          "Time to end the integration of the data and start to use the fit"},
        { "-bfit", FALSE, etREAL, {&tbegin},
          "Begin time of fit" },
        { "-efit", FALSE, etREAL, {&tend},
          "End time of fit" },
        { "-tail", FALSE, etREAL, {&tail},
          "Length of function including data and tail from fit" },
        { "-A", FALSE, etREAL, {&A},
          "Start value for fit parameter A" },
        { "-tau1", FALSE, etREAL, {&tau1},
          "Start value for fit parameter [GRK]tau[grk]1" },
        { "-tau2", FALSE, etREAL, {&tau2},
          "Start value for fit parameter [GRK]tau[grk]2" },
        { "-eps0", FALSE, etREAL, {&eps0},
          "[GRK]epsilon[grk]0 of your liquid" },
        { "-epsRF", FALSE, etREAL, {&epsRF},
          "[GRK]epsilon[grk] of the reaction field used in your simulation. A value of 0 means infinity." },
        { "-fix", FALSE, etINT,  {&fix},
          "Fix parameters at their start values, A (2), tau1 (1), or tau2 (4)" },
        { "-ffn",    FALSE, etENUM, {s_ffn},
          "Fit function" },
        { "-nsmooth", FALSE, etINT, {&nsmooth},
          "Number of points for smoothing" }
    };

    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW | PCA_BE_NICE,
                           NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv))
    {
        return 0;
    }
    please_cite(stdout, "Spoel98a");
    printf("WARNING: non-polarizable models can never yield an infinite\n"
           "dielectric constant that is different from 1. This is incorrect\n"
           "in the reference given above (Spoel98a).\n\n");


    nx     = read_xvg(opt2fn("-f", NFILE, fnm), &yd, &ny);
    dt     = yd[0][1] - yd[0][0];
    nxtail = min(tail/dt, nx);

    printf("Read data set containing %d colums and %d rows\n", ny, nx);
    printf("Assuming (from data) that timestep is %g, nxtail = %d\n",
           dt, nxtail);
    snew(y, 6);
    for (i = 0; (i < ny); i++)
    {
        snew(y[i], max(nx, nxtail));
    }
    for (i = 0; (i < nx); i++)
    {
        y[0][i] = yd[0][i];
        for (j = 1; (j < ny); j++)
        {
            y[j][i] = yd[j][i];
        }
    }
    if (nxtail > nx)
    {
        for (i = nx; (i < nxtail); i++)
        {
            y[0][i] = dt*i+y[0][0];
            for (j = 1; (j < ny); j++)
            {
                y[j][i] = 0.0;
            }
        }
        nx = nxtail;
    }


    /* We have read a file WITHOUT standard deviations, so we make our own... */
    if (ny == 2)
    {
        printf("Creating standard deviation numbers ...\n");
        srenew(y, 3);
        snew(y[2], nx);

        fac = 1.0/((real)nx);
        for (i = 0; (i < nx); i++)
        {
            y[2][i] = fac;
        }
    }

    eFitFn   = sffn2effn(s_ffn);
    nfitparm = nfp_ffn[eFitFn];
    snew(fitparms, 4);
    fitparms[0] = tau1;
    if (nfitparm > 1)
    {
        fitparms[1] = A;
    }
    if (nfitparm > 2)
    {
        fitparms[2] = tau2;
    }


    snew(y[3], nx);
    snew(y[4], nx);
    snew(y[5], nx);

    integral = print_and_integrate(NULL, calc_nbegin(nx, y[0], tbegin),
                                   dt, y[1], NULL, 1);
    integral += do_lmfit(nx, y[1], y[2], dt, y[0], tbegin, tend,
                         oenv, TRUE, eFitFn, fitparms, fix);
    for (i = 0; i < nx; i++)
    {
        y[3][i] = fit_function(eFitFn, fitparms, y[0][i]);
    }

    if (epsRF == 0)
    {
        /* This means infinity! */
        lambda = 0;
        rffac  = 1;
    }
    else
    {
        lambda = (eps0 - 1.0)/(2*epsRF - 1.0);
        rffac  = (2*epsRF+eps0)/(2*epsRF+1);
    }
    printf("DATA INTEGRAL: %5.1f, tauD(old) = %5.1f ps, "
           "tau_slope = %5.1f, tau_slope,D = %5.1f ps\n",
           integral, integral*rffac, fitparms[0], fitparms[0]*rffac);

    printf("tau_D from tau1 = %8.3g , eps(Infty) = %8.3f\n",
           fitparms[0]*(1 + fitparms[1]*lambda),
           1 + ((1 - fitparms[1])*(eps0 - 1))/(1 + fitparms[1]*lambda));

    fitintegral = numerical_deriv(nx, y[0], y[1], y[3], y[4], y[5], tendInt, nsmooth);
    printf("FIT INTEGRAL (tau_M): %5.1f, tau_D = %5.1f\n",
           fitintegral, fitintegral*rffac);

    /* Now we have the negative gradient of <Phi(0) Phi(t)> */
    write_xvg(opt2fn("-d", NFILE, fnm), "Data", nx-1, 6, y, legend, oenv);

    /* Do FFT and analysis */
    do_four(opt2fn("-o", NFILE, fnm), opt2fn("-c", NFILE, fnm),
            nx-1, y[0], y[5], eps0, epsRF, oenv);

    do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy");
    do_view(oenv, opt2fn("-c", NFILE, fnm), NULL);
    do_view(oenv, opt2fn("-d", NFILE, fnm), "-nxy");

    return 0;
}
コード例 #5
0
ファイル: gmx_anaeig.c プロジェクト: martinhoefling/gromacs
int gmx_anaeig(int argc,char *argv[])
{
  static const char *desc[] = {
    "[TT]g_anaeig[tt] analyzes eigenvectors. The eigenvectors can be of a",
    "covariance matrix ([TT]g_covar[tt]) or of a Normal Modes analysis",
    "([TT]g_nmeig[tt]).[PAR]",
    
    "When a trajectory is projected on eigenvectors, all structures are",
    "fitted to the structure in the eigenvector file, if present, otherwise",
    "to the structure in the structure file. When no run input file is",
    "supplied, periodicity will not be taken into account. Most analyses",
    "are performed on eigenvectors [TT]-first[tt] to [TT]-last[tt], but when",
    "[TT]-first[tt] is set to -1 you will be prompted for a selection.[PAR]",
    
    "[TT]-comp[tt]: plot the vector components per atom of eigenvectors",
    "[TT]-first[tt] to [TT]-last[tt].[PAR]",
    
    "[TT]-rmsf[tt]: plot the RMS fluctuation per atom of eigenvectors",
    "[TT]-first[tt] to [TT]-last[tt] (requires [TT]-eig[tt]).[PAR]",

    "[TT]-proj[tt]: calculate projections of a trajectory on eigenvectors",
    "[TT]-first[tt] to [TT]-last[tt].",
    "The projections of a trajectory on the eigenvectors of its",
    "covariance matrix are called principal components (pc's).",
    "It is often useful to check the cosine content of the pc's,",
    "since the pc's of random diffusion are cosines with the number",
    "of periods equal to half the pc index.",
    "The cosine content of the pc's can be calculated with the program",
    "[TT]g_analyze[tt].[PAR]",
    
    "[TT]-2d[tt]: calculate a 2d projection of a trajectory on eigenvectors",
    "[TT]-first[tt] and [TT]-last[tt].[PAR]",
    
    "[TT]-3d[tt]: calculate a 3d projection of a trajectory on the first",
    "three selected eigenvectors.[PAR]",
    
    "[TT]-filt[tt]: filter the trajectory to show only the motion along",
    "eigenvectors [TT]-first[tt] to [TT]-last[tt].[PAR]",
    
    "[TT]-extr[tt]: calculate the two extreme projections along a trajectory",
    "on the average structure and interpolate [TT]-nframes[tt] frames",
    "between them, or set your own extremes with [TT]-max[tt]. The",
    "eigenvector [TT]-first[tt] will be written unless [TT]-first[tt] and",
    "[TT]-last[tt] have been set explicitly, in which case all eigenvectors",
    "will be written to separate files. Chain identifiers will be added",
    "when writing a [TT].pdb[tt] file with two or three structures (you",
    "can use [TT]rasmol -nmrpdb[tt] to view such a [TT].pdb[tt] file).[PAR]",
    
    "  Overlap calculations between covariance analysis:[BR]",
    "  [BB]Note:[bb] the analysis should use the same fitting structure[PAR]",
    
    "[TT]-over[tt]: calculate the subspace overlap of the eigenvectors in",
    "file [TT]-v2[tt] with eigenvectors [TT]-first[tt] to [TT]-last[tt]",
    "in file [TT]-v[tt].[PAR]",
    
    "[TT]-inpr[tt]: calculate a matrix of inner-products between",
    "eigenvectors in files [TT]-v[tt] and [TT]-v2[tt]. All eigenvectors",
    "of both files will be used unless [TT]-first[tt] and [TT]-last[tt]",
    "have been set explicitly.[PAR]",
    
    "When [TT]-v[tt], [TT]-eig[tt], [TT]-v2[tt] and [TT]-eig2[tt] are given,",
    "a single number for the overlap between the covariance matrices is",
    "generated. The formulas are:[BR]",
    "        difference = sqrt(tr((sqrt(M1) - sqrt(M2))^2))[BR]",
    "normalized overlap = 1 - difference/sqrt(tr(M1) + tr(M2))[BR]",
    "     shape overlap = 1 - sqrt(tr((sqrt(M1/tr(M1)) - sqrt(M2/tr(M2)))^2))[BR]",
    "where M1 and M2 are the two covariance matrices and tr is the trace",
    "of a matrix. The numbers are proportional to the overlap of the square",
    "root of the fluctuations. The normalized overlap is the most useful",
    "number, it is 1 for identical matrices and 0 when the sampled",
    "subspaces are orthogonal.[PAR]",
    "When the [TT]-entropy[tt] flag is given an entropy estimate will be",
    "computed based on the Quasiharmonic approach and based on",
    "Schlitter's formula."
  };
  static int  first=1,last=-1,skip=1,nextr=2,nskip=6;
  static real max=0.0,temp=298.15;
  static gmx_bool bSplit=FALSE,bEntropy=FALSE;
  t_pargs pa[] = {
    { "-first", FALSE, etINT, {&first},     
      "First eigenvector for analysis (-1 is select)" },
    { "-last",  FALSE, etINT, {&last}, 
      "Last eigenvector for analysis (-1 is till the last)" },
    { "-skip",  FALSE, etINT, {&skip},
      "Only analyse every nr-th frame" },
    { "-max",  FALSE, etREAL, {&max}, 
      "Maximum for projection of the eigenvector on the average structure, "
      "max=0 gives the extremes" },
    { "-nframes",  FALSE, etINT, {&nextr}, 
      "Number of frames for the extremes output" },
    { "-split",   FALSE, etBOOL, {&bSplit},
      "Split eigenvector projections where time is zero" },
    { "-entropy", FALSE, etBOOL, {&bEntropy},
      "Compute entropy according to the Quasiharmonic formula or Schlitter's method." },
    { "-temp",    FALSE, etREAL, {&temp},
      "Temperature for entropy calculations" },
    { "-nevskip", FALSE, etINT, {&nskip},
      "Number of eigenvalues to skip when computing the entropy due to the quasi harmonic approximation. When you do a rotational and/or translational fit prior to the covariance analysis, you get 3 or 6 eigenvalues that are very close to zero, and which should not be taken into account when computing the entropy." }
  };
#define NPA asize(pa)
  
  FILE       *out;
  int        status,trjout;
  t_topology top;
  int        ePBC=-1;
  t_atoms    *atoms=NULL;
  rvec       *xtop,*xref1,*xref2,*xrefp=NULL;
  gmx_bool       bDMR1,bDMA1,bDMR2,bDMA2;
  int        nvec1,nvec2,*eignr1=NULL,*eignr2=NULL;
  rvec       *x,*xread,*xav1,*xav2,**eigvec1=NULL,**eigvec2=NULL;
  matrix     topbox;
  real       xid,totmass,*sqrtm,*w_rls,t,lambda;
  int        natoms,step;
  char       *grpname;
  const char *indexfile;
  char       title[STRLEN];
  int        i,j,d;
  int        nout,*iout,noutvec,*outvec,nfit;
  atom_id    *index,*ifit;
  const char *VecFile,*Vec2File,*topfile;
  const char *EigFile,*Eig2File;
  const char *CompFile,*RmsfFile,*ProjOnVecFile;
  const char *TwoDPlotFile,*ThreeDPlotFile;
  const char *FilterFile,*ExtremeFile;
  const char *OverlapFile,*InpMatFile;
  gmx_bool       bFit1,bFit2,bM,bIndex,bTPS,bTop,bVec2,bProj;
  gmx_bool       bFirstToLast,bFirstLastSet,bTraj,bCompare,bPDB3D;
  real       *eigval1=NULL,*eigval2=NULL;
  int        neig1,neig2;
  double     **xvgdata;
  output_env_t oenv;
  gmx_rmpbc_t  gpbc;

  t_filenm fnm[] = { 
    { efTRN, "-v",    "eigenvec",    ffREAD  },
    { efTRN, "-v2",   "eigenvec2",   ffOPTRD },
    { efTRX, "-f",    NULL,          ffOPTRD }, 
    { efTPS, NULL,    NULL,          ffOPTRD },
    { efNDX, NULL,    NULL,          ffOPTRD },
    { efXVG, "-eig", "eigenval",     ffOPTRD },
    { efXVG, "-eig2", "eigenval2",   ffOPTRD },
    { efXVG, "-comp", "eigcomp",     ffOPTWR },
    { efXVG, "-rmsf", "eigrmsf",     ffOPTWR },
    { efXVG, "-proj", "proj",        ffOPTWR },
    { efXVG, "-2d",   "2dproj",      ffOPTWR },
    { efSTO, "-3d",   "3dproj.pdb",  ffOPTWR },
    { efTRX, "-filt", "filtered",    ffOPTWR },
    { efTRX, "-extr", "extreme.pdb", ffOPTWR },
    { efXVG, "-over", "overlap",     ffOPTWR },
    { efXPM, "-inpr", "inprod",      ffOPTWR }
  }; 
#define NFILE asize(fnm) 

  parse_common_args(&argc,argv,
                    PCA_CAN_TIME | PCA_TIME_UNIT | PCA_CAN_VIEW | PCA_BE_NICE ,
		    NFILE,fnm,NPA,pa,asize(desc),desc,0,NULL,&oenv); 

  indexfile=ftp2fn_null(efNDX,NFILE,fnm);

  VecFile         = opt2fn("-v",NFILE,fnm);
  Vec2File        = opt2fn_null("-v2",NFILE,fnm);
  topfile         = ftp2fn(efTPS,NFILE,fnm); 
  EigFile         = opt2fn_null("-eig",NFILE,fnm);
  Eig2File        = opt2fn_null("-eig2",NFILE,fnm);
  CompFile        = opt2fn_null("-comp",NFILE,fnm);
  RmsfFile        = opt2fn_null("-rmsf",NFILE,fnm);
  ProjOnVecFile   = opt2fn_null("-proj",NFILE,fnm);
  TwoDPlotFile    = opt2fn_null("-2d",NFILE,fnm);
  ThreeDPlotFile  = opt2fn_null("-3d",NFILE,fnm);
  FilterFile      = opt2fn_null("-filt",NFILE,fnm);
  ExtremeFile     = opt2fn_null("-extr",NFILE,fnm);
  OverlapFile     = opt2fn_null("-over",NFILE,fnm);
  InpMatFile      = ftp2fn_null(efXPM,NFILE,fnm);
  
  bTop   = fn2bTPX(topfile);
  bProj  = ProjOnVecFile || TwoDPlotFile || ThreeDPlotFile 
    || FilterFile || ExtremeFile;
  bFirstLastSet  = 
    opt2parg_bSet("-first",NPA,pa) && opt2parg_bSet("-last",NPA,pa);
  bFirstToLast = CompFile || RmsfFile || ProjOnVecFile || FilterFile ||
    OverlapFile || ((ExtremeFile || InpMatFile) && bFirstLastSet);
  bVec2  = Vec2File || OverlapFile || InpMatFile;
  bM     = RmsfFile || bProj;
  bTraj  = ProjOnVecFile || FilterFile || (ExtremeFile && (max==0))
    || TwoDPlotFile || ThreeDPlotFile;
  bIndex = bM || bProj;
  bTPS   = ftp2bSet(efTPS,NFILE,fnm) || bM || bTraj ||
    FilterFile  || (bIndex && indexfile);
  bCompare = Vec2File || Eig2File;
  bPDB3D = fn2ftp(ThreeDPlotFile)==efPDB;
  
  read_eigenvectors(VecFile,&natoms,&bFit1,
		    &xref1,&bDMR1,&xav1,&bDMA1,
		    &nvec1,&eignr1,&eigvec1,&eigval1);
  neig1 = DIM*natoms;
  
  /* Overwrite eigenvalues from separate files if the user provides them */
  if (EigFile != NULL) {
    int neig_tmp = read_xvg(EigFile,&xvgdata,&i);
    if (neig_tmp != neig1)
      fprintf(stderr,"Warning: number of eigenvalues in xvg file (%d) does not mtch trr file (%d)\n",neig1,natoms);
    neig1 = neig_tmp;
    srenew(eigval1,neig1);
    for(j=0;j<neig1;j++) {
      real tmp = eigval1[j];
      eigval1[j]=xvgdata[1][j];
      if (debug && (eigval1[j] != tmp))
	fprintf(debug,"Replacing eigenvalue %d. From trr: %10g, from xvg: %10g\n",
		j,tmp,eigval1[j]);
    }
    for(j=0;j<i;j++)
      sfree(xvgdata[j]);
    sfree(xvgdata);
    fprintf(stderr,"Read %d eigenvalues from %s\n",neig1,EigFile);
  }
    
  if (bEntropy) {
    if (bDMA1) {
      gmx_fatal(FARGS,"Can not calculate entropies from mass-weighted eigenvalues, redo the analysis without mass-weighting");
    }
    calc_entropy_qh(stdout,neig1,eigval1,temp,nskip);
    calc_entropy_schlitter(stdout,neig1,nskip,eigval1,temp);
  }
  
  if (bVec2) {
    if (!Vec2File)
      gmx_fatal(FARGS,"Need a second eigenvector file to do this analysis.");
    read_eigenvectors(Vec2File,&neig2,&bFit2,
		      &xref2,&bDMR2,&xav2,&bDMA2,&nvec2,&eignr2,&eigvec2,&eigval2);
    
    neig2 = DIM*neig2;
    if (neig2 != neig1)
      gmx_fatal(FARGS,"Dimensions in the eigenvector files don't match");
  }
  
  if(Eig2File != NULL) {
    neig2 = read_xvg(Eig2File,&xvgdata,&i);
    srenew(eigval2,neig2);
    for(j=0;j<neig2;j++)
      eigval2[j]=xvgdata[1][j];
    for(j=0;j<i;j++)
      sfree(xvgdata[j]);
    sfree(xvgdata);
    fprintf(stderr,"Read %d eigenvalues from %s\n",neig2,Eig2File);      
  }
  
  
  if ((!bFit1 || xref1) && !bDMR1 && !bDMA1) 
    bM=FALSE;
  if ((xref1==NULL) && (bM || bTraj))
    bTPS=TRUE;
  
  xtop=NULL;
  nfit=0;
  ifit=NULL;
  w_rls=NULL;

  if (!bTPS) {
    bTop=FALSE;
  } else {
    bTop=read_tps_conf(ftp2fn(efTPS,NFILE,fnm),
		       title,&top,&ePBC,&xtop,NULL,topbox,bM);
    atoms=&top.atoms;
    gpbc = gmx_rmpbc_init(&top.idef,ePBC,atoms->nr,topbox);
    gmx_rmpbc(gpbc,atoms->nr,topbox,xtop);
    /* Fitting is only required for the projection */ 
    if (bProj && bFit1) {
      if (xref1 == NULL) {
	  printf("\nNote: the structure in %s should be the same\n"
		 "      as the one used for the fit in g_covar\n",topfile);
      }
      printf("\nSelect the index group that was used for the least squares fit in g_covar\n");
      get_index(atoms,indexfile,1,&nfit,&ifit,&grpname);

      snew(w_rls,atoms->nr);
      for(i=0; (i<nfit); i++) {
	if (bDMR1) {
	  w_rls[ifit[i]] = atoms->atom[ifit[i]].m;
	} else {
	  w_rls[ifit[i]] = 1.0;
	}
      }

      snew(xrefp,atoms->nr);
      if (xref1 != NULL) {
	for(i=0; (i<nfit); i++) {
	  copy_rvec(xref1[i],xrefp[ifit[i]]);
	}
      } else {
	/* The top coordinates are the fitting reference */
	for(i=0; (i<nfit); i++) {
	  copy_rvec(xtop[ifit[i]],xrefp[ifit[i]]);
	}
	reset_x(nfit,ifit,atoms->nr,NULL,xrefp,w_rls);
      }
    }
    gmx_rmpbc_done(gpbc);
  }

  if (bIndex) {
    printf("\nSelect an index group of %d elements that corresponds to the eigenvectors\n",natoms);
    get_index(atoms,indexfile,1,&i,&index,&grpname);
    if (i!=natoms)
      gmx_fatal(FARGS,"you selected a group with %d elements instead of %d",i,natoms);
      printf("\n");
  }
  
  snew(sqrtm,natoms);
  if (bM && bDMA1) {
    proj_unit="u\\S1/2\\Nnm";
    for(i=0; (i<natoms); i++)
      sqrtm[i]=sqrt(atoms->atom[index[i]].m);
  }
  else {
    proj_unit="nm";
    for(i=0; (i<natoms); i++)
      sqrtm[i]=1.0;
  }
  
  if (bVec2) {
    t=0;
    totmass=0;
    for(i=0; (i<natoms); i++)
      for(d=0;(d<DIM);d++) {
	t+=sqr((xav1[i][d]-xav2[i][d])*sqrtm[i]);
	totmass+=sqr(sqrtm[i]);
      }
    fprintf(stdout,"RMSD (without fit) between the two average structures:"
	    " %.3f (nm)\n\n",sqrt(t/totmass));
  }
  
  if (last==-1)
    last=natoms*DIM;
  if (first>-1) {
    if (bFirstToLast) {
      /* make an index from first to last */
      nout=last-first+1;
      snew(iout,nout);
      for(i=0; i<nout; i++)
	iout[i]=first-1+i;
    } 
    else if (ThreeDPlotFile) {
      /* make an index of first+(0,1,2) and last */
      nout = bPDB3D ? 4 : 3;
      nout = min(last-first+1, nout);
      snew(iout,nout);
      iout[0]=first-1;
      iout[1]=first;
      if (nout>3)
	iout[2]=first+1;
      iout[nout-1]=last-1;
    }
    else {
      /* make an index of first and last */
      nout=2;
      snew(iout,nout);
      iout[0]=first-1;
      iout[1]=last-1;
    }
  }
  else {
    printf("Select eigenvectors for output, end your selection with 0\n");
    nout=-1;
    iout=NULL;
    
    do {
      nout++;
      srenew(iout,nout+1);
      if(1 != scanf("%d",&iout[nout]))
      {
	  gmx_fatal(FARGS,"Error reading user input");
      }
      iout[nout]--;
    }
    while (iout[nout]>=0);
    
    printf("\n");
  }
  /* make an index of the eigenvectors which are present */
  snew(outvec,nout);
  noutvec=0;
  for(i=0; i<nout; i++) 
    {
      j=0;
      while ((j<nvec1) && (eignr1[j]!=iout[i]))
	j++;
      if ((j<nvec1) && (eignr1[j]==iout[i])) 
	{
	  outvec[noutvec]=j;
	  noutvec++;
	}
    }
  fprintf(stderr,"%d eigenvectors selected for output",noutvec);
  if (noutvec <= 100) 
    {
      fprintf(stderr,":");
      for(j=0; j<noutvec; j++)
	fprintf(stderr," %d",eignr1[outvec[j]]+1);
    }
  fprintf(stderr,"\n");
    
  if (CompFile)
    components(CompFile,natoms,eignr1,eigvec1,noutvec,outvec,oenv);
  
  if (RmsfFile)
    rmsf(RmsfFile,natoms,sqrtm,eignr1,eigvec1,noutvec,outvec,eigval1,
         neig1,oenv);
    
  if (bProj)
    project(bTraj ? opt2fn("-f",NFILE,fnm) : NULL,
	    bTop ? &top : NULL,ePBC,topbox,
	    ProjOnVecFile,TwoDPlotFile,ThreeDPlotFile,FilterFile,skip,
	    ExtremeFile,bFirstLastSet,max,nextr,atoms,natoms,index,
	    bFit1,xrefp,nfit,ifit,w_rls,
	    sqrtm,xav1,eignr1,eigvec1,noutvec,outvec,bSplit,
            oenv);
    
  if (OverlapFile)
    overlap(OverlapFile,natoms,
	    eigvec1,nvec2,eignr2,eigvec2,noutvec,outvec,oenv);
    
  if (InpMatFile)
    inprod_matrix(InpMatFile,natoms,
		  nvec1,eignr1,eigvec1,nvec2,eignr2,eigvec2,
		  bFirstLastSet,noutvec,outvec);
    
  if (bCompare)
    compare(natoms,nvec1,eigvec1,nvec2,eigvec2,eigval1,neig1,eigval2,neig2);
  
  
  if (!CompFile && !bProj && !OverlapFile && !InpMatFile && 
          !bCompare && !bEntropy)
  {
    fprintf(stderr,"\nIf you want some output,"
	    " set one (or two or ...) of the output file options\n");
  }
  
  
  view_all(oenv,NFILE, fnm);
  
  thanx(stdout);
  
  return 0;
}
コード例 #6
0
static void read_tables(FILE *fp,const char *fn,
			int ntab,int angle,t_tabledata td[])
{
  char *libfn;
  char buf[STRLEN];
  double **yy=NULL,start,end,dx0,dx1,ssd,vm,vp,f,numf;
  int  k,i,nx,nx0=0,ny,nny,ns;
  gmx_bool bAllZero,bZeroV,bZeroF;
  double tabscale;

  nny = 2*ntab+1;  
  libfn = gmxlibfn(fn);
  nx  = read_xvg(libfn,&yy,&ny);
  if (ny != nny)
    gmx_fatal(FARGS,"Trying to read file %s, but nr columns = %d, should be %d",
		libfn,ny,nny);
  if (angle == 0) {
    if (yy[0][0] != 0.0)
      gmx_fatal(FARGS,
		"The first distance in file %s is %f nm instead of %f nm",
		libfn,yy[0][0],0.0);
  } else {
    if (angle == 1)
      start = 0.0;
    else
      start = -180.0;
    end = 180.0;
    if (yy[0][0] != start || yy[0][nx-1] != end)
      gmx_fatal(FARGS,"The angles in file %s should go from %f to %f instead of %f to %f\n",
		libfn,start,end,yy[0][0],yy[0][nx-1]);
  }

  tabscale = (nx-1)/(yy[0][nx-1] - yy[0][0]);
  
  if (fp) {
    fprintf(fp,"Read user tables from %s with %d data points.\n",libfn,nx);
    if (angle == 0)
      fprintf(fp,"Tabscale = %g points/nm\n",tabscale);
  }

  bAllZero = TRUE;
  for(k=0; k<ntab; k++) {
    bZeroV = TRUE;
    bZeroF = TRUE;
    for(i=0; (i < nx); i++) {
      if (i >= 2) {
	dx0 = yy[0][i-1] - yy[0][i-2];
	dx1 = yy[0][i]   - yy[0][i-1];
	/* Check for 1% deviation in spacing */
	if (fabs(dx1 - dx0) >= 0.005*(fabs(dx0) + fabs(dx1))) {
	  gmx_fatal(FARGS,"In table file '%s' the x values are not equally spaced: %f %f %f",fn,yy[0][i-2],yy[0][i-1],yy[0][i]);
	}
      }
      if (yy[1+k*2][i] != 0) {
	bZeroV = FALSE;
	if (bAllZero) {
	  bAllZero = FALSE;
	  nx0 = i;
	}
	if (yy[1+k*2][i] >  0.01*GMX_REAL_MAX ||
	    yy[1+k*2][i] < -0.01*GMX_REAL_MAX) {
	  gmx_fatal(FARGS,"Out of range potential value %g in file '%s'",
		    yy[1+k*2][i],fn);
	}
      }
      if (yy[1+k*2+1][i] != 0) {
	bZeroF = FALSE;
	if (bAllZero) {
	  bAllZero = FALSE;
	  nx0 = i;
	}
	if (yy[1+k*2+1][i] >  0.01*GMX_REAL_MAX ||
	    yy[1+k*2+1][i] < -0.01*GMX_REAL_MAX) {
	  gmx_fatal(FARGS,"Out of range force value %g in file '%s'",
		    yy[1+k*2+1][i],fn);
	}
      }
    }

    if (!bZeroV && bZeroF) {
      set_forces(fp,angle,nx,1/tabscale,yy[1+k*2],yy[1+k*2+1],k);
    } else {
      /* Check if the second column is close to minus the numerical
       * derivative of the first column.
       */
      ssd = 0;
      ns = 0;
      for(i=1; (i < nx-1); i++) {
	vm = yy[1+2*k][i-1];
	vp = yy[1+2*k][i+1];
	f  = yy[1+2*k+1][i];
	if (vm != 0 && vp != 0 && f != 0) {
	  /* Take the centered difference */
	  numf = -(vp - vm)*0.5*tabscale;
	  ssd += fabs(2*(f - numf)/(f + numf));
	  ns++;
	}
      }
      if (ns > 0) {
	ssd /= ns;
	sprintf(buf,"For the %d non-zero entries for table %d in %s the forces deviate on average %d%% from minus the numerical derivative of the potential\n",ns,k,libfn,(int)(100*ssd+0.5));
	if (debug)
	  fprintf(debug,"%s",buf);
	if (ssd > 0.2) {
	  if (fp)
	    fprintf(fp,"\nWARNING: %s\n",buf);
	  fprintf(stderr,"\nWARNING: %s\n",buf);
	}
      }
    }
  }
  if (bAllZero && fp) {
    fprintf(fp,"\nNOTE: All elements in table %s are zero\n\n",libfn);
  }

  for(k=0; (k<ntab); k++) {
    init_table(fp,nx,nx0,tabscale,&(td[k]),TRUE);
    for(i=0; (i<nx); i++) {
      td[k].x[i] = yy[0][i];
      td[k].v[i] = yy[2*k+1][i];
      td[k].f[i] = yy[2*k+2][i];
    }
  }
  for(i=0; (i<ny); i++)
    sfree(yy[i]);
  sfree(yy);
  sfree(libfn);
}
コード例 #7
0
ファイル: gmx_genbox.cpp プロジェクト: alwanderer/gromacs
static char *insert_mols(const char *mol_insrt, int nmol_insrt, int ntry, int seed,
                         t_atoms *atoms, rvec **x, real **r, int ePBC, matrix box,
                         gmx_atomprop_t aps, 
                         real r_distance, real r_scale, real rshell,
                         const output_env_t oenv,
                         const char* posfn, const rvec deltaR, int enum_rot,
                         gmx_bool bCheckAllPairDist)
{
    t_pbc            pbc;
    static  char    *title_insrt;
    t_atoms          atoms_insrt;
    rvec            *x_insrt, *x_n;
    real            *r_insrt;
    int              ePBC_insrt;
    matrix           box_insrt;
    int              i, mol, onr, ncol;
    real             alfa = 0., beta = 0., gamma = 0.;
    rvec             offset_x;
    int              trial;
    double         **rpos;

    set_pbc(&pbc, ePBC, box);

    /* read number of atoms of insert molecules */
    get_stx_coordnum(mol_insrt, &atoms_insrt.nr);
    if (atoms_insrt.nr == 0)
    {
        gmx_fatal(FARGS, "No molecule in %s, please check your input\n", mol_insrt);
    }
    /* allocate memory for atom coordinates of insert molecules */
    snew(x_insrt, atoms_insrt.nr);
    snew(r_insrt, atoms_insrt.nr);
    snew(atoms_insrt.resinfo, atoms_insrt.nr);
    snew(atoms_insrt.atomname, atoms_insrt.nr);
    snew(atoms_insrt.atom, atoms_insrt.nr);
    atoms_insrt.pdbinfo = NULL;
    snew(x_n, atoms_insrt.nr);
    snew(title_insrt, STRLEN);

    /* read residue number, residue names, atomnames, coordinates etc. */
    fprintf(stderr, "Reading molecule configuration \n");
    read_stx_conf(mol_insrt, title_insrt, &atoms_insrt, x_insrt, NULL,
                  &ePBC_insrt, box_insrt);
    fprintf(stderr, "%s\nContaining %d atoms in %d residue\n",
            title_insrt, atoms_insrt.nr, atoms_insrt.nres);
    srenew(atoms_insrt.resinfo, atoms_insrt.nres);

    /* initialise van der waals arrays of insert molecules */
    mk_vdw(&atoms_insrt, r_insrt, aps, r_distance, r_scale);

    /* With -ip, take nmol_insrt from file posfn */
    if (posfn != NULL)
    {
        nmol_insrt = read_xvg(posfn, &rpos, &ncol);
        if (ncol != 3)
        {
            gmx_fatal(FARGS, "Expected 3 columns (x/y/z coordinates) in file %s\n", ncol, posfn);
        }
        fprintf(stderr, "Read %d positions from file %s\n\n", nmol_insrt, posfn);
    }

    srenew(atoms->resinfo, (atoms->nres+nmol_insrt*atoms_insrt.nres));
    srenew(atoms->atomname, (atoms->nr+atoms_insrt.nr*nmol_insrt));
    srenew(atoms->atom, (atoms->nr+atoms_insrt.nr*nmol_insrt));
    srenew(*x, (atoms->nr+atoms_insrt.nr*nmol_insrt));
    srenew(*r, (atoms->nr+atoms_insrt.nr*nmol_insrt));

    trial = mol = 0;
    while ((mol < nmol_insrt) && (trial < ntry*nmol_insrt))
    {
        fprintf(stderr, "\rTry %d", trial++);
        for (i = 0; (i < atoms_insrt.nr); i++)
        {
            copy_rvec(x_insrt[i], x_n[i]);
        }
        switch (enum_rot)
        {
            case en_rotXYZ:
                alfa  = 2*M_PI *rando(&seed);
                beta  = 2*M_PI *rando(&seed);
                gamma = 2*M_PI *rando(&seed);
                break;
            case en_rotZ:
                alfa  = beta = 0.;
                gamma = 2*M_PI*rando(&seed);
                break;
            case en_rotNone:
                alfa = beta = gamma = 0.;
                break;
        }
        if (enum_rot == en_rotXYZ || (enum_rot == en_rotZ))
        {
            rotate_conf(atoms_insrt.nr, x_n, NULL, alfa, beta, gamma);
        }
        if (posfn == NULL)
        {
            /* insert at random positions */
            offset_x[XX] = box[XX][XX]*rando(&seed);
            offset_x[YY] = box[YY][YY]*rando(&seed);
            offset_x[ZZ] = box[ZZ][ZZ]*rando(&seed);
            gen_box(0, atoms_insrt.nr, x_n, box_insrt, offset_x, TRUE);
            if (!in_box(&pbc, x_n[0]) || !in_box(&pbc, x_n[atoms_insrt.nr-1]))
            {
                continue;
            }
        }
        else
        {
            /* Insert at positions taken from option -ip file */
            offset_x[XX] = rpos[XX][mol] + deltaR[XX]*(2*rando(&seed)-1);
            offset_x[YY] = rpos[YY][mol] + deltaR[YY]*(2*rando(&seed)-1);
            offset_x[ZZ] = rpos[ZZ][mol] + deltaR[ZZ]*(2*rando(&seed)-1);
            for (i = 0; i < atoms_insrt.nr; i++)
            {
                rvec_inc(x_n[i], offset_x);
            }
        }

        onr = atoms->nr;

        /* This is a (maybe) slow workaround to avoid too many calls of add_conf, which
         * leaks memory (status May 2012). If the momory leaks in add_conf() are fixed,
         * this check could be removed. Note, however, that allPairsDistOk is probably
         * even faster than add_conf() when inserting a small molecule into a moderately
         * small system.
         */
        if (bCheckAllPairDist && !allPairsDistOk(atoms, *x, *r, ePBC, box, &atoms_insrt, x_n, r_insrt))
        {
            continue;
        }

        add_conf(atoms, x, NULL, r, FALSE, ePBC, box, TRUE,
                 &atoms_insrt, x_n, NULL, r_insrt, FALSE, rshell, 0, oenv);

        if (atoms->nr == (atoms_insrt.nr+onr))
        {
            mol++;
            fprintf(stderr, " success (now %d atoms)!\n", atoms->nr);
        }
    }
    srenew(atoms->resinfo,  atoms->nres);
    srenew(atoms->atomname, atoms->nr);
    srenew(atoms->atom,     atoms->nr);
    srenew(*x,              atoms->nr);
    srenew(*r,              atoms->nr);

    fprintf(stderr, "\n");
    /* print number of molecules added */
    fprintf(stderr, "Added %d molecules (out of %d requested) of %s\n",
            mol, nmol_insrt, *atoms_insrt.resinfo[0].name);

    return title_insrt;
}
コード例 #8
0
static void insert_mols(int nmol_insrt, int ntry, int seed,
                        t_atoms *atoms, rvec **x, real **exclusionDistances,
                        t_atoms *atoms_insrt, rvec *x_insrt, real *exclusionDistances_insrt,
                        int ePBC, matrix box,
                        const char* posfn, const rvec deltaR, int enum_rot)
{
    t_pbc            pbc;
    rvec            *x_n;
    int              mol;
    int              trial;
    double         **rpos;

    const real       maxInsertRadius
        = *std::max_element(exclusionDistances_insrt,
                            exclusionDistances_insrt + atoms_insrt->nr);
    real             maxRadius = maxInsertRadius;
    if (atoms->nr > 0)
    {
        const real maxExistingRadius
            = *std::max_element(*exclusionDistances,
                                *exclusionDistances + atoms->nr);
        maxRadius = std::max(maxInsertRadius, maxExistingRadius);
    }

    // TODO: Make all of this exception-safe.
    gmx::AnalysisNeighborhood nb;
    nb.setCutoff(maxInsertRadius + maxRadius);

    gmx_rng_t        rng = gmx_rng_init(seed);
    set_pbc(&pbc, ePBC, box);

    snew(x_n, atoms_insrt->nr);

    /* With -ip, take nmol_insrt from file posfn */
    if (posfn != NULL)
    {
        int ncol;
        nmol_insrt = read_xvg(posfn, &rpos, &ncol);
        if (ncol != 3)
        {
            gmx_fatal(FARGS, "Expected 3 columns (x/y/z coordinates) in file %s\n", ncol, posfn);
        }
        fprintf(stderr, "Read %d positions from file %s\n\n", nmol_insrt, posfn);
    }

    {
        const int finalAtomCount    = atoms->nr + nmol_insrt * atoms_insrt->nr;
        const int finalResidueCount = atoms->nres + nmol_insrt * atoms_insrt->nres;
        srenew(atoms->resinfo,      finalResidueCount);
        srenew(atoms->atomname,     finalAtomCount);
        srenew(atoms->atom,         finalAtomCount);
        srenew(*x,                  finalAtomCount);
        srenew(*exclusionDistances, finalAtomCount);
    }

    trial = mol = 0;
    while ((mol < nmol_insrt) && (trial < ntry*nmol_insrt))
    {
        fprintf(stderr, "\rTry %d", trial++);
        rvec offset_x;
        if (posfn == NULL)
        {
            /* insert at random positions */
            offset_x[XX] = box[XX][XX] * gmx_rng_uniform_real(rng);
            offset_x[YY] = box[YY][YY] * gmx_rng_uniform_real(rng);
            offset_x[ZZ] = box[ZZ][ZZ] * gmx_rng_uniform_real(rng);
        }
        else
        {
            /* Insert at positions taken from option -ip file */
            offset_x[XX] = rpos[XX][mol] + deltaR[XX]*(2 * gmx_rng_uniform_real(rng)-1);
            offset_x[YY] = rpos[YY][mol] + deltaR[YY]*(2 * gmx_rng_uniform_real(rng)-1);
            offset_x[ZZ] = rpos[ZZ][mol] + deltaR[ZZ]*(2 * gmx_rng_uniform_real(rng)-1);
        }
        generate_trial_conf(atoms_insrt->nr, x_insrt, offset_x, enum_rot, rng,
                            x_n);
        gmx::AnalysisNeighborhoodPositions pos(*x, atoms->nr);
        gmx::AnalysisNeighborhoodSearch    search = nb.initSearch(&pbc, pos);
        if (is_insertion_allowed(&search, *exclusionDistances, atoms_insrt->nr,
                                 x_n, exclusionDistances_insrt))
        {
            const int firstIndex = atoms->nr;
            for (int i = 0; i < atoms_insrt->nr; ++i)
            {
                copy_rvec(x_n[i], (*x)[firstIndex + i]);
                (*exclusionDistances)[firstIndex + i] = exclusionDistances_insrt[i];
            }
            merge_atoms_noalloc(atoms, atoms_insrt);
            ++mol;
            fprintf(stderr, " success (now %d atoms)!\n", atoms->nr);
        }
    }
    gmx_rng_destroy(rng);
    srenew(atoms->resinfo,  atoms->nres);
    srenew(atoms->atomname, atoms->nr);
    srenew(atoms->atom,     atoms->nr);
    srenew(*x,              atoms->nr);
    srenew(*exclusionDistances, atoms->nr);

    fprintf(stderr, "\n");
    /* print number of molecules added */
    fprintf(stderr, "Added %d molecules (out of %d requested) of %s\n",
            mol, nmol_insrt, *atoms_insrt->resinfo[0].name);

    sfree(x_n);
}
コード例 #9
0
static void insert_mols(int nmol_insrt, int ntry, int seed,
                        real defaultDistance, real scaleFactor,
                        t_atoms *atoms, rvec **x,
                        const t_atoms *atoms_insrt, const rvec *x_insrt,
                        int ePBC, matrix box,
                        const std::string &posfn, const rvec deltaR, int enum_rot)
{
    t_pbc            pbc;
    rvec            *x_n;

    fprintf(stderr, "Initialising inter-atomic distances...\n");
    gmx_atomprop_t   aps = gmx_atomprop_init();
    real            *exclusionDistances
        = makeExclusionDistances(atoms, aps, defaultDistance, scaleFactor);
    real            *exclusionDistances_insrt
        = makeExclusionDistances(atoms_insrt, aps, defaultDistance, scaleFactor);
    gmx_atomprop_destroy(aps);

    const real       maxInsertRadius
        = *std::max_element(exclusionDistances_insrt,
                            exclusionDistances_insrt + atoms_insrt->nr);
    real             maxRadius = maxInsertRadius;
    if (atoms->nr > 0)
    {
        const real maxExistingRadius
            = *std::max_element(exclusionDistances,
                                exclusionDistances + atoms->nr);
        maxRadius = std::max(maxInsertRadius, maxExistingRadius);
    }

    // TODO: Make all of this exception-safe.
    gmx::AnalysisNeighborhood nb;
    nb.setCutoff(maxInsertRadius + maxRadius);

    gmx_rng_t        rng = gmx_rng_init(seed);
    set_pbc(&pbc, ePBC, box);

    snew(x_n, atoms_insrt->nr);

    /* With -ip, take nmol_insrt from file posfn */
    double         **rpos = NULL;
    if (!posfn.empty())
    {
        int ncol;
        nmol_insrt = read_xvg(posfn.c_str(), &rpos, &ncol);
        if (ncol != 3)
        {
            gmx_fatal(FARGS, "Expected 3 columns (x/y/z coordinates) in file %s\n",
                      posfn.c_str());
        }
        fprintf(stderr, "Read %d positions from file %s\n\n",
                nmol_insrt, posfn.c_str());
    }

    {
        const int finalAtomCount    = atoms->nr + nmol_insrt * atoms_insrt->nr;
        const int finalResidueCount = atoms->nres + nmol_insrt * atoms_insrt->nres;
        srenew(atoms->resinfo,      finalResidueCount);
        srenew(atoms->atomname,     finalAtomCount);
        srenew(atoms->atom,         finalAtomCount);
        srenew(*x,                  finalAtomCount);
        srenew(exclusionDistances,  finalAtomCount);
    }

    int mol        = 0;
    int trial      = 0;
    int firstTrial = 0;
    int failed     = 0;
    while ((mol < nmol_insrt) && (trial < ntry*nmol_insrt))
    {
        rvec offset_x;
        if (posfn.empty())
        {
            // Insert at random positions.
            offset_x[XX] = box[XX][XX] * gmx_rng_uniform_real(rng);
            offset_x[YY] = box[YY][YY] * gmx_rng_uniform_real(rng);
            offset_x[ZZ] = box[ZZ][ZZ] * gmx_rng_uniform_real(rng);
        }
        else
        {
            // Skip a position if ntry trials were not successful.
            if (trial >= firstTrial + ntry)
            {
                fprintf(stderr, " skipped position (%.3f, %.3f, %.3f)\n",
                        rpos[XX][mol], rpos[YY][mol], rpos[ZZ][mol]);
                ++mol;
                ++failed;
            }
            // Insert at positions taken from option -ip file.
            offset_x[XX] = rpos[XX][mol] + deltaR[XX]*(2 * gmx_rng_uniform_real(rng)-1);
            offset_x[YY] = rpos[YY][mol] + deltaR[YY]*(2 * gmx_rng_uniform_real(rng)-1);
            offset_x[ZZ] = rpos[ZZ][mol] + deltaR[ZZ]*(2 * gmx_rng_uniform_real(rng)-1);
        }
        fprintf(stderr, "\rTry %d", ++trial);
        generate_trial_conf(atoms_insrt->nr, x_insrt, offset_x, enum_rot, rng,
                            x_n);
        gmx::AnalysisNeighborhoodPositions pos(*x, atoms->nr);
        gmx::AnalysisNeighborhoodSearch    search = nb.initSearch(&pbc, pos);
        if (is_insertion_allowed(&search, exclusionDistances, atoms_insrt->nr,
                                 x_n, exclusionDistances_insrt))
        {
            const int firstIndex = atoms->nr;
            for (int i = 0; i < atoms_insrt->nr; ++i)
            {
                copy_rvec(x_n[i], (*x)[firstIndex + i]);
                exclusionDistances[firstIndex + i] = exclusionDistances_insrt[i];
            }
            merge_atoms_noalloc(atoms, atoms_insrt);
            ++mol;
            firstTrial = trial;
            fprintf(stderr, " success (now %d atoms)!\n", atoms->nr);
        }
    }
    gmx_rng_destroy(rng);
    srenew(atoms->resinfo,  atoms->nres);
    srenew(atoms->atomname, atoms->nr);
    srenew(atoms->atom,     atoms->nr);
    srenew(*x,              atoms->nr);

    fprintf(stderr, "\n");
    /* print number of molecules added */
    fprintf(stderr, "Added %d molecules (out of %d requested)\n",
            mol - failed, nmol_insrt);

    sfree(x_n);
    sfree(exclusionDistances);
    sfree(exclusionDistances_insrt);
    if (rpos != NULL)
    {
        for (int i = 0; i < DIM; ++i)
        {
            sfree(rpos[i]);
        }
        sfree(rpos);
    }
}