Exemple #1
0
static void calc_x_times_f(int nxf, const rvec x[], const rvec f[],
                           gmx_bool bScrewPBC, const matrix box,
                           matrix x_times_f)
{
    clear_mat(x_times_f);

    for (int i = 0; i < nxf; i++)
    {
        for (int d = 0; d < DIM; d++)
        {
            for (int n = 0; n < DIM; n++)
            {
                x_times_f[d][n] += x[i][d]*f[i][n];
            }
        }

        if (bScrewPBC)
        {
            int isx = IS2X(i);
            /* We should correct all odd x-shifts, but the range of isx is -2 to 2 */
            if (isx == 1 || isx == -1)
            {
                for (int d = 0; d < DIM; d++)
                {
                    for (int n = 0; n < DIM; n++)
                    {
                        x_times_f[d][n] += box[d][d]*f[i][n];
                    }
                }
            }
        }
    }
}
Exemple #2
0
void calc_vir(int nxf, rvec x[], rvec f[], tensor vir,
              gmx_bool bScrewPBC, matrix box)
{
    int      i;
    double   dvxx = 0, dvxy = 0, dvxz = 0, dvyx = 0, dvyy = 0, dvyz = 0, dvzx = 0, dvzy = 0, dvzz = 0;

#pragma omp parallel for num_threads(gmx_omp_nthreads_get(emntDefault)) \
    schedule(static) \
    reduction(+: dvxx, dvxy, dvxz, dvyx, dvyy, dvyz, dvzx, dvzy, dvzz)
    for (i = 0; i < nxf; i++)
    {
        dvxx += x[i][XX]*f[i][XX];
        dvxy += x[i][XX]*f[i][YY];
        dvxz += x[i][XX]*f[i][ZZ];

        dvyx += x[i][YY]*f[i][XX];
        dvyy += x[i][YY]*f[i][YY];
        dvyz += x[i][YY]*f[i][ZZ];

        dvzx += x[i][ZZ]*f[i][XX];
        dvzy += x[i][ZZ]*f[i][YY];
        dvzz += x[i][ZZ]*f[i][ZZ];

        if (bScrewPBC)
        {
            int isx = IS2X(i);
            /* We should correct all odd x-shifts, but the range of isx is -2 to 2 */
            if (isx == 1 || isx == -1)
            {
                dvyy += box[YY][YY]*f[i][YY];
                dvyz += box[YY][YY]*f[i][ZZ];

                dvzy += box[ZZ][ZZ]*f[i][YY];
                dvzz += box[ZZ][ZZ]*f[i][ZZ];
            }
        }
    }

    upd_vir(vir[XX], dvxx, dvxy, dvxz);
    upd_vir(vir[YY], dvyx, dvyy, dvyz);
    upd_vir(vir[ZZ], dvzx, dvzy, dvzz);
}
Exemple #3
0
void calc_vir(int nxf, rvec x[], rvec f[], tensor vir,
              gmx_bool bScrewPBC, matrix box)
{
    int      i, isx;
    double   dvxx = 0, dvxy = 0, dvxz = 0, dvyx = 0, dvyy = 0, dvyz = 0, dvzx = 0, dvzy = 0, dvzz = 0;

    for (i = 0; (i < nxf); i++)
    {
        dvxx += x[i][XX]*f[i][XX];
        dvxy += x[i][XX]*f[i][YY];
        dvxz += x[i][XX]*f[i][ZZ];

        dvyx += x[i][YY]*f[i][XX];
        dvyy += x[i][YY]*f[i][YY];
        dvyz += x[i][YY]*f[i][ZZ];

        dvzx += x[i][ZZ]*f[i][XX];
        dvzy += x[i][ZZ]*f[i][YY];
        dvzz += x[i][ZZ]*f[i][ZZ];

        if (bScrewPBC)
        {
            isx = IS2X(i);
            /* We should correct all odd x-shifts, but the range of isx is -2 to 2 */
            if (isx == 1 || isx == -1)
            {
                dvyy += box[YY][YY]*f[i][YY];
                dvyz += box[YY][YY]*f[i][ZZ];

                dvzy += box[ZZ][ZZ]*f[i][YY];
                dvzz += box[ZZ][ZZ]*f[i][ZZ];
            }
        }
    }

    upd_vir(vir[XX], dvxx, dvxy, dvxz);
    upd_vir(vir[YY], dvyx, dvyy, dvyz);
    upd_vir(vir[ZZ], dvzx, dvzy, dvzz);
}
Exemple #4
0
void update_QMMMrec(t_commrec *cr,
		    t_forcerec *fr,
		    rvec x[],
		    t_mdatoms *md,
		    matrix box,
		    gmx_localtop_t *top)
{
  /* updates the coordinates of both QM atoms and MM atoms and stores
   * them in the QMMMrec.
   *
   * NOTE: is NOT yet working if there are no PBC. Also in ns.c, simple
   * ns needs to be fixed!
   */
  int
    mm_max=0,mm_nr=0,mm_nr_new,i,j,is,k,shift;
  t_j_particle
    *mm_j_particles=NULL,*qm_i_particles=NULL;
  t_QMMMrec
    *qr;
  t_nblist
    QMMMlist;
  rvec
    dx,crd;
  int
    *MMatoms;
  t_QMrec
    *qm;
  t_MMrec
    *mm;
  t_pbc
    pbc;
  int
    *parallelMMarray=NULL;
  real
    c12au,c6au;

  c6au  = (HARTREE2KJ*AVOGADRO*pow(BOHR2NM,6));
  c12au = (HARTREE2KJ*AVOGADRO*pow(BOHR2NM,12));

  /* every cpu has this array. On every processor we fill this array
   * with 1's and 0's. 1's indicate the atoms is a QM atom on the
   * current cpu in a later stage these arrays are all summed. indexes
   * > 0 indicate the atom is a QM atom. Every node therefore knows
   * whcih atoms are part of the QM subsystem.
   */
  /* copy some pointers */
  qr          = fr->qr;
  mm          = qr->mm;
  QMMMlist    = fr->QMMMlist;



  /*  init_pbc(box);  needs to be called first, see pbc.h */
  set_pbc_dd(&pbc,fr->ePBC,DOMAINDECOMP(cr) ? cr->dd : NULL,FALSE,box);
  /* only in standard (normal) QMMM we need the neighbouring MM
   * particles to provide a electric field of point charges for the QM
   * atoms.
   */
  if(qr->QMMMscheme==eQMMMschemenormal){ /* also implies 1 QM-layer */
    /* we NOW create/update a number of QMMMrec entries:
     *
     * 1) the shiftQM, containing the shifts of the QM atoms
     *
     * 2) the indexMM array, containing the index of the MM atoms
     *
     * 3) the shiftMM, containing the shifts of the MM atoms
     *
     * 4) the shifted coordinates of the MM atoms
     *
     * the shifts are used for computing virial of the QM/MM particles.
     */
    qm = qr->qm[0]; /* in case of normal QMMM, there is only one group */
    snew(qm_i_particles,QMMMlist.nri);
    if(QMMMlist.nri){
      qm_i_particles[0].shift = XYZ2IS(0,0,0);
      for(i=0;i<QMMMlist.nri;i++){
	qm_i_particles[i].j     = QMMMlist.iinr[i];

	if(i){
	  qm_i_particles[i].shift = pbc_dx_aiuc(&pbc,x[QMMMlist.iinr[0]],
						x[QMMMlist.iinr[i]],dx);

	}
	/* However, since nri >= nrQMatoms, we do a quicksort, and throw
	 * out double, triple, etc. entries later, as we do for the MM
	 * list too.
	 */

	/* compute the shift for the MM j-particles with respect to
	 * the QM i-particle and store them.
	 */

	crd[0] = IS2X(QMMMlist.shift[i]) + IS2X(qm_i_particles[i].shift);
	crd[1] = IS2Y(QMMMlist.shift[i]) + IS2Y(qm_i_particles[i].shift);
	crd[2] = IS2Z(QMMMlist.shift[i]) + IS2Z(qm_i_particles[i].shift);
	is = XYZ2IS(crd[0],crd[1],crd[2]);
	for(j=QMMMlist.jindex[i];
	    j<QMMMlist.jindex[i+1];
	    j++){
	  if(mm_nr >= mm_max){
	    mm_max += 1000;
	    srenew(mm_j_particles,mm_max);
	  }

	  mm_j_particles[mm_nr].j = QMMMlist.jjnr[j];
	  mm_j_particles[mm_nr].shift = is;
	  mm_nr++;
	}
      }

      /* quicksort QM and MM shift arrays and throw away multiple entries */



      qsort(qm_i_particles,QMMMlist.nri,
	    (size_t)sizeof(qm_i_particles[0]),
	    struct_comp);
      qsort(mm_j_particles,mm_nr,
	    (size_t)sizeof(mm_j_particles[0]),
	    struct_comp);
      /* remove multiples in the QM shift array, since in init_QMMM() we
       * went through the atom numbers from 0 to md.nr, the order sorted
       * here matches the one of QMindex already.
       */
      j=0;
      for(i=0;i<QMMMlist.nri;i++){
	if (i==0 || qm_i_particles[i].j!=qm_i_particles[i-1].j){
	  qm_i_particles[j++] = qm_i_particles[i];
	}
      }
      mm_nr_new = 0;
      if(qm->bTS||qm->bOPT){
	/* only remove double entries for the MM array */
	for(i=0;i<mm_nr;i++){
	  if((i==0 || mm_j_particles[i].j!=mm_j_particles[i-1].j)
	     && !md->bQM[mm_j_particles[i].j]){
	    mm_j_particles[mm_nr_new++] = mm_j_particles[i];
	  }
	}
      }
      /* we also remove mm atoms that have no charges!
      * actually this is already done in the ns.c
      */
      else{
	for(i=0;i<mm_nr;i++){
	  if((i==0 || mm_j_particles[i].j!=mm_j_particles[i-1].j)
	     && !md->bQM[mm_j_particles[i].j]
	     && (md->chargeA[mm_j_particles[i].j]
		 || (md->chargeB && md->chargeB[mm_j_particles[i].j]))) {
	    mm_j_particles[mm_nr_new++] = mm_j_particles[i];
	  }
	}
      }
      mm_nr = mm_nr_new;
      /* store the data retrieved above into the QMMMrec
       */
      k=0;
      /* Keep the compiler happy,
       * shift will always be set in the loop for i=0
       */
      shift = 0;
      for(i=0;i<qm->nrQMatoms;i++){
	/* not all qm particles might have appeared as i
	 * particles. They might have been part of the same charge
	 * group for instance.
	 */
	if (qm->indexQM[i] == qm_i_particles[k].j) {
	  shift = qm_i_particles[k++].shift;
	}
	/* use previous shift, assuming they belong the same charge
	 * group anyway,
	 */

	qm->shiftQM[i] = shift;
      }
    }
    /* parallel excecution */
    if(PAR(cr)){
      snew(parallelMMarray,2*(md->nr));
      /* only MM particles have a 1 at their atomnumber. The second part
       * of the array contains the shifts. Thus:
       * p[i]=1/0 depending on wether atomnumber i is a MM particle in the QM
       * step or not. p[i+md->nr] is the shift of atomnumber i.
       */
      for(i=0;i<2*(md->nr);i++){
	parallelMMarray[i]=0;
      }

      for(i=0;i<mm_nr;i++){
	parallelMMarray[mm_j_particles[i].j]=1;
	parallelMMarray[mm_j_particles[i].j+(md->nr)]=mm_j_particles[i].shift;
      }
      gmx_sumi(md->nr,parallelMMarray,cr);
      mm_nr=0;

      mm_max = 0;
      for(i=0;i<md->nr;i++){
	if(parallelMMarray[i]){
	  if(mm_nr >= mm_max){
	    mm_max += 1000;
	    srenew(mm->indexMM,mm_max);
	    srenew(mm->shiftMM,mm_max);
	  }
	  mm->indexMM[mm_nr]  = i;
	  mm->shiftMM[mm_nr++]= parallelMMarray[i+md->nr]/parallelMMarray[i];
	}
      }
      mm->nrMMatoms=mm_nr;
      free(parallelMMarray);
    }
    /* serial execution */
    else{
      mm->nrMMatoms = mm_nr;
      srenew(mm->shiftMM,mm_nr);
      srenew(mm->indexMM,mm_nr);
      for(i=0;i<mm_nr;i++){
	mm->indexMM[i]=mm_j_particles[i].j;
	mm->shiftMM[i]=mm_j_particles[i].shift;
      }

    }
    /* (re) allocate memory for the MM coordiate array. The QM
     * coordinate array was already allocated in init_QMMM, and is
     * only (re)filled in the update_QMMM_coordinates routine
     */
    srenew(mm->xMM,mm->nrMMatoms);
    /* now we (re) fill the array that contains the MM charges with
     * the forcefield charges. If requested, these charges will be
     * scaled by a factor
     */
    srenew(mm->MMcharges,mm->nrMMatoms);
    for(i=0;i<mm->nrMMatoms;i++){/* no free energy yet */
      mm->MMcharges[i]=md->chargeA[mm->indexMM[i]]*mm->scalefactor;
    }
    if(qm->bTS||qm->bOPT){
      /* store (copy) the c6 and c12 parameters into the MMrec struct
       */
      srenew(mm->c6,mm->nrMMatoms);
      srenew(mm->c12,mm->nrMMatoms);
      for (i=0;i<mm->nrMMatoms;i++){
	mm->c6[i]  = C6(fr->nbfp,top->idef.atnr,
			md->typeA[mm->indexMM[i]],
			md->typeA[mm->indexMM[i]])/c6au;
	mm->c12[i] =C12(fr->nbfp,top->idef.atnr,
			md->typeA[mm->indexMM[i]],
			md->typeA[mm->indexMM[i]])/c12au;
      }
      punch_QMMM_excl(qr->qm[0],mm,&(top->excls));
    }
    /* the next routine fills the coordinate fields in the QMMM rec of
     * both the qunatum atoms and the MM atoms, using the shifts
     * calculated above.
     */

    update_QMMM_coord(x,fr,qr->qm[0],qr->mm);
    free(qm_i_particles);
    free(mm_j_particles);
  }
  else { /* ONIOM */ /* ????? */
    mm->nrMMatoms=0;
    /* do for each layer */
    for (j=0;j<qr->nrQMlayers;j++){
      qm = qr->qm[j];
      qm->shiftQM[0]=XYZ2IS(0,0,0);
      for(i=1;i<qm->nrQMatoms;i++){
	qm->shiftQM[i] = pbc_dx_aiuc(&pbc,x[qm->indexQM[0]],x[qm->indexQM[i]],
				     dx);
      }
      update_QMMM_coord(x,fr,qm,mm);
    }
  }
} /* update_QMMM_rec */