/* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: Xiaohu Hu, CMB/ORNL (hux2@ornl.gov) David Hyde-Volpe, Tigran Abramyan, and Robert A. Latour (Clemson University) Chris Lorenz (Kings College-London) Implementation of the CHARMM CMAP; adds an extra energy term for the peptide backbone dihedrals. The tools/ch2lmp/charmm2lammps.pl conversion script, which generates an extra section in the LAMMPS data file, is needed in order to generate the info used by this fix style. References: - MacKerell et al., J. Am. Chem. Soc. 126(2004):698-699. - MacKerell et al., J. Comput. Chem. 25(2004):1400-1415. ------------------------------------------------------------------------- */ #include <mpi.h> #include <cmath> #include <cstdlib> #include <cstring> #include <cstdio> #include "fix_cmap.h" #include "atom.h" #include "atom_vec.h" #include "update.h" #include "respa.h" #include "modify.h" #include "domain.h" #include "force.h" #include "group.h" #include "comm.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace FixConst; using namespace MathConst; #define MAXLINE 256 #define LISTDELTA 10000 #define LB_FACTOR 1.5 #define CMAPMAX 6 // max # of CMAP terms stored by one atom #define CMAPDIM 24 // grid map dimension is 24 x 24 #define CMAPXMIN -360.0 #define CMAPXMIN2 -180.0 #define CMAPDX 15.0 // 360/CMAPDIM /* ---------------------------------------------------------------------- */ FixCMAP::FixCMAP(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), crosstermlist(NULL), num_crossterm(NULL), crossterm_type(NULL), crossterm_atom1(NULL), crossterm_atom2(NULL), crossterm_atom3(NULL), crossterm_atom4(NULL), crossterm_atom5(NULL), g_axis(NULL), cmapgrid(NULL), d1cmapgrid(NULL), d2cmapgrid(NULL), d12cmapgrid(NULL) { if (narg != 4) error->all(FLERR,"Illegal fix cmap command"); restart_global = 1; restart_peratom = 1; peatom_flag = 1; virial_flag = 1; thermo_virial = 1; peratom_freq = 1; scalar_flag = 1; global_freq = 1; extscalar = 1; extvector = 1; wd_header = 1; wd_section = 1; MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); // allocate memory for CMAP data memory->create(g_axis,CMAPDIM,"cmap:g_axis"); memory->create(cmapgrid,6,CMAPDIM,CMAPDIM,"cmap:grid"); memory->create(d1cmapgrid,6,CMAPDIM,CMAPDIM,"cmap:d1grid"); memory->create(d2cmapgrid,6,CMAPDIM,CMAPDIM,"cmap:d2grid"); memory->create(d12cmapgrid,6,CMAPDIM,CMAPDIM,"cmap:d12grid"); // read and setup CMAP data read_grid_map(arg[3]); // perform initial allocation of atom-based arrays // register with Atom class num_crossterm = NULL; crossterm_type = NULL; crossterm_atom1 = NULL; crossterm_atom2 = NULL; crossterm_atom3 = NULL; crossterm_atom4 = NULL; crossterm_atom5 = NULL; nmax_previous = 0; grow_arrays(atom->nmax); atom->add_callback(0); atom->add_callback(1); // local list of crossterms ncmap = 0; maxcrossterm = 0; crosstermlist = NULL; } /* --------------------------------------------------------------------- */ FixCMAP::~FixCMAP() { // unregister callbacks to this fix from Atom class atom->delete_callback(id,0); atom->delete_callback(id,1); memory->destroy(g_axis); memory->destroy(cmapgrid); memory->destroy(d1cmapgrid); memory->destroy(d2cmapgrid); memory->destroy(d12cmapgrid); memory->destroy(crosstermlist); memory->destroy(num_crossterm); memory->destroy(crossterm_type); memory->destroy(crossterm_atom1); memory->destroy(crossterm_atom2); memory->destroy(crossterm_atom3); memory->destroy(crossterm_atom4); memory->destroy(crossterm_atom5); } /* ---------------------------------------------------------------------- */ int FixCMAP::setmask() { int mask = 0; mask |= PRE_NEIGHBOR; mask |= PRE_REVERSE; mask |= POST_FORCE; mask |= THERMO_ENERGY; mask |= POST_FORCE_RESPA; mask |= MIN_POST_FORCE; return mask; } /* ---------------------------------------------------------------------- */ void FixCMAP::init() { int i; double angle; i = 0; angle = -180.0; while (angle < 180.0) { g_axis[i] = angle; angle += CMAPDX; i++; } // pre-compute the derivatives of the maps for (i = 0; i < 6; i++) set_map_derivatives(cmapgrid[i],d1cmapgrid[i],d2cmapgrid[i],d12cmapgrid[i]); // define newton_bond here in case restart file was read (not data file) newton_bond = force->newton_bond; } /* --------------------------------------------------------------------- */ void FixCMAP::setup(int vflag) { pre_neighbor(); if (strstr(update->integrate_style,"verlet")) post_force(vflag); else { ((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1); post_force_respa(vflag,nlevels_respa-1,0); ((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1); } } /* --------------------------------------------------------------------- */ void FixCMAP::setup_pre_neighbor() { pre_neighbor(); } /* --------------------------------------------------------------------- */ void FixCMAP::setup_pre_reverse(int eflag, int vflag) { pre_reverse(eflag,vflag); } /* --------------------------------------------------------------------- */ void FixCMAP::min_setup(int vflag) { pre_neighbor(); post_force(vflag); } /* ---------------------------------------------------------------------- store local neighbor list as if newton_bond = OFF, even if actually ON ------------------------------------------------------------------------- */ void FixCMAP::pre_neighbor() { int i,m,atom1,atom2,atom3,atom4,atom5; // guesstimate initial length of local crossterm list // if ncmap was not set (due to read_restart, no read_data), // then list will grow by LISTDELTA chunks if (maxcrossterm == 0) { if (nprocs == 1) maxcrossterm = ncmap; else maxcrossterm = static_cast<int> (LB_FACTOR*ncmap/nprocs); memory->create(crosstermlist,maxcrossterm,6,"cmap:crosstermlist"); } int nlocal = atom->nlocal; ncrosstermlist = 0; for (i = 0; i < nlocal; i++) { for (m = 0; m < num_crossterm[i]; m++) { atom1 = atom->map(crossterm_atom1[i][m]); atom2 = atom->map(crossterm_atom2[i][m]); atom3 = atom->map(crossterm_atom3[i][m]); atom4 = atom->map(crossterm_atom4[i][m]); atom5 = atom->map(crossterm_atom5[i][m]); if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1 || atom5 == -1) { char str[128]; sprintf(str,"CMAP atoms " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " missing on proc %d at step " BIGINT_FORMAT, crossterm_atom1[i][m],crossterm_atom2[i][m], crossterm_atom3[i][m],crossterm_atom4[i][m], crossterm_atom5[i][m],me,update->ntimestep); error->one(FLERR,str); } atom1 = domain->closest_image(i,atom1); atom2 = domain->closest_image(i,atom2); atom3 = domain->closest_image(i,atom3); atom4 = domain->closest_image(i,atom4); atom5 = domain->closest_image(i,atom5); if (i <= atom1 && i <= atom2 && i <= atom3 && i <= atom4 && i <= atom5) { if (ncrosstermlist == maxcrossterm) { maxcrossterm += LISTDELTA; memory->grow(crosstermlist,maxcrossterm,6,"cmap:crosstermlist"); } crosstermlist[ncrosstermlist][0] = atom1; crosstermlist[ncrosstermlist][1] = atom2; crosstermlist[ncrosstermlist][2] = atom3; crosstermlist[ncrosstermlist][3] = atom4; crosstermlist[ncrosstermlist][4] = atom5; crosstermlist[ncrosstermlist][5] = crossterm_type[i][m]; ncrosstermlist++; } } } } /* ---------------------------------------------------------------------- store eflag, so can use it in post_force to tally per-atom energies ------------------------------------------------------------------------- */ void FixCMAP::pre_reverse(int eflag, int vflag) { eflag_caller = eflag; } /* ---------------------------------------------------------------------- compute CMAP terms as if newton_bond = OFF, even if actually ON ------------------------------------------------------------------------- */ void FixCMAP::post_force(int vflag) { int n,i1,i2,i3,i4,i5,type,nlist; int li1, li2, mli1,mli2,mli11,mli21,t1,li3,li4,mli3,mli4,mli31,mli41; int list[5]; // vectors needed to calculate the cross-term dihedral angles double vb21x,vb21y,vb21z,vb32x,vb32y,vb32z,vb34x,vb34y,vb34z; double vb23x,vb23y,vb23z; double vb43x,vb43y,vb43z,vb45x,vb45y,vb45z,a1x,a1y,a1z,b1x,b1y,b1z; double a2x,a2y,a2z,b2x,b2y,b2z,r32,a1sq,b1sq,a2sq,b2sq,dpr21r32,dpr34r32; double dpr32r43,dpr45r43,r43,vb12x,vb12y,vb12z,vb54x,vb54y,vb54z; // cross-term dihedral angles double phi,psi,phi1,psi1; double f1[3],f2[3],f3[3],f4[3],f5[3],vcmap[6]; double gs[4],d1gs[4],d2gs[4],d12gs[4]; double engfraction; // vectors needed for the gradient/force calculation double dphidr1x,dphidr1y,dphidr1z,dphidr2x,dphidr2y,dphidr2z; double dphidr3x,dphidr3y,dphidr3z,dphidr4x,dphidr4y,dphidr4z; double dpsidr1x,dpsidr1y,dpsidr1z,dpsidr2x,dpsidr2y,dpsidr2z; double dpsidr3x,dpsidr3y,dpsidr3z,dpsidr4x,dpsidr4y,dpsidr4z; // Definition of cross-term dihedrals // phi dihedral // |--------------------| // a1-----a2-----a3-----a4-----a5 cross-term atoms // C N CA C N cross-term atom types // |--------------------| // psi dihedral double **x = atom->x; double **f = atom->f; int nlocal = atom->nlocal; ecmap = 0.0; int eflag = eflag_caller; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; for (n = 0; n < ncrosstermlist; n++) { i1 = crosstermlist[n][0]; i2 = crosstermlist[n][1]; i3 = crosstermlist[n][2]; i4 = crosstermlist[n][3]; i5 = crosstermlist[n][4]; type = crosstermlist[n][5]; if (type == 0) continue; // calculate bond vectors for both dihedrals // phi // vb21 = r2 - r1 vb21x = x[i2][0] - x[i1][0]; vb21y = x[i2][1] - x[i1][1]; vb21z = x[i2][2] - x[i1][2]; vb12x = -1.0*vb21x; vb12y = -1.0*vb21y; vb12z = -1.0*vb21z; vb32x = x[i3][0] - x[i2][0]; vb32y = x[i3][1] - x[i2][1]; vb32z = x[i3][2] - x[i2][2]; vb23x = -1.0*vb32x; vb23y = -1.0*vb32y; vb23z = -1.0*vb32z; vb34x = x[i3][0] - x[i4][0]; vb34y = x[i3][1] - x[i4][1]; vb34z = x[i3][2] - x[i4][2]; // psi // bond vectors same as for phi: vb32 vb43x = -1.0*vb34x; vb43y = -1.0*vb34y; vb43z = -1.0*vb34z; vb45x = x[i4][0] - x[i5][0]; vb45y = x[i4][1] - x[i5][1]; vb45z = x[i4][2] - x[i5][2]; vb54x = -1.0*vb45x; vb54y = -1.0*vb45y; vb54z = -1.0*vb45z; // calculate normal vectors for planes that define the dihedral angles a1x = vb12y*vb23z - vb12z*vb23y; a1y = vb12z*vb23x - vb12x*vb23z; a1z = vb12x*vb23y - vb12y*vb23x; b1x = vb43y*vb23z - vb43z*vb23y; b1y = vb43z*vb23x - vb43x*vb23z; b1z = vb43x*vb23y - vb43y*vb23x; a2x = vb23y*vb34z - vb23z*vb34y; a2y = vb23z*vb34x - vb23x*vb34z; a2z = vb23x*vb34y - vb23y*vb34x; b2x = vb45y*vb43z - vb45z*vb43y; b2y = vb45z*vb43x - vb45x*vb43z; b2z = vb45x*vb43y - vb45y*vb43x; // calculate terms used later in calculations r32 = sqrt(vb32x*vb32x + vb32y*vb32y + vb32z*vb32z); a1sq = a1x*a1x + a1y*a1y + a1z*a1z; b1sq = b1x*b1x + b1y*b1y + b1z*b1z; r43 = sqrt(vb43x*vb43x + vb43y*vb43y + vb43z*vb43z); a2sq = a2x*a2x + a2y*a2y + a2z*a2z; b2sq = b2x*b2x + b2y*b2y + b2z*b2z; //if (a1sq<0.0001 || b1sq<0.0001 || a2sq<0.0001 || b2sq<0.0001) // printf("a1sq b1sq a2sq b2sq: %f %f %f %f \n",a1sq,b1sq,a2sq,b2sq); if (a1sq<0.0001 || b1sq<0.0001 || a2sq<0.0001 || b2sq<0.0001) continue; dpr21r32 = vb21x*vb32x + vb21y*vb32y + vb21z*vb32z; dpr34r32 = vb34x*vb32x + vb34y*vb32y + vb34z*vb32z; dpr32r43 = vb32x*vb43x + vb32y*vb43y + vb32z*vb43z; dpr45r43 = vb45x*vb43x + vb45y*vb43y + vb45z*vb43z; // calculate the backbone dihedral angles as VMD and GROMACS phi = dihedral_angle_atan2(vb21x,vb21y,vb21z,a1x,a1y,a1z,b1x,b1y,b1z,r32); psi = dihedral_angle_atan2(vb32x,vb32y,vb32z,a2x,a2y,a2z,b2x,b2y,b2z,r43); if (phi == 180.0) phi= -180.0; if (psi == 180.0) psi= -180.0; phi1 = phi; if (phi1 < 0.0) phi1 += 360.0; psi1 = psi; if (psi1 < 0.0) psi1 += 360.0; // find the neighbor grid point index li1 = int(((phi1+CMAPXMIN2)/CMAPDX)+((CMAPDIM*1.0)/2.0)); li2 = int(((psi1+CMAPXMIN2)/CMAPDX)+((CMAPDIM*1.0)/2.0)); li3 = int((phi-CMAPXMIN2)/CMAPDX); li4 = int((psi-CMAPXMIN2)/CMAPDX); mli3 = li3 % CMAPDIM; mli4 = li4 % CMAPDIM; mli31 = (li3+1) % CMAPDIM; mli41 = (li4+1) %CMAPDIM; mli1 = li1 % CMAPDIM; mli2 = li2 % CMAPDIM; mli11 = (li1+1) % CMAPDIM; mli21 = (li2+1) %CMAPDIM; t1 = type-1; if (t1 < 0 || t1 > 5) error->all(FLERR,"Invalid CMAP crossterm_type"); // determine the values and derivatives for the grid square points gs[0] = cmapgrid[t1][mli3][mli4]; gs[1] = cmapgrid[t1][mli31][mli4]; gs[2] = cmapgrid[t1][mli31][mli41]; gs[3] = cmapgrid[t1][mli3][mli41]; d1gs[0] = d1cmapgrid[t1][mli1][mli2]; d1gs[1] = d1cmapgrid[t1][mli11][mli2]; d1gs[2] = d1cmapgrid[t1][mli11][mli21]; d1gs[3] = d1cmapgrid[t1][mli1][mli21]; d2gs[0] = d2cmapgrid[t1][mli1][mli2]; d2gs[1] = d2cmapgrid[t1][mli11][mli2]; d2gs[2] = d2cmapgrid[t1][mli11][mli21]; d2gs[3] = d2cmapgrid[t1][mli1][mli21]; d12gs[0] = d12cmapgrid[t1][mli1][mli2]; d12gs[1] = d12cmapgrid[t1][mli11][mli2]; d12gs[2] = d12cmapgrid[t1][mli11][mli21]; d12gs[3] = d12cmapgrid[t1][mli1][mli21]; // calculate the cmap energy and the gradient (dE/dphi,dE/dpsi) bc_interpol(phi,psi,li3,li4,gs,d1gs,d2gs,d12gs); // sum up cmap energy contributions engfraction = 0.2 * E; if (i1 < nlocal) ecmap += engfraction; if (i2 < nlocal) ecmap += engfraction; if (i3 < nlocal) ecmap += engfraction; if (i4 < nlocal) ecmap += engfraction; if (i5 < nlocal) ecmap += engfraction; // calculate the derivatives dphi/dr_i dphidr1x = 1.0*r32/a1sq*a1x; dphidr1y = 1.0*r32/a1sq*a1y; dphidr1z = 1.0*r32/a1sq*a1z; dphidr2x = -1.0*r32/a1sq*a1x - dpr21r32/a1sq/r32*a1x + dpr34r32/b1sq/r32*b1x; dphidr2y = -1.0*r32/a1sq*a1y - dpr21r32/a1sq/r32*a1y + dpr34r32/b1sq/r32*b1y; dphidr2z = -1.0*r32/a1sq*a1z - dpr21r32/a1sq/r32*a1z + dpr34r32/b1sq/r32*b1z; dphidr3x = dpr34r32/b1sq/r32*b1x - dpr21r32/a1sq/r32*a1x - r32/b1sq*b1x; dphidr3y = dpr34r32/b1sq/r32*b1y - dpr21r32/a1sq/r32*a1y - r32/b1sq*b1y; dphidr3z = dpr34r32/b1sq/r32*b1z - dpr21r32/a1sq/r32*a1z - r32/b1sq*b1z; dphidr4x = r32/b1sq*b1x; dphidr4y = r32/b1sq*b1y; dphidr4z = r32/b1sq*b1z; // calculate the derivatives dpsi/dr_i dpsidr1x = 1.0*r43/a2sq*a2x; dpsidr1y = 1.0*r43/a2sq*a2y; dpsidr1z = 1.0*r43/a2sq*a2z; dpsidr2x = r43/a2sq*a2x + dpr32r43/a2sq/r43*a2x - dpr45r43/b2sq/r43*b2x; dpsidr2y = r43/a2sq*a2y + dpr32r43/a2sq/r43*a2y - dpr45r43/b2sq/r43*b2y; dpsidr2z = r43/a2sq*a2z + dpr32r43/a2sq/r43*a2z - dpr45r43/b2sq/r43*b2z; dpsidr3x = dpr45r43/b2sq/r43*b2x - dpr32r43/a2sq/r43*a2x - r43/b2sq*b2x; dpsidr3y = dpr45r43/b2sq/r43*b2y - dpr32r43/a2sq/r43*a2y - r43/b2sq*b2y; dpsidr3z = dpr45r43/b2sq/r43*b2z - dpr32r43/a2sq/r43*a2z - r43/b2sq*b2z; dpsidr4x = r43/b2sq*b2x; dpsidr4y = r43/b2sq*b2y; dpsidr4z = r43/b2sq*b2z; // calculate forces on cross-term atoms: F = -(dE/dPhi)*(dPhi/dr) f1[0] = dEdPhi*dphidr1x; f1[1] = dEdPhi*dphidr1y; f1[2] = dEdPhi*dphidr1z; f2[0] = dEdPhi*dphidr2x + dEdPsi*dpsidr1x; f2[1] = dEdPhi*dphidr2y + dEdPsi*dpsidr1y; f2[2] = dEdPhi*dphidr2z + dEdPsi*dpsidr1z; f3[0] = -dEdPhi*dphidr3x - dEdPsi*dpsidr2x; f3[1] = -dEdPhi*dphidr3y - dEdPsi*dpsidr2y; f3[2] = -dEdPhi*dphidr3z - dEdPsi*dpsidr2z; f4[0] = -dEdPhi*dphidr4x - dEdPsi*dpsidr3x; f4[1] = -dEdPhi*dphidr4y - dEdPsi*dpsidr3y; f4[2] = -dEdPhi*dphidr4z - dEdPsi*dpsidr3z; f5[0] = -dEdPsi*dpsidr4x; f5[1] = -dEdPsi*dpsidr4y; f5[2] = -dEdPsi*dpsidr4z; // apply force to each of the 5 atoms if (i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (i5 < nlocal) { f[i5][0] += f5[0]; f[i5][1] += f5[1]; f[i5][2] += f5[2]; } // tally energy and/or virial if (evflag) { nlist = 0; if (i1 < nlocal) list[nlist++] = i1; if (i2 < nlocal) list[nlist++] = i2; if (i3 < nlocal) list[nlist++] = i3; if (i4 < nlocal) list[nlist++] = i4; if (i5 < nlocal) list[nlist++] = i5; vcmap[0] = (vb12x*f1[0])+(vb32x*f3[0])+((vb43x+vb32x)*f4[0])+ ((vb54x+vb43x+vb32x)*f5[0]); vcmap[1] = (vb12y*f1[1])+(vb32y*f3[1])+((vb43y+vb32y)*f4[1])+ ((vb54y+vb43y+vb32y)*f5[1]); vcmap[2] = (vb12z*f1[2])+(vb32z*f3[2])+((vb43z+vb32z)*f4[2])+ ((vb54z+vb43z+vb32z)*f5[2]); vcmap[3] = (vb12x*f1[1])+(vb32x*f3[1])+((vb43x+vb32x)*f4[1])+ ((vb54x+vb43x+vb32x)*f5[1]); vcmap[4] = (vb12x*f1[2])+(vb32x*f3[2])+((vb43x+vb32x)*f4[2])+ ((vb54x+vb43x+vb32x)*f5[2]); vcmap[5] = (vb12y*f1[2])+(vb32y*f3[2])+((vb43y+vb32y)*f4[2])+ ((vb54y+vb43y+vb32y)*f5[2]); ev_tally(nlist,list,5.0,E,vcmap); //ev_tally(5,list,nlocal,newton_bond,E,vcmap); } } } /* ---------------------------------------------------------------------- */ void FixCMAP::post_force_respa(int vflag, int ilevel, int iloop) { if (ilevel == nlevels_respa-1) post_force(vflag); } /* ---------------------------------------------------------------------- */ void FixCMAP::min_post_force(int vflag) { post_force(vflag); } /* ---------------------------------------------------------------------- energy of CMAP term ------------------------------------------------------------------------- */ double FixCMAP::compute_scalar() { double all; MPI_Allreduce(&ecmap,&all,1,MPI_DOUBLE,MPI_SUM,world); return all; } // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // methods to read CMAP potential file, perform interpolation // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- void FixCMAP::read_grid_map(char *cmapfile) { char linebuf[MAXLINE]; char *chunk,*line; int i1, i2, i3, i4, i5, i6, j1, j2, j3, j4, j5, j6, counter; FILE *fp = NULL; if (comm->me == 0) { fp = force->open_potential(cmapfile); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open fix cmap file %s",cmapfile); error->one(FLERR,str); } } for (int ix1 = 0; ix1 < 6; ix1++) for (int ix2 = 0; ix2 < CMAPDIM; ix2++) for (int ix3 = 0; ix3 < CMAPDIM; ix3++) cmapgrid[ix1][ix2][ix3] = 0.0; counter = 0; i1 = i2 = i3 = i4 = i5 = i6 = 0; j1 = j2 = j3 = j4 = j5 = j6 = 0; int done = 0; while (!done) { // only read on rank 0 and broadcast to all other ranks if (comm->me == 0) done = (fgets(linebuf,MAXLINE,fp) == NULL); MPI_Bcast(&done,1,MPI_INT,0,world); if (done) continue; MPI_Bcast(linebuf,MAXLINE,MPI_CHAR,0,world); // remove leading whitespace line = linebuf; while (line && (*line == ' ' || *line == '\t' || *line == '\r')) ++line; // skip if empty line or comment if (!line || *line =='\n' || *line == '\0' || *line == '#') continue; // read in the cmap grid point values // NOTE: The order to read the 6 grid maps is HARD-CODED, thus errors // will occur if content of the file "cmap.data" is altered // // Reading order of the maps: // 1. Alanine map // 2. Alanine before proline map // 3. Proline map // 4. Two adjacent prolines map // 5. Glycine map // 6. Glycine before proline map chunk = strtok(line, " \r\n"); while (chunk != NULL) { // alanine map if (counter < CMAPDIM*CMAPDIM) { cmapgrid[0][i1][j1] = atof(chunk); chunk = strtok(NULL, " \r\n"); j1++; if (j1 == CMAPDIM) { j1 = 0; i1++; } counter++; } // alanine-proline map else if (counter >= CMAPDIM*CMAPDIM && counter < 2*CMAPDIM*CMAPDIM) { cmapgrid[1][i2][j2]= atof(chunk); chunk = strtok(NULL, " \r\n"); j2++; if (j2 == CMAPDIM) { j2 = 0; i2++; } counter++; } // proline map else if (counter >= 2*CMAPDIM*CMAPDIM && counter < 3*CMAPDIM*CMAPDIM) { cmapgrid[2][i3][j3] = atof(chunk); chunk = strtok(NULL, " \r\n"); j3++; if (j3 == CMAPDIM) { j3 = 0; i3++; } counter++; } // 2 adjacent prolines map else if (counter >= 3*CMAPDIM*CMAPDIM && counter < 4*CMAPDIM*CMAPDIM) { cmapgrid[3][i4][j4] = atof(chunk); chunk = strtok(NULL, " \r\n"); j4++; if (j4 == CMAPDIM) { j4 = 0; i4++; } counter++; } // glycine map else if (counter >= 4*CMAPDIM*CMAPDIM && counter < 5*CMAPDIM*CMAPDIM) { cmapgrid[4][i5][j5] = atof(chunk); chunk = strtok(NULL, " \r\n"); j5++; if (j5 == CMAPDIM) { j5 = 0; i5++; } counter++; } // glycine-proline map else if (counter >= 5*CMAPDIM*CMAPDIM && counter < 6*CMAPDIM*CMAPDIM) { cmapgrid[5][i6][j6] = atof(chunk); chunk = strtok(NULL, " \r\n"); j6++; if (j6 == CMAPDIM) { j6 = 0; i6++; } counter++; } else break; } } if (comm->me == 0) fclose(fp); } /* ---------------------------------------------------------------------- */ void FixCMAP::spline(double *y, double *ddy, int n) { // create the 2nd dervatives of a taublated function y_i(x_i) // at the tabulated points int i, j; double p, *u; memory->create(u,n-1,"cmap:u"); ddy[0] = u[0] = 0.0; for (i = 1; i <= n-2; i++) { p = 1.0/(ddy[i-1]+4.0); ddy[i] = -p; u[i] = ((((6.0*y[i+1])-(12.0*y[i])+(6.0*y[i-1]))/(CMAPDX*CMAPDX))-u[i-1])*p; } ddy[n-1] = 0.0; for (j = n-2; j >= 0; j--) ddy[j] = ddy[j]*ddy[j+1] + u[j]; memory->destroy(u); } /* ---------------------------------------------------------------------- */ void FixCMAP::spl_interpolate(double x, double *y, double *ddy, double &yo, double &dyo) { // perform a 1D cubic spline interpolation int ix; double a,b,a1,b1,a2,b2; ix = int((x-CMAPXMIN)/CMAPDX-(1./2.)); a = (CMAPXMIN+(ix*1.0)*CMAPDX-x)/CMAPDX; b = (x-CMAPXMIN-(((ix-1)*1.0)*CMAPDX))/CMAPDX; a1 = a*a*a-a; b1 = b*b*b-b; a2 = 3.0*a*a-1.0; b2 = 3.0*b*b-1.0; yo = a*y[ix]+b*y[ix+1]+(a1*ddy[ix]+b1*ddy[ix+1])*(CMAPDX*CMAPDX)/6.0; dyo = (y[ix+1]-y[ix])/CMAPDX-a2/6.0*CMAPDX*ddy[ix]+b2/6.0*CMAPDX*ddy[ix+1]; } /* ---------------------------------------------------------------------- */ void FixCMAP::set_map_derivatives(double **map, double **d1yo, double **d2yo, double **d12yo) { // precompute the gradient and cross-derivatives of the map grid points. // use the bicubic spline to calculate the derivatives int i, j, k, ii, jj, xm, p; double phi, psi, d1y, d2y, d12y, tyyk,tdyk; double *tmp_y, *tmp_dy, *tmp_ddy, **tmap, **tddmap; int ix; double a,b,a1,b1,a2,b2; xm = CMAPDIM/2; p = CMAPDIM; d1y = 0.; d2y = 0.; d12y = 0.; memory->create(tmp_y,CMAPDIM*2,"cmap:tmp_y"); memory->create(tmp_dy,CMAPDIM*2,"cmap:tmp_dy"); memory->create(tmp_ddy,CMAPDIM*2,"cmap:tmp_ddy"); memory->create(tmap,CMAPDIM*2,CMAPDIM*2,"cmap:tmap"); memory->create(tddmap,CMAPDIM*2,CMAPDIM*2,"cmap:tddmap"); // periodically expand the original map // use the expanded map for bicubic spline interpolation, // which is used to obtain the derivatives // actual interpolation is done with bicubic interpolation for (i = 0; i < CMAPDIM*2; i++) { ii = ((i+CMAPDIM-xm)%CMAPDIM); for (j = 0; j < CMAPDIM*2; j++) { jj = ((j+CMAPDIM-xm)%CMAPDIM); tmap[i][j] = map[ii][jj]; } } for (i = 0; i < CMAPDIM*2; i++) spline(tmap[i], tddmap[i], CMAPDIM*2); for (i = xm; i < CMAPDIM+xm; i++) { phi = (i-xm)*CMAPDX-180.0; for (j = xm; j < CMAPDIM+xm; j++) { psi = (j-xm)*CMAPDX-180.0; ix = int((psi-CMAPXMIN)/CMAPDX); a = (CMAPXMIN+((ix+1)*1.0)*CMAPDX-psi)/CMAPDX; b = (psi-CMAPXMIN-((ix)*1.0)*CMAPDX)/CMAPDX; a1 = a*a*a-a; b1 = b*b*b-b; a2 = 3.0*a*a-1.0; b2 = 3.0*b*b-1.0; for (k = 0; k < CMAPDIM*2; k++) { tyyk = tmp_y[k]; tdyk = tmp_dy[k]; tyyk = a*tmap[k][ix]+b*tmap[k][ix+1]+ (a1*tddmap[k][ix]+b1*tddmap[k][ix+1])*(CMAPDX*CMAPDX)/6.0; tdyk = (tmap[k][ix+1]-tmap[k][ix])/CMAPDX- (a2/6.0*CMAPDX*tddmap[k][ix])+(b2/6.0*CMAPDX*tddmap[k][ix+1]); tmp_y[k] = tyyk; tmp_dy[k] = tdyk; } spline(tmp_y,tmp_ddy,CMAPDIM+xm+xm); ix = int((phi-CMAPXMIN)/CMAPDX); a = (CMAPXMIN+((ix+1)*1.0)*CMAPDX-phi)/CMAPDX; b = (phi-CMAPXMIN-(ix*1.0)*CMAPDX)/CMAPDX; a1 = a*a*a-a; b1 = b*b*b-b; a2 = 3.0*a*a-1.0; b2 = 3.0*b*b-1.0; d1y = (tmp_y[ix+1]-tmp_y[ix])/CMAPDX- a2/6.0*CMAPDX*tmp_ddy[ix]+b2/6.0*CMAPDX*tmp_ddy[ix+1]; spline(tmp_dy,tmp_ddy,CMAPDIM+xm+xm); ix = int((phi-CMAPXMIN)/CMAPDX); a = (CMAPXMIN+((ix+1)*1.0)*CMAPDX-phi)/CMAPDX; b = (phi-CMAPXMIN-(ix*1.0)*CMAPDX)/CMAPDX; a1 = a*a*a-a; b1 = b*b*b-b; a2 = 3.0*a*a-1.0; b2 = 3.0*b*b-1.0; d2y = a*tmp_dy[ix]+b*tmp_dy[ix+1]+ (a1*tmp_ddy[ix]+b1*tmp_ddy[ix+1])*(CMAPDX*CMAPDX)/6.0; d12y = (tmp_dy[ix+1]-tmp_dy[ix])/CMAPDX- a2/6.0*CMAPDX*tmp_ddy[ix]+b2/6.0*CMAPDX*tmp_ddy[ix+1]; d1yo[i%p][j%p] = d1y; d2yo[i%p][j%p] = d2y; d12yo[i%p][j%p] = d12y; } } memory->destroy(tmp_y); memory->destroy(tmp_dy); memory->destroy(tmp_ddy); memory->destroy(tmap); memory->destroy(tddmap); } /* ---------------------------------------------------------------------- */ double FixCMAP::dihedral_angle_atan2(double fx, double fy, double fz, double ax, double ay, double az, double bx, double by, double bz, double absg) { // calculate the dihedral angle double angle, arg1, arg2; arg1 = absg*(fx*bx+fy*by+fz*bz); arg2 = ax*bx+ay*by+az*bz; if (arg1 == 0 && arg2 == 0) error->all(FLERR,"CMAP: atan2 function cannot take 2 zero arguments"); else { angle = atan2(arg1,arg2); angle = angle*180.0/MY_PI; } return angle; } /* ---------------------------------------------------------------------- */ void FixCMAP::bc_coeff(double *gs, double *d1gs, double *d2gs, double *d12gs) { // calculate the bicubic interpolation coefficients c_ij static int wt[16][16] = { {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, {-3, 0, 0, 3, 0, 0, 0, 0,-2, 0, 0,-1, 0, 0, 0, 0}, {2, 0, 0,-2, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0}, {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, {0, 0, 0, 0,-3, 0, 0, 3, 0, 0, 0, 0,-2, 0, 0,-1}, {0, 0, 0, 0, 2, 0, 0,-2, 0, 0, 0, 0, 1, 0, 0, 1}, {-3, 3, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0,-2,-1, 0, 0}, {9,-9, 9,-9, 6, 3,-3,-6, 6,-6,-3, 3, 4, 2, 1, 2}, {-6, 6,-6, 6,-4,-2, 2, 4,-3, 3, 3,-3,-2,-1,-1,-2}, {2,-2, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 1, 1, 0, 0}, {-6, 6,-6, 6,-3,-3, 3, 3,-4, 4, 2,-2,-2,-2,-1,-1}, {4,-4, 4,-4, 2, 2,-2,-2, 2,-2,-2, 2, 1, 1, 1, 1} }; int i, j, k, in; double xx, x[16]; for (i = 0; i < 4; i++) { x[i] = gs[i]; x[i+4] = d1gs[i]*CMAPDX; x[i+8] = d2gs[i]*CMAPDX; x[i+12] = d12gs[i]*CMAPDX*CMAPDX; } in = 0; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { xx = 0.0; for (k = 0; k < 16; k++) xx += wt[in][k]*x[k]; in++; cij[i][j] = xx; } } } /* ---------------------------------------------------------------------- */ void FixCMAP::bc_interpol(double x1, double x2, int low1, int low2, double *gs, double *d1gs, double *d2gs, double *d12gs) { // for a given point of interest and its corresponding grid square values, // gradients and cross-derivatives // calculate the interpolated value of the point of interest (POI) int i; double t, u, gs1l, gs2l; // set the interpolation coefficients bc_coeff(gs,d1gs,d2gs,d12gs); gs1l = g_axis[low1]; gs2l = g_axis[low2]; t = (x1-gs1l)/CMAPDX; u = (x2-gs2l)/CMAPDX; E = dEdPhi = dEdPsi = 0.0; for (i = 3; i >= 0; i--) { E = t*E + ((cij[i][3]*u+cij[i][2])*u+cij[i][1])*u+cij[i][0]; dEdPhi = u*dEdPhi + (3.0*cij[3][i]*t+2.0*cij[2][i])*t+cij[1][i]; dEdPsi = t*dEdPsi + (3.0*cij[i][3]*u+2.0*cij[i][2])*u+cij[i][1]; } dEdPhi *= (180.0/MY_PI/CMAPDX); dEdPsi *= (180.0/MY_PI/CMAPDX); } // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // methods to read and write data file // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- void FixCMAP::read_data_header(char *line) { if (strstr(line,"crossterms")) { sscanf(line,BIGINT_FORMAT,&ncmap); } else error->all(FLERR,"Invalid read data header line for fix cmap"); // didn't set in constructor b/c this fix could be defined // before newton command newton_bond = force->newton_bond; } /* ---------------------------------------------------------------------- unpack N lines in buf from section of data file labeled by keyword id_offset is applied to atomID fields if multiple data files are read store CMAP interactions as if newton_bond = OFF, even if actually ON ------------------------------------------------------------------------- */ void FixCMAP::read_data_section(char *keyword, int n, char *buf, tagint id_offset) { int m,tmp,itype; tagint atom1,atom2,atom3,atom4,atom5; char *next; next = strchr(buf,'\n'); *next = '\0'; int nwords = atom->count_words(buf); *next = '\n'; if (nwords != 7) { char str[128]; sprintf(str,"Incorrect %s format in data file",keyword); error->all(FLERR,str); } // loop over lines of CMAP crossterms // tokenize the line into values // add crossterm to one of my atoms, depending on newton_bond for (int i = 0; i < n; i++) { next = strchr(buf,'\n'); *next = '\0'; sscanf(buf,"%d %d " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, &tmp,&itype,&atom1,&atom2,&atom3,&atom4,&atom5); atom1 += id_offset; atom2 += id_offset; atom3 += id_offset; atom4 += id_offset; atom5 += id_offset; if ((m = atom->map(atom1)) >= 0) { if (num_crossterm[m] == CMAPMAX) error->one(FLERR,"Too many CMAP crossterms for one atom"); crossterm_type[m][num_crossterm[m]] = itype; crossterm_atom1[m][num_crossterm[m]] = atom1; crossterm_atom2[m][num_crossterm[m]] = atom2; crossterm_atom3[m][num_crossterm[m]] = atom3; crossterm_atom4[m][num_crossterm[m]] = atom4; crossterm_atom5[m][num_crossterm[m]] = atom5; num_crossterm[m]++; } if ((m = atom->map(atom2)) >= 0) { if (num_crossterm[m] == CMAPMAX) error->one(FLERR,"Too many CMAP crossterms for one atom"); crossterm_type[m][num_crossterm[m]] = itype; crossterm_atom1[m][num_crossterm[m]] = atom1; crossterm_atom2[m][num_crossterm[m]] = atom2; crossterm_atom3[m][num_crossterm[m]] = atom3; crossterm_atom4[m][num_crossterm[m]] = atom4; crossterm_atom5[m][num_crossterm[m]] = atom5; num_crossterm[m]++; } if ((m = atom->map(atom3)) >= 0) { if (num_crossterm[m] == CMAPMAX) error->one(FLERR,"Too many CMAP crossterms for one atom"); crossterm_type[m][num_crossterm[m]] = itype; crossterm_atom1[m][num_crossterm[m]] = atom1; crossterm_atom2[m][num_crossterm[m]] = atom2; crossterm_atom3[m][num_crossterm[m]] = atom3; crossterm_atom4[m][num_crossterm[m]] = atom4; crossterm_atom5[m][num_crossterm[m]] = atom5; num_crossterm[m]++; } if ((m = atom->map(atom4)) >= 0) { if (num_crossterm[m] == CMAPMAX) error->one(FLERR,"Too many CMAP crossterms for one atom"); crossterm_type[m][num_crossterm[m]] = itype; crossterm_atom1[m][num_crossterm[m]] = atom1; crossterm_atom2[m][num_crossterm[m]] = atom2; crossterm_atom3[m][num_crossterm[m]] = atom3; crossterm_atom4[m][num_crossterm[m]] = atom4; crossterm_atom5[m][num_crossterm[m]] = atom5; num_crossterm[m]++; } if ((m = atom->map(atom5)) >= 0) { if (num_crossterm[m] == CMAPMAX) error->one(FLERR,"Too many CMAP crossterms for one atom"); crossterm_type[m][num_crossterm[m]] = itype; crossterm_atom1[m][num_crossterm[m]] = atom1; crossterm_atom2[m][num_crossterm[m]] = atom2; crossterm_atom3[m][num_crossterm[m]] = atom3; crossterm_atom4[m][num_crossterm[m]] = atom4; crossterm_atom5[m][num_crossterm[m]] = atom5; num_crossterm[m]++; } buf = next + 1; } } /* ---------------------------------------------------------------------- */ bigint FixCMAP::read_data_skip_lines(char *keyword) { return ncmap; } /* ---------------------------------------------------------------------- write Mth header line to file only called by proc 0 ------------------------------------------------------------------------- */ void FixCMAP::write_data_header(FILE *fp, int mth) { fprintf(fp,BIGINT_FORMAT " cmap crossterms\n",ncmap); } /* ---------------------------------------------------------------------- return size I own for Mth data section # of data sections = 1 for this fix nx = # of crossterms owned by my local atoms if newton_bond off, atom only owns crossterm if it is atom3 ny = columns = type + 5 atom IDs ------------------------------------------------------------------------- */ void FixCMAP::write_data_section_size(int mth, int &nx, int &ny) { int i,m; tagint *tag = atom->tag; int nlocal = atom->nlocal; nx = 0; for (i = 0; i < nlocal; i++) for (m = 0; m < num_crossterm[i]; m++) if (crossterm_atom3[i][m] == tag[i]) nx++; ny = 6; } /* ---------------------------------------------------------------------- pack values for Mth data section into 2d buf buf allocated by caller as owned crossterms by 6 ------------------------------------------------------------------------- */ void FixCMAP::write_data_section_pack(int mth, double **buf) { int i,m; // 1st column = CMAP type // 2nd-6th columns = 5 atom IDs tagint *tag = atom->tag; int nlocal = atom->nlocal; int n = 0; for (i = 0; i < nlocal; i++) { for (m = 0; m < num_crossterm[i]; m++) { if (crossterm_atom3[i][m] != tag[i]) continue; buf[n][0] = ubuf(crossterm_type[i][m]).d; buf[n][1] = ubuf(crossterm_atom1[i][m]).d; buf[n][2] = ubuf(crossterm_atom2[i][m]).d; buf[n][3] = ubuf(crossterm_atom3[i][m]).d; buf[n][4] = ubuf(crossterm_atom4[i][m]).d; buf[n][5] = ubuf(crossterm_atom5[i][m]).d; n++; } } } /* ---------------------------------------------------------------------- write section keyword for Mth data section to file use Molecules or Charges if that is only field, else use fix ID only called by proc 0 ------------------------------------------------------------------------- */ void FixCMAP::write_data_section_keyword(int mth, FILE *fp) { fprintf(fp,"\nCMAP\n\n"); } /* ---------------------------------------------------------------------- write N lines from buf to file convert buf fields to int or double depending on styles index can be used to prepend global numbering only called by proc 0 ------------------------------------------------------------------------- */ void FixCMAP::write_data_section(int mth, FILE *fp, int n, double **buf, int index) { for (int i = 0; i < n; i++) fprintf(fp,"%d %d " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT "\n", index+i,(int) ubuf(buf[i][0]).i,(tagint) ubuf(buf[i][1]).i, (tagint) ubuf(buf[i][2]).i,(tagint) ubuf(buf[i][3]).i, (tagint) ubuf(buf[i][4]).i,(tagint) ubuf(buf[i][5]).i); } // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // methods for restart and communication // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- /* ---------------------------------------------------------------------- pack entire state of Fix into one write ------------------------------------------------------------------------- */ void FixCMAP::write_restart(FILE *fp) { if (comm->me == 0) { int size = sizeof(bigint); fwrite(&size,sizeof(int),1,fp); fwrite(&ncmap,sizeof(bigint),1,fp); } } /* ---------------------------------------------------------------------- use state info from restart file to restart the Fix ------------------------------------------------------------------------- */ void FixCMAP::restart(char *buf) { ncmap = *((bigint *) buf); } /* ---------------------------------------------------------------------- pack values in local atom-based arrays for restart file ------------------------------------------------------------------------- */ int FixCMAP::pack_restart(int i, double *buf) { int n = 1; for (int m = 0; m < num_crossterm[i]; m++) { buf[n++] = ubuf(MAX(crossterm_type[i][m],-crossterm_type[i][m])).d; buf[n++] = ubuf(crossterm_atom1[i][m]).d; buf[n++] = ubuf(crossterm_atom2[i][m]).d; buf[n++] = ubuf(crossterm_atom3[i][m]).d; buf[n++] = ubuf(crossterm_atom4[i][m]).d; buf[n++] = ubuf(crossterm_atom5[i][m]).d; } buf[0] = n; return n; } /* ---------------------------------------------------------------------- unpack values from atom->extra array to restart the fix ------------------------------------------------------------------------- */ void FixCMAP::unpack_restart(int nlocal, int nth) { double **extra = atom->extra; // skip to Nth set of extra values int n = 0; for (int i = 0; i < nth; i++) n += static_cast<int> (extra[nlocal][n]); int count = static_cast<int> (extra[nlocal][n++]); num_crossterm[nlocal] = (count-1)/6; for (int m = 0; m < num_crossterm[nlocal]; m++) { crossterm_type[nlocal][m] = (int) ubuf(extra[nlocal][n++]).i; crossterm_atom1[nlocal][m] = (tagint) ubuf(extra[nlocal][n++]).i; crossterm_atom2[nlocal][m] = (tagint) ubuf(extra[nlocal][n++]).i; crossterm_atom3[nlocal][m] = (tagint) ubuf(extra[nlocal][n++]).i; crossterm_atom4[nlocal][m] = (tagint) ubuf(extra[nlocal][n++]).i; crossterm_atom5[nlocal][m] = (tagint) ubuf(extra[nlocal][n++]).i; } } /* ---------------------------------------------------------------------- maxsize of any atom's restart data ------------------------------------------------------------------------- */ int FixCMAP::maxsize_restart() { return 1 + CMAPMAX*6; } /* ---------------------------------------------------------------------- size of atom nlocal's restart data ------------------------------------------------------------------------- */ int FixCMAP::size_restart(int nlocal) { return 1 + num_crossterm[nlocal]*6; } /* ---------------------------------------------------------------------- allocate atom-based array ------------------------------------------------------------------------- */ void FixCMAP::grow_arrays(int nmax) { num_crossterm = memory->grow(num_crossterm,nmax,"cmap:num_crossterm"); crossterm_type = memory->grow(crossterm_type,nmax,CMAPMAX, "cmap:crossterm_type"); crossterm_atom1 = memory->grow(crossterm_atom1,nmax,CMAPMAX, "cmap:crossterm_atom1"); crossterm_atom2 = memory->grow(crossterm_atom2,nmax,CMAPMAX, "cmap:crossterm_atom2"); crossterm_atom3 = memory->grow(crossterm_atom3,nmax,CMAPMAX, "cmap:crossterm_atom3"); crossterm_atom4 = memory->grow(crossterm_atom4,nmax,CMAPMAX, "cmap:crossterm_atom4"); crossterm_atom5 = memory->grow(crossterm_atom5,nmax,CMAPMAX, "cmap:crossterm_atom5"); // must initialize num_crossterm to 0 for added atoms // may never be set for some atoms when data file is read for (int i = nmax_previous; i < nmax; i++) num_crossterm[i] = 0; nmax_previous = nmax; } /* ---------------------------------------------------------------------- copy values within local atom-based array ------------------------------------------------------------------------- */ void FixCMAP::copy_arrays(int i, int j, int delflag) { num_crossterm[j] = num_crossterm[i]; for (int k = 0; k < num_crossterm[j]; k++){ crossterm_type[j][k] = crossterm_type[i][k]; crossterm_atom1[j][k] = crossterm_atom1[i][k]; crossterm_atom2[j][k] = crossterm_atom2[i][k]; crossterm_atom3[j][k] = crossterm_atom3[i][k]; crossterm_atom4[j][k] = crossterm_atom4[i][k]; crossterm_atom5[j][k] = crossterm_atom5[i][k]; } } /* ---------------------------------------------------------------------- initialize one atom's array values, called when atom is created ------------------------------------------------------------------------- */ void FixCMAP::set_arrays(int i) { num_crossterm[i] = 0; } /* ---------------------------------------------------------------------- pack values in local atom-based array for exchange with another proc ------------------------------------------------------------------------- */ int FixCMAP::pack_exchange(int i, double *buf) { int n = 0; buf[n++] = ubuf(num_crossterm[i]).d; for (int m = 0; m < num_crossterm[i]; m++) { buf[n++] = ubuf(crossterm_type[i][m]).d; buf[n++] = ubuf(crossterm_atom1[i][m]).d; buf[n++] = ubuf(crossterm_atom2[i][m]).d; buf[n++] = ubuf(crossterm_atom3[i][m]).d; buf[n++] = ubuf(crossterm_atom4[i][m]).d; buf[n++] = ubuf(crossterm_atom5[i][m]).d; } return n; } /* ---------------------------------------------------------------------- unpack values in local atom-based array from exchange with another proc ------------------------------------------------------------------------- */ int FixCMAP::unpack_exchange(int nlocal, double *buf) { int n = 0; num_crossterm[nlocal] = (int) ubuf(buf[n++]).i; for (int m = 0; m < num_crossterm[nlocal]; m++) { crossterm_type[nlocal][m] = (int) ubuf(buf[n++]).i; crossterm_atom1[nlocal][m] = (tagint) ubuf(buf[n++]).i; crossterm_atom2[nlocal][m] = (tagint) ubuf(buf[n++]).i; crossterm_atom3[nlocal][m] = (tagint) ubuf(buf[n++]).i; crossterm_atom4[nlocal][m] = (tagint) ubuf(buf[n++]).i; crossterm_atom5[nlocal][m] = (tagint) ubuf(buf[n++]).i; } return n; } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double FixCMAP::memory_usage() { int nmax = atom->nmax; double bytes = nmax * sizeof(int); // num_crossterm bytes += nmax*CMAPMAX * sizeof(int); // crossterm_type bytes += 5*nmax*CMAPMAX * sizeof(int); // crossterm_atom 12345 bytes += maxcrossterm*6 * sizeof(int); // crosstermlist return bytes; }