int gmx_genconf(int argc, char *argv[]) { const char *desc[] = { "genconf multiplies a given coordinate file by simply stacking them", "on top of each other, like a small child playing with wooden blocks.", "The program makes a grid of [IT]user defined[it]", "proportions ([TT]-nbox[tt]), ", "and interspaces the grid point with an extra space [TT]-dist[tt].[PAR]", "When option [TT]-rot[tt] is used the program does not check for overlap", "between molecules on grid points. It is recommended to make the box in", "the input file at least as big as the coordinates + ", "Van der Waals radius.[PAR]", "If the optional trajectory file is given, conformations are not", "generated, but read from this file and translated appropriately to", "build the grid." }; const char *bugs[] = { "The program should allow for random displacement of lattice points." }; int vol; t_atoms *atoms; /* list with all atoms */ char title[STRLEN]; rvec *x,*xx,*v; /* coordinates? */ real t; vec4 *xrot,*vrot; int ePBC; matrix box,boxx; /* box length matrix */ rvec shift; int natoms; /* number of atoms in one molecule */ int nres; /* number of molecules? */ int i,j,k,l,m,ndx,nrdx,nx,ny,nz; t_trxstatus *status; gmx_bool bTRX; output_env_t oenv; t_filenm fnm[] = { { efSTX, "-f", "conf", ffREAD }, { efSTO, "-o", "out", ffWRITE }, { efTRX, "-trj",NULL, ffOPTRD } }; #define NFILE asize(fnm) static rvec nrbox = {1,1,1}; static int seed = 0; /* seed for random number generator */ static int nmolat = 3; static int nblock = 1; static gmx_bool bShuffle = FALSE; static gmx_bool bSort = FALSE; static gmx_bool bRandom = FALSE; /* False: no random rotations */ static gmx_bool bRenum = TRUE; /* renumber residues */ static rvec dist = {0,0,0}; /* space added between molecules ? */ static rvec max_rot = {180,180,180}; /* maximum rotation */ t_pargs pa[] = { { "-nbox", FALSE, etRVEC, {nrbox}, "Number of boxes" }, { "-dist", FALSE, etRVEC, {dist}, "Distance between boxes" }, { "-seed", FALSE, etINT, {&seed}, "Random generator seed, if 0 generated from the time" }, { "-rot", FALSE, etBOOL, {&bRandom}, "Randomly rotate conformations" }, { "-shuffle",FALSE, etBOOL, {&bShuffle},"Random shuffling of molecules" }, { "-sort", FALSE, etBOOL, {&bSort}, "Sort molecules on X coord" }, { "-block", FALSE, etINT, {&nblock}, "Divide the box in blocks on this number of cpus" }, { "-nmolat", FALSE, etINT, {&nmolat}, "Number of atoms per molecule, assumed to start from 0. " "If you set this wrong, it will screw up your system!" }, { "-maxrot", FALSE, etRVEC, {max_rot}, "Maximum random rotation" }, { "-renumber",FALSE,etBOOL, {&bRenum}, "Renumber residues" } }; CopyRight(stderr,argv[0]); parse_common_args(&argc,argv,0,NFILE,fnm,asize(pa),pa, asize(desc),desc,asize(bugs),bugs,&oenv); if (bRandom && (seed == 0)) seed = make_seed(); bTRX = ftp2bSet(efTRX,NFILE,fnm); nx = (int)(nrbox[XX]+0.5); ny = (int)(nrbox[YY]+0.5); nz = (int)(nrbox[ZZ]+0.5); if ((nx <= 0) || (ny <= 0) || (nz <= 0)) gmx_fatal(FARGS,"Number of boxes (-nbox) should be larger than zero"); if ((nmolat <= 0) && bShuffle) gmx_fatal(FARGS,"Can not shuffle if the molecules only have %d atoms", nmolat); vol=nx*ny*nz; /* calculate volume in grid points (= nr. molecules) */ get_stx_coordnum(opt2fn("-f",NFILE,fnm),&natoms); snew(atoms,1); /* make space for all the atoms */ init_t_atoms(atoms,natoms*vol,FALSE); snew(x,natoms*vol); /* get space for coordinates of all atoms */ snew(xrot,natoms); /* get space for rotation matrix? */ snew(v,natoms*vol); /* velocities. not really needed? */ snew(vrot,natoms); /* set atoms->nr to the number in one box * * to avoid complaints in read_stx_conf * */ atoms->nr = natoms; read_stx_conf(opt2fn("-f",NFILE,fnm),title,atoms,x,v,&ePBC,box); nres=atoms->nres; /* nr of residues in one element? */ if (bTRX) { if (!read_first_x(oenv,&status,ftp2fn(efTRX,NFILE,fnm),&t,&xx,boxx)) gmx_fatal(FARGS,"No atoms in trajectory %s",ftp2fn(efTRX,NFILE,fnm)); } else { snew(xx,natoms); for(i=0; i<natoms; i++) { copy_rvec(x[i],xx[i]); } } for(k=0; (k<nz); k++) { /* loop over all gridpositions */ shift[ZZ]=k*(dist[ZZ]+box[ZZ][ZZ]); for(j=0; (j<ny); j++) { shift[YY]=j*(dist[YY]+box[YY][YY])+k*box[ZZ][YY]; for(i=0; (i<nx); i++) { shift[XX]=i*(dist[XX]+box[XX][XX])+j*box[YY][XX]+k*box[ZZ][XX]; ndx=(i*ny*nz+j*nz+k)*natoms; nrdx=(i*ny*nz+j*nz+k)*nres; /* Random rotation on input coords */ if (bRandom) rand_rot(natoms,xx,v,xrot,vrot,&seed,max_rot); for(l=0; (l<natoms); l++) { for(m=0; (m<DIM); m++) { if (bRandom) { x[ndx+l][m] = xrot[l][m]; v[ndx+l][m] = vrot[l][m]; } else { x[ndx+l][m] = xx[l][m]; v[ndx+l][m] = v[l][m]; } } if (ePBC == epbcSCREW && i % 2 == 1) { /* Rotate around x axis */ for(m=YY; m<=ZZ; m++) { x[ndx+l][m] = box[YY][m] + box[ZZ][m] - x[ndx+l][m]; v[ndx+l][m] = -v[ndx+l][m]; } } for(m=0; (m<DIM); m++) { x[ndx+l][m] += shift[m]; } atoms->atom[ndx+l].resind = nrdx + atoms->atom[l].resind; atoms->atomname[ndx+l]=atoms->atomname[l]; } for(l=0; (l<nres); l++) { atoms->resinfo[nrdx+l] = atoms->resinfo[l]; if (bRenum) atoms->resinfo[nrdx+l].nr += nrdx; } if (bTRX) if (!read_next_x(oenv,status,&t,natoms,xx,boxx) && ((i+1)*(j+1)*(k+1) < vol)) gmx_fatal(FARGS,"Not enough frames in trajectory"); } } } if (bTRX) close_trj(status); /* make box bigger */ for(m=0; (m<DIM); m++) box[m][m] += dist[m]; svmul(nx,box[XX],box[XX]); svmul(ny,box[YY],box[YY]); svmul(nz,box[ZZ],box[ZZ]); if (ePBC == epbcSCREW && nx % 2 == 0) { /* With an even number of boxes in x we can forgot about the screw */ ePBC = epbcXYZ; } /* move_x(natoms*vol,x,box); */ /* put atoms in box? */ atoms->nr*=vol; atoms->nres*=vol; /*depending on how you look at it, this is either a nasty hack or the way it should work*/ if (bRenum) for (i=0;i<atoms->nres;i++) atoms->resinfo[i].nr=i+1; if (bShuffle) randwater(0,atoms->nr/nmolat,nmolat,x,v,&seed); else if (bSort) sortwater(0,atoms->nr/nmolat,nmolat,x,v); else if (opt2parg_bSet("-block",asize(pa),pa)) mkcompact(0,atoms->nr/nmolat,nmolat,x,v,nblock,box); write_sto_conf(opt2fn("-o",NFILE,fnm),title,atoms,x,v,ePBC,box); thanx(stderr); return 0; }
int gmx_convert_tpr(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] can edit run input files in four ways.[PAR]", "[BB]1.[bb] by modifying the number of steps in a run input file", "with options [TT]-extend[tt], [TT]-until[tt] or [TT]-nsteps[tt]", "(nsteps=-1 means unlimited number of steps)[PAR]", "[BB]2.[bb] (OBSOLETE) by creating a run input file", "for a continuation run when your simulation has crashed due to e.g.", "a full disk, or by making a continuation run input file.", "This option is obsolete, since mdrun now writes and reads", "checkpoint files.", "[BB]Note[bb] that a frame with coordinates and velocities is needed.", "When pressure and/or Nose-Hoover temperature coupling is used", "an energy file can be supplied to get an exact continuation", "of the original run.[PAR]", "[BB]3.[bb] by creating a [REF].tpx[ref] file for a subset of your original", "tpx file, which is useful when you want to remove the solvent from", "your [REF].tpx[ref] file, or when you want to make e.g. a pure C[GRK]alpha[grk] [REF].tpx[ref] file.", "Note that you may need to use [TT]-nsteps -1[tt] (or similar) to get", "this to work.", "[BB]WARNING: this [REF].tpx[ref] file is not fully functional[bb].[PAR]", "[BB]4.[bb] by setting the charges of a specified group", "to zero. This is useful when doing free energy estimates", "using the LIE (Linear Interaction Energy) method." }; const char *top_fn, *frame_fn; struct t_fileio *fp; ener_file_t fp_ener = NULL; gmx_trr_header_t head; int i; gmx_int64_t nsteps_req, run_step, frame; double run_t, state_t; gmx_bool bOK, bNsteps, bExtend, bUntil, bTime, bTraj; gmx_bool bFrame, bUse, bSel, bNeedEner, bReadEner, bScanEner, bFepState; gmx_mtop_t mtop; t_atoms atoms; t_inputrec *ir; t_state state; rvec *newx = NULL, *newv = NULL, *tmpx, *tmpv; matrix newbox; int gnx; char *grpname; atom_id *index = NULL; int nre; gmx_enxnm_t *enm = NULL; t_enxframe *fr_ener = NULL; char buf[200], buf2[200]; gmx_output_env_t *oenv; t_filenm fnm[] = { { efTPR, NULL, NULL, ffREAD }, { efTRN, "-f", NULL, ffOPTRD }, { efEDR, "-e", NULL, ffOPTRD }, { efNDX, NULL, NULL, ffOPTRD }, { efTPR, "-o", "tprout", ffWRITE } }; #define NFILE asize(fnm) /* Command line options */ static int nsteps_req_int = 0; static real start_t = -1.0, extend_t = 0.0, until_t = 0.0; static int init_fep_state = 0; static gmx_bool bContinuation = TRUE, bZeroQ = FALSE, bVel = TRUE; static t_pargs pa[] = { { "-extend", FALSE, etREAL, {&extend_t}, "Extend runtime by this amount (ps)" }, { "-until", FALSE, etREAL, {&until_t}, "Extend runtime until this ending time (ps)" }, { "-nsteps", FALSE, etINT, {&nsteps_req_int}, "Change the number of steps" }, { "-time", FALSE, etREAL, {&start_t}, "Continue from frame at this time (ps) instead of the last frame" }, { "-zeroq", FALSE, etBOOL, {&bZeroQ}, "Set the charges of a group (from the index) to zero" }, { "-vel", FALSE, etBOOL, {&bVel}, "Require velocities from trajectory" }, { "-cont", FALSE, etBOOL, {&bContinuation}, "For exact continuation, the constraints should not be applied before the first step" }, { "-init_fep_state", FALSE, etINT, {&init_fep_state}, "fep state to initialize from" }, }; /* Parse the command line */ if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv)) { return 0; } /* Convert int to gmx_int64_t */ nsteps_req = nsteps_req_int; bNsteps = opt2parg_bSet("-nsteps", asize(pa), pa); bExtend = opt2parg_bSet("-extend", asize(pa), pa); bUntil = opt2parg_bSet("-until", asize(pa), pa); bFepState = opt2parg_bSet("-init_fep_state", asize(pa), pa); bTime = opt2parg_bSet("-time", asize(pa), pa); bTraj = (opt2bSet("-f", NFILE, fnm) || bTime); top_fn = ftp2fn(efTPR, NFILE, fnm); fprintf(stderr, "Reading toplogy and stuff from %s\n", top_fn); snew(ir, 1); read_tpx_state(top_fn, ir, &state, &mtop); run_step = ir->init_step; run_t = ir->init_step*ir->delta_t + ir->init_t; if (!EI_STATE_VELOCITY(ir->eI)) { bVel = FALSE; } if (bTraj) { fprintf(stderr, "\n" "NOTE: Reading the state from trajectory is an obsolete feature of gmx convert-tpr.\n" " Continuation should be done by loading a checkpoint file with mdrun -cpi\n" " This guarantees that all state variables are transferred.\n" " gmx convert-tpr is now only useful for increasing nsteps,\n" " but even that can often be avoided by using mdrun -maxh\n" "\n"); if (ir->bContinuation != bContinuation) { fprintf(stderr, "Modifying ir->bContinuation to %s\n", bool_names[bContinuation]); } ir->bContinuation = bContinuation; bNeedEner = (ir->epc == epcPARRINELLORAHMAN || ir->etc == etcNOSEHOOVER); bReadEner = (bNeedEner && ftp2bSet(efEDR, NFILE, fnm)); bScanEner = (bReadEner && !bTime); if (ir->epc != epcNO || EI_SD(ir->eI) || ir->eI == eiBD) { fprintf(stderr, "NOTE: The simulation uses pressure coupling and/or stochastic dynamics.\n" "gmx convert-tpr can not provide binary identical continuation.\n" "If you want that, supply a checkpoint file to mdrun\n\n"); } if (EI_SD(ir->eI) || ir->eI == eiBD) { fprintf(stderr, "\nChanging ld-seed from %" GMX_PRId64 " ", ir->ld_seed); ir->ld_seed = (gmx_int64_t)gmx_rng_make_seed(); fprintf(stderr, "to %" GMX_PRId64 "\n\n", ir->ld_seed); } frame_fn = ftp2fn(efTRN, NFILE, fnm); if (fn2ftp(frame_fn) == efCPT) { int sim_part; fprintf(stderr, "\nREADING STATE FROM CHECKPOINT %s...\n\n", frame_fn); read_checkpoint_state(frame_fn, &sim_part, &run_step, &run_t, &state); } else { fprintf(stderr, "\nREADING COORDS, VELS AND BOX FROM TRAJECTORY %s...\n\n", frame_fn); fp = gmx_trr_open(frame_fn, "r"); if (bScanEner) { fp_ener = open_enx(ftp2fn(efEDR, NFILE, fnm), "r"); do_enxnms(fp_ener, &nre, &enm); snew(fr_ener, 1); fr_ener->t = -1e-12; } /* Now scan until the last set of x and v (step == 0) * or the ones at step step. */ bFrame = TRUE; frame = 0; while (bFrame) { bFrame = gmx_trr_read_frame_header(fp, &head, &bOK); if (bOK && frame == 0) { if (mtop.natoms != head.natoms) { gmx_fatal(FARGS, "Number of atoms in Topology (%d) " "is not the same as in Trajectory (%d)\n", mtop.natoms, head.natoms); } snew(newx, head.natoms); snew(newv, head.natoms); } bFrame = bFrame && bOK; if (bFrame) { bOK = gmx_trr_read_frame_data(fp, &head, newbox, newx, newv, NULL); } bFrame = bFrame && bOK; bUse = FALSE; if (bFrame && (head.x_size) && (head.v_size || !bVel)) { bUse = TRUE; if (bScanEner) { /* Read until the energy time is >= the trajectory time */ while (fr_ener->t < head.t && do_enx(fp_ener, fr_ener)) { ; } bUse = (fr_ener->t == head.t); } if (bUse) { tmpx = newx; newx = state.x; state.x = tmpx; tmpv = newv; newv = state.v; state.v = tmpv; run_t = head.t; run_step = head.step; state.fep_state = head.fep_state; state.lambda[efptFEP] = head.lambda; copy_mat(newbox, state.box); } } if (bFrame || !bOK) { sprintf(buf, "\r%s %s frame %s%s: step %s%s time %s", "%s", "%s", "%6", GMX_PRId64, "%6", GMX_PRId64, " %8.3f"); fprintf(stderr, buf, bUse ? "Read " : "Skipped", ftp2ext(fn2ftp(frame_fn)), frame, head.step, head.t); frame++; if (bTime && (head.t >= start_t)) { bFrame = FALSE; } } } if (bScanEner) { close_enx(fp_ener); free_enxframe(fr_ener); free_enxnms(nre, enm); } gmx_trr_close(fp); fprintf(stderr, "\n"); if (!bOK) { fprintf(stderr, "%s frame %s (step %s, time %g) is incomplete\n", ftp2ext(fn2ftp(frame_fn)), gmx_step_str(frame-1, buf2), gmx_step_str(head.step, buf), head.t); } fprintf(stderr, "\nUsing frame of step %s time %g\n", gmx_step_str(run_step, buf), run_t); if (bNeedEner) { if (bReadEner) { get_enx_state(ftp2fn(efEDR, NFILE, fnm), run_t, &mtop.groups, ir, &state); } else { fprintf(stderr, "\nWARNING: The simulation uses %s temperature and/or %s pressure coupling,\n" " the continuation will only be exact when an energy file is supplied\n\n", ETCOUPLTYPE(etcNOSEHOOVER), EPCOUPLTYPE(epcPARRINELLORAHMAN)); } } if (bFepState) { ir->fepvals->init_fep_state = init_fep_state; } } } if (bNsteps) { fprintf(stderr, "Setting nsteps to %s\n", gmx_step_str(nsteps_req, buf)); ir->nsteps = nsteps_req; } else { /* Determine total number of steps remaining */ if (bExtend) { ir->nsteps = ir->nsteps - (run_step - ir->init_step) + (gmx_int64_t)(extend_t/ir->delta_t + 0.5); printf("Extending remaining runtime of by %g ps (now %s steps)\n", extend_t, gmx_step_str(ir->nsteps, buf)); } else if (bUntil) { printf("nsteps = %s, run_step = %s, current_t = %g, until = %g\n", gmx_step_str(ir->nsteps, buf), gmx_step_str(run_step, buf2), run_t, until_t); ir->nsteps = (gmx_int64_t)((until_t - run_t)/ir->delta_t + 0.5); printf("Extending remaining runtime until %g ps (now %s steps)\n", until_t, gmx_step_str(ir->nsteps, buf)); } else { ir->nsteps -= run_step - ir->init_step; /* Print message */ printf("%s steps (%g ps) remaining from first run.\n", gmx_step_str(ir->nsteps, buf), ir->nsteps*ir->delta_t); } } if (bNsteps || bZeroQ || (ir->nsteps > 0)) { ir->init_step = run_step; if (ftp2bSet(efNDX, NFILE, fnm) || !(bNsteps || bExtend || bUntil || bTraj)) { atoms = gmx_mtop_global_atoms(&mtop); get_index(&atoms, ftp2fn_null(efNDX, NFILE, fnm), 1, &gnx, &index, &grpname); if (!bZeroQ) { bSel = (gnx != state.natoms); for (i = 0; ((i < gnx) && (!bSel)); i++) { bSel = (i != index[i]); } } else { bSel = FALSE; } if (bSel) { fprintf(stderr, "Will write subset %s of original tpx containing %d " "atoms\n", grpname, gnx); reduce_topology_x(gnx, index, &mtop, state.x, state.v); state.natoms = gnx; } else if (bZeroQ) { zeroq(index, &mtop); fprintf(stderr, "Zero-ing charges for group %s\n", grpname); } else { fprintf(stderr, "Will write full tpx file (no selection)\n"); } } state_t = ir->init_t + ir->init_step*ir->delta_t; sprintf(buf, "Writing statusfile with starting step %s%s and length %s%s steps...\n", "%10", GMX_PRId64, "%10", GMX_PRId64); fprintf(stderr, buf, ir->init_step, ir->nsteps); fprintf(stderr, " time %10.3f and length %10.3f ps\n", state_t, ir->nsteps*ir->delta_t); write_tpx_state(opt2fn("-o", NFILE, fnm), ir, &state, &mtop); } else { printf("You've simulated long enough. Not writing tpr file\n"); } return 0; }
int read_ter_db(char *FF,char ter,t_hackblock **tbptr,t_atomtype atype) { FILE *in; char inf[STRLEN],header[STRLEN],buf[STRLEN],line[STRLEN]; t_hackblock *tb; int i,j,n,ni,kwnr,nb,maxnb,nh; sprintf(inf,"%s-%c.tdb",FF,ter); in=libopen(inf); if (debug) fprintf(debug,"Opened %s\n",inf); tb=NULL; nb=-1; maxnb=0; kwnr=NOTSET; get_a_line(in,line,STRLEN); while (!feof(in)) { if (get_header(line,header)) { /* this is a new block, or a new keyword */ kwnr=find_kw(header); if (kwnr == NOTSET) { nb++; /* here starts a new block */ if ( nb >= maxnb ) { maxnb+=100; srenew(tb,maxnb); } clear_t_hackblock(&tb[nb]); tb[nb].name=strdup(header); } } else { if (nb < 0) gmx_fatal(FARGS,"reading termini database: " "directive expected before line:\n%s\n" "This might be a file in an old format.",line); /* this is not a header, so it must be data */ if (kwnr >= ebtsNR) { /* this is a hack: add/rename/delete atoms */ /* make space for hacks */ if (tb[nb].nhack >= tb[nb].maxhack) { tb[nb].maxhack+=10; srenew(tb[nb].hack, tb[nb].maxhack); } nh=tb[nb].nhack; clear_t_hack(&(tb[nb].hack[nh])); for(i=0; i<4; i++) tb[nb].hack[nh].a[i]=NULL; tb[nb].nhack++; /* get data */ n=0; if ( kwnr==ekwRepl || kwnr==ekwDel ) { if (sscanf(line, "%s%n", buf, &n) != 1) gmx_fatal(FARGS,"Reading Termini Database: " "expected atom name on line\n%s",line); tb[nb].hack[nh].oname = strdup(buf); /* we only replace or delete one atom at a time */ tb[nb].hack[nh].nr = 1; } else if ( kwnr==ekwAdd ) { read_ab(line, inf, &(tb[nb].hack[nh])); get_a_line(in, line, STRLEN); } else gmx_fatal(FARGS,"unimplemented keyword number %d (%s:%d)", kwnr,__FILE__,__LINE__); if ( kwnr==ekwRepl || kwnr==ekwAdd ) { snew(tb[nb].hack[nh].atom, 1); read_atom(line+n, tb[nb].hack[nh].atom, atype, &tb[nb].hack[nh].cgnr); if (!tb[nb].hack[nh].nname) { if (tb[nb].hack[nh].oname) tb[nb].hack[nh].nname = strdup(tb[nb].hack[nh].oname); else gmx_fatal(FARGS,"Don't know which name the new atom should have"); } } } else if (kwnr >= 0 && kwnr < ebtsNR) { /* this is bonded data: bonds, angles, dihedrals or impropers */ srenew(tb[nb].rb[kwnr].b,tb[nb].rb[kwnr].nb+1); n=0; for(j=0; j<btsNiatoms[kwnr]; j++) { if ( sscanf(line+n, "%s%n", buf, &ni) == 1 ) tb[nb].rb[kwnr].b[tb[nb].rb[kwnr].nb].a[j] = strdup(buf); else gmx_fatal(FARGS,"Reading Termini Database: expected %d atom names (found %d) on line\n%s", btsNiatoms[kwnr], j-1, line); n+=ni; } for( ; j<MAXATOMLIST; j++) tb[nb].rb[kwnr].b[tb[nb].rb[kwnr].nb].a[j] = NULL; strcpy(buf, ""); sscanf(line+n, "%s", buf); tb[nb].rb[kwnr].b[tb[nb].rb[kwnr].nb].s = strdup(buf); tb[nb].rb[kwnr].nb++; } else gmx_fatal(FARGS,"Reading Termini Database: Expecting a header at line\n" "%s",line); } get_a_line(in,line,STRLEN); } nb++; srenew(tb,nb); fclose(in); if (debug) print_ter_db(FF,ter,nb,tb,atype); *tbptr=tb; return nb; }
void calc_h2order(const char *fn, atom_id index[], int ngx, rvec **slDipole, real **slOrder, real *slWidth, int *nslices, t_topology *top, int ePBC, int axis, gmx_bool bMicel, atom_id micel[], int nmic, const output_env_t oenv) { rvec *x0, /* coordinates with pbc */ dipole, /* dipole moment due to one molecules */ normal, com; /* center of mass of micel, with bMicel */ rvec *dip; /* sum of dipoles, unnormalized */ matrix box; /* box (3x3) */ t_trxstatus *status; real t, /* time from trajectory */ *sum, /* sum of all cosines of dipoles, per slice */ *frame; /* order over one frame */ int natoms, /* nr. atoms in trj */ i, j, teller = 0, slice = 0, /* current slice number */ *count; /* nr. of atoms in one slice */ gmx_rmpbc_t gpbc = NULL; if ((natoms = read_first_x(oenv, &status, fn, &t, &x0, box)) == 0) { gmx_fatal(FARGS, "Could not read coordinates from statusfile\n"); } if (!*nslices) { *nslices = (int)(box[axis][axis] * 10); /* default value */ } switch (axis) { case 0: normal[0] = 1; normal[1] = 0; normal[2] = 0; break; case 1: normal[0] = 0; normal[1] = 1; normal[2] = 0; break; case 2: normal[0] = 0; normal[1] = 0; normal[2] = 1; break; default: gmx_fatal(FARGS, "No valid value for -axis-. Exiting.\n"); /* make compiler happy */ normal[0] = 1; normal[1] = 0; normal[2] = 0; } clear_rvec(dipole); snew(count, *nslices); snew(sum, *nslices); snew(dip, *nslices); snew(frame, *nslices); *slWidth = box[axis][axis]/(*nslices); fprintf(stderr, "Box divided in %d slices. Initial width of slice: %f\n", *nslices, *slWidth); teller = 0; gpbc = gmx_rmpbc_init(&top->idef, ePBC, natoms); /*********** Start processing trajectory ***********/ do { *slWidth = box[axis][axis]/(*nslices); teller++; gmx_rmpbc(gpbc, natoms, box, x0); if (bMicel) { calc_xcm(x0, nmic, micel, top->atoms.atom, com, FALSE); } for (i = 0; i < ngx/3; i++) { /* put all waters in box */ for (j = 0; j < DIM; j++) { if (x0[index[3*i]][j] < 0) { x0[index[3*i]][j] += box[j][j]; x0[index[3*i+1]][j] += box[j][j]; x0[index[3*i+2]][j] += box[j][j]; } if (x0[index[3*i]][j] > box[j][j]) { x0[index[3*i]][j] -= box[j][j]; x0[index[3*i+1]][j] -= box[j][j]; x0[index[3*i+2]][j] -= box[j][j]; } } for (j = 0; j < DIM; j++) { dipole[j] = x0[index[3*i]][j] * top->atoms.atom[index[3*i]].q + x0[index[3*i+1]][j] * top->atoms.atom[index[3*i+1]].q + x0[index[3*i+2]][j] * top->atoms.atom[index[3*i+2]].q; } /* now we have a dipole vector. Might as well safe it. Then the rest depends on whether we're dealing with a flat or a spherical interface. */ if (bMicel) { /* this is for spherical interfaces */ rvec_sub(com, x0[index[3*i]], normal); /* vector from Oxygen to COM */ slice = norm(normal)/(*slWidth); /* spherical slice */ sum[slice] += iprod(dipole, normal) / (norm(dipole) * norm(normal)); frame[slice] += iprod(dipole, normal) / (norm(dipole) * norm(normal)); count[slice]++; } else { /* this is for flat interfaces */ /* determine which slice atom is in */ slice = (x0[index[3*i]][axis] / (*slWidth)); if (slice < 0 || slice >= *nslices) { fprintf(stderr, "Coordinate: %f ", x0[index[3*i]][axis]); fprintf(stderr, "HELP PANIC! slice = %d, OUT OF RANGE!\n", slice); } else { rvec_add(dipole, dip[slice], dip[slice]); /* Add dipole to total. mag[slice] is total dipole in axis direction */ sum[slice] += iprod(dipole, normal)/norm(dipole); frame[slice] += iprod(dipole, normal)/norm(dipole); /* increase count for that slice */ count[slice]++; } } } } while (read_next_x(oenv, status, &t, x0, box)); /*********** done with status file **********/ fprintf(stderr, "\nRead trajectory. Printing parameters to file\n"); gmx_rmpbc_done(gpbc); for (i = 0; i < *nslices; i++) /* average over frames */ { fprintf(stderr, "%d waters in slice %d\n", count[i], i); if (count[i] > 0) /* divide by number of molecules in each slice */ { sum[i] = sum[i] / count[i]; dip[i][XX] = dip[i][XX] / count[i]; dip[i][YY] = dip[i][YY] / count[i]; dip[i][ZZ] = dip[i][ZZ] / count[i]; } else { fprintf(stderr, "No water in slice %d\n", i); } } *slOrder = sum; /* copy a pointer, I hope */ *slDipole = dip; sfree(x0); /* free memory used by coordinate arrays */ }
int gmx_sorient(int argc, char *argv[]) { t_topology top; int ePBC = -1; char title[STRLEN]; t_trxstatus *status; int natoms; real t; rvec *xtop, *x; matrix box; FILE *fp; int i, j, p, sa0, sa1, sa2, n, ntot, nf, m, *hist1, *hist2, *histn, nbin1, nbin2, nrbin; real *histi1, *histi2, invbw, invrbw; double sum1, sum2; int *isize, nrefgrp, nrefat; atom_id **index; char **grpname; real inp, outp, two_pi, nav, normfac, rmin2, rmax2, rcut, rcut2, r2, r, mass, mtot; real c1, c2; char str[STRLEN]; gmx_bool bTPS; rvec xref, dx, dxh1, dxh2, outer; gmx_rmpbc_t gpbc = NULL; t_pbc pbc; const char *legr[] = { "<cos(\\8q\\4\\s1\\N)>", "<3cos\\S2\\N(\\8q\\4\\s2\\N)-1>" }; const char *legc[] = { "cos(\\8q\\4\\s1\\N)", "3cos\\S2\\N(\\8q\\4\\s2\\N)-1" }; const char *desc[] = { "[TT]g_sorient[tt] analyzes solvent orientation around solutes.", "It calculates two angles between the vector from one or more", "reference positions to the first atom of each solvent molecule:[PAR]", "[GRK]theta[grk][SUB]1[sub]: the angle with the vector from the first atom of the solvent", "molecule to the midpoint between atoms 2 and 3.[BR]", "[GRK]theta[grk][SUB]2[sub]: the angle with the normal of the solvent plane, defined by the", "same three atoms, or, when the option [TT]-v23[tt] is set, ", "the angle with the vector between atoms 2 and 3.[PAR]", "The reference can be a set of atoms or", "the center of mass of a set of atoms. The group of solvent atoms should", "consist of 3 atoms per solvent molecule.", "Only solvent molecules between [TT]-rmin[tt] and [TT]-rmax[tt] are", "considered for [TT]-o[tt] and [TT]-no[tt] each frame.[PAR]", "[TT]-o[tt]: distribtion of [MATH][COS][GRK]theta[grk][SUB]1[sub][cos][math] for rmin<=r<=rmax.[PAR]", "[TT]-no[tt]: distribution of [MATH][COS][GRK]theta[grk][SUB]2[sub][cos][math] for rmin<=r<=rmax.[PAR]", "[TT]-ro[tt]: [MATH][CHEVRON][COS][GRK]theta[grk][SUB]1[sub][cos][chevron][math] and [MATH][CHEVRON]3[COS]^2[GRK]theta[grk][SUB]2[sub][cos]-1[chevron][math] as a function of the", "distance.[PAR]", "[TT]-co[tt]: the sum over all solvent molecules within distance r", "of [MATH][COS][GRK]theta[grk][SUB]1[sub][cos][math] and [MATH]3[COS]^2([GRK]theta[grk][SUB]2[sub])-1[cos][math] as a function of r.[PAR]", "[TT]-rc[tt]: the distribution of the solvent molecules as a function of r" }; output_env_t oenv; static gmx_bool bCom = FALSE, bVec23 = FALSE, bPBC = FALSE; static real rmin = 0.0, rmax = 0.5, binwidth = 0.02, rbinw = 0.02; t_pargs pa[] = { { "-com", FALSE, etBOOL, {&bCom}, "Use the center of mass as the reference postion" }, { "-v23", FALSE, etBOOL, {&bVec23}, "Use the vector between atoms 2 and 3" }, { "-rmin", FALSE, etREAL, {&rmin}, "Minimum distance (nm)" }, { "-rmax", FALSE, etREAL, {&rmax}, "Maximum distance (nm)" }, { "-cbin", FALSE, etREAL, {&binwidth}, "Binwidth for the cosine" }, { "-rbin", FALSE, etREAL, {&rbinw}, "Binwidth for r (nm)" }, { "-pbc", FALSE, etBOOL, {&bPBC}, "Check PBC for the center of mass calculation. Only necessary when your reference group consists of several molecules." } }; t_filenm fnm[] = { { efTRX, NULL, NULL, ffREAD }, { efTPS, NULL, NULL, ffREAD }, { efNDX, NULL, NULL, ffOPTRD }, { efXVG, NULL, "sori.xvg", ffWRITE }, { efXVG, "-no", "snor.xvg", ffWRITE }, { efXVG, "-ro", "sord.xvg", ffWRITE }, { efXVG, "-co", "scum.xvg", ffWRITE }, { efXVG, "-rc", "scount.xvg", ffWRITE } }; #define NFILE asize(fnm) 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); two_pi = 2/M_PI; bTPS = (opt2bSet("-s", NFILE, fnm) || !opt2bSet("-n", NFILE, fnm) || bCom); if (bTPS) { read_tps_conf(ftp2fn(efTPS, NFILE, fnm), title, &top, &ePBC, &xtop, NULL, box, bCom); } /* get index groups */ printf("Select a group of reference particles and a solvent group:\n"); snew(grpname, 2); snew(index, 2); snew(isize, 2); if (bTPS) { get_index(&top.atoms, ftp2fn_null(efNDX, NFILE, fnm), 2, isize, index, grpname); } else { get_index(NULL, ftp2fn(efNDX, NFILE, fnm), 2, isize, index, grpname); } if (bCom) { nrefgrp = 1; nrefat = isize[0]; } else { nrefgrp = isize[0]; nrefat = 1; } if (isize[1] % 3) { gmx_fatal(FARGS, "The number of solvent atoms (%d) is not a multiple of 3", isize[1]); } /* initialize reading trajectory: */ natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box); rmin2 = sqr(rmin); rmax2 = sqr(rmax); rcut = 0.99*sqrt(max_cutoff2(guess_ePBC(box), box)); if (rcut == 0) { rcut = 10*rmax; } rcut2 = sqr(rcut); invbw = 1/binwidth; nbin1 = 1+(int)(2*invbw + 0.5); nbin2 = 1+(int)(invbw + 0.5); invrbw = 1/rbinw; snew(hist1, nbin1); snew(hist2, nbin2); nrbin = 1+(int)(rcut/rbinw); if (nrbin == 0) { nrbin = 1; } snew(histi1, nrbin); snew(histi2, nrbin); snew(histn, nrbin); ntot = 0; nf = 0; sum1 = 0; sum2 = 0; if (bTPS) { /* make molecules whole again */ gpbc = gmx_rmpbc_init(&top.idef, ePBC, natoms); } /* start analysis of trajectory */ do { if (bTPS) { /* make molecules whole again */ gmx_rmpbc(gpbc, natoms, box, x); } set_pbc(&pbc, ePBC, box); n = 0; inp = 0; outp = 0; for (p = 0; (p < nrefgrp); p++) { if (bCom) { calc_com_pbc(nrefat, &top, x, &pbc, index[0], xref, bPBC); } else { copy_rvec(x[index[0][p]], xref); } for (m = 0; m < isize[1]; m += 3) { sa0 = index[1][m]; sa1 = index[1][m+1]; sa2 = index[1][m+2]; range_check(sa0, 0, natoms); range_check(sa1, 0, natoms); range_check(sa2, 0, natoms); pbc_dx(&pbc, x[sa0], xref, dx); r2 = norm2(dx); if (r2 < rcut2) { r = sqrt(r2); if (!bVec23) { /* Determine the normal to the plain */ rvec_sub(x[sa1], x[sa0], dxh1); rvec_sub(x[sa2], x[sa0], dxh2); rvec_inc(dxh1, dxh2); svmul(1/r, dx, dx); unitv(dxh1, dxh1); inp = iprod(dx, dxh1); cprod(dxh1, dxh2, outer); unitv(outer, outer); outp = iprod(dx, outer); } else { /* Use the vector between the 2nd and 3rd atom */ rvec_sub(x[sa2], x[sa1], dxh2); unitv(dxh2, dxh2); outp = iprod(dx, dxh2)/r; } { int ii = (int)(invrbw*r); range_check(ii, 0, nrbin); histi1[ii] += inp; histi2[ii] += 3*sqr(outp) - 1; histn[ii]++; } if ((r2 >= rmin2) && (r2 < rmax2)) { int ii1 = (int)(invbw*(inp + 1)); int ii2 = (int)(invbw*fabs(outp)); range_check(ii1, 0, nbin1); range_check(ii2, 0, nbin2); hist1[ii1]++; hist2[ii2]++; sum1 += inp; sum2 += outp; n++; } } } } ntot += n; nf++; } while (read_next_x(oenv, status, &t, x, box)); /* clean up */ sfree(x); close_trj(status); gmx_rmpbc_done(gpbc); /* Add the bin for the exact maximum to the previous bin */ hist1[nbin1-1] += hist1[nbin1]; hist2[nbin2-1] += hist2[nbin2]; nav = (real)ntot/(nrefgrp*nf); normfac = invbw/ntot; fprintf(stderr, "Average nr of molecules between %g and %g nm: %.1f\n", rmin, rmax, nav); if (ntot > 0) { sum1 /= ntot; sum2 /= ntot; fprintf(stderr, "Average cos(theta1) between %g and %g nm: %6.3f\n", rmin, rmax, sum1); fprintf(stderr, "Average 3cos2(theta2)-1 between %g and %g nm: %6.3f\n", rmin, rmax, sum2); } sprintf(str, "Solvent orientation between %g and %g nm", rmin, rmax); fp = xvgropen(opt2fn("-o", NFILE, fnm), str, "cos(\\8q\\4\\s1\\N)", "", oenv); if (output_env_get_print_xvgr_codes(oenv)) { fprintf(fp, "@ subtitle \"average shell size %.1f molecules\"\n", nav); } for (i = 0; i < nbin1; i++) { fprintf(fp, "%g %g\n", (i+0.5)*binwidth-1, 2*normfac*hist1[i]); } ffclose(fp); sprintf(str, "Solvent normal orientation between %g and %g nm", rmin, rmax); fp = xvgropen(opt2fn("-no", NFILE, fnm), str, "cos(\\8q\\4\\s2\\N)", "", oenv); if (output_env_get_print_xvgr_codes(oenv)) { fprintf(fp, "@ subtitle \"average shell size %.1f molecules\"\n", nav); } for (i = 0; i < nbin2; i++) { fprintf(fp, "%g %g\n", (i+0.5)*binwidth, normfac*hist2[i]); } ffclose(fp); sprintf(str, "Solvent orientation"); fp = xvgropen(opt2fn("-ro", NFILE, fnm), str, "r (nm)", "", oenv); if (output_env_get_print_xvgr_codes(oenv)) { fprintf(fp, "@ subtitle \"as a function of distance\"\n"); } xvgr_legend(fp, 2, legr, oenv); for (i = 0; i < nrbin; i++) { fprintf(fp, "%g %g %g\n", (i+0.5)*rbinw, histn[i] ? histi1[i]/histn[i] : 0, histn[i] ? histi2[i]/histn[i] : 0); } ffclose(fp); sprintf(str, "Cumulative solvent orientation"); fp = xvgropen(opt2fn("-co", NFILE, fnm), str, "r (nm)", "", oenv); if (output_env_get_print_xvgr_codes(oenv)) { fprintf(fp, "@ subtitle \"as a function of distance\"\n"); } xvgr_legend(fp, 2, legc, oenv); normfac = 1.0/(nrefgrp*nf); c1 = 0; c2 = 0; fprintf(fp, "%g %g %g\n", 0.0, c1, c2); for (i = 0; i < nrbin; i++) { c1 += histi1[i]*normfac; c2 += histi2[i]*normfac; fprintf(fp, "%g %g %g\n", (i+1)*rbinw, c1, c2); } ffclose(fp); sprintf(str, "Solvent distribution"); fp = xvgropen(opt2fn("-rc", NFILE, fnm), str, "r (nm)", "molecules/nm", oenv); if (output_env_get_print_xvgr_codes(oenv)) { fprintf(fp, "@ subtitle \"as a function of distance\"\n"); } normfac = 1.0/(rbinw*nf); for (i = 0; i < nrbin; i++) { fprintf(fp, "%g %g\n", (i+0.5)*rbinw, histn[i]*normfac); } ffclose(fp); do_view(oenv, opt2fn("-o", NFILE, fnm), NULL); do_view(oenv, opt2fn("-no", NFILE, fnm), NULL); do_view(oenv, opt2fn("-ro", NFILE, fnm), "-nxy"); do_view(oenv, opt2fn("-co", NFILE, fnm), "-nxy"); return 0; }
void do_force_lowlevel(FILE *fplog, gmx_large_int_t step, t_forcerec *fr, t_inputrec *ir, t_idef *idef, t_commrec *cr, t_nrnb *nrnb, gmx_wallcycle_t wcycle, t_mdatoms *md, t_grpopts *opts, rvec x[], history_t *hist, rvec f[], rvec f_longrange[], gmx_enerdata_t *enerd, t_fcdata *fcd, gmx_mtop_t *mtop, gmx_localtop_t *top, gmx_genborn_t *born, t_atomtypes *atype, gmx_bool bBornRadii, matrix box, t_lambda *fepvals, real *lambda, t_graph *graph, t_blocka *excl, rvec mu_tot[], int flags, float *cycles_pme) { int i, j, status; int donb_flags; gmx_bool bDoEpot, bSepDVDL, bSB; int pme_flags; matrix boxs; rvec box_size; real Vsr, Vlr, Vcorr = 0; t_pbc pbc; real dvdgb; char buf[22]; double clam_i, vlam_i; real dvdl_dum[efptNR], dvdl, dvdl_nb[efptNR], lam_i[efptNR]; real dvdlsum; #ifdef GMX_MPI double t0 = 0.0, t1, t2, t3; /* time measurement for coarse load balancing */ #endif #define PRINT_SEPDVDL(s, v, dvdlambda) if (bSepDVDL) {fprintf(fplog, sepdvdlformat, s, v, dvdlambda); } GMX_MPE_LOG(ev_force_start); set_pbc(&pbc, fr->ePBC, box); /* reset free energy components */ for (i = 0; i < efptNR; i++) { dvdl_nb[i] = 0; dvdl_dum[i] = 0; } /* Reset box */ for (i = 0; (i < DIM); i++) { box_size[i] = box[i][i]; } bSepDVDL = (fr->bSepDVDL && do_per_step(step, ir->nstlog)); debug_gmx(); /* do QMMM first if requested */ if (fr->bQMMM) { enerd->term[F_EQM] = calculate_QMMM(cr, x, f, fr, md); } if (bSepDVDL) { fprintf(fplog, "Step %s: non-bonded V and dVdl for node %d:\n", gmx_step_str(step, buf), cr->nodeid); } /* Call the short range functions all in one go. */ GMX_MPE_LOG(ev_do_fnbf_start); #ifdef GMX_MPI /*#define TAKETIME ((cr->npmenodes) && (fr->timesteps < 12))*/ #define TAKETIME FALSE if (TAKETIME) { MPI_Barrier(cr->mpi_comm_mygroup); t0 = MPI_Wtime(); } #endif if (ir->nwall) { /* foreign lambda component for walls */ dvdl = do_walls(ir, fr, box, md, x, f, lambda[efptVDW], enerd->grpp.ener[egLJSR], nrnb); PRINT_SEPDVDL("Walls", 0.0, dvdl); enerd->dvdl_lin[efptVDW] += dvdl; } /* If doing GB, reset dvda and calculate the Born radii */ if (ir->implicit_solvent) { wallcycle_sub_start(wcycle, ewcsNONBONDED); for (i = 0; i < born->nr; i++) { fr->dvda[i] = 0; } if (bBornRadii) { calc_gb_rad(cr, fr, ir, top, atype, x, &(fr->gblist), born, md, nrnb); } wallcycle_sub_stop(wcycle, ewcsNONBONDED); } where(); /* We only do non-bonded calculation with group scheme here, the verlet * calls are done from do_force_cutsVERLET(). */ if (fr->cutoff_scheme == ecutsGROUP && (flags & GMX_FORCE_NONBONDED)) { donb_flags = 0; /* Add short-range interactions */ donb_flags |= GMX_NONBONDED_DO_SR; if (flags & GMX_FORCE_FORCES) { donb_flags |= GMX_NONBONDED_DO_FORCE; } if (flags & GMX_FORCE_ENERGY) { donb_flags |= GMX_NONBONDED_DO_POTENTIAL; } if (flags & GMX_FORCE_DO_LR) { donb_flags |= GMX_NONBONDED_DO_LR; } wallcycle_sub_start(wcycle, ewcsNONBONDED); do_nonbonded(cr, fr, x, f, f_longrange, md, excl, &enerd->grpp, box_size, nrnb, lambda, dvdl_nb, -1, -1, donb_flags); /* If we do foreign lambda and we have soft-core interactions * we have to recalculate the (non-linear) energies contributions. */ if (fepvals->n_lambda > 0 && (flags & GMX_FORCE_DHDL) && fepvals->sc_alpha != 0) { for (i = 0; i < enerd->n_lambda; i++) { for (j = 0; j < efptNR; j++) { lam_i[j] = (i == 0 ? lambda[j] : fepvals->all_lambda[j][i-1]); } reset_foreign_enerdata(enerd); do_nonbonded(cr, fr, x, f, f_longrange, md, excl, &(enerd->foreign_grpp), box_size, nrnb, lam_i, dvdl_dum, -1, -1, (donb_flags & ~GMX_NONBONDED_DO_FORCE) | GMX_NONBONDED_DO_FOREIGNLAMBDA); sum_epot(&ir->opts, &(enerd->foreign_grpp), enerd->foreign_term); enerd->enerpart_lambda[i] += enerd->foreign_term[F_EPOT]; } } wallcycle_sub_stop(wcycle, ewcsNONBONDED); where(); } /* If we are doing GB, calculate bonded forces and apply corrections * to the solvation forces */ /* MRS: Eventually, many need to include free energy contribution here! */ if (ir->implicit_solvent) { wallcycle_sub_start(wcycle, ewcsBONDED); calc_gb_forces(cr, md, born, top, atype, x, f, fr, idef, ir->gb_algorithm, ir->sa_algorithm, nrnb, bBornRadii, &pbc, graph, enerd); wallcycle_sub_stop(wcycle, ewcsBONDED); } #ifdef GMX_MPI if (TAKETIME) { t1 = MPI_Wtime(); fr->t_fnbf += t1-t0; } #endif if (fepvals->sc_alpha != 0) { enerd->dvdl_nonlin[efptVDW] += dvdl_nb[efptVDW]; } else { enerd->dvdl_lin[efptVDW] += dvdl_nb[efptVDW]; } if (fepvals->sc_alpha != 0) /* even though coulomb part is linear, we already added it, beacuse we need to go through the vdw calculation anyway */ { enerd->dvdl_nonlin[efptCOUL] += dvdl_nb[efptCOUL]; } else { enerd->dvdl_lin[efptCOUL] += dvdl_nb[efptCOUL]; } Vsr = 0; if (bSepDVDL) { for (i = 0; i < enerd->grpp.nener; i++) { Vsr += (fr->bBHAM ? enerd->grpp.ener[egBHAMSR][i] : enerd->grpp.ener[egLJSR][i]) + enerd->grpp.ener[egCOULSR][i] + enerd->grpp.ener[egGB][i]; } dvdlsum = dvdl_nb[efptVDW] + dvdl_nb[efptCOUL]; PRINT_SEPDVDL("VdW and Coulomb SR particle-p.", Vsr, dvdlsum); } debug_gmx(); GMX_MPE_LOG(ev_do_fnbf_finish); if (debug) { pr_rvecs(debug, 0, "fshift after SR", fr->fshift, SHIFTS); } /* Shift the coordinates. Must be done before bonded forces and PPPM, * but is also necessary for SHAKE and update, therefore it can NOT * go when no bonded forces have to be evaluated. */ /* Here sometimes we would not need to shift with NBFonly, * but we do so anyhow for consistency of the returned coordinates. */ if (graph) { shift_self(graph, box, x); if (TRICLINIC(box)) { inc_nrnb(nrnb, eNR_SHIFTX, 2*graph->nnodes); } else { inc_nrnb(nrnb, eNR_SHIFTX, graph->nnodes); } } /* Check whether we need to do bondeds or correct for exclusions */ if (fr->bMolPBC && ((flags & GMX_FORCE_BONDED) || EEL_RF(fr->eeltype) || EEL_FULL(fr->eeltype))) { /* Since all atoms are in the rectangular or triclinic unit-cell, * only single box vector shifts (2 in x) are required. */ set_pbc_dd(&pbc, fr->ePBC, cr->dd, TRUE, box); } debug_gmx(); if (flags & GMX_FORCE_BONDED) { GMX_MPE_LOG(ev_calc_bonds_start); wallcycle_sub_start(wcycle, ewcsBONDED); calc_bonds(fplog, cr->ms, idef, x, hist, f, fr, &pbc, graph, enerd, nrnb, lambda, md, fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL, atype, born, flags, fr->bSepDVDL && do_per_step(step, ir->nstlog), step); /* Check if we have to determine energy differences * at foreign lambda's. */ if (fepvals->n_lambda > 0 && (flags & GMX_FORCE_DHDL) && idef->ilsort != ilsortNO_FE) { if (idef->ilsort != ilsortFE_SORTED) { gmx_incons("The bonded interactions are not sorted for free energy"); } for (i = 0; i < enerd->n_lambda; i++) { reset_foreign_enerdata(enerd); for (j = 0; j < efptNR; j++) { lam_i[j] = (i == 0 ? lambda[j] : fepvals->all_lambda[j][i-1]); } calc_bonds_lambda(fplog, idef, x, fr, &pbc, graph, &(enerd->foreign_grpp), enerd->foreign_term, nrnb, lam_i, md, fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL); sum_epot(&ir->opts, &(enerd->foreign_grpp), enerd->foreign_term); enerd->enerpart_lambda[i] += enerd->foreign_term[F_EPOT]; } } debug_gmx(); GMX_MPE_LOG(ev_calc_bonds_finish); wallcycle_sub_stop(wcycle, ewcsBONDED); } where(); *cycles_pme = 0; if (EEL_FULL(fr->eeltype)) { bSB = (ir->nwall == 2); if (bSB) { copy_mat(box, boxs); svmul(ir->wall_ewald_zfac, boxs[ZZ], boxs[ZZ]); box_size[ZZ] *= ir->wall_ewald_zfac; } clear_mat(fr->vir_el_recip); if (fr->bEwald) { Vcorr = 0; dvdl = 0; /* With the Verlet scheme exclusion forces are calculated * in the non-bonded kernel. */ /* The TPI molecule does not have exclusions with the rest * of the system and no intra-molecular PME grid contributions * will be calculated in gmx_pme_calc_energy. */ if ((ir->cutoff_scheme == ecutsGROUP && fr->n_tpi == 0) || ir->ewald_geometry != eewg3D || ir->epsilon_surface != 0) { int nthreads, t; wallcycle_sub_start(wcycle, ewcsEWALD_CORRECTION); if (fr->n_tpi > 0) { gmx_fatal(FARGS, "TPI with PME currently only works in a 3D geometry with tin-foil boundary conditions"); } nthreads = gmx_omp_nthreads_get(emntBonded); #pragma omp parallel for num_threads(nthreads) schedule(static) for (t = 0; t < nthreads; t++) { int s, e, i; rvec *fnv; tensor *vir; real *Vcorrt, *dvdlt; if (t == 0) { fnv = fr->f_novirsum; vir = &fr->vir_el_recip; Vcorrt = &Vcorr; dvdlt = &dvdl; } else { fnv = fr->f_t[t].f; vir = &fr->f_t[t].vir; Vcorrt = &fr->f_t[t].Vcorr; dvdlt = &fr->f_t[t].dvdl[efptCOUL]; for (i = 0; i < fr->natoms_force; i++) { clear_rvec(fnv[i]); } clear_mat(*vir); } *dvdlt = 0; *Vcorrt = ewald_LRcorrection(fplog, fr->excl_load[t], fr->excl_load[t+1], cr, t, fr, md->chargeA, md->nChargePerturbed ? md->chargeB : NULL, ir->cutoff_scheme != ecutsVERLET, excl, x, bSB ? boxs : box, mu_tot, ir->ewald_geometry, ir->epsilon_surface, fnv, *vir, lambda[efptCOUL], dvdlt); } if (nthreads > 1) { reduce_thread_forces(fr->natoms_force, fr->f_novirsum, fr->vir_el_recip, &Vcorr, efptCOUL, &dvdl, nthreads, fr->f_t); } wallcycle_sub_stop(wcycle, ewcsEWALD_CORRECTION); } if (fr->n_tpi == 0) { Vcorr += ewald_charge_correction(cr, fr, lambda[efptCOUL], box, &dvdl, fr->vir_el_recip); } PRINT_SEPDVDL("Ewald excl./charge/dip. corr.", Vcorr, dvdl); enerd->dvdl_lin[efptCOUL] += dvdl; } status = 0; Vlr = 0; dvdl = 0; switch (fr->eeltype) { case eelPME: case eelPMESWITCH: case eelPMEUSER: case eelPMEUSERSWITCH: case eelP3M_AD: if (cr->duty & DUTY_PME) { assert(fr->n_tpi >= 0); if (fr->n_tpi == 0 || (flags & GMX_FORCE_STATECHANGED)) { pme_flags = GMX_PME_SPREAD_Q | GMX_PME_SOLVE; if (flags & GMX_FORCE_FORCES) { pme_flags |= GMX_PME_CALC_F; } if (flags & (GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY)) { pme_flags |= GMX_PME_CALC_ENER_VIR; } if (fr->n_tpi > 0) { /* We don't calculate f, but we do want the potential */ pme_flags |= GMX_PME_CALC_POT; } wallcycle_start(wcycle, ewcPMEMESH); status = gmx_pme_do(fr->pmedata, md->start, md->homenr - fr->n_tpi, x, fr->f_novirsum, md->chargeA, md->chargeB, bSB ? boxs : box, cr, DOMAINDECOMP(cr) ? dd_pme_maxshift_x(cr->dd) : 0, DOMAINDECOMP(cr) ? dd_pme_maxshift_y(cr->dd) : 0, nrnb, wcycle, fr->vir_el_recip, fr->ewaldcoeff, &Vlr, lambda[efptCOUL], &dvdl, pme_flags); *cycles_pme = wallcycle_stop(wcycle, ewcPMEMESH); /* We should try to do as little computation after * this as possible, because parallel PME synchronizes * the nodes, so we want all load imbalance of the rest * of the force calculation to be before the PME call. * DD load balancing is done on the whole time of * the force call (without PME). */ } if (fr->n_tpi > 0) { /* Determine the PME grid energy of the test molecule * with the PME grid potential of the other charges. */ gmx_pme_calc_energy(fr->pmedata, fr->n_tpi, x + md->homenr - fr->n_tpi, md->chargeA + md->homenr - fr->n_tpi, &Vlr); } PRINT_SEPDVDL("PME mesh", Vlr, dvdl); } break; case eelEWALD: Vlr = do_ewald(fplog, FALSE, ir, x, fr->f_novirsum, md->chargeA, md->chargeB, box_size, cr, md->homenr, fr->vir_el_recip, fr->ewaldcoeff, lambda[efptCOUL], &dvdl, fr->ewald_table); PRINT_SEPDVDL("Ewald long-range", Vlr, dvdl); break; default: gmx_fatal(FARGS, "No such electrostatics method implemented %s", eel_names[fr->eeltype]); } if (status != 0) { gmx_fatal(FARGS, "Error %d in long range electrostatics routine %s", status, EELTYPE(fr->eeltype)); } /* Note that with separate PME nodes we get the real energies later */ enerd->dvdl_lin[efptCOUL] += dvdl; enerd->term[F_COUL_RECIP] = Vlr + Vcorr; if (debug) { fprintf(debug, "Vlr = %g, Vcorr = %g, Vlr_corr = %g\n", Vlr, Vcorr, enerd->term[F_COUL_RECIP]); pr_rvecs(debug, 0, "vir_el_recip after corr", fr->vir_el_recip, DIM); pr_rvecs(debug, 0, "fshift after LR Corrections", fr->fshift, SHIFTS); } } else { if (EEL_RF(fr->eeltype)) { /* With the Verlet scheme exclusion forces are calculated * in the non-bonded kernel. */ if (ir->cutoff_scheme != ecutsVERLET && fr->eeltype != eelRF_NEC) { dvdl = 0; enerd->term[F_RF_EXCL] = RF_excl_correction(fplog, fr, graph, md, excl, x, f, fr->fshift, &pbc, lambda[efptCOUL], &dvdl); } enerd->dvdl_lin[efptCOUL] += dvdl; PRINT_SEPDVDL("RF exclusion correction", enerd->term[F_RF_EXCL], dvdl); } } where(); debug_gmx(); if (debug) { print_nrnb(debug, nrnb); } debug_gmx(); #ifdef GMX_MPI if (TAKETIME) { t2 = MPI_Wtime(); MPI_Barrier(cr->mpi_comm_mygroup); t3 = MPI_Wtime(); fr->t_wait += t3-t2; if (fr->timesteps == 11) { fprintf(stderr, "* PP load balancing info: node %d, step %s, rel wait time=%3.0f%% , load string value: %7.2f\n", cr->nodeid, gmx_step_str(fr->timesteps, buf), 100*fr->t_wait/(fr->t_wait+fr->t_fnbf), (fr->t_fnbf+fr->t_wait)/fr->t_fnbf); } fr->timesteps++; } #endif if (debug) { pr_rvecs(debug, 0, "fshift after bondeds", fr->fshift, SHIFTS); } GMX_MPE_LOG(ev_force_finish); }
int gmx_velacc(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] computes the velocity autocorrelation function.", "When the [TT]-m[tt] option is used, the momentum autocorrelation", "function is calculated.[PAR]", "With option [TT]-mol[tt] the velocity autocorrelation function of", "molecules is calculated. In this case the index group should consist", "of molecule numbers instead of atom numbers.[PAR]", "Be sure that your trajectory contains frames with velocity information", "(i.e. [TT]nstvout[tt] was set in your original [REF].mdp[ref] file),", "and that the time interval between data collection points is", "much shorter than the time scale of the autocorrelation." }; static gmx_bool bMass = FALSE, bMol = FALSE, bRecip = TRUE; t_pargs pa[] = { { "-m", FALSE, etBOOL, {&bMass}, "Calculate the momentum autocorrelation function" }, { "-recip", FALSE, etBOOL, {&bRecip}, "Use cm^-1 on X-axis instead of 1/ps for spectra." }, { "-mol", FALSE, etBOOL, {&bMol}, "Calculate the velocity acf of molecules" } }; t_topology top; int ePBC = -1; t_trxframe fr; matrix box; gmx_bool bTPS = FALSE, bTop = FALSE; int gnx; atom_id *index; char *grpname; /* t0, t1 are the beginning and end time respectively. * dt is the time step, mass is temp variable for atomic mass. */ real t0, t1, dt, mass; t_trxstatus *status; int counter, n_alloc, i, j, counter_dim, k, l; rvec mv_mol; /* Array for the correlation function */ real **c1; real *normm = NULL; output_env_t oenv; #define NHISTO 360 t_filenm fnm[] = { { efTRN, "-f", NULL, ffREAD }, { efTPS, NULL, NULL, ffOPTRD }, { efNDX, NULL, NULL, ffOPTRD }, { efXVG, "-o", "vac", ffWRITE }, { efXVG, "-os", "spectrum", ffOPTWR } }; #define NFILE asize(fnm) int npargs; t_pargs *ppa; npargs = asize(pa); ppa = add_acf_pargs(&npargs, pa); if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv)) { return 0; } if (bMol || bMass) { bTPS = ftp2bSet(efTPS, NFILE, fnm) || !ftp2bSet(efNDX, NFILE, fnm); } if (bTPS) { bTop = read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &ePBC, NULL, NULL, box, TRUE); get_index(&top.atoms, ftp2fn_null(efNDX, NFILE, fnm), 1, &gnx, &index, &grpname); } else { rd_index(ftp2fn(efNDX, NFILE, fnm), 1, &gnx, &index, &grpname); } if (bMol) { if (!bTop) { gmx_fatal(FARGS, "Need a topology to determine the molecules"); } snew(normm, top.atoms.nr); precalc(top, normm); index_atom2mol(&gnx, index, &top.mols); } /* Correlation stuff */ snew(c1, gnx); for (i = 0; (i < gnx); i++) { c1[i] = NULL; } read_first_frame(oenv, &status, ftp2fn(efTRN, NFILE, fnm), &fr, TRX_NEED_V); t0 = fr.time; n_alloc = 0; counter = 0; do { if (counter >= n_alloc) { n_alloc += 100; for (i = 0; i < gnx; i++) { srenew(c1[i], DIM*n_alloc); } } counter_dim = DIM*counter; if (bMol) { for (i = 0; i < gnx; i++) { clear_rvec(mv_mol); k = top.mols.index[index[i]]; l = top.mols.index[index[i]+1]; for (j = k; j < l; j++) { if (bMass) { mass = top.atoms.atom[j].m; } else { mass = normm[j]; } mv_mol[XX] += mass*fr.v[j][XX]; mv_mol[YY] += mass*fr.v[j][YY]; mv_mol[ZZ] += mass*fr.v[j][ZZ]; } c1[i][counter_dim+XX] = mv_mol[XX]; c1[i][counter_dim+YY] = mv_mol[YY]; c1[i][counter_dim+ZZ] = mv_mol[ZZ]; } } else { for (i = 0; i < gnx; i++) { if (bMass) { mass = top.atoms.atom[index[i]].m; } else { mass = 1; } c1[i][counter_dim+XX] = mass*fr.v[index[i]][XX]; c1[i][counter_dim+YY] = mass*fr.v[index[i]][YY]; c1[i][counter_dim+ZZ] = mass*fr.v[index[i]][ZZ]; } } t1 = fr.time; counter++; } while (read_next_frame(oenv, status, &fr)); close_trj(status); if (counter >= 4) { /* Compute time step between frames */ dt = (t1-t0)/(counter-1); do_autocorr(opt2fn("-o", NFILE, fnm), oenv, bMass ? "Momentum Autocorrelation Function" : "Velocity Autocorrelation Function", counter, gnx, c1, dt, eacVector, TRUE); do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy"); if (opt2bSet("-os", NFILE, fnm)) { calc_spectrum(counter/2, (real *) (c1[0]), (t1-t0)/2, opt2fn("-os", NFILE, fnm), oenv, bRecip); do_view(oenv, opt2fn("-os", NFILE, fnm), "-nxy"); } } else { fprintf(stderr, "Not enough frames in trajectory - no output generated.\n"); } return 0; }
int gmx_rotacf(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] calculates the rotational correlation function", "for molecules. Atom triplets (i,j,k) must be given in the index", "file, defining two vectors ij and jk. The rotational ACF", "is calculated as the autocorrelation function of the vector", "n = ij x jk, i.e. the cross product of the two vectors.", "Since three atoms span a plane, the order of the three atoms", "does not matter. Optionally, by invoking the [TT]-d[tt] switch, you can", "calculate the rotational correlation function for linear molecules", "by specifying atom pairs (i,j) in the index file.", "[PAR]", "EXAMPLES[PAR]", "[TT]gmx rotacf -P 1 -nparm 2 -fft -n index -o rotacf-x-P1", "-fa expfit-x-P1 -beginfit 2.5 -endfit 20.0[tt][PAR]", "This will calculate the rotational correlation function using a first", "order Legendre polynomial of the angle of a vector defined by the index", "file. The correlation function will be fitted from 2.5 ps until 20.0 ps", "to a two-parameter exponential." }; static gmx_bool bVec = FALSE, bAver = TRUE; t_pargs pa[] = { { "-d", FALSE, etBOOL, {&bVec}, "Use index doublets (vectors) for correlation function instead of triplets (planes)" }, { "-aver", FALSE, etBOOL, {&bAver}, "Average over molecules" } }; t_trxstatus *status; int isize; atom_id *index; char *grpname; rvec *x, *x_s; matrix box; real **c1; rvec xij, xjk, n; int i, m, teller, n_alloc, natoms, nvec, ai, aj, ak; unsigned long mode; real t, t0, t1, dt; gmx_rmpbc_t gpbc = NULL; t_topology *top; int ePBC; t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efTPR, NULL, NULL, ffREAD }, { efNDX, NULL, NULL, ffREAD }, { efXVG, "-o", "rotacf", ffWRITE } }; #define NFILE asize(fnm) int npargs; t_pargs *ppa; output_env_t oenv; npargs = asize(pa); ppa = add_acf_pargs(&npargs, pa); if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv)) { return 0; } rd_index(ftp2fn(efNDX, NFILE, fnm), 1, &isize, &index, &grpname); if (bVec) { nvec = isize/2; } else { nvec = isize/3; } if (((isize % 3) != 0) && !bVec) { gmx_fatal(FARGS, "number of index elements not multiple of 3, " "these can not be atom triplets\n"); } if (((isize % 2) != 0) && bVec) { gmx_fatal(FARGS, "number of index elements not multiple of 2, " "these can not be atom doublets\n"); } top = read_top(ftp2fn(efTPR, NFILE, fnm), &ePBC); snew(c1, nvec); for (i = 0; (i < nvec); i++) { c1[i] = NULL; } n_alloc = 0; natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box); snew(x_s, natoms); gpbc = gmx_rmpbc_init(&(top->idef), ePBC, natoms); /* Start the loop over frames */ t1 = t0 = t; teller = 0; do { if (teller >= n_alloc) { n_alloc += 100; for (i = 0; (i < nvec); i++) { srenew(c1[i], DIM*n_alloc); } } t1 = t; /* Remove periodicity */ gmx_rmpbc_copy(gpbc, natoms, box, x, x_s); /* Compute crossproducts for all vectors, if triplets. * else, just get the vectors in case of doublets. */ if (bVec == FALSE) { for (i = 0; (i < nvec); i++) { ai = index[3*i]; aj = index[3*i+1]; ak = index[3*i+2]; rvec_sub(x_s[ai], x_s[aj], xij); rvec_sub(x_s[aj], x_s[ak], xjk); cprod(xij, xjk, n); for (m = 0; (m < DIM); m++) { c1[i][DIM*teller+m] = n[m]; } } } else { for (i = 0; (i < nvec); i++) { ai = index[2*i]; aj = index[2*i+1]; rvec_sub(x_s[ai], x_s[aj], n); for (m = 0; (m < DIM); m++) { c1[i][DIM*teller+m] = n[m]; } } } /* Increment loop counter */ teller++; } while (read_next_x(oenv, status, &t, x, box)); close_trj(status); fprintf(stderr, "\nDone with trajectory\n"); gmx_rmpbc_done(gpbc); /* Autocorrelation function */ if (teller < 2) { fprintf(stderr, "Not enough frames for correlation function\n"); } else { dt = (t1 - t0)/(teller-1); mode = eacVector; do_autocorr(ftp2fn(efXVG, NFILE, fnm), oenv, "Rotational Correlation Function", teller, nvec, c1, dt, mode, bAver); } do_view(oenv, ftp2fn(efXVG, NFILE, fnm), NULL); return 0; }
void init_disres(FILE *fplog, const gmx_mtop_t *mtop, t_inputrec *ir, const t_commrec *cr, t_fcdata *fcd, t_state *state, gmx_bool bIsREMD) { int fa, nmol, npair, np; t_disresdata *dd; history_t *hist; gmx_mtop_ilistloop_t iloop; t_ilist *il; char *ptr; dd = &(fcd->disres); if (gmx_mtop_ftype_count(mtop, F_DISRES) == 0) { dd->nres = 0; return; } if (fplog) { fprintf(fplog, "Initializing the distance restraints\n"); } if (ir->eDisre == edrEnsemble) { gmx_fatal(FARGS, "Sorry, distance restraints with ensemble averaging over multiple molecules in one system are not functional in this version of GROMACS"); } dd->dr_weighting = ir->eDisreWeighting; dd->dr_fc = ir->dr_fc; if (EI_DYNAMICS(ir->eI)) { dd->dr_tau = ir->dr_tau; } else { dd->dr_tau = 0.0; } if (dd->dr_tau == 0.0) { dd->dr_bMixed = FALSE; dd->ETerm = 0.0; } else { dd->dr_bMixed = ir->bDisreMixed; dd->ETerm = std::exp(-(ir->delta_t/ir->dr_tau)); } dd->ETerm1 = 1.0 - dd->ETerm; dd->nres = 0; dd->npair = 0; iloop = gmx_mtop_ilistloop_init(mtop); while (gmx_mtop_ilistloop_next(iloop, &il, &nmol)) { np = 0; for (fa = 0; fa < il[F_DISRES].nr; fa += 3) { np++; npair = mtop->ffparams.iparams[il[F_DISRES].iatoms[fa]].disres.npair; if (np == npair) { dd->nres += (ir->eDisre == edrEnsemble ? 1 : nmol)*npair; dd->npair += nmol*npair; np = 0; } } } if (cr && PAR(cr)) { /* Temporary check, will be removed when disre is implemented with DD */ const char *notestr = "NOTE: atoms involved in distance restraints should be within the same domain. If this is not the case mdrun generates a fatal error. If you encounter this, use a single MPI rank (Verlet+OpenMP+GPUs work fine)."; if (MASTER(cr)) { fprintf(stderr, "\n%s\n\n", notestr); } if (fplog) { fprintf(fplog, "%s\n", notestr); } if (dd->dr_tau != 0 || ir->eDisre == edrEnsemble || cr->ms != NULL || dd->nres != dd->npair) { gmx_fatal(FARGS, "Time or ensemble averaged or multiple pair distance restraints do not work (yet) with domain decomposition, use a single MPI rank%s", cr->ms ? " per simulation" : ""); } if (ir->nstdisreout != 0) { if (fplog) { fprintf(fplog, "\nWARNING: Can not write distance restraint data to energy file with domain decomposition\n\n"); } if (MASTER(cr)) { fprintf(stderr, "\nWARNING: Can not write distance restraint data to energy file with domain decomposition\n"); } ir->nstdisreout = 0; } } snew(dd->rt, dd->npair); if (dd->dr_tau != 0.0) { hist = &state->hist; /* Set the "history lack" factor to 1 */ state->flags |= (1<<estDISRE_INITF); hist->disre_initf = 1.0; /* Allocate space for the r^-3 time averages */ state->flags |= (1<<estDISRE_RM3TAV); hist->ndisrepairs = dd->npair; snew(hist->disre_rm3tav, hist->ndisrepairs); } /* Allocate space for a copy of rm3tav, * so we can call do_force without modifying the state. */ snew(dd->rm3tav, dd->npair); /* Allocate Rt_6 and Rtav_6 consecutively in memory so they can be * averaged over the processors in one call (in calc_disre_R_6) */ snew(dd->Rt_6, 2*dd->nres); dd->Rtav_6 = &(dd->Rt_6[dd->nres]); ptr = getenv("GMX_DISRE_ENSEMBLE_SIZE"); if (cr && cr->ms != NULL && ptr != NULL && !bIsREMD) { #if GMX_MPI dd->nsystems = 0; sscanf(ptr, "%d", &dd->nsystems); if (fplog) { fprintf(fplog, "Found GMX_DISRE_ENSEMBLE_SIZE set to %d systems per ensemble\n", dd->nsystems); } /* This check is only valid on MASTER(cr), so probably * ensemble-averaged distance restraints are broken on more * than one processor per simulation system. */ if (MASTER(cr)) { check_multi_int(fplog, cr->ms, dd->nsystems, "the number of systems per ensemble", FALSE); } gmx_bcast_sim(sizeof(int), &dd->nsystems, cr); /* We use to allow any value of nsystems which was a divisor * of ms->nsim. But this required an extra communicator which * was stored in t_fcdata. This pulled in mpi.h in nearly all C files. */ if (!(cr->ms->nsim == 1 || cr->ms->nsim == dd->nsystems)) { gmx_fatal(FARGS, "GMX_DISRE_ENSEMBLE_SIZE (%d) is not equal to 1 or the number of systems (option -multi) %d", dd->nsystems, cr->ms->nsim); } if (fplog) { fprintf(fplog, "Our ensemble consists of systems:"); for (int i = 0; i < dd->nsystems; i++) { fprintf(fplog, " %d", (cr->ms->sim/dd->nsystems)*dd->nsystems+i); } fprintf(fplog, "\n"); } snew(dd->Rtl_6, dd->nres); #endif } else { dd->nsystems = 1; dd->Rtl_6 = dd->Rt_6; } if (dd->npair > 0) { if (fplog) { fprintf(fplog, "There are %d distance restraints involving %d atom pairs\n", dd->nres, dd->npair); } /* Have to avoid g_disre de-referencing cr blindly, mdrun not * doing consistency checks for ensemble-averaged distance * restraints when that's not happening, and only doing those * checks from appropriate processes (since check_multi_int is * too broken to check whether the communication will * succeed...) */ if (cr && cr->ms && dd->nsystems > 1 && MASTER(cr)) { check_multi_int(fplog, cr->ms, fcd->disres.nres, "the number of distance restraints", FALSE); } please_cite(fplog, "Tropp80a"); please_cite(fplog, "Torda89a"); } }
int gmx_fft_1d_real (gmx_fft_t fft, enum gmx_fft_direction dir, void * in_data, void * out_data) { int i, n; real * p1; real * p2; n = fft->n; if (n == 1) { p1 = (real *)in_data; p2 = (real *)out_data; p2[0] = p1[0]; if (dir == GMX_FFT_REAL_TO_COMPLEX) { p2[1] = 0.0; } } if (dir == GMX_FFT_REAL_TO_COMPLEX) { /* FFTPACK only does in-place transforms, so emulate out-of-place * by copying data to the output array first. This works fine, since * the complex array must be larger than the real. */ if (in_data != out_data) { p1 = (real *)in_data; p2 = (real *)out_data; for (i = 0; i < 2*(n/2+1); i++) { p2[i] = p1[i]; } } /* Elements 0 .. n-1 in work are used for ffac values, * Elements n .. 2*n-1 are internal FFTPACK work space. */ fftpack_rfftf1(n, (real *)out_data, fft->work+n, fft->work, fft->ifac); /* * FFTPACK has a slightly more compact storage than we, time to * convert it: ove most of the array one step up to make room for * zero imaginary parts. */ p2 = (real *)out_data; for (i = n-1; i > 0; i--) { p2[i+1] = p2[i]; } /* imaginary zero freq. */ p2[1] = 0; /* Is n even? */ if ( (n & 0x1) == 0) { p2[n+1] = 0; } } else if (dir == GMX_FFT_COMPLEX_TO_REAL) { /* FFTPACK only does in-place transforms, and we cannot just copy * input to output first here since our real array is smaller than * the complex one. However, since the FFTPACK complex storage format * is more compact than ours (2 reals) it will fit, so compact it * and copy on-the-fly to the output array. */ p1 = (real *) in_data; p2 = (real *)out_data; p2[0] = p1[0]; for (i = 1; i < n; i++) { p2[i] = p1[i+1]; } fftpack_rfftb1(n, (real *)out_data, fft->work+n, fft->work, fft->ifac); } else { gmx_fatal(FARGS, "FFT plan mismatch - bad plan or direction."); return EINVAL; } return 0; }
int gmx_fft_2d_real (gmx_fft_t fft, enum gmx_fft_direction dir, void * in_data, void * out_data) { int i, j, nx, ny, nyc; t_complex * data; real * work; real * p1; real * p2; nx = fft->n; ny = fft->next->n; /* Number of complex elements in y direction */ nyc = (ny/2+1); work = fft->work+4*nx; if (dir == GMX_FFT_REAL_TO_COMPLEX) { /* If we are doing an in-place transform the 2D array is already * properly padded by the user, and we are all set. * * For out-of-place there is no array padding, but FFTPACK only * does in-place FFTs internally, so we need to start by copying * data from the input to the padded (larger) output array. */ if (in_data != out_data) { p1 = (real *)in_data; p2 = (real *)out_data; for (i = 0; i < nx; i++) { for (j = 0; j < ny; j++) { p2[i*nyc*2+j] = p1[i*ny+j]; } } } data = (t_complex *)out_data; /* y real-to-complex FFTs */ for (i = 0; i < nx; i++) { gmx_fft_1d_real(fft->next, GMX_FFT_REAL_TO_COMPLEX, data+i*nyc, data+i*nyc); } /* Transform to get X data in place */ gmx_fft_transpose_2d(data, data, nx, nyc); /* Complex-to-complex X FFTs */ for (i = 0; i < nyc; i++) { gmx_fft_1d(fft, GMX_FFT_FORWARD, data+i*nx, data+i*nx); } /* Transpose back */ gmx_fft_transpose_2d(data, data, nyc, nx); } else if (dir == GMX_FFT_COMPLEX_TO_REAL) { /* An in-place complex-to-real transform is straightforward, * since the output array must be large enough for the padding to fit. * * For out-of-place complex-to-real transforms we cannot just copy * data to the output array, since it is smaller than the input. * In this case there's nothing to do but employing temporary work data, * starting at work+4*nx and using nx*nyc*2 elements. */ if (in_data != out_data) { memcpy(work, in_data, sizeof(t_complex)*nx*nyc); data = (t_complex *)work; } else { /* in-place */ data = (t_complex *)out_data; } /* Transpose to get X arrays */ gmx_fft_transpose_2d(data, data, nx, nyc); /* Do X iFFTs */ for (i = 0; i < nyc; i++) { gmx_fft_1d(fft, GMX_FFT_BACKWARD, data+i*nx, data+i*nx); } /* Transpose to get Y arrays */ gmx_fft_transpose_2d(data, data, nyc, nx); /* Do Y iFFTs */ for (i = 0; i < nx; i++) { gmx_fft_1d_real(fft->next, GMX_FFT_COMPLEX_TO_REAL, data+i*nyc, data+i*nyc); } if (in_data != out_data) { /* Output (pointed to by data) is now in padded format. * Pack it into out_data if we were doing an out-of-place transform. */ p1 = (real *)data; p2 = (real *)out_data; for (i = 0; i < nx; i++) { for (j = 0; j < ny; j++) { p2[i*ny+j] = p1[i*nyc*2+j]; } } } } else { gmx_fatal(FARGS, "FFT plan mismatch - bad plan or direction."); return EINVAL; } return 0; }
static void set_tric_dir(ivec *dd_nc,gmx_ddbox_t *ddbox,matrix box) { int npbcdim,d,i,j; rvec *v,*normal; real dep,inv_skew_fac2; npbcdim = ddbox->npbcdim; normal = ddbox->normal; for(d=0; d<DIM; d++) { ddbox->tric_dir[d] = 0; for(j=d+1; j<npbcdim; j++) { if (box[j][d] != 0) { ddbox->tric_dir[d] = 1; if (dd_nc != NULL && (*dd_nc)[j] > 1 && (*dd_nc)[d] == 1) { gmx_fatal(FARGS,"Domain decomposition has not been implemented for box vectors that have non-zero components in directions that do not use domain decomposition: ncells = %d %d %d, box vector[%d] = %f %f %f", dd_nc[XX],dd_nc[YY],dd_nc[ZZ], j+1,box[j][XX],box[j][YY],box[j][ZZ]); } } } /* Convert box vectors to orthogonal vectors for this dimension, * for use in distance calculations. * Set the trilinic skewing factor that translates * the thickness of a slab perpendicular to this dimension * into the real thickness of the slab. */ if (ddbox->tric_dir[d]) { inv_skew_fac2 = 1; v = ddbox->v[d]; if (d == XX || d == YY) { /* Normalize such that the "diagonal" is 1 */ svmul(1/box[d+1][d+1],box[d+1],v[d+1]); for(i=0; i<d; i++) { v[d+1][i] = 0; } inv_skew_fac2 += sqr(v[d+1][d]); if (d == XX) { /* Normalize such that the "diagonal" is 1 */ svmul(1/box[d+2][d+2],box[d+2],v[d+2]); for(i=0; i<d; i++) { v[d+2][i] = 0; } /* Make vector [d+2] perpendicular to vector [d+1], * this does not affect the normalization. */ dep = iprod(v[d+1],v[d+2])/norm2(v[d+1]); for(i=0; i<DIM; i++) { v[d+2][i] -= dep*v[d+1][i]; } inv_skew_fac2 += sqr(v[d+2][d]); cprod(v[d+1],v[d+2],normal[d]); } else { /* cross product with (1,0,0) */ normal[d][XX] = 0; normal[d][YY] = v[d+1][ZZ]; normal[d][ZZ] = -v[d+1][YY]; } if (debug) { fprintf(debug,"box[%d] %.3f %.3f %.3f\n", d,box[d][XX],box[d][YY],box[d][ZZ]); for(i=d+1; i<DIM; i++) { fprintf(debug," v[%d] %.3f %.3f %.3f\n", i,v[i][XX],v[i][YY],v[i][ZZ]); } } } ddbox->skew_fac[d] = 1.0/sqrt(inv_skew_fac2); /* Set the normal vector length to skew_fac */ dep = ddbox->skew_fac[d]/norm(normal[d]); svmul(dep,normal[d],normal[d]); if (debug) { fprintf(debug,"skew_fac[%d] = %f\n",d,ddbox->skew_fac[d]); fprintf(debug,"normal[%d] %.3f %.3f %.3f\n", d,normal[d][XX],normal[d][YY],normal[d][ZZ]); } } else { ddbox->skew_fac[d] = 1; for(i=0; i<DIM; i++) { clear_rvec(ddbox->v[d][i]); ddbox->v[d][i][i] = 1; } clear_rvec(normal[d]); normal[d][d] = 1; } } }
int gmx_make_edi(int argc, char *argv[]) { static const char *desc[] = { "[THISMODULE] generates an essential dynamics (ED) sampling input file to be used with [TT]mdrun[tt]", "based on eigenvectors of a covariance matrix ([gmx-covar]) or from a", "normal modes analysis ([gmx-nmeig]).", "ED sampling can be used to manipulate the position along collective coordinates", "(eigenvectors) of (biological) macromolecules during a simulation. Particularly,", "it may be used to enhance the sampling efficiency of MD simulations by stimulating", "the system to explore new regions along these collective coordinates. A number", "of different algorithms are implemented to drive the system along the eigenvectors", "([TT]-linfix[tt], [TT]-linacc[tt], [TT]-radfix[tt], [TT]-radacc[tt], [TT]-radcon[tt]),", "to keep the position along a certain (set of) coordinate(s) fixed ([TT]-linfix[tt]),", "or to only monitor the projections of the positions onto", "these coordinates ([TT]-mon[tt]).[PAR]", "References:[BR]", "A. Amadei, A.B.M. Linssen, B.L. de Groot, D.M.F. van Aalten and ", "H.J.C. Berendsen; An efficient method for sampling the essential subspace ", "of proteins., J. Biomol. Struct. Dyn. 13:615-626 (1996)[BR]", "B.L. de Groot, A. Amadei, D.M.F. van Aalten and H.J.C. Berendsen; ", "Towards an exhaustive sampling of the configurational spaces of the ", "two forms of the peptide hormone guanylin,", "J. Biomol. Struct. Dyn. 13 : 741-751 (1996)[BR]", "B.L. de Groot, A.Amadei, R.M. Scheek, N.A.J. van Nuland and H.J.C. Berendsen; ", "An extended sampling of the configurational space of HPr from E. coli", "Proteins: Struct. Funct. Gen. 26: 314-322 (1996)", "[PAR]You will be prompted for one or more index groups that correspond to the eigenvectors,", "reference structure, target positions, etc.[PAR]", "[TT]-mon[tt]: monitor projections of the coordinates onto selected eigenvectors.[PAR]", "[TT]-linfix[tt]: perform fixed-step linear expansion along selected eigenvectors.[PAR]", "[TT]-linacc[tt]: perform acceptance linear expansion along selected eigenvectors.", "(steps in the desired directions will be accepted, others will be rejected).[PAR]", "[TT]-radfix[tt]: perform fixed-step radius expansion along selected eigenvectors.[PAR]", "[TT]-radacc[tt]: perform acceptance radius expansion along selected eigenvectors.", "(steps in the desired direction will be accepted, others will be rejected).", "[BB]Note:[bb] by default the starting MD structure will be taken as origin of the first", "expansion cycle for radius expansion. If [TT]-ori[tt] is specified, you will be able", "to read in a structure file that defines an external origin.[PAR]", "[TT]-radcon[tt]: perform acceptance radius contraction along selected eigenvectors", "towards a target structure specified with [TT]-tar[tt].[PAR]", "NOTE: each eigenvector can be selected only once. [PAR]", "[TT]-outfrq[tt]: frequency (in steps) of writing out projections etc. to [TT].xvg[tt] file[PAR]", "[TT]-slope[tt]: minimal slope in acceptance radius expansion. A new expansion", "cycle will be started if the spontaneous increase of the radius (in nm/step)", "is less than the value specified.[PAR]", "[TT]-maxedsteps[tt]: maximum number of steps per cycle in radius expansion", "before a new cycle is started.[PAR]", "Note on the parallel implementation: since ED sampling is a 'global' thing", "(collective coordinates etc.), at least on the 'protein' side, ED sampling", "is not very parallel-friendly from an implementation point of view. Because", "parallel ED requires some extra communication, expect the performance to be", "lower as in a free MD simulation, especially on a large number of nodes and/or", "when the ED group contains a lot of atoms. [PAR]", "Please also note that if your ED group contains more than a single protein,", "then the [TT].tpr[tt] file must contain the correct PBC representation of the ED group.", "Take a look on the initial RMSD from the reference structure, which is printed", "out at the start of the simulation; if this is much higher than expected, one", "of the ED molecules might be shifted by a box vector. [PAR]", "All ED-related output of [TT]mdrun[tt] (specify with [TT]-eo[tt]) is written to a [TT].xvg[tt] file", "as a function of time in intervals of OUTFRQ steps.[PAR]", "[BB]Note[bb] that you can impose multiple ED constraints and flooding potentials in", "a single simulation (on different molecules) if several [TT].edi[tt] files were concatenated", "first. The constraints are applied in the order they appear in the [TT].edi[tt] file. ", "Depending on what was specified in the [TT].edi[tt] input file, the output file contains for each ED dataset[PAR]", "[TT]*[tt] the RMSD of the fitted molecule to the reference structure (for atoms involved in fitting prior to calculating the ED constraints)[BR]", "[TT]*[tt] projections of the positions onto selected eigenvectors[BR]", "[PAR][PAR]", "FLOODING:[PAR]", "with [TT]-flood[tt], you can specify which eigenvectors are used to compute a flooding potential,", "which will lead to extra forces expelling the structure out of the region described", "by the covariance matrix. If you switch -restrain the potential is inverted and the structure", "is kept in that region.", "[PAR]", "The origin is normally the average structure stored in the [TT]eigvec.trr[tt] file.", "It can be changed with [TT]-ori[tt] to an arbitrary position in configuration space.", "With [TT]-tau[tt], [TT]-deltaF0[tt], and [TT]-Eflnull[tt] you control the flooding behaviour.", "Efl is the flooding strength, it is updated according to the rule of adaptive flooding.", "Tau is the time constant of adaptive flooding, high [GRK]tau[grk] means slow adaption (i.e. growth). ", "DeltaF0 is the flooding strength you want to reach after tau ps of simulation.", "To use constant Efl set [TT]-tau[tt] to zero.", "[PAR]", "[TT]-alpha[tt] is a fudge parameter to control the width of the flooding potential. A value of 2 has been found", "to give good results for most standard cases in flooding of proteins.", "[GRK]alpha[grk] basically accounts for incomplete sampling, if you sampled further the width of the ensemble would", "increase, this is mimicked by [GRK]alpha[grk] > 1.", "For restraining, [GRK]alpha[grk] < 1 can give you smaller width in the restraining potential.", "[PAR]", "RESTART and FLOODING:", "If you want to restart a crashed flooding simulation please find the values deltaF and Efl in", "the output file and manually put them into the [TT].edi[tt] file under DELTA_F0 and EFL_NULL." }; /* Save all the params in this struct and then save it in an edi file. * ignoring fields nmass,massnrs,mass,tmass,nfit,fitnrs,edo */ static t_edipar edi_params; enum { evStepNr = evRADFIX + 1 }; static const char* evSelections[evNr] = {NULL, NULL, NULL, NULL, NULL, NULL}; static const char* evOptions[evNr] = {"-linfix", "-linacc", "-flood", "-radfix", "-radacc", "-radcon", "-mon"}; static const char* evParams[evStepNr] = {NULL, NULL}; static const char* evStepOptions[evStepNr] = {"-linstep", "-accdir", "-not_used", "-radstep"}; static const char* ConstForceStr; static real * evStepList[evStepNr]; static real radstep = 0.0; static real deltaF0 = 150; static real deltaF = 0; static real tau = .1; static real constEfl = 0.0; static real alpha = 1; static int eqSteps = 0; static int * listen[evNr]; static real T = 300.0; const real kB = 2.5 / 300.0; /* k_boltzmann in MD units */ static gmx_bool bRestrain = FALSE; static gmx_bool bHesse = FALSE; static gmx_bool bHarmonic = FALSE; t_pargs pa[] = { { "-mon", FALSE, etSTR, {&evSelections[evMON]}, "Indices of eigenvectors for projections of x (e.g. 1,2-5,9) or 1-100:10 means 1 11 21 31 ... 91" }, { "-linfix", FALSE, etSTR, {&evSelections[0]}, "Indices of eigenvectors for fixed increment linear sampling" }, { "-linacc", FALSE, etSTR, {&evSelections[1]}, "Indices of eigenvectors for acceptance linear sampling" }, { "-radfix", FALSE, etSTR, {&evSelections[3]}, "Indices of eigenvectors for fixed increment radius expansion" }, { "-radacc", FALSE, etSTR, {&evSelections[4]}, "Indices of eigenvectors for acceptance radius expansion" }, { "-radcon", FALSE, etSTR, {&evSelections[5]}, "Indices of eigenvectors for acceptance radius contraction" }, { "-flood", FALSE, etSTR, {&evSelections[2]}, "Indices of eigenvectors for flooding"}, { "-outfrq", FALSE, etINT, {&edi_params.outfrq}, "Freqency (in steps) of writing output in [TT].xvg[tt] file" }, { "-slope", FALSE, etREAL, { &edi_params.slope}, "Minimal slope in acceptance radius expansion"}, { "-linstep", FALSE, etSTR, {&evParams[0]}, "Stepsizes (nm/step) for fixed increment linear sampling (put in quotes! \"1.0 2.3 5.1 -3.1\")"}, { "-accdir", FALSE, etSTR, {&evParams[1]}, "Directions for acceptance linear sampling - only sign counts! (put in quotes! \"-1 +1 -1.1\")"}, { "-radstep", FALSE, etREAL, {&radstep}, "Stepsize (nm/step) for fixed increment radius expansion"}, { "-maxedsteps", FALSE, etINT, {&edi_params.maxedsteps}, "Maximum number of steps per cycle" }, { "-eqsteps", FALSE, etINT, {&eqSteps}, "Number of steps to run without any perturbations "}, { "-deltaF0", FALSE, etREAL, {&deltaF0}, "Target destabilization energy for flooding"}, { "-deltaF", FALSE, etREAL, {&deltaF}, "Start deltaF with this parameter - default 0, nonzero values only needed for restart"}, { "-tau", FALSE, etREAL, {&tau}, "Coupling constant for adaption of flooding strength according to deltaF0, 0 = infinity i.e. constant flooding strength"}, { "-Eflnull", FALSE, etREAL, {&constEfl}, "The starting value of the flooding strength. The flooding strength is updated " "according to the adaptive flooding scheme. For a constant flooding strength use [TT]-tau[tt] 0. "}, { "-T", FALSE, etREAL, {&T}, "T is temperature, the value is needed if you want to do flooding "}, { "-alpha", FALSE, etREAL, {&alpha}, "Scale width of gaussian flooding potential with alpha^2 "}, { "-restrain", FALSE, etBOOL, {&bRestrain}, "Use the flooding potential with inverted sign -> effects as quasiharmonic restraining potential"}, { "-hessian", FALSE, etBOOL, {&bHesse}, "The eigenvectors and eigenvalues are from a Hessian matrix"}, { "-harmonic", FALSE, etBOOL, {&bHarmonic}, "The eigenvalues are interpreted as spring constant"}, { "-constF", FALSE, etSTR, {&ConstForceStr}, "Constant force flooding: manually set the forces for the eigenvectors selected with -flood " "(put in quotes! \"1.0 2.3 5.1 -3.1\"). No other flooding parameters are needed when specifying the forces directly."} }; #define NPA asize(pa) rvec *xref1; int nvec1, *eignr1 = NULL; rvec *xav1, **eigvec1 = NULL; t_atoms *atoms = NULL; int nav; /* Number of atoms in the average structure */ char *grpname; const char *indexfile; int i; atom_id *index, *ifit; int nfit; /* Number of atoms in the reference/fit structure */ int ev_class; /* parameter _class i.e. evMON, evRADFIX etc. */ int nvecs; real *eigval1 = NULL; /* in V3.3 this is parameter of read_eigenvectors */ const char *EdiFile; const char *TargetFile; const char *OriginFile; const char *EigvecFile; output_env_t oenv; /*to read topology file*/ t_topology top; int ePBC; char title[STRLEN]; matrix topbox; rvec *xtop; gmx_bool bTop, bFit1; t_filenm fnm[] = { { efTRN, "-f", "eigenvec", ffREAD }, { efXVG, "-eig", "eigenval", ffOPTRD }, { efTPS, NULL, NULL, ffREAD }, { efNDX, NULL, NULL, ffOPTRD }, { efSTX, "-tar", "target", ffOPTRD}, { efSTX, "-ori", "origin", ffOPTRD}, { efEDI, "-o", "sam", ffWRITE } }; #define NFILE asize(fnm) edi_params.outfrq = 100; edi_params.slope = 0.0; edi_params.maxedsteps = 0; if (!parse_common_args(&argc, argv, 0, NFILE, fnm, NPA, pa, asize(desc), desc, 0, NULL, &oenv)) { return 0; } indexfile = ftp2fn_null(efNDX, NFILE, fnm); EdiFile = ftp2fn(efEDI, NFILE, fnm); TargetFile = opt2fn_null("-tar", NFILE, fnm); OriginFile = opt2fn_null("-ori", NFILE, fnm); for (ev_class = 0; ev_class < evNr; ++ev_class) { if (opt2parg_bSet(evOptions[ev_class], NPA, pa)) { /*get list of eigenvectors*/ nvecs = sscan_list(&(listen[ev_class]), opt2parg_str(evOptions[ev_class], NPA, pa), evOptions[ev_class]); if (ev_class < evStepNr-2) { /*if apropriate get list of stepsizes for these eigenvectors*/ if (opt2parg_bSet(evStepOptions[ev_class], NPA, pa)) { evStepList[ev_class] = scan_vecparams(opt2parg_str(evStepOptions[ev_class], NPA, pa), evStepOptions[ev_class], nvecs); } else /*if list is not given fill with zeros */ { snew(evStepList[ev_class], nvecs); for (i = 0; i < nvecs; i++) { evStepList[ev_class][i] = 0.0; } } } else if (ev_class == evRADFIX) { snew(evStepList[ev_class], nvecs); for (i = 0; i < nvecs; i++) { evStepList[ev_class][i] = radstep; } } else if (ev_class == evFLOOD) { snew(evStepList[ev_class], nvecs); /* Are we doing constant force flooding? In that case, we read in * the fproj values from the command line */ if (opt2parg_bSet("-constF", NPA, pa)) { evStepList[ev_class] = scan_vecparams(opt2parg_str("-constF", NPA, pa), "-constF", nvecs); } } else { }; /*to avoid ambiguity */ } else /* if there are no eigenvectors for this option set list to zero */ { listen[ev_class] = NULL; snew(listen[ev_class], 1); listen[ev_class][0] = 0; } } /* print the interpreted list of eigenvectors - to give some feedback*/ for (ev_class = 0; ev_class < evNr; ++ev_class) { printf("Eigenvector list %7s consists of the indices: ", evOptions[ev_class]); i = 0; while (listen[ev_class][i]) { printf("%d ", listen[ev_class][i++]); } printf("\n"); } EigvecFile = opt2fn("-f", NFILE, fnm); /*read eigenvectors from eigvec.trr*/ read_eigenvectors(EigvecFile, &nav, &bFit1, &xref1, &edi_params.fitmas, &xav1, &edi_params.pcamas, &nvec1, &eignr1, &eigvec1, &eigval1); bTop = read_tps_conf(ftp2fn(efTPS, NFILE, fnm), title, &top, &ePBC, &xtop, NULL, topbox, 0); atoms = &top.atoms; printf("\nSelect an index group of %d elements that corresponds to the eigenvectors\n", nav); get_index(atoms, indexfile, 1, &i, &index, &grpname); /*if indexfile != NULL parameter 'atoms' is ignored */ if (i != nav) { gmx_fatal(FARGS, "you selected a group with %d elements instead of %d", i, nav); } printf("\n"); if (xref1 == NULL) { if (bFit1) { /* if g_covar used different coordinate groups to fit and to do the PCA */ printf("\nNote: the structure in %s should be the same\n" " as the one used for the fit in g_covar\n", ftp2fn(efTPS, NFILE, fnm)); printf("\nSelect the index group that was used for the least squares fit in g_covar\n"); } else { printf("\nNote: Apparently no fitting was done in g_covar.\n" " However, you need to select a reference group for fitting in mdrun\n"); } get_index(atoms, indexfile, 1, &nfit, &ifit, &grpname); snew(xref1, nfit); for (i = 0; i < nfit; i++) { copy_rvec(xtop[ifit[i]], xref1[i]); } } else { nfit = nav; ifit = index; } if (opt2parg_bSet("-constF", NPA, pa)) { /* Constant force flooding is special: Most of the normal flooding * options are not needed. */ edi_params.flood.bConstForce = TRUE; } else { /* For normal flooding read eigenvalues and store them in evSteplist[evFLOOD] */ if (listen[evFLOOD][0] != 0) { read_eigenvalues(listen[evFLOOD], opt2fn("-eig", NFILE, fnm), evStepList[evFLOOD], bHesse, kB*T); } edi_params.flood.tau = tau; edi_params.flood.deltaF0 = deltaF0; edi_params.flood.deltaF = deltaF; edi_params.presteps = eqSteps; edi_params.flood.kT = kB*T; edi_params.flood.bHarmonic = bHarmonic; if (bRestrain) { /* Trick: invert sign of Efl and alpha2 then this will give the same sign in the exponential and inverted sign outside */ edi_params.flood.constEfl = -constEfl; edi_params.flood.alpha2 = -sqr(alpha); } else { edi_params.flood.constEfl = constEfl; edi_params.flood.alpha2 = sqr(alpha); } } edi_params.ned = nav; /*number of system atoms */ edi_params.nini = atoms->nr; /*store reference and average structure in edi_params*/ make_t_edx(&edi_params.sref, nfit, xref1, ifit ); make_t_edx(&edi_params.sav, nav, xav1, index); /* Store target positions in edi_params */ if (opt2bSet("-tar", NFILE, fnm)) { if (0 != listen[evFLOOD][0]) { fprintf(stderr, "\nNote: Providing a TARGET structure has no effect when using flooding.\n" " You may want to use -ori to define the flooding potential center.\n\n"); } get_structure(atoms, indexfile, TargetFile, &edi_params.star, nfit, ifit, nav, index); } else { make_t_edx(&edi_params.star, 0, NULL, index); } /* Store origin positions */ if (opt2bSet("-ori", NFILE, fnm)) { get_structure(atoms, indexfile, OriginFile, &edi_params.sori, nfit, ifit, nav, index); } else { make_t_edx(&edi_params.sori, 0, NULL, index); } /* Write edi-file */ write_the_whole_thing(gmx_ffopen(EdiFile, "w"), &edi_params, eigvec1, nvec1, listen, evStepList); return 0; }
int sscan_list(int *list[], const char *str, const char *listname) { /*this routine scans a string of the form 1,3-6,9 and returns the selected numbers (in this case 1 3 4 5 6 9) in NULL-terminated array of integers. memory for this list will be allocated in this routine -- sscan_list expects *list to be a NULL-Pointer listname is a string used in the errormessage*/ int i, istep; char c; char *pos, *startpos, *step; int n = strlen(str); /*enums to define the different lexical stati */ enum { sBefore, sNumber, sMinus, sRange, sZero, sSmaller, sError, sSteppedRange }; int status = sBefore; /*status of the deterministic automat to scan str */ int number = 0; int end_number = 0; char *start = NULL; /*holds the string of the number behind a ','*/ char *end = NULL; /*holds the string of the number behind a '-' */ int nvecs = 0; /* counts the number of vectors in the list*/ step = NULL; snew(pos, n+4); startpos = pos; strcpy(pos, str); pos[n] = ','; pos[n+1] = '1'; pos[n+2] = '\0'; *list = NULL; while ((c = *pos) != 0) { switch (status) { /* expect a number */ case sBefore: if (isdigit(c)) { start = pos; status = sNumber; break; } else { status = sError; } break; /* have read a number, expect ',' or '-' */ case sNumber: if (c == ',') { /*store number*/ srenew(*list, nvecs+1); (*list)[nvecs++] = number = strtol(start, NULL, 10); status = sBefore; if (number == 0) { status = sZero; } break; } else if (c == '-') { status = sMinus; break; } else if (isdigit(c)) { break; } else { status = sError; } break; /* have read a '-' -> expect a number */ case sMinus: if (isdigit(c)) { end = pos; status = sRange; break; } else { status = sError; } break; case sSteppedRange: if (isdigit(c)) { if (step) { status = sError; break; } else { step = pos; } status = sRange; break; } else { status = sError; } break; /* have read the number after a minus, expect ',' or ':' */ case sRange: if (c == ',') { /*store numbers*/ end_number = strtol(end, NULL, 10); number = strtol(start, NULL, 10); status = sBefore; if (number == 0) { status = sZero; break; } if (end_number <= number) { status = sSmaller; break; } srenew(*list, nvecs+end_number-number+1); if (step) { istep = strtol(step, NULL, 10); step = NULL; } else { istep = 1; } for (i = number; i <= end_number; i += istep) { (*list)[nvecs++] = i; } break; } else if (c == ':') { status = sSteppedRange; break; } else if (isdigit(c)) { break; } else { status = sError; } break; /* format error occured */ case sError: gmx_fatal(FARGS, "Error in the list of eigenvectors for %s at pos %d with char %c", listname, pos-startpos, *(pos-1)); break; /* logical error occured */ case sZero: gmx_fatal(FARGS, "Error in the list of eigenvectors for %s at pos %d: eigenvector 0 is not valid", listname, pos-startpos); break; case sSmaller: gmx_fatal(FARGS, "Error in the list of eigenvectors for %s at pos %d: second index %d is not bigger than %d", listname, pos-startpos, end_number, number); break; } ++pos; /* read next character */ } /*scanner has finished */ /* append zero to list of eigenvectors */ srenew(*list, nvecs+1); (*list)[nvecs] = 0; sfree(startpos); return nvecs; } /*sscan_list*/
void low_do_autocorr(const char *fn,const char *title, int nframes,int nitem,int nout,real **c1, real dt,unsigned long mode,int nrestart, bool bAver,bool bNormalize, bool bVerbose,real tbeginfit,real tendfit, int eFitFn,int nskip) { FILE *fp,*gp=NULL; int i,k,nfour; real *csum; real *ctmp,*fit; real c0,sum,Ct2av,Ctav; bool bFour = acf.bFour; /* Check flags and parameters */ /* nout = get_acfnout();*/ if (nout == -1) nout = acf.nout = (nframes+1)/2; else if (nout > nframes) nout=nframes; if (MODE(eacCos) && MODE(eacVector)) gmx_fatal(FARGS,"Incompatible options bCos && bVector (%s, %d)", __FILE__,__LINE__); if ((MODE(eacP3) || MODE(eacRcross)) && bFour) { fprintf(stderr,"Can't combine mode %lu with FFT, turning off FFT\n",mode); bFour = FALSE; } if (MODE(eacNormal) && MODE(eacVector)) gmx_fatal(FARGS,"Incompatible mode bits: normal and vector (or Legendre)"); /* Print flags and parameters */ if (bVerbose) { printf("Will calculate %s of %d thingies for %d frames\n", title ? title : "autocorrelation",nitem,nframes); printf("bAver = %s, bFour = %s bNormalize= %s\n", bool_names[bAver],bool_names[bFour],bool_names[bNormalize]); printf("mode = %lu, dt = %g, nrestart = %d\n",mode,dt,nrestart); } if (bFour) { c0 = log((double)nframes)/log(2.0); k = c0; if (k < c0) k++; k++; nfour = 1<<k; if (debug) fprintf(debug,"Using FFT to calculate %s, #points for FFT = %d\n", title,nfour); /* Allocate temp arrays */ snew(csum,nfour); snew(ctmp,nfour); } else { nfour = 0; /* To keep the compiler happy */ snew(csum,nframes); snew(ctmp,nframes); } /* Loop over items (e.g. molecules or dihedrals) * In this loop the actual correlation functions are computed, but without * normalizing them. */ k = max(1,pow(10,(int)(log(nitem)/log(100)))); for(i=0; i<nitem; i++) { if (bVerbose && ((i%k==0 || i==nitem-1))) fprintf(stderr,"\rThingie %d",i+1); if (bFour) do_four_core(mode,nfour,nframes,nframes,c1[i],csum,ctmp); else do_ac_core(nframes,nout,ctmp,c1[i],nrestart,mode); } if (bVerbose) fprintf(stderr,"\n"); sfree(ctmp); sfree(csum); if (fn) { snew(fit,nout); fp=xvgropen(fn,title,"Time (ps)","C(t)"); } else { fit = NULL; fp = NULL; } if (bAver) { if (nitem > 1) average_acf(bVerbose,nframes,nitem,c1); if (bNormalize) normalize_acf(nout,c1[0]); if (eFitFn != effnNONE) { fit_acf(nout,eFitFn,fn!=NULL,tbeginfit,tendfit,dt,c1[0],fit); sum = print_and_integrate(fp,nout,dt,c1[0],fit,1); } else { sum = print_and_integrate(fp,nout,dt,c1[0],NULL,1); if (bVerbose) printf("Correlation time (integral over corrfn): %g (ps)\n",sum); } } else { /* Not averaging. Normalize individual ACFs */ Ctav = Ct2av = 0; if (debug) gp = xvgropen("ct-distr.xvg","Correlation times","item","time (ps)"); for(i=0; i<nitem; i++) { if (bNormalize) normalize_acf(nout,c1[i]); if (eFitFn != effnNONE) { fit_acf(nout,eFitFn,fn!=NULL,tbeginfit,tendfit,dt,c1[i],fit); sum = print_and_integrate(fp,nout,dt,c1[i],fit,1); } else { sum = print_and_integrate(fp,nout,dt,c1[i],NULL,1); if (debug) fprintf(debug, "CORRelation time (integral over corrfn %d): %g (ps)\n", i,sum); } Ctav += sum; Ct2av += sum*sum; if (debug) fprintf(gp,"%5d %.3f\n",i,sum); } if (debug) ffclose(gp); if (nitem > 1) { Ctav /= nitem; Ct2av /= nitem; printf("Average correlation time %.3f Std. Dev. %.3f Error %.3f (ps)\n", Ctav,sqrt((Ct2av - sqr(Ctav))), sqrt((Ct2av - sqr(Ctav))/(nitem-1))); } } if (fp) ffclose(fp); sfree(fit); }
int main(int argc,char *argv[]) { static char *desc[] = { "The ffscan program performs a single point energy and force calculation", "in which the force field is modified. This way a range of parameters can", "be changed and tested for reproduction of e.g. quantum chemical or", "experimental data. A grid scan over the parameters is done as specified", "using command line arguments. All parameters that reproduce the energy", "within a given absolute tolerance are printed to a log file.[PAR]", "Obviously polarizable models can be used, and shell optimisation is", "performed if necessary. Also, like in [TT]mdrun[tt] table functions can be used", "for user defined potential functions.[PAR]", "If the option -ga with appropriate file is passed, a genetic algorithm will", "be used rather than a grid scan." }; t_commrec *cr; static t_filenm fnm[] = { { efTPX, NULL, NULL, ffREAD }, { efLOG, "-g", "md", ffWRITE }, { efXVG, "-table", "table", ffOPTRD }, { efDAT, "-parm", "params", ffREAD }, { efDAT, "-ga", "genalg", ffOPTRD }, { efGRO, "-c", "junk", ffWRITE }, { efEDR, "-e", "junk", ffWRITE }, { efTRN, "-o", "junk", ffWRITE } }; #define NFILE asize(fnm) /* Command line options ! */ static t_ffscan ff = { /* tol */ 0.1, /* f_max */ 100.0, /* npow */ 12.0, /* epot */ 0.0, /* fac_epot */ 1.0, /* fac_pres */ 0.1, /* fac_msf */ 0.1, /* pres */ 1.0, /* molsize */ 1, /* nmol */ 1, /* bComb */ TRUE, /* bVerbose */ FALSE, /* bLogEps */ FALSE }; static char *loadx=NULL,*loady=NULL,*loadz=NULL; static t_pargs pa[] = { { "-tol", FALSE, etREAL, {&ff.tol}, "Energy tolerance (kJ/mol) (zero means everything is printed)" }, { "-fmax", FALSE, etREAL, {&ff.f_max}, "Force tolerance (zero means everything is printed)" }, { "-comb", FALSE, etBOOL, {&ff.bComb}, "Use combination rules" }, { "-npow", FALSE, etREAL, {&ff.npow}, "Power for LJ in case of table use" }, { "-logeps",FALSE, etBOOL, {&ff.bLogEps}, "Use a logarithmic scale for epsilon" }, { "-v", FALSE, etBOOL, {&ff.bVerbose}, "Be loud and noisy" }, { "-epot", FALSE, etREAL, {&ff.epot}, "Target energy (kJ/mol)" }, { "-fepot", FALSE, etREAL, {&ff.fac_epot}, "Factor for scaling energy violations (0 turns energy contribution off)" }, { "-pres", FALSE, etREAL, {&ff.pres}, "Value for reference pressure" }, { "-fpres", FALSE, etREAL, {&ff.fac_pres}, "Factor for scaling pressure violations (0 turns pressure contribution off)" }, { "-fmsf", FALSE, etREAL, {&ff.fac_msf}, "Factor for scaling mean square force violations (0 turns MSF contribution off)" }, { "-molsize",FALSE,etINT, {&ff.molsize}, "Number of atoms per molecule" }, { "-nmol", FALSE, etINT, {&ff.nmol}, "Number of molecules (Epot is divided by this value!)" } }; #define NPA asize(pa) unsigned long Flags = 0; gmx_edsam_t ed=NULL; FILE *fplog; ivec ddxyz = { 1,1,1 }; cr = init_par(&argc,&argv); ff.bVerbose = ff.bVerbose && MASTER(cr); #if 0 snew(ed,1); ed->eEDtype=eEDnone; #endif if (MASTER(cr)) CopyRight(stderr,argv[0]); parse_common_args(&argc,argv,PCA_BE_NICE,NFILE,fnm, NPA,pa,asize(desc),desc,0,NULL); if (ff.npow <= 6.0) gmx_fatal(FARGS,"Can not have repulsion with smaller exponent than 6"); if (ff.nmol < 1) gmx_fatal(FARGS,"Can not fit %d molecules",ff.nmol); gmx_log_open(ftp2fn(efLOG,NFILE,fnm),cr,FALSE,0,&fplog); if (MASTER(cr)) { CopyRight(fplog,argv[0]); please_cite(fplog,"Lindahl2001a"); please_cite(fplog,"Berendsen95a"); } set_ffvars(&ff); Flags = (Flags | MD_FFSCAN); mdrunner(fplog,cr,NFILE,fnm,ff.bVerbose,FALSE, ddxyz,0,0,0,loadx,loady,loadz,1, 0,0,Flags); if (gmx_parallel_env_initialized()) gmx_finalize(cr); gmx_log_close(fplog); return 0; }
static int read_atom(t_symtab *symtab, char line[],int type,int natom, t_atoms *atoms,rvec x[],int chainnum,gmx_bool bChange) { t_atom *atomn; int j,k; char nc='\0'; char anr[12],anm[12],anm_copy[12],altloc,resnm[12],rnr[12]; char xc[12],yc[12],zc[12],occup[12],bfac[12]; unsigned char resic; char chainid; int resnr,atomnumber; if (natom>=atoms->nr) gmx_fatal(FARGS,"\nFound more atoms (%d) in pdb file than expected (%d)", natom+1,atoms->nr); /* Skip over type */ j=6; for(k=0; (k<5); k++,j++) anr[k]=line[j]; anr[k]=nc; trim(anr); j++; for(k=0; (k<4); k++,j++) anm[k]=line[j]; anm[k]=nc; strcpy(anm_copy,anm); atomnumber = NOTSET; trim(anm); altloc=line[j]; j++; for(k=0; (k<4); k++,j++) resnm[k]=line[j]; resnm[k]=nc; trim(resnm); chainid = line[j]; j++; for(k=0; (k<4); k++,j++) { rnr[k] = line[j]; } rnr[k] = nc; trim(rnr); resnr = strtol(rnr, NULL, 10); resic = line[j]; j+=4; /* X,Y,Z Coordinate */ for(k=0; (k<8); k++,j++) xc[k]=line[j]; xc[k]=nc; for(k=0; (k<8); k++,j++) yc[k]=line[j]; yc[k]=nc; for(k=0; (k<8); k++,j++) zc[k]=line[j]; zc[k]=nc; /* Weight */ for(k=0; (k<6); k++,j++) occup[k]=line[j]; occup[k]=nc; /* B-Factor */ for(k=0; (k<7); k++,j++) bfac[k]=line[j]; bfac[k]=nc; if (atoms->atom) { atomn=&(atoms->atom[natom]); if ((natom==0) || atoms->resinfo[atoms->atom[natom-1].resind].nr != resnr || atoms->resinfo[atoms->atom[natom-1].resind].ic != resic || (strcmp(*atoms->resinfo[atoms->atom[natom-1].resind].name,resnm) != 0)) { if (natom == 0) { atomn->resind = 0; } else { atomn->resind = atoms->atom[natom-1].resind + 1; } atoms->nres = atomn->resind + 1; t_atoms_set_resinfo(atoms,natom,symtab,resnm,resnr,resic,chainnum,chainid); } else { atomn->resind = atoms->atom[natom-1].resind; } if (bChange) { xlate_atomname_pdb2gmx(anm); } atoms->atomname[natom]=put_symtab(symtab,anm); atomn->m = 0.0; atomn->q = 0.0; atomn->atomnumber = atomnumber; atomn->elem[0] = '\0'; } x[natom][XX]=strtod(xc,NULL)*0.1; x[natom][YY]=strtod(yc,NULL)*0.1; x[natom][ZZ]=strtod(zc,NULL)*0.1; if (atoms->pdbinfo) { atoms->pdbinfo[natom].type=type; atoms->pdbinfo[natom].atomnr=strtol(anr, NULL, 10); atoms->pdbinfo[natom].altloc=altloc; strcpy(atoms->pdbinfo[natom].atomnm,anm_copy); atoms->pdbinfo[natom].bfac=strtod(bfac,NULL); atoms->pdbinfo[natom].occup=strtod(occup,NULL); } natom++; return natom; }
real read_gaussian_output(rvec QMgrad[], rvec MMgrad[], int step, t_QMrec *qm, t_MMrec *mm) { int i, j, atnum; char buf[300]; real QMener; FILE *in; in = fopen("fort.7", "r"); /* in case of an optimization, the coordinates are printed in the * fort.7 file first, followed by the energy, coordinates and (if * required) the CI eigenvectors. */ if (qm->bTS || qm->bOPT) { for (i = 0; i < qm->nrQMatoms; i++) { if (NULL == fgets(buf, 300, in)) { gmx_fatal(FARGS, "Error reading Gaussian output - not enough atom lines?"); } #ifdef GMX_DOUBLE sscanf(buf, "%d %lf %lf %lf\n", &atnum, &qm->xQM[i][XX], &qm->xQM[i][YY], &qm->xQM[i][ZZ]); #else sscanf(buf, "%d %f %f %f\n", &atnum, &qm->xQM[i][XX], &qm->xQM[i][YY], &qm->xQM[i][ZZ]); #endif for (j = 0; j < DIM; j++) { qm->xQM[i][j] *= BOHR2NM; } } } /* the next line is the energy and in the case of CAS, the energy * difference between the two states. */ if (NULL == fgets(buf, 300, in)) { gmx_fatal(FARGS, "Error reading Gaussian output"); } #ifdef GMX_DOUBLE sscanf(buf, "%lf\n", &QMener); #else sscanf(buf, "%f\n", &QMener); #endif /* next lines contain the gradients of the QM atoms */ for (i = 0; i < qm->nrQMatoms; i++) { if (NULL == fgets(buf, 300, in)) { gmx_fatal(FARGS, "Error reading Gaussian output"); } #ifdef GMX_DOUBLE sscanf(buf, "%lf %lf %lf\n", &QMgrad[i][XX], &QMgrad[i][YY], &QMgrad[i][ZZ]); #else sscanf(buf, "%f %f %f\n", &QMgrad[i][XX], &QMgrad[i][YY], &QMgrad[i][ZZ]); #endif } /* the next lines are the gradients of the MM atoms */ if (qm->QMmethod >= eQMmethodRHF) { for (i = 0; i < mm->nrMMatoms; i++) { if (NULL == fgets(buf, 300, in)) { gmx_fatal(FARGS, "Error reading Gaussian output"); } #ifdef GMX_DOUBLE sscanf(buf, "%lf %lf %lf\n", &MMgrad[i][XX], &MMgrad[i][YY], &MMgrad[i][ZZ]); #else sscanf(buf, "%f %f %f\n", &MMgrad[i][XX], &MMgrad[i][YY], &MMgrad[i][ZZ]); #endif } } fclose(in); return(QMener); }
void init_multisystem(t_commrec *cr, int nsim, char **multidirs, int nfile, const t_filenm fnm[], gmx_bool bParFn) { gmx_multisim_t *ms; int nnodes, nnodpersim, sim, i, ftp; char buf[256]; #ifdef GMX_MPI MPI_Group mpi_group_world; #endif int *rank; #ifndef GMX_MPI if (nsim > 1) { gmx_fatal(FARGS, "This binary is compiled without MPI support, can not do multiple simulations."); } #endif nnodes = cr->nnodes; if (nnodes % nsim != 0) { gmx_fatal(FARGS, "The number of nodes (%d) is not a multiple of the number of simulations (%d)", nnodes, nsim); } nnodpersim = nnodes/nsim; sim = cr->nodeid/nnodpersim; if (debug) { fprintf(debug, "We have %d simulations, %d nodes per simulation, local simulation is %d\n", nsim, nnodpersim, sim); } snew(ms, 1); cr->ms = ms; ms->nsim = nsim; ms->sim = sim; #ifdef GMX_MPI /* Create a communicator for the master nodes */ snew(rank, ms->nsim); for (i = 0; i < ms->nsim; i++) { rank[i] = i*nnodpersim; } MPI_Comm_group(MPI_COMM_WORLD, &mpi_group_world); MPI_Group_incl(mpi_group_world, nsim, rank, &ms->mpi_group_masters); sfree(rank); MPI_Comm_create(MPI_COMM_WORLD, ms->mpi_group_masters, &ms->mpi_comm_masters); #if !defined(GMX_THREAD_MPI) && !defined(MPI_IN_PLACE_EXISTS) /* initialize the MPI_IN_PLACE replacement buffers */ snew(ms->mpb, 1); ms->mpb->ibuf = NULL; ms->mpb->libuf = NULL; ms->mpb->fbuf = NULL; ms->mpb->dbuf = NULL; ms->mpb->ibuf_alloc = 0; ms->mpb->libuf_alloc = 0; ms->mpb->fbuf_alloc = 0; ms->mpb->dbuf_alloc = 0; #endif #endif /* Reduce the intra-simulation communication */ cr->sim_nodeid = cr->nodeid % nnodpersim; cr->nnodes = nnodpersim; #ifdef GMX_MPI MPI_Comm_split(MPI_COMM_WORLD, sim, cr->sim_nodeid, &cr->mpi_comm_mysim); cr->mpi_comm_mygroup = cr->mpi_comm_mysim; cr->nodeid = cr->sim_nodeid; #endif if (debug) { fprintf(debug, "This is simulation %d", cr->ms->sim); if (PAR(cr)) { fprintf(debug, ", local number of nodes %d, local nodeid %d", cr->nnodes, cr->sim_nodeid); } fprintf(debug, "\n\n"); } if (multidirs) { int ret; if (debug) { fprintf(debug, "Changing to directory %s\n", multidirs[cr->ms->sim]); } if (chdir(multidirs[cr->ms->sim]) != 0) { gmx_fatal(FARGS, "Couldn't change directory to %s: %s", multidirs[cr->ms->sim], strerror(errno)); } } else if (bParFn) { /* Patch output and tpx, cpt and rerun input file names */ for (i = 0; (i < nfile); i++) { /* Because of possible multiple extensions per type we must look * at the actual file name */ if (is_output(&fnm[i]) || fnm[i].ftp == efTPX || fnm[i].ftp == efCPT || strcmp(fnm[i].opt, "-rerun") == 0) { ftp = fn2ftp(fnm[i].fns[0]); par_fn(fnm[i].fns[0], ftp, cr, TRUE, FALSE, buf, 255); sfree(fnm[i].fns[0]); fnm[i].fns[0] = gmx_strdup(buf); } } } }
void init_gaussian(t_commrec *cr, t_QMrec *qm, t_MMrec *mm) { FILE *rffile = NULL, *out = NULL; ivec basissets[eQMbasisNR] = {{0, 3, 0}, {0, 3, 0}, /*added for double sto-3g entry in names.c*/ {5, 0, 0}, {5, 0, 1}, {5, 0, 11}, {5, 6, 0}, {1, 6, 0}, {1, 6, 1}, {1, 6, 11}, {4, 6, 0}}; char *buf = NULL; int i; /* using the ivec above to convert the basis read form the mdp file * in a human readable format into some numbers for the gaussian * route. This is necessary as we are using non standard routes to * do SH. */ /* per layer we make a new subdir for integral file, checkpoint * files and such. These dirs are stored in the QMrec for * convenience */ if (!qm->nQMcpus) /* this we do only once per layer * as we call g01 externally */ { for (i = 0; i < DIM; i++) { qm->SHbasis[i] = basissets[qm->QMbasis][i]; } /* init gradually switching on of the SA */ qm->SAstep = 0; /* we read the number of cpus and environment from the environment * if set. */ buf = getenv("GMX_QM_GAUSSIAN_NCPUS"); if (buf) { sscanf(buf, "%d", &qm->nQMcpus); } else { qm->nQMcpus = 1; } fprintf(stderr, "number of CPUs for gaussian = %d\n", qm->nQMcpus); buf = getenv("GMX_QM_GAUSSIAN_MEMORY"); if (buf) { sscanf(buf, "%d", &qm->QMmem); } else { qm->QMmem = 50000000; } fprintf(stderr, "memory for gaussian = %d\n", qm->QMmem); buf = getenv("GMX_QM_ACCURACY"); if (buf) { sscanf(buf, "%d", &qm->accuracy); } else { qm->accuracy = 8; } fprintf(stderr, "accuracy in l510 = %d\n", qm->accuracy); buf = getenv("GMX_QM_CPMCSCF"); if (buf) { sscanf(buf, "%d", &i); qm->cpmcscf = (i != 0); } else { qm->cpmcscf = FALSE; } if (qm->cpmcscf) { fprintf(stderr, "using cp-mcscf in l1003\n"); } else { fprintf(stderr, "NOT using cp-mcscf in l1003\n"); } buf = getenv("GMX_QM_SA_STEP"); if (buf) { sscanf(buf, "%d", &qm->SAstep); } else { /* init gradually switching on of the SA */ qm->SAstep = 0; } /* we read the number of cpus and environment from the environment * if set. */ fprintf(stderr, "Level of SA at start = %d\n", qm->SAstep); /* punch the LJ C6 and C12 coefficients to be picked up by * gaussian and usd to compute the LJ interaction between the * MM and QM atoms. */ if (qm->bTS || qm->bOPT) { out = fopen("LJ.dat", "w"); for (i = 0; i < qm->nrQMatoms; i++) { #ifdef GMX_DOUBLE fprintf(out, "%3d %10.7lf %10.7lf\n", qm->atomicnumberQM[i], qm->c6[i], qm->c12[i]); #else fprintf(out, "%3d %10.7f %10.7f\n", qm->atomicnumberQM[i], qm->c6[i], qm->c12[i]); #endif } fclose(out); } /* gaussian settings on the system */ buf = getenv("GMX_QM_GAUSS_DIR"); fprintf(stderr, "%s", buf); if (buf) { qm->gauss_dir = strdup(buf); } else { gmx_fatal(FARGS, "no $GMX_QM_GAUSS_DIR, check gaussian manual\n"); } buf = getenv("GMX_QM_GAUSS_EXE"); if (buf) { qm->gauss_exe = strdup(buf); } else { gmx_fatal(FARGS, "no $GMX_QM_GAUSS_EXE set, check gaussian manual\n"); } buf = getenv("GMX_QM_MODIFIED_LINKS_DIR"); if (buf) { qm->devel_dir = strdup (buf); } else { gmx_fatal(FARGS, "no $GMX_QM_MODIFIED_LINKS_DIR, this is were the modified links reside.\n"); } /* if(fr->bRF){*/ /* reactionfield, file is needed using gaussian */ /* rffile=fopen("rf.dat","w");*/ /* fprintf(rffile,"%f %f\n",fr->epsilon_r,fr->rcoulomb/BOHR2NM);*/ /* fclose(rffile);*/ /* }*/ } fprintf(stderr, "gaussian initialised...\n"); }
void calc_potential(const char *fn, atom_id **index, int gnx[], double ***slPotential, double ***slCharge, double ***slField, int *nslices, t_topology *top, int ePBC, int axis, int nr_grps, double *slWidth, double fudge_z, gmx_bool bSpherical, gmx_bool bCorrect, const output_env_t oenv) { rvec *x0; /* coordinates without pbc */ matrix box; /* box (3x3) */ int natoms; /* nr. atoms in trj */ t_trxstatus *status; int **slCount, /* nr. of atoms in one slice for a group */ i,j,n, /* loop indices */ teller = 0, ax1=0, ax2=0, nr_frames = 0, /* number of frames */ slice; /* current slice */ double slVolume; /* volume of slice for spherical averaging */ double qsum,nn; real t; double z; rvec xcm; gmx_rmpbc_t gpbc=NULL; switch(axis) { case 0: ax1 = 1; ax2 = 2; break; case 1: ax1 = 0; ax2 = 2; break; case 2: ax1 = 0; ax2 = 1; break; default: gmx_fatal(FARGS,"Invalid axes. Terminating\n"); } if ((natoms = read_first_x(oenv,&status,fn,&t,&x0,box)) == 0) gmx_fatal(FARGS,"Could not read coordinates from statusfile\n"); if (! *nslices) *nslices = (int)(box[axis][axis] * 10); /* default value */ fprintf(stderr,"\nDividing the box in %d slices\n",*nslices); snew(*slField, nr_grps); snew(*slCharge, nr_grps); snew(*slPotential, nr_grps); for (i = 0; i < nr_grps; i++) { snew((*slField)[i], *nslices); snew((*slCharge)[i], *nslices); snew((*slPotential)[i], *nslices); } gpbc = gmx_rmpbc_init(&top->idef,ePBC,natoms,box); /*********** Start processing trajectory ***********/ do { *slWidth = box[axis][axis]/(*nslices); teller++; gmx_rmpbc(gpbc,natoms,box,x0); /* calculate position of center of mass based on group 1 */ calc_xcm(x0, gnx[0], index[0], top->atoms.atom, xcm, FALSE); svmul(-1,xcm,xcm); for (n = 0; n < nr_grps; n++) { /* Check whether we actually have all positions of the requested index * group in the trajectory file */ if (gnx[n] > natoms) { gmx_fatal(FARGS, "You selected a group with %d atoms, but only %d atoms\n" "were found in the trajectory.\n", gnx[n], natoms); } for (i = 0; i < gnx[n]; i++) /* loop over all atoms in index file */ { if (bSpherical) { rvec_add(x0[index[n][i]], xcm, x0[index[n][i]]); /* only distance from origin counts, not sign */ slice = norm(x0[index[n][i]])/(*slWidth); /* this is a nice check for spherical groups but not for all water in a cubic box since a lot will fall outside the sphere if (slice > (*nslices)) { fprintf(stderr,"Warning: slice = %d\n",slice); } */ (*slCharge)[n][slice] += top->atoms.atom[index[n][i]].q; } else { z = x0[index[n][i]][axis]; z = z + fudge_z; if (z < 0) z += box[axis][axis]; if (z > box[axis][axis]) z -= box[axis][axis]; /* determine which slice atom is in */ slice = (z / (*slWidth)); (*slCharge)[n][slice] += top->atoms.atom[index[n][i]].q; } } } nr_frames++; } while (read_next_x(oenv,status,&t,natoms,x0,box)); gmx_rmpbc_done(gpbc); /*********** done with status file **********/ close_trj(status); /* slCharge now contains the total charge per slice, summed over all frames. Now divide by nr_frames and integrate twice */ if (bSpherical) fprintf(stderr,"\n\nRead %d frames from trajectory. Calculating potential" "in spherical coordinates\n", nr_frames); else fprintf(stderr,"\n\nRead %d frames from trajectory. Calculating potential\n", nr_frames); for (n =0; n < nr_grps; n++) { for (i = 0; i < *nslices; i++) { if (bSpherical) { /* charge per volume is now the summed charge, divided by the nr of frames and by the volume of the slice it's in, 4pi r^2 dr */ slVolume = 4*M_PI * sqr(i) * sqr(*slWidth) * *slWidth; if (slVolume == 0) { (*slCharge)[n][i] = 0; } else { (*slCharge)[n][i] = (*slCharge)[n][i] / (nr_frames * slVolume); } } else { /* get charge per volume */ (*slCharge)[n][i] = (*slCharge)[n][i] * (*nslices) / (nr_frames * box[axis][axis] * box[ax1][ax1] * box[ax2][ax2]); } } /* Now we have charge densities */ } if(bCorrect && !bSpherical) { for(n =0; n < nr_grps; n++) { nn = 0; qsum = 0; for (i = 0; i < *nslices; i++) { if( fabs((*slCharge)[n][i]) >= GMX_DOUBLE_MIN ) { nn++; qsum += (*slCharge)[n][i]; } } qsum /= nn; for (i = 0; i < *nslices; i++) { if( fabs((*slCharge)[n][i]) >= GMX_DOUBLE_MIN ) { (*slCharge)[n][i] -= qsum; } } } } for(n =0; n < nr_grps; n++) { /* integrate twice to get field and potential */ p_integrate((*slField)[n], (*slCharge)[n], *nslices, *slWidth); } if(bCorrect && !bSpherical) { for(n =0; n < nr_grps; n++) { nn = 0; qsum = 0; for (i = 0; i < *nslices; i++) { if( fabs((*slCharge)[n][i]) >= GMX_DOUBLE_MIN ) { nn++; qsum += (*slField)[n][i]; } } qsum /= nn; for (i = 0; i < *nslices; i++) { if( fabs((*slCharge)[n][i]) >= GMX_DOUBLE_MIN ) { (*slField)[n][i] -= qsum; } } } } for(n =0; n < nr_grps; n++) { p_integrate((*slPotential)[n],(*slField)[n], *nslices, *slWidth); } /* Now correct for eps0 and in spherical case for r*/ for (n = 0; n < nr_grps; n++) for (i = 0; i < *nslices; i++) { if (bSpherical) { (*slPotential)[n][i] = ELC * (*slPotential)[n][i] * -1.0E9 / (EPS0 * i * (*slWidth)); (*slField)[n][i] = ELC * (*slField)[n][i] * 1E18 / (EPS0 * i * (*slWidth)); } else { (*slPotential)[n][i] = ELC * (*slPotential)[n][i] * -1.0E9 / EPS0 ; (*slField)[n][i] = ELC * (*slField)[n][i] * 1E18 / EPS0; } } sfree(x0); /* free memory used by coordinate array */ }
real read_gaussian_SH_output(rvec QMgrad[], rvec MMgrad[], int step, gmx_bool swapped, t_QMrec *qm, t_MMrec *mm) { int i; char buf[300]; real QMener, DeltaE; FILE *in; in = fopen("fort.7", "r"); /* first line is the energy and in the case of CAS, the energy * difference between the two states. */ if (NULL == fgets(buf, 300, in)) { gmx_fatal(FARGS, "Error reading Gaussian output"); } #ifdef GMX_DOUBLE sscanf(buf, "%lf %lf\n", &QMener, &DeltaE); #else sscanf(buf, "%f %f\n", &QMener, &DeltaE); #endif /* switch on/off the State Averaging */ if (DeltaE > qm->SAoff) { if (qm->SAstep > 0) { qm->SAstep--; } } else if (DeltaE < qm->SAon || (qm->SAstep > 0)) { if (qm->SAstep < qm->SAsteps) { qm->SAstep++; } } /* for debugging: */ fprintf(stderr, "Gap = %5f,SA = %3d\n", DeltaE, (qm->SAstep > 0)); /* next lines contain the gradients of the QM atoms */ for (i = 0; i < qm->nrQMatoms; i++) { if (NULL == fgets(buf, 300, in)) { gmx_fatal(FARGS, "Error reading Gaussian output"); } #ifdef GMX_DOUBLE sscanf(buf, "%lf %lf %lf\n", &QMgrad[i][XX], &QMgrad[i][YY], &QMgrad[i][ZZ]); #else sscanf(buf, "%f %f %f\n", &QMgrad[i][XX], &QMgrad[i][YY], &QMgrad[i][ZZ]); #endif } /* the next lines, are the gradients of the MM atoms */ for (i = 0; i < mm->nrMMatoms; i++) { if (NULL == fgets(buf, 300, in)) { gmx_fatal(FARGS, "Error reading Gaussian output"); } #ifdef GMX_DOUBLE sscanf(buf, "%lf %lf %lf\n", &MMgrad[i][XX], &MMgrad[i][YY], &MMgrad[i][ZZ]); #else sscanf(buf, "%f %f %f\n", &MMgrad[i][XX], &MMgrad[i][YY], &MMgrad[i][ZZ]); #endif } /* the next line contains the two CI eigenvector elements */ if (NULL == fgets(buf, 300, in)) { gmx_fatal(FARGS, "Error reading Gaussian output"); } if (!step) { sscanf(buf, "%d", &qm->CIdim); snew(qm->CIvec1, qm->CIdim); snew(qm->CIvec1old, qm->CIdim); snew(qm->CIvec2, qm->CIdim); snew(qm->CIvec2old, qm->CIdim); } else { /* before reading in the new current CI vectors, copy the current * CI vector into the old one. */ for (i = 0; i < qm->CIdim; i++) { qm->CIvec1old[i] = qm->CIvec1[i]; qm->CIvec2old[i] = qm->CIvec2[i]; } } /* first vector */ for (i = 0; i < qm->CIdim; i++) { if (NULL == fgets(buf, 300, in)) { gmx_fatal(FARGS, "Error reading Gaussian output"); } #ifdef GMX_DOUBLE sscanf(buf, "%lf\n", &qm->CIvec1[i]); #else sscanf(buf, "%f\n", &qm->CIvec1[i]); #endif } /* second vector */ for (i = 0; i < qm->CIdim; i++) { if (NULL == fgets(buf, 300, in)) { gmx_fatal(FARGS, "Error reading Gaussian output"); } #ifdef GMX_DOUBLE sscanf(buf, "%lf\n", &qm->CIvec2[i]); #else sscanf(buf, "%f\n", &qm->CIvec2[i]); #endif } fclose(in); return(QMener); }
int gmx_x2top(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] generates a primitive topology from a coordinate file.", "The program assumes all hydrogens are present when defining", "the hybridization from the atom name and the number of bonds.", "The program can also make an [TT].rtp[tt] entry, which you can then add", "to the [TT].rtp[tt] database.[PAR]", "When [TT]-param[tt] is set, equilibrium distances and angles", "and force constants will be printed in the topology for all", "interactions. The equilibrium distances and angles are taken", "from the input coordinates, the force constant are set with", "command line options.", "The force fields somewhat supported currently are:[PAR]", "G53a5 GROMOS96 53a5 Forcefield (official distribution)[PAR]", "oplsaa OPLS-AA/L all-atom force field (2001 aminoacid dihedrals)[PAR]", "The corresponding data files can be found in the library directory", "with name [TT]atomname2type.n2t[tt]. Check Chapter 5 of the manual for more", "information about file formats. By default, the force field selection", "is interactive, but you can use the [TT]-ff[tt] option to specify", "one of the short names above on the command line instead. In that", "case [THISMODULE] just looks for the corresponding file.[PAR]", }; const char *bugs[] = { "The atom type selection is primitive. Virtually no chemical knowledge is used", "Periodic boundary conditions screw up the bonding", "No improper dihedrals are generated", "The atoms to atomtype translation table is incomplete ([TT]atomname2type.n2t[tt] file in the data directory). Please extend it and send the results back to the GROMACS crew." }; FILE *fp; t_params plist[F_NRE]; t_excls *excls; t_atoms *atoms; /* list with all atoms */ gpp_atomtype_t atype; t_nextnb nnb; t_nm2type *nm2t; t_mols mymol; int nnm; char title[STRLEN], forcefield[32], ffdir[STRLEN]; rvec *x; /* coordinates? */ int *nbonds, *cgnr; int bts[] = { 1, 1, 1, 2 }; matrix box; /* box length matrix */ int natoms; /* number of atoms in one molecule */ int nres; /* number of molecules? */ int i, j, k, l, m, ndih; int epbc; gmx_bool bRTP, bTOP, bOPLS; t_symtab symtab; real cutoff, qtot, mtot; char n2t[STRLEN]; output_env_t oenv; t_filenm fnm[] = { { efSTX, "-f", "conf", ffREAD }, { efTOP, "-o", "out", ffOPTWR }, { efRTP, "-r", "out", ffOPTWR } }; #define NFILE asize(fnm) static real scale = 1.1, kb = 4e5, kt = 400, kp = 5; static t_restp rtp_header_settings; static gmx_bool bRemoveDihedralIfWithImproper = FALSE; static gmx_bool bGenerateHH14Interactions = TRUE; static gmx_bool bKeepAllGeneratedDihedrals = FALSE; static int nrexcl = 3; static gmx_bool bParam = TRUE, bRound = TRUE; static gmx_bool bPairs = TRUE, bPBC = TRUE; static gmx_bool bUsePDBcharge = FALSE, bVerbose = FALSE; static const char *molnm = "ICE"; static const char *ff = "oplsaa"; t_pargs pa[] = { { "-ff", FALSE, etSTR, {&ff}, "Force field for your simulation. Type \"select\" for interactive selection." }, { "-v", FALSE, etBOOL, {&bVerbose}, "Generate verbose output in the top file." }, { "-nexcl", FALSE, etINT, {&nrexcl}, "Number of exclusions" }, { "-H14", FALSE, etBOOL, {&bGenerateHH14Interactions}, "Use 3rd neighbour interactions for hydrogen atoms" }, { "-alldih", FALSE, etBOOL, {&bKeepAllGeneratedDihedrals}, "Generate all proper dihedrals" }, { "-remdih", FALSE, etBOOL, {&bRemoveDihedralIfWithImproper}, "Remove dihedrals on the same bond as an improper" }, { "-pairs", FALSE, etBOOL, {&bPairs}, "Output 1-4 interactions (pairs) in topology file" }, { "-name", FALSE, etSTR, {&molnm}, "Name of your molecule" }, { "-pbc", FALSE, etBOOL, {&bPBC}, "Use periodic boundary conditions." }, { "-pdbq", FALSE, etBOOL, {&bUsePDBcharge}, "Use the B-factor supplied in a [TT].pdb[tt] file for the atomic charges" }, { "-param", FALSE, etBOOL, {&bParam}, "Print parameters in the output" }, { "-round", FALSE, etBOOL, {&bRound}, "Round off measured values" }, { "-kb", FALSE, etREAL, {&kb}, "Bonded force constant (kJ/mol/nm^2)" }, { "-kt", FALSE, etREAL, {&kt}, "Angle force constant (kJ/mol/rad^2)" }, { "-kp", FALSE, etREAL, {&kp}, "Dihedral angle force constant (kJ/mol/rad^2)" } }; if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa, asize(desc), desc, asize(bugs), bugs, &oenv)) { return 0; } bRTP = opt2bSet("-r", NFILE, fnm); bTOP = opt2bSet("-o", NFILE, fnm); /* C89 requirements mean that these struct members cannot be used in * the declaration of pa. So some temporary variables are needed. */ rtp_header_settings.bRemoveDihedralIfWithImproper = bRemoveDihedralIfWithImproper; rtp_header_settings.bGenerateHH14Interactions = bGenerateHH14Interactions; rtp_header_settings.bKeepAllGeneratedDihedrals = bKeepAllGeneratedDihedrals; rtp_header_settings.nrexcl = nrexcl; if (!bRTP && !bTOP) { gmx_fatal(FARGS, "Specify at least one output file"); } /* Force field selection, interactive or direct */ choose_ff(strcmp(ff, "select") == 0 ? NULL : ff, forcefield, sizeof(forcefield), ffdir, sizeof(ffdir)); bOPLS = (strcmp(forcefield, "oplsaa") == 0); mymol.name = strdup(molnm); mymol.nr = 1; /* Init parameter lists */ init_plist(plist); /* Read coordinates */ get_stx_coordnum(opt2fn("-f", NFILE, fnm), &natoms); snew(atoms, 1); /* make space for all the atoms */ init_t_atoms(atoms, natoms, TRUE); snew(x, natoms); read_stx_conf(opt2fn("-f", NFILE, fnm), title, atoms, x, NULL, &epbc, box); sprintf(n2t, "%s", ffdir); nm2t = rd_nm2type(n2t, &nnm); if (nnm == 0) { gmx_fatal(FARGS, "No or incorrect atomname2type.n2t file found (looking for %s)", n2t); } else { printf("There are %d name to type translations in file %s\n", nnm, n2t); } if (debug) { dump_nm2type(debug, nnm, nm2t); } printf("Generating bonds from distances...\n"); snew(nbonds, atoms->nr); mk_bonds(nnm, nm2t, atoms, x, &(plist[F_BONDS]), nbonds, bPBC, box); open_symtab(&symtab); atype = set_atom_type(&symtab, atoms, &(plist[F_BONDS]), nbonds, nnm, nm2t); /* Make Angles and Dihedrals */ snew(excls, atoms->nr); printf("Generating angles and dihedrals from bonds...\n"); init_nnb(&nnb, atoms->nr, 4); gen_nnb(&nnb, plist); print_nnb(&nnb, "NNB"); gen_pad(&nnb, atoms, &rtp_header_settings, plist, excls, NULL, TRUE); done_nnb(&nnb); if (!bPairs) { plist[F_LJ14].nr = 0; } fprintf(stderr, "There are %4d %s dihedrals, %4d impropers, %4d angles\n" " %4d pairs, %4d bonds and %4d atoms\n", plist[F_PDIHS].nr, bOPLS ? "Ryckaert-Bellemans" : "proper", plist[F_IDIHS].nr, plist[F_ANGLES].nr, plist[F_LJ14].nr, plist[F_BONDS].nr, atoms->nr); calc_angles_dihs(&plist[F_ANGLES], &plist[F_PDIHS], x, bPBC, box); set_force_const(plist, kb, kt, kp, bRound, bParam); cgnr = set_cgnr(atoms, bUsePDBcharge, &qtot, &mtot); printf("Total charge is %g, total mass is %g\n", qtot, mtot); if (bOPLS) { bts[2] = 3; bts[3] = 1; } if (bTOP) { fp = ftp2FILE(efTOP, NFILE, fnm, "w"); print_top_header(fp, ftp2fn(efTOP, NFILE, fnm), TRUE, ffdir, 1.0); write_top(fp, NULL, mymol.name, atoms, FALSE, bts, plist, excls, atype, cgnr, rtp_header_settings.nrexcl); print_top_mols(fp, mymol.name, ffdir, NULL, 0, NULL, 1, &mymol); gmx_ffclose(fp); } if (bRTP) { print_rtp(ftp2fn(efRTP, NFILE, fnm), "Generated by x2top", atoms, plist, atype, cgnr); } if (debug) { dump_hybridization(debug, atoms, nbonds); } close_symtab(&symtab); sfree(mymol.name); printf("\nWARNING: topologies generated by %s can not be trusted at face value.\n", ShortProgram()); printf(" Please verify atomtypes and charges by comparison to other\n"); printf(" topologies.\n"); return 0; }
void add_conf(t_atoms *atoms, rvec **x, rvec **v, real **r, bool bSrenew, int ePBC, matrix box, bool bInsert, t_atoms *atoms_solvt,rvec *x_solvt,rvec *v_solvt,real *r_solvt, bool bVerbose,real rshell,int max_sol) { t_nblist *nlist; t_atoms *atoms_all; real max_vdw,*r_prot,*r_all,n2,r2,ib1,ib2; int natoms_prot,natoms_solvt; int i,j,jj,m,j0,j1,jjj,jnres,jnr,inr,iprot,is1,is2; int prev,resnr,nresadd,d,k,ncells,maxincell; int dx0,dx1,dy0,dy1,dz0,dz1; int ntest,nremove,nkeep; rvec dx,xi,xj,xpp,*x_all,*v_all; bool *remove,*keep; int bSolSol; natoms_prot = atoms->nr; natoms_solvt = atoms_solvt->nr; if (natoms_solvt <= 0) { fprintf(stderr,"WARNING: Nothing to add\n"); return; } if (ePBC == epbcSCREW) gmx_fatal(FARGS,"Sorry, %s pbc is not yet supported",epbc_names[ePBC]); if (bVerbose) fprintf(stderr,"Calculating Overlap...\n"); /* Set margin around box edges to largest solvent dimension. * The maximum distance between atoms in a solvent molecule should * be calculated. At the moment a fudge factor of 3 is used. */ r_prot = *r; box_margin = 3*find_max_real(natoms_solvt,r_solvt); max_vdw = max(3*find_max_real(natoms_prot,r_prot),box_margin); fprintf(stderr,"box_margin = %g\n",box_margin); snew(remove,natoms_solvt); nremove = 0; for(i=0; i<atoms_solvt->nr; i++) if ( outside_box_plus_margin(x_solvt[i],box) ) i=mark_res(i,remove,atoms_solvt->nr,atoms_solvt->atom,&nremove); fprintf(stderr,"Removed %d atoms that were outside the box\n",nremove); /* Define grid stuff for genbox */ /* Largest VDW radius */ snew(r_all,natoms_prot+natoms_solvt); for(i=j=0; i<natoms_prot; i++,j++) r_all[j]=r_prot[i]; for(i=0; i<natoms_solvt; i++,j++) r_all[j]=r_solvt[i]; /* Combine arrays */ combine_atoms(atoms,atoms_solvt,*x,v?*v:NULL,x_solvt,v_solvt, &atoms_all,&x_all,&v_all); /* Do neighboursearching step */ do_nsgrid(stdout,bVerbose,box,x_all,atoms_all,max_vdw); /* check solvent with solute */ nlist = &(fr->nblists[0].nlist_sr[eNL_VDW]); fprintf(stderr,"nri = %d, nrj = %d\n",nlist->nri,nlist->nrj); for(bSolSol=0; (bSolSol<=1); bSolSol++) { ntest = nremove = 0; fprintf(stderr,"Checking %s-Solvent overlap:", bSolSol ? "Solvent" : "Protein"); for(i=0; (i<nlist->nri); i++) { inr = nlist->iinr[i]; j0 = nlist->jindex[i]; j1 = nlist->jindex[i+1]; rvec_add(x_all[inr],fr->shift_vec[nlist->shift[i]],xi); for(j=j0; (j<j1); j++) { jnr = nlist->jjnr[j]; copy_rvec(x_all[jnr],xj); /* Check solvent-protein and solvent-solvent */ is1 = inr-natoms_prot; is2 = jnr-natoms_prot; /* Check if at least one of the atoms is a solvent that is not yet * listed for removal, and if both are solvent, that they are not in the * same residue. */ if ((!bSolSol && bXor((is1 >= 0),(is2 >= 0)) && /* One atom is protein */ ((is1 < 0) || ((is1 >= 0) && !remove[is1])) && ((is2 < 0) || ((is2 >= 0) && !remove[is2]))) || (bSolSol && (is1 >= 0) && (!remove[is1]) && /* is1 is solvent */ (is2 >= 0) && (!remove[is2]) && /* is2 is solvent */ (bInsert || /* when inserting also check inside the box */ (outside_box_minus_margin2(x_solvt[is1],box) && /* is1 on edge */ outside_box_minus_margin2(x_solvt[is2],box)) /* is2 on edge */ ) && (atoms_solvt->atom[is1].resnr != /* Not the same residue */ atoms_solvt->atom[is2].resnr))) { ntest++; rvec_sub(xi,xj,dx); n2 = norm2(dx); r2 = sqr(r_all[inr]+r_all[jnr]); if (n2 < r2) { /* Need only remove one of the solvents... */ if (is2 >= 0) (void) mark_res(is2,remove,natoms_solvt,atoms_solvt->atom, &nremove); else if (is1 >= 0) (void) mark_res(is1,remove,natoms_solvt,atoms_solvt->atom, &nremove); else fprintf(stderr,"Neither atom is solvent%d %d\n",is1,is2); } } } } fprintf(stderr," tested %d pairs, removed %d atoms.\n",ntest,nremove); } if (debug) for(i=0; i<natoms_solvt; i++) fprintf(debug,"remove[%5d] = %s\n",i,bool_names[remove[i]]); /* Search again, now with another cut-off */ if (rshell > 0) { do_nsgrid(stdout,bVerbose,box,x_all,atoms_all,rshell); nlist = &(fr->nblists[0].nlist_sr[eNL_VDW]); fprintf(stderr,"nri = %d, nrj = %d\n",nlist->nri,nlist->nrj); nkeep = 0; snew(keep,natoms_solvt); for(i=0; i<nlist->nri; i++) { inr = nlist->iinr[i]; j0 = nlist->jindex[i]; j1 = nlist->jindex[i+1]; for(j=j0; j<j1; j++) { jnr = nlist->jjnr[j]; /* Check solvent-protein and solvent-solvent */ is1 = inr-natoms_prot; is2 = jnr-natoms_prot; /* Check if at least one of the atoms is a solvent that is not yet * listed for removal, and if both are solvent, that they are not in the * same residue. */ if (is1>=0 && is2<0) mark_res(is1,keep,natoms_solvt,atoms_solvt->atom,&nkeep); else if (is1<0 && is2>=0) mark_res(is2,keep,natoms_solvt,atoms_solvt->atom,&nkeep); } } fprintf(stderr,"Keeping %d solvent atoms after proximity check\n", nkeep); for (i=0; i<natoms_solvt; i++) remove[i] = remove[i] || !keep[i]; sfree(keep); } /* count how many atoms and residues will be added and make space */ j = 0; jnres = 0; for (i=0; ((i<atoms_solvt->nr) && ((max_sol == 0) || (jnres < max_sol))); i++) { if (!remove[i]) { j++; if ((i == 0) || (atoms_solvt->atom[i].resnr != atoms_solvt->atom[i-1].resnr)) jnres++; } } if (debug) fprintf(debug,"Will add %d atoms in %d residues\n",j,jnres); /* Flag the remaing solvent atoms to be removed */ jjj = atoms_solvt->atom[i-1].resnr; for ( ; (i<atoms_solvt->nr); i++) if (atoms_solvt->atom[i].resnr > jjj) remove[i] = TRUE; else j++; if (bSrenew) { srenew(atoms->resname, atoms->nres+atoms_solvt->nres); srenew(atoms->atomname, atoms->nr+j); srenew(atoms->atom, atoms->nr+j); srenew(*x, atoms->nr+j); if (v) srenew(*v, atoms->nr+j); srenew(*r, atoms->nr+j); } /* add the selected atoms_solvt to atoms */ prev=NOTSET; nresadd=0; for (i=0; i<atoms_solvt->nr; i++) if (!remove[i]) { if (prev==NOTSET || atoms_solvt->atom[i].resnr != atoms_solvt->atom[prev].resnr) { nresadd ++; atoms->nres++; /* calculate shift of the solvent molecule using the first atom */ copy_rvec(x_solvt[i],dx); put_atoms_in_box(box,1,&dx); rvec_dec(dx,x_solvt[i]); } atoms->atom[atoms->nr] = atoms_solvt->atom[i]; atoms->atomname[atoms->nr] = atoms_solvt->atomname[i]; rvec_add(x_solvt[i],dx,(*x)[atoms->nr]); if (v) copy_rvec(v_solvt[i],(*v)[atoms->nr]); (*r)[atoms->nr] = r_solvt[i]; atoms->atom[atoms->nr].resnr = atoms->nres-1; atoms->resname[atoms->nres-1] = atoms_solvt->resname[atoms_solvt->atom[i].resnr]; atoms->nr++; prev=i; } if (bSrenew) srenew(atoms->resname, atoms->nres+nresadd); if (bVerbose) fprintf(stderr,"Added %d molecules\n",nresadd); sfree(remove); done_atom(atoms_all); sfree(x_all); sfree(v_all); }
real call_mopac(t_QMrec *qm, t_MMrec *mm, rvec f[], rvec fshift[]) { /* do the actual QMMM calculation using directly linked mopac subroutines */ double /* always double as the MOPAC routines are always compiled in double precission! */ *qmcrd = NULL, *qmchrg = NULL, *mmcrd = NULL, *mmchrg = NULL, *qmgrad, *mmgrad = NULL, energy; int i, j; real QMener = 0.0; snew(qmcrd, 3*(qm->nrQMatoms)); snew(qmgrad, 3*(qm->nrQMatoms)); /* copy the data from qr into the arrays that are going to be used * in the fortran routines of MOPAC */ for (i = 0; i < qm->nrQMatoms; i++) { for (j = 0; j < DIM; j++) { qmcrd[3*i+j] = (double)qm->xQM[i][j]*10; } } if (mm->nrMMatoms) { /* later we will add the point charges here. There are some * conceptual problems with semi-empirical QM in combination with * point charges that we need to solve first.... */ gmx_fatal(FARGS, "At present only ONIOM is allowed in combination" " with MOPAC QM subroutines\n"); } else { /* now compute the energy and the gradients. */ snew(qmchrg, qm->nrQMatoms); F77_FUNC(domop, DOMOP) (&qm->nrQMatoms, qmcrd, &mm->nrMMatoms, mmchrg, mmcrd, qmgrad, mmgrad, &energy, qmchrg); /* add the gradients to the f[] array, and also to the fshift[]. * the mopac gradients are in kCal/angstrom. */ for (i = 0; i < qm->nrQMatoms; i++) { for (j = 0; j < DIM; j++) { f[i][j] = (real)10*CAL2JOULE*qmgrad[3*i+j]; fshift[i][j] = (real)10*CAL2JOULE*qmgrad[3*i+j]; } } QMener = (real)CAL2JOULE*energy; /* do we do something with the mulliken charges?? */ free(qmchrg); } free(qmgrad); free(qmcrd); return (QMener); }
static void do_ac_core(int nframes,int nout, real corr[],real c1[],int nrestart, unsigned long mode) { int j,k,j3,jk3,m,n; real ccc,cth; rvec xj,xk,rr; if (nrestart < 1) { printf("WARNING: setting number of restarts to 1\n"); nrestart = 1; } if (debug) fprintf(debug, "Starting do_ac_core: nframes=%d, nout=%d, nrestart=%d,mode=%lu\n", nframes,nout,nrestart,mode); for(j=0; (j<nout); j++) corr[j]=0; /* Loop over starting points. */ for(j=0; (j<nframes); j+=nrestart) { j3 = DIM*j; /* Loop over the correlation length for this starting point */ for(k=0; (k<nout) && (j+k < nframes); k++) { jk3 = DIM*(j+k); /* Switch over possible ACF types. * It might be more efficient to put the loops inside the switch, * but this is more clear, and save development time! */ if (MODE(eacNormal)) { corr[k] += c1[j]*c1[j+k]; } else if (MODE(eacCos)) { /* Compute the cos (phi(t)-phi(t+dt)) */ corr[k] += cos(c1[j]-c1[j+k]); } else if (MODE(eacIden)) { /* Check equality (phi(t)==phi(t+dt)) */ corr[k] += (c1[j]==c1[j+k])? 1 : 0; } else if (MODE(eacP1) || MODE(eacP2) || MODE(eacP3)) { for(m=0; (m<DIM); m++) { xj[m] = c1[j3+m]; xk[m] = c1[jk3+m]; } cth=cos_angle(xj,xk); if (cth-1.0 > 1.0e-15) { printf("j: %d, k: %d, xj:(%g,%g,%g), xk:(%g,%g,%g)\n", j,k,xj[XX],xj[YY],xj[ZZ],xk[XX],xk[YY],xk[ZZ]); } corr[k] += LegendreP(cth,mode); /* 1.5*cth*cth-0.5; */ } else if (MODE(eacRcross)) { for(m=0; (m<DIM); m++) { xj[m] = c1[j3+m]; xk[m] = c1[jk3+m]; } cprod(xj,xk,rr); corr[k] += iprod(rr,rr); } else if (MODE(eacVector)) { for(m=0; (m<DIM); m++) { xj[m] = c1[j3+m]; xk[m] = c1[jk3+m]; } ccc = iprod(xj,xk); corr[k] += ccc; } else gmx_fatal(FARGS,"\nInvalid mode (%d) in do_ac_core",mode); } } /* Correct for the number of points and copy results to the data array */ for(j=0; (j<nout); j++) { n = (nframes-j+(nrestart-1))/nrestart; c1[j] = corr[j]/n; } }
static void print_ter_db(char *ff,char C,int nb,t_hackblock tb[],t_atomtype atype) { FILE *out; int i,j,k,bt,nrepl,nadd,ndel; char buf[STRLEN],nname[STRLEN]; sprintf(buf,"%s-%c_new.tdb",ff,C); out = gmx_fio_fopen(buf,"w"); for(i=0; (i<nb); i++) { fprintf(out,"[ %s ]\n",tb[i].name); /* first count: */ nrepl=0; nadd=0; ndel=0; for(j=0; j<tb[i].nhack; j++) if ( tb[i].hack[j].oname!=NULL && tb[i].hack[j].nname!=NULL ) nrepl++; else if ( tb[i].hack[j].oname==NULL && tb[i].hack[j].nname!=NULL ) nadd++; else if ( tb[i].hack[j].oname!=NULL && tb[i].hack[j].nname==NULL ) ndel++; else if ( tb[i].hack[j].oname==NULL && tb[i].hack[j].nname==NULL ) gmx_fatal(FARGS,"invalid hack (%s) in termini database",tb[i].name); if (nrepl) { fprintf(out,"[ %s ]\n",kw_names[ekwRepl-ebtsNR-1]); for(j=0; j<tb[i].nhack; j++) if ( tb[i].hack[j].oname!=NULL && tb[i].hack[j].nname!=NULL ) { fprintf(out,"%s\t",tb[i].hack[j].oname); print_atom(out,tb[i].hack[j].atom,atype,tb[i].hack[j].nname); } } if (nadd) { fprintf(out,"[ %s ]\n",kw_names[ekwAdd-ebtsNR-1]); for(j=0; j<tb[i].nhack; j++) if ( tb[i].hack[j].oname==NULL && tb[i].hack[j].nname!=NULL ) { print_ab(out,&(tb[i].hack[j]),tb[i].hack[j].nname); print_atom(out,tb[i].hack[j].atom,atype,tb[i].hack[j].nname); } } if (ndel) { fprintf(out,"[ %s ]\n",kw_names[ekwDel-ebtsNR-1]); for(j=0; j<tb[i].nhack; j++) if ( tb[i].hack[j].oname!=NULL && tb[i].hack[j].nname==NULL ) fprintf(out,"%s\n",tb[i].hack[j].oname); } for(bt=0; bt<ebtsNR; bt++) if (tb[i].rb[bt].nb) { fprintf(out,"[ %s ]\n", btsNames[bt]); for(j=0; j<tb[i].rb[bt].nb; j++) { for(k=0; k<btsNiatoms[bt]; k++) fprintf(out,"%s%s",k?"\t":"",tb[i].rb[bt].b[j].a[k]); if ( tb[i].rb[bt].b[j].s ) fprintf(out,"\t%s",tb[i].rb[bt].b[j].s); fprintf(out,"\n"); } } fprintf(out,"\n"); } gmx_fio_fclose(out); }
void do_four_core(unsigned long mode,int nfour,int nf2,int nframes, real c1[],real csum[],real ctmp[]) { real *cfour; char buf[32]; real fac; int j,m,m1; snew(cfour,nfour); if (MODE(eacNormal)) { /******************************************** * N O R M A L ********************************************/ low_do_four_core(nfour,nf2,c1,csum,enNorm,FALSE); } else if (MODE(eacCos)) { /*************************************************** * C O S I N E ***************************************************/ /* Copy the data to temp array. Since we need it twice * we can't overwrite original. */ for(j=0; (j<nf2); j++) ctmp[j]=c1[j]; /* Cosine term of AC function */ low_do_four_core(nfour,nf2,ctmp,cfour,enCos,FALSE); for(j=0; (j<nf2); j++) c1[j] = cfour[j]; /* Sine term of AC function */ low_do_four_core(nfour,nf2,ctmp,cfour,enSin,FALSE); for(j=0; (j<nf2); j++) { c1[j] += cfour[j]; csum[j] = c1[j]; } } else if (MODE(eacP2)) { /*************************************************** * Legendre polynomials ***************************************************/ /* First normalize the vectors */ norm_and_scale_vectors(nframes,c1,1.0); /* For P2 thingies we have to do six FFT based correls * First for XX^2, then for YY^2, then for ZZ^2 * Then we have to do XY, YZ and XZ (counting these twice) * After that we sum them and normalise * P2(x) = (3 * cos^2 (x) - 1)/2 * for unit vectors u and v we compute the cosine as the inner product * cos(u,v) = uX vX + uY vY + uZ vZ * * oo * / * C(t) = | (3 cos^2(u(t'),u(t'+t)) - 1)/2 dt' * / * 0 * * For ACF we need: * P2(u(0),u(t)) = [3 * (uX(0) uX(t) + * uY(0) uY(t) + * uZ(0) uZ(t))^2 - 1]/2 * = [3 * ((uX(0) uX(t))^2 + * (uY(0) uY(t))^2 + * (uZ(0) uZ(t))^2 + * 2(uX(0) uY(0) uX(t) uY(t)) + * 2(uX(0) uZ(0) uX(t) uZ(t)) + * 2(uY(0) uZ(0) uY(t) uZ(t))) - 1]/2 * * = [(3/2) * (<uX^2> + <uY^2> + <uZ^2> + * 2<uXuY> + 2<uXuZ> + 2<uYuZ>) - 0.5] * */ /* Because of normalization the number of -0.5 to subtract * depends on the number of data points! */ for(j=0; (j<nf2); j++) csum[j] = -0.5*(nf2-j); /***** DIAGONAL ELEMENTS ************/ for(m=0; (m<DIM); m++) { /* Copy the vector data in a linear array */ for(j=0; (j<nf2); j++) ctmp[j] = sqr(c1[DIM*j+m]); if (debug) { sprintf(buf,"c1diag%d.xvg",m); dump_tmp(buf,nf2,ctmp); } low_do_four_core(nfour,nf2,ctmp,cfour,enNorm,FALSE); if (debug) { sprintf(buf,"c1dfout%d.xvg",m); dump_tmp(buf,nf2,cfour); } fac = 1.5; for(j=0; (j<nf2); j++) csum[j] += fac*(cfour[j]); } /******* OFF-DIAGONAL ELEMENTS **********/ for(m=0; (m<DIM); m++) { /* Copy the vector data in a linear array */ m1=(m+1) % DIM; for(j=0; (j<nf2); j++) ctmp[j]=c1[DIM*j+m]*c1[DIM*j+m1]; if (debug) { sprintf(buf,"c1off%d.xvg",m); dump_tmp(buf,nf2,ctmp); } low_do_four_core(nfour,nf2,ctmp,cfour,enNorm,FALSE); if (debug) { sprintf(buf,"c1ofout%d.xvg",m); dump_tmp(buf,nf2,cfour); } fac = 3.0; for(j=0; (j<nf2); j++) { csum[j] += fac*cfour[j]; } } } else if (MODE(eacP1) || MODE(eacVector)) { /*************************************************** * V E C T O R & P1 ***************************************************/ if (MODE(eacP1)) { /* First normalize the vectors */ norm_and_scale_vectors(nframes,c1,1.0); } /* For vector thingies we have to do three FFT based correls * First for XX, then for YY, then for ZZ * After that we sum them and normalise */ for(j=0; (j<nf2); j++) { csum[j]=0.0; } for(m=0; (m<DIM); m++) { /* Copy the vector data in a linear array */ for(j=0; (j<nf2); j++) ctmp[j]=c1[DIM*j+m]; low_do_four_core(nfour,nf2,ctmp,cfour,enNorm,FALSE); for(j=0; (j<nf2); j++) csum[j] += cfour[j]; } } else gmx_fatal(FARGS,"\nUnknown mode in do_autocorr (%d)",mode); sfree(cfour); for(j=0; (j<nf2); j++) c1[j] = csum[j]/(real)(nframes-j); }
static void edit_files(char **fnms,int nfiles,real *readtime, real *timestep, real *settime, int *cont_type, bool bSetTime,bool bSort) { int i; bool ok; char inputstring[STRLEN],*chptr; if(bSetTime) { fprintf(stderr,"\n\nEnter the new start time (%s) for each file.\n" "There are two special options, both disable sorting:\n\n" "c (continue) - The start time is taken from the end\n" "of the previous file. Use it when your continuation run\n" "restarts with t=0.\n\n" "l (last) - The time in this file will be changed the\n" "same amount as in the previous. Use it when the time in the\n" "new run continues from the end of the previous one,\n" "since this takes possible overlap into account.\n\n", time_unit() ); fprintf(stderr, " File Current start (%s) New start (%s)\n" "---------------------------------------------------------\n", time_unit(), time_unit() ); for(i=0;i<nfiles;i++) { fprintf(stderr,"%25s %10.3f %s ", fnms[i],convert_time(readtime[i]), time_unit()); ok=FALSE; do { if(NULL==fgets(inputstring,STRLEN-1,stdin)) { gmx_fatal(FARGS,"Error reading user input"); } inputstring[strlen(inputstring)-1]=0; if(inputstring[0]=='c' || inputstring[0]=='C') { cont_type[i]=TIME_CONTINUE; bSort=FALSE; ok=TRUE; settime[i]=FLT_MAX; } else if(inputstring[0]=='l' || inputstring[0]=='L') { cont_type[i]=TIME_LAST; bSort=FALSE; ok=TRUE; settime[i]=FLT_MAX; } else { settime[i]=strtod(inputstring,&chptr)*time_invfactor(); if(chptr==inputstring) { fprintf(stderr,"'%s' not recognized as a floating point number, 'c' or 'l'. " "Try again: ",inputstring); } else { cont_type[i]=TIME_EXPLICIT; ok=TRUE; } } } while (!ok); } if(cont_type[0]!=TIME_EXPLICIT) { cont_type[0]=TIME_EXPLICIT; settime[0]=0; } } else for(i=0;i<nfiles;i++) settime[i]=readtime[i]; if(!bSort) fprintf(stderr,"Sorting disabled.\n"); else sort_files(fnms,settime,nfiles); /* Write out the new order and start times */ fprintf(stderr,"\nSummary of files and start times used:\n\n" " File Start time Time step\n" "---------------------------------------------------------\n"); for(i=0;i<nfiles;i++) switch(cont_type[i]) { case TIME_EXPLICIT: fprintf(stderr,"%25s %10.3f %s %10.3f %s", fnms[i], convert_time(settime[i]),time_unit(), convert_time(timestep[i]),time_unit()); if ( i>0 && cont_type[i-1]==TIME_EXPLICIT && settime[i]==settime[i-1] ) fprintf(stderr," WARNING: same Start time as previous"); fprintf(stderr,"\n"); break; case TIME_CONTINUE: fprintf(stderr,"%25s Continue from last file\n",fnms[i]); break; case TIME_LAST: fprintf(stderr,"%25s Change by same amount as last file\n", fnms[i]); break; } fprintf(stderr,"\n"); settime[nfiles]=FLT_MAX; cont_type[nfiles]=TIME_EXPLICIT; readtime[nfiles]=FLT_MAX; }
int gmx_confrms(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] computes the root mean square deviation (RMSD) of two", "structures after least-squares fitting the second structure on the first one.", "The two structures do NOT need to have the same number of atoms,", "only the two index groups used for the fit need to be identical.", "With [TT]-name[tt] only matching atom names from the selected groups", "will be used for the fit and RMSD calculation. This can be useful ", "when comparing mutants of a protein.", "[PAR]", "The superimposed structures are written to file. In a [REF].pdb[ref] file", "the two structures will be written as separate models", "(use [TT]rasmol -nmrpdb[tt]). Also in a [REF].pdb[ref] file, B-factors", "calculated from the atomic MSD values can be written with [TT]-bfac[tt].", }; static gmx_bool bOne = FALSE, bRmpbc = FALSE, bMW = TRUE, bName = FALSE, bBfac = FALSE, bFit = TRUE, bLabel = FALSE; t_pargs pa[] = { { "-one", FALSE, etBOOL, {&bOne}, "Only write the fitted structure to file" }, { "-mw", FALSE, etBOOL, {&bMW}, "Mass-weighted fitting and RMSD" }, { "-pbc", FALSE, etBOOL, {&bRmpbc}, "Try to make molecules whole again" }, { "-fit", FALSE, etBOOL, {&bFit}, "Do least squares superposition of the target structure to the reference" }, { "-name", FALSE, etBOOL, {&bName}, "Only compare matching atom names" }, { "-label", FALSE, etBOOL, {&bLabel}, "Added chain labels A for first and B for second structure"}, { "-bfac", FALSE, etBOOL, {&bBfac}, "Output B-factors from atomic MSD values" } }; t_filenm fnm[] = { { efTPS, "-f1", "conf1.gro", ffREAD }, { efSTX, "-f2", "conf2", ffREAD }, { efSTO, "-o", "fit.pdb", ffWRITE }, { efNDX, "-n1", "fit1", ffOPTRD }, { efNDX, "-n2", "fit2", ffOPTRD }, { efNDX, "-no", "match", ffOPTWR } }; #define NFILE asize(fnm) /* the two structure files */ const char *conf1file, *conf2file, *matchndxfile, *outfile; FILE *fp; char *name1, *name2; t_topology *top1, *top2; int ePBC1, ePBC2; t_atoms *atoms1, *atoms2; int warn = 0; atom_id at; real *w_rls, mass, totmass; rvec *x1, *v1, *x2, *v2, *fit_x; matrix box1, box2; output_env_t oenv; /* counters */ int i, m; /* center of mass calculation */ rvec xcm1, xcm2; /* variables for fit */ char *groupnames1, *groupnames2; int isize1, isize2; atom_id *index1, *index2; real rms, msd, minmsd, maxmsd; real *msds; if (!parse_common_args(&argc, argv, PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv)) { return 0; } matchndxfile = opt2fn_null("-no", NFILE, fnm); conf1file = ftp2fn(efTPS, NFILE, fnm); conf2file = ftp2fn(efSTX, NFILE, fnm); /* reading reference structure from first structure file */ fprintf(stderr, "\nReading first structure file\n"); snew(top1, 1); read_tps_conf(conf1file, top1, &ePBC1, &x1, &v1, box1, TRUE); atoms1 = &(top1->atoms); fprintf(stderr, "%s\nContaining %d atoms in %d residues\n", *top1->name, atoms1->nr, atoms1->nres); if (bRmpbc) { rm_gropbc(atoms1, x1, box1); } fprintf(stderr, "Select group from first structure\n"); get_index(atoms1, opt2fn_null("-n1", NFILE, fnm), 1, &isize1, &index1, &groupnames1); printf("\n"); if (bFit && (isize1 < 3)) { gmx_fatal(FARGS, "Need >= 3 points to fit!\n"); } /* reading second structure file */ fprintf(stderr, "\nReading second structure file\n"); snew(top2, 1); read_tps_conf(conf2file, top2, &ePBC2, &x2, &v2, box2, TRUE); atoms2 = &(top2->atoms); fprintf(stderr, "%s\nContaining %d atoms in %d residues\n", *top2->name, atoms2->nr, atoms2->nres); if (bRmpbc) { rm_gropbc(atoms2, x2, box2); } fprintf(stderr, "Select group from second structure\n"); get_index(atoms2, opt2fn_null("-n2", NFILE, fnm), 1, &isize2, &index2, &groupnames2); if (bName) { find_matching_names(&isize1, index1, atoms1, &isize2, index2, atoms2); if (matchndxfile) { fp = gmx_ffopen(matchndxfile, "w"); fprintf(fp, "; Matching atoms between %s from %s and %s from %s\n", groupnames1, conf1file, groupnames2, conf2file); fprintf(fp, "[ Match_%s_%s ]\n", conf1file, groupnames1); for (i = 0; i < isize1; i++) { fprintf(fp, "%4d%s", index1[i]+1, (i%15 == 14 || i == isize1-1) ? "\n" : " "); } fprintf(fp, "[ Match_%s_%s ]\n", conf2file, groupnames2); for (i = 0; i < isize2; i++) { fprintf(fp, "%4d%s", index2[i]+1, (i%15 == 14 || i == isize2-1) ? "\n" : " "); } } } /* check isizes, must be equal */ if (isize2 != isize1) { gmx_fatal(FARGS, "You selected groups with differen number of atoms.\n"); } for (i = 0; i < isize1; i++) { name1 = *atoms1->atomname[index1[i]]; name2 = *atoms2->atomname[index2[i]]; if (std::strcmp(name1, name2)) { if (warn < 20) { fprintf(stderr, "Warning: atomnames at index %d don't match: %d %s, %d %s\n", i+1, index1[i]+1, name1, index2[i]+1, name2); } warn++; } if (!bMW) { atoms1->atom[index1[i]].m = 1; atoms2->atom[index2[i]].m = 1; } } if (warn) { fprintf(stderr, "%d atomname%s did not match\n", warn, (warn == 1) ? "" : "s"); } if (bFit) { /* calculate and remove center of mass of structures */ calc_rm_cm(isize1, index1, atoms1, x1, xcm1); calc_rm_cm(isize2, index2, atoms2, x2, xcm2); snew(w_rls, atoms2->nr); snew(fit_x, atoms2->nr); for (at = 0; (at < isize1); at++) { w_rls[index2[at]] = atoms1->atom[index1[at]].m; copy_rvec(x1[index1[at]], fit_x[index2[at]]); } /* do the least squares fit to the reference structure */ do_fit(atoms2->nr, w_rls, fit_x, x2); sfree(fit_x); sfree(w_rls); w_rls = NULL; } else { clear_rvec(xcm1); clear_rvec(xcm2); w_rls = NULL; } /* calculate the rms deviation */ rms = 0; totmass = 0; maxmsd = -1e18; minmsd = 1e18; snew(msds, isize1); for (at = 0; at < isize1; at++) { mass = atoms1->atom[index1[at]].m; for (m = 0; m < DIM; m++) { msd = sqr(x1[index1[at]][m] - x2[index2[at]][m]); rms += msd*mass; msds[at] += msd; } maxmsd = std::max(maxmsd, msds[at]); minmsd = std::min(minmsd, msds[at]); totmass += mass; } rms = std::sqrt(rms/totmass); printf("Root mean square deviation after lsq fit = %g nm\n", rms); if (bBfac) { printf("Atomic MSD's range from %g to %g nm^2\n", minmsd, maxmsd); } if (bFit) { /* reset coordinates of reference and fitted structure */ for (i = 0; i < atoms1->nr; i++) { for (m = 0; m < DIM; m++) { x1[i][m] += xcm1[m]; } } for (i = 0; i < atoms2->nr; i++) { for (m = 0; m < DIM; m++) { x2[i][m] += xcm1[m]; } } } outfile = ftp2fn(efSTO, NFILE, fnm); switch (fn2ftp(outfile)) { case efPDB: case efBRK: case efENT: if (bBfac || bLabel) { srenew(atoms1->pdbinfo, atoms1->nr); srenew(atoms1->atom, atoms1->nr); /* Why renew atom? */ /* Avoid segfaults when writing the pdb-file */ for (i = 0; i < atoms1->nr; i++) { atoms1->pdbinfo[i].type = eptAtom; atoms1->pdbinfo[i].occup = 1.00; atoms1->pdbinfo[i].bAnisotropic = FALSE; if (bBfac) { atoms1->pdbinfo[i].bfac = 0; } if (bLabel) { atoms1->resinfo[atoms1->atom[i].resind].chainid = 'A'; } } for (i = 0; i < isize1; i++) { /* atoms1->pdbinfo[index1[i]].type = eptAtom; */ /* atoms1->pdbinfo[index1[i]].bAnisotropic = FALSE; */ if (bBfac) { atoms1->pdbinfo[index1[i]].bfac = (800*M_PI*M_PI/3.0)*msds[i]; } /* if (bLabel) */ /* atoms1->resinfo[atoms1->atom[index1[i]].resind].chain = 'A'; */ } srenew(atoms2->pdbinfo, atoms2->nr); srenew(atoms2->atom, atoms2->nr); /* Why renew atom? */ for (i = 0; i < atoms2->nr; i++) { atoms2->pdbinfo[i].type = eptAtom; atoms2->pdbinfo[i].occup = 1.00; atoms2->pdbinfo[i].bAnisotropic = FALSE; if (bBfac) { atoms2->pdbinfo[i].bfac = 0; } if (bLabel) { atoms2->resinfo[atoms1->atom[i].resind].chainid = 'B'; } } for (i = 0; i < isize2; i++) { /* atoms2->pdbinfo[index2[i]].type = eptAtom; */ /* atoms2->pdbinfo[index2[i]].bAnisotropic = FALSE; */ if (bBfac) { atoms2->pdbinfo[index2[i]].bfac = (800*M_PI*M_PI/3.0)*msds[i]; } /* if (bLabel) */ /* atoms2->resinfo[atoms2->atom[index2[i]].resind].chain = 'B'; */ } } fp = gmx_ffopen(outfile, "w"); if (!bOne) { write_pdbfile(fp, *top1->name, atoms1, x1, ePBC1, box1, ' ', 1, NULL, TRUE); } write_pdbfile(fp, *top2->name, atoms2, x2, ePBC2, box2, ' ', bOne ? -1 : 2, NULL, TRUE); gmx_ffclose(fp); break; case efGRO: if (bBfac) { fprintf(stderr, "WARNING: cannot write B-factor values to gro file\n"); } fp = gmx_ffopen(outfile, "w"); if (!bOne) { write_hconf_p(fp, *top1->name, atoms1, 3, x1, v1, box1); } write_hconf_p(fp, *top2->name, atoms2, 3, x2, v2, box2); gmx_ffclose(fp); break; default: if (bBfac) { fprintf(stderr, "WARNING: cannot write B-factor values to %s file\n", ftp2ext(fn2ftp(outfile))); } if (!bOne) { fprintf(stderr, "WARNING: cannot write the reference structure to %s file\n", ftp2ext(fn2ftp(outfile))); } write_sto_conf(outfile, *top2->name, atoms2, x2, v2, ePBC2, box2); break; } view_all(oenv, NFILE, fnm); return 0; }