static void generate_trial_conf(int atomCount, const rvec xin[], const rvec offset, int enum_rot, gmx_rng_t rng, rvec xout[]) { for (int i = 0; i < atomCount; ++i) { copy_rvec(xin[i], xout[i]); } real alfa = 0.0, beta = 0.0, gamma = 0.0; switch (enum_rot) { case en_rotXYZ: alfa = 2*M_PI * gmx_rng_uniform_real(rng); beta = 2*M_PI * gmx_rng_uniform_real(rng); gamma = 2*M_PI * gmx_rng_uniform_real(rng); break; case en_rotZ: alfa = beta = 0.; gamma = 2*M_PI * gmx_rng_uniform_real(rng); break; case en_rotNone: alfa = beta = gamma = 0.; break; } if (enum_rot == en_rotXYZ || (enum_rot == en_rotZ)) { rotate_conf(atomCount, xout, NULL, alfa, beta, gamma); } for (int i = 0; i < atomCount; ++i) { rvec_inc(xout[i], offset); } }
static char *insert_mols(const char *mol_insrt, int nmol_insrt, int ntry, int seed, t_atoms *atoms, rvec **x, real **r, int ePBC, matrix box, gmx_atomprop_t aps, real r_distance, real rshell, const output_env_t oenv) { t_pbc pbc; static char *title_insrt; t_atoms atoms_insrt; rvec *x_insrt, *x_n; real *r_insrt; int ePBC_insrt; matrix box_insrt; int i, mol, onr; real alfa, beta, gamma; rvec offset_x; int trial; set_pbc(&pbc, ePBC, box); /* read number of atoms of insert molecules */ get_stx_coordnum(mol_insrt, &atoms_insrt.nr); if (atoms_insrt.nr == 0) { gmx_fatal(FARGS, "No molecule in %s, please check your input\n", mol_insrt); } /* allocate memory for atom coordinates of insert molecules */ snew(x_insrt, atoms_insrt.nr); snew(r_insrt, atoms_insrt.nr); snew(atoms_insrt.resinfo, atoms_insrt.nr); snew(atoms_insrt.atomname, atoms_insrt.nr); snew(atoms_insrt.atom, atoms_insrt.nr); atoms_insrt.pdbinfo = NULL; snew(x_n, atoms_insrt.nr); snew(title_insrt, STRLEN); /* read residue number, residue names, atomnames, coordinates etc. */ fprintf(stderr, "Reading molecule configuration \n"); read_stx_conf(mol_insrt, title_insrt, &atoms_insrt, x_insrt, NULL, &ePBC_insrt, box_insrt); fprintf(stderr, "%s\nContaining %d atoms in %d residue\n", title_insrt, atoms_insrt.nr, atoms_insrt.nres); srenew(atoms_insrt.resinfo, atoms_insrt.nres); /* initialise van der waals arrays of insert molecules */ mk_vdw(&atoms_insrt, r_insrt, aps, r_distance); srenew(atoms->resinfo, (atoms->nres+nmol_insrt*atoms_insrt.nres)); srenew(atoms->atomname, (atoms->nr+atoms_insrt.nr*nmol_insrt)); srenew(atoms->atom, (atoms->nr+atoms_insrt.nr*nmol_insrt)); srenew(*x, (atoms->nr+atoms_insrt.nr*nmol_insrt)); srenew(*r, (atoms->nr+atoms_insrt.nr*nmol_insrt)); trial = mol = 0; while ((mol < nmol_insrt) && (trial < ntry*nmol_insrt)) { fprintf(stderr, "\rTry %d", trial++); for (i = 0; (i < atoms_insrt.nr); i++) { copy_rvec(x_insrt[i], x_n[i]); } alfa = 2*M_PI*rando( &seed); beta = 2*M_PI*rando( &seed); gamma = 2*M_PI*rando( &seed); rotate_conf(atoms_insrt.nr, x_n, NULL, alfa, beta, gamma); offset_x[XX] = box[XX][XX]*rando(&seed); offset_x[YY] = box[YY][YY]*rando(&seed); offset_x[ZZ] = box[ZZ][ZZ]*rando(&seed); gen_box(0, atoms_insrt.nr, x_n, box_insrt, offset_x, TRUE); if (!in_box(&pbc, x_n[0]) || !in_box(&pbc, x_n[atoms_insrt.nr-1])) { continue; } onr = atoms->nr; add_conf(atoms, x, NULL, r, FALSE, ePBC, box, TRUE, &atoms_insrt, x_n, NULL, r_insrt, FALSE, rshell, 0, oenv); if (atoms->nr == (atoms_insrt.nr+onr)) { mol++; fprintf(stderr, " success (now %d atoms)!", atoms->nr); } } srenew(atoms->resinfo, atoms->nres); srenew(atoms->atomname, atoms->nr); srenew(atoms->atom, atoms->nr); srenew(*x, atoms->nr); srenew(*r, atoms->nr); fprintf(stderr, "\n"); /* print number of molecules added */ fprintf(stderr, "Added %d molecules (out of %d requested) of %s\n", mol, nmol_insrt, *atoms_insrt.resinfo[0].name); return title_insrt; }
static char *insert_mols(char *mol_insrt,int nmol_insrt,int ntry,int seed, t_atoms *atoms,rvec **x,real **r,int ePBC,matrix box, gmx_atomprop_t aps,real r_distance,real rshell) { t_pbc pbc; static char *title_insrt; t_atoms atoms_insrt; rvec *x_insrt,*x_n; real *r_insrt; int ePBC_insrt; matrix box_insrt; int i,mol,onr; real alfa,beta,gamma; rvec offset_x; int try; set_pbc(&pbc,ePBC,box); /* read number of atoms of insert molecules */ get_stx_coordnum(mol_insrt,&atoms_insrt.nr); if (atoms_insrt.nr == 0) gmx_fatal(FARGS,"No molecule in %s, please check your input\n",mol_insrt); /* allocate memory for atom coordinates of insert molecules */ snew(x_insrt,atoms_insrt.nr); snew(r_insrt,atoms_insrt.nr); snew(atoms_insrt.resname,atoms_insrt.nr); snew(atoms_insrt.atomname,atoms_insrt.nr); snew(atoms_insrt.atom,atoms_insrt.nr); atoms_insrt.pdbinfo = NULL; snew(x_n,atoms_insrt.nr); snew(title_insrt,STRLEN); /* read residue number, residue names, atomnames, coordinates etc. */ fprintf(stderr,"Reading molecule configuration \n"); read_stx_conf(mol_insrt,title_insrt,&atoms_insrt,x_insrt,NULL, &ePBC_insrt,box_insrt); fprintf(stderr,"%s\nContaining %d atoms in %d residue\n", title_insrt,atoms_insrt.nr,atoms_insrt.nres); srenew(atoms_insrt.resname,atoms_insrt.nres); /* initialise van der waals arrays of insert molecules */ mk_vdw(&atoms_insrt,r_insrt,aps,r_distance); srenew(atoms->resname,(atoms->nres+nmol_insrt)); srenew(atoms->atomname,(atoms->nr+atoms_insrt.nr*nmol_insrt)); srenew(atoms->atom,(atoms->nr+atoms_insrt.nr*nmol_insrt)); srenew(*x,(atoms->nr+atoms_insrt.nr*nmol_insrt)); srenew(*r,(atoms->nr+atoms_insrt.nr*nmol_insrt)); try=mol=0; while ((mol < nmol_insrt) && (try < ntry*nmol_insrt)) { fprintf(stderr,"\rTry %d",try++); for (i=0;(i<atoms_insrt.nr);i++) { if (atoms_insrt.atom[i].resnr!=0) gmx_fatal(FARGS,"more then one residue in insert molecules\n" "program terminated\n"); copy_rvec(x_insrt[i],x_n[i]); } alfa=2*M_PI*rando(&seed); beta=2*M_PI*rando(&seed); gamma=2*M_PI*rando(&seed); rotate_conf(atoms_insrt.nr,x_n,NULL,alfa,beta,gamma); offset_x[XX]=box[XX][XX]*rando(&seed); offset_x[YY]=box[YY][YY]*rando(&seed); offset_x[ZZ]=box[ZZ][ZZ]*rando(&seed); gen_box(0,atoms_insrt.nr,x_n,box_insrt,offset_x,TRUE); if (!in_box(&pbc,x_n[0]) || !in_box(&pbc,x_n[atoms_insrt.nr-1])) continue; onr=atoms->nr; add_conf(atoms,x,NULL,r,FALSE,ePBC,box,TRUE, &atoms_insrt,x_n,NULL,r_insrt,FALSE,rshell,0); if (atoms->nr==(atoms_insrt.nr+onr)) { mol++; fprintf(stderr," success (now %d atoms)!",atoms->nr); } } srenew(atoms->resname, atoms->nres); srenew(atoms->atomname, atoms->nr); srenew(atoms->atom, atoms->nr); srenew(*x, atoms->nr); srenew(*r, atoms->nr); fprintf(stderr,"\n"); /* print number of molecules added */ fprintf(stderr,"Added %d molecules (out of %d requested) of %s\n", mol,nmol_insrt,*atoms_insrt.resname[0]); return title_insrt; } static void add_solv(char *fn,t_atoms *atoms,rvec **x,rvec **v,real **r, int ePBC,matrix box, gmx_atomprop_t aps,real r_distance,int *atoms_added, int *residues_added,real rshell,int max_sol) { int i,nmol; ivec n_box; char filename[STRLEN]; char title_solvt[STRLEN]; t_atoms *atoms_solvt; rvec *x_solvt,*v_solvt=NULL; real *r_solvt; int ePBC_solvt; matrix box_solvt; int onr,onres; strncpy(filename,libfn(fn),STRLEN); snew(atoms_solvt,1); get_stx_coordnum(filename,&(atoms_solvt->nr)); if (atoms_solvt->nr == 0) gmx_fatal(FARGS,"No solvent in %s, please check your input\n",filename); snew(x_solvt,atoms_solvt->nr); if (v) snew(v_solvt,atoms_solvt->nr); snew(r_solvt,atoms_solvt->nr); snew(atoms_solvt->resname,atoms_solvt->nr); snew(atoms_solvt->atomname,atoms_solvt->nr); snew(atoms_solvt->atom,atoms_solvt->nr); atoms_solvt->pdbinfo = NULL; fprintf(stderr,"Reading solvent configuration%s\n", v_solvt?" and velocities":""); read_stx_conf(filename,title_solvt,atoms_solvt,x_solvt,v_solvt, &ePBC_solvt,box_solvt); fprintf(stderr,"\"%s\"\n",title_solvt); fprintf(stderr,"solvent configuration contains %d atoms in %d residues\n", atoms_solvt->nr,atoms_solvt->nres); fprintf(stderr,"\n"); /* apply pbc for solvent configuration for whole molecules */ rm_res_pbc(atoms_solvt,x_solvt,box_solvt); /* initialise van der waals arrays of solvent configuration */ mk_vdw(atoms_solvt,r_solvt,aps,r_distance); /* calculate the box multiplication factors n_box[0...DIM] */ nmol=1; for (i=0; (i < DIM);i++) { n_box[i] = 1; while (n_box[i]*box_solvt[i][i] < box[i][i]) n_box[i]++; nmol*=n_box[i]; } fprintf(stderr,"Will generate new solvent configuration of %dx%dx%d boxes\n", n_box[XX],n_box[YY],n_box[ZZ]); /* realloc atoms_solvt for the new solvent configuration */ srenew(atoms_solvt->resname,atoms_solvt->nres*nmol); srenew(atoms_solvt->atomname,atoms_solvt->nr*nmol); srenew(atoms_solvt->atom,atoms_solvt->nr*nmol); srenew(x_solvt,atoms_solvt->nr*nmol); if (v_solvt) srenew(v_solvt,atoms_solvt->nr*nmol); srenew(r_solvt,atoms_solvt->nr*nmol); /* generate a new solvent configuration */ genconf(atoms_solvt,x_solvt,v_solvt,r_solvt,box_solvt,n_box); #ifdef DEBUG print_stat(x_solvt,atoms_solvt->nr,box_solvt); #endif #ifdef DEBUG print_stat(x_solvt,atoms_solvt->nr,box_solvt); #endif /* Sort the solvent mixture, not the protein... */ sort_molecule(&atoms_solvt,x_solvt,v_solvt,r_solvt); /* add the two configurations */ onr=atoms->nr; onres=atoms->nres; add_conf(atoms,x,v,r,TRUE,ePBC,box,FALSE, atoms_solvt,x_solvt,v_solvt,r_solvt,TRUE,rshell,max_sol); *atoms_added=atoms->nr-onr; *residues_added=atoms->nres-onres; sfree(x_solvt); sfree(r_solvt); fprintf(stderr,"Generated solvent containing %d atoms in %d residues\n", *atoms_added,*residues_added); }
void orient(int natom,rvec *x,rvec *v, rvec angle,matrix box) { real longest,rij,rzi; int i,j,m,max_i=0,max_j=0; rvec origin; int temp; real alfa=0,beta=0,gamma=0; t_pbc pbc; set_pbc(&pbc,-1,box); /*first i am going to look for the longest atom-atom distance*/ longest=dist2(&pbc,x[0],x[1]); i=0; j=1; for (i=0;(i<natom);i++) { for (j=0;(j<natom);j++) { rij=dist2(&pbc,x[i],x[j]); if (rij>longest) { max_i=i; max_j=j; longest=rij; } } } /* first check if x[max_i]<x[max_j] else swap*/ if (x[max_i][2]>x[max_j][2]) { temp=max_i; max_i=max_j; max_j=temp; } /*set the origin to x[i]*/ for(m=0;(m<DIM);m++) origin[m]=x[max_i][m]; for(i=0;(i<natom);i++) for(m=0;(m<DIM);m++) x[i][m]-=origin[m]; /* calculate the rotation angles alfa(x_axis) and beta(y_axis) * the rotation angles must be calculated clockwise looking * along the rotation axis to the origin* * alfa (x-axis) */ alfa=atan(x[max_j][ZZ]/x[max_j][YY])-M_PI_2; beta=M_PI_2-atan(x[max_j][ZZ]/x[max_j][XX]); rotate_conf(natom,x,v,alfa,beta,gamma); /* now search the longest distance for rotation along the z_axis */ longest=distance_to_z(x[0]); max_i=0; for (i=1;(i<natom);i++) { rzi=distance_to_z(x[i]); if (rzi>longest) { longest = rzi; max_i=i; } } gamma=atan(x[max_i][YY]/x[max_i][XX])-M_PI_2; rotate_conf(natom,x,v,0,0,gamma); angle[0]=alfa; angle[1]=beta; angle[2]=gamma; } /*orient()*/
int main(int argc,char *argv[]) { const char *desc[] = { "[TT]do_multiprot[tt] ", "reads a trajectory file and aligns it to a reference structure ", "each time frame", "calling the multiprot program. This allows you to use a reference", "structure whose sequence is different than that of the protein in the ", "trajectory, since the alignment is based on the geometry, not sequence.", "The output of [TT]do_multiprot[tt] includes the rmsd and the number of residues", "on which it was calculated.", "[PAR]", "An aligned trajectory file is generated with the [TT]-ox[tt] option.[PAR]", "With the [TT]-cr[tt] option, the number of hits in the alignment is given", "per residue. This number can be between 0 and the number of frames, and", "indicates the structural conservation of this residue.[PAR]", "If you do not have the [TT]multiprot[tt] program, get it. [TT]do_multiprot[tt] assumes", "that the [TT]multiprot[tt] executable is [TT]/usr/local/bin/multiprot[tt]. If this is ", "not the case, then you should set an environment variable [BB]MULTIPROT[bb]", "pointing to the [TT]multiprot[tt] executable, e.g.: [PAR]", "[TT]setenv MULTIPROT /usr/MultiProtInstall/multiprot.Linux[tt][PAR]", "Note that at the current implementation only binary alignment (your", "molecule to a reference) is supported. In addition, note that the ", "by default [TT]multiprot[tt] aligns the two proteins on their C-alpha carbons.", "and that this depends on the [TT]multiprot[tt] parameters which are not dealt ", "with here. Thus, the C-alpha carbons is expected to give the same " "results as choosing the whole protein and will be slightly faster.[PAR]", "For information about [TT]multiprot[tt], see:", "http://bioinfo3d.cs.tau.ac.il/MultiProt/.[PAR]" }; static bool bVerbose; t_pargs pa[] = { { "-v", FALSE, etBOOL, {&bVerbose}, "HIDDENGenerate miles of useless information" } }; const char *bugs[] = { "The program is very slow, since multiprot is run externally" }; t_trxstatus *status; t_trxstatus *trxout=NULL; FILE *tapein,*fo,*frc,*tmpf,*out=NULL,*fres=NULL; const char *fnRef; const char *fn="2_sol.res"; t_topology top; int ePBC; t_atoms *atoms,ratoms,useatoms; t_trxframe fr; t_pdbinfo p; int nres,nres2,nr0; real t; int i,j,natoms,nratoms,nframe=0,model_nr=-1; int cur_res,prev_res; int nout; t_countres *countres=NULL; matrix box,rbox; int gnx; char *grpnm,*ss_str; atom_id *index; rvec *xp,*x,*xr; char pdbfile[32],refpdb[256],title[256],rtitle[256],filemode[5]; char out_title[256]; char multiprot[256],*mptr; int ftp; int outftp=-1; real rmsd; bool bTrjout,bCountres; const char *TrjoutFile=NULL; output_env_t oenv; static rvec translation={0,0,0},rotangles={0,0,0}; gmx_rmpbc_t gpbc=NULL; t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efTPS, NULL, NULL, ffREAD }, { efNDX, NULL, NULL, ffOPTRD }, { efSTX, "-r", NULL , ffREAD }, { efXVG, "-o", "rmss", ffWRITE }, { efXVG, "-rc", "rescount", ffWRITE}, { efXVG, "-cr", "countres", ffOPTWR}, { efTRX, "-ox", "aligned", ffOPTWR } }; #define NFILE asize(fnm) CopyRight(stderr,argv[0]); parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_CAN_VIEW | PCA_TIME_UNIT, NFILE,fnm, asize(pa),pa, asize(desc),desc, asize(bugs),bugs,&oenv ); fnRef=opt2fn("-r",NFILE,fnm); bTrjout = opt2bSet("-ox",NFILE,fnm); bCountres= opt2bSet("-cr",NFILE,fnm); if (bTrjout) { TrjoutFile = opt2fn_null("-ox",NFILE,fnm); } read_tps_conf(ftp2fn(efTPS,NFILE,fnm),title,&top,&ePBC,&xp,NULL,box,FALSE); gpbc = gmx_rmpbc_init(&top.idef,ePBC,top.atoms.nr,box); atoms=&(top.atoms); ftp=fn2ftp(fnRef); get_stx_coordnum(fnRef,&nratoms); init_t_atoms(&ratoms,nratoms,TRUE); snew(xr,nratoms); read_stx_conf(fnRef,rtitle,&ratoms,xr,NULL,&ePBC,rbox); if (bVerbose) { fprintf(stderr,"Read %d atoms\n",atoms->nr); fprintf(stderr,"Read %d reference atoms\n",ratoms.nr); } if (bCountres) { snew(countres,ratoms.nres); j=0; cur_res=0; for (i=0;i<ratoms.nr;i++) { prev_res=cur_res; cur_res=ratoms.atom[i].resind; if (cur_res != prev_res) { countres[j].resnr=cur_res; countres[j].count=0; j++; } } } get_index(atoms,ftp2fn_null(efNDX,NFILE,fnm),1,&gnx,&index,&grpnm); nres=0; nr0=-1; for(i=0; (i<gnx); i++) { if (atoms->atom[index[i]].resind != nr0) { nr0=atoms->atom[index[i]].resind; nres++; } } fprintf(stderr,"There are %d residues in your selected group\n",nres); strcpy(pdbfile,"ddXXXXXX"); gmx_tmpnam(pdbfile); if ((tmpf = fopen(pdbfile,"w")) == NULL) { sprintf(pdbfile,"%ctmp%cfilterXXXXXX",DIR_SEPARATOR,DIR_SEPARATOR); gmx_tmpnam(pdbfile); if ((tmpf = fopen(pdbfile,"w")) == NULL) { gmx_fatal(FARGS,"Can not open tmp file %s",pdbfile); } } else { gmx_ffclose(tmpf); } if (ftp != efPDB) { strcpy(refpdb,"ddXXXXXX"); gmx_tmpnam(refpdb); strcat(refpdb,".pdb"); write_sto_conf(refpdb,rtitle,&ratoms,xr,NULL,ePBC,rbox); } else { strcpy(refpdb,fnRef); } if ((mptr=getenv("MULTIPROT")) == NULL) { mptr="/usr/local/bin/multiprot"; } if (!gmx_fexist(mptr)) { gmx_fatal(FARGS,"MULTIPROT executable (%s) does not exist (use setenv MULTIPROT)", mptr); } sprintf (multiprot,"%s %s %s > /dev/null %s", mptr, refpdb, pdbfile, "2> /dev/null"); if (bVerbose) fprintf(stderr,"multiprot cmd='%s'\n",multiprot); if (!read_first_frame(oenv,&status,ftp2fn(efTRX,NFILE,fnm),&fr,TRX_READ_X)) gmx_fatal(FARGS,"Could not read a frame from %s",ftp2fn(efTRX,NFILE,fnm)); natoms = fr.natoms; if (bTrjout) { nout=natoms; /* open file now */ outftp=fn2ftp(TrjoutFile); if (bVerbose) fprintf(stderr,"Will write %s: %s\n",ftp2ext(ftp),ftp2desc(outftp)); strcpy(filemode,"w"); switch (outftp) { case efXTC: case efG87: case efTRR: case efTRJ: out=NULL; trxout = open_trx(TrjoutFile,filemode); break; case efGRO: case efG96: case efPDB: /* Make atoms struct for output in GRO or PDB files */ /* get memory for stuff to go in pdb file */ init_t_atoms(&useatoms,nout,FALSE); sfree(useatoms.resinfo); useatoms.resinfo=atoms->resinfo; for(i=0;(i<nout);i++) { useatoms.atomname[i]=atoms->atomname[i]; useatoms.atom[i]=atoms->atom[i]; useatoms.nres=max(useatoms.nres,useatoms.atom[i].resind+1); } useatoms.nr=nout; out=gmx_ffopen(TrjoutFile,filemode); break; } } if (natoms > atoms->nr) { gmx_fatal(FARGS,"\nTrajectory does not match topology!"); } if (gnx > natoms) { gmx_fatal(FARGS,"\nTrajectory does not match selected group!"); } fo = xvgropen(opt2fn("-o",NFILE,fnm),"RMSD","Time (ps)","RMSD (nm)",oenv); frc = xvgropen(opt2fn("-rc",NFILE,fnm),"Number of Residues in the alignment","Time (ps)","Residues",oenv); do { t = output_env_conv_time(oenv,fr.time); gmx_rmpbc(gpbc,natoms,fr.box,fr.x); tapein=gmx_ffopen(pdbfile,"w"); write_pdbfile_indexed(tapein,NULL,atoms,fr.x,ePBC,fr.box,' ',-1,gnx,index,NULL,TRUE); gmx_ffclose(tapein); system(multiprot); remove(pdbfile); process_multiprot_output(fn, &rmsd, &nres2,rotangles,translation,bCountres,countres); fprintf(fo,"%12.7f",t); fprintf(fo," %12.7f\n",rmsd); fprintf(frc,"%12.7f",t); fprintf(frc,"%12d\n",nres2); if (bTrjout) { rotate_conf(natoms,fr.x,NULL,rotangles[XX],rotangles[YY],rotangles[ZZ]); for(i=0; i<natoms; i++) { rvec_inc(fr.x[i],translation); } switch(outftp) { case efTRJ: case efTRR: case efG87: case efXTC: write_trxframe(trxout,&fr,NULL); break; case efGRO: case efG96: case efPDB: sprintf(out_title,"Generated by do_multiprot : %s t= %g %s", title,output_env_conv_time(oenv,fr.time),output_env_get_time_unit(oenv)); switch(outftp) { case efGRO: write_hconf_p(out,out_title,&useatoms,prec2ndec(fr.prec), fr.x,NULL,fr.box); break; case efPDB: fprintf(out,"REMARK GENERATED BY DO_MULTIPROT\n"); sprintf(out_title,"%s t= %g %s",title,output_env_conv_time(oenv,fr.time),output_env_get_time_unit(oenv)); /* if reading from pdb, we want to keep the original model numbering else we write the output frame number plus one, because model 0 is not allowed in pdb */ if (ftp==efPDB && fr.step > model_nr) { model_nr = fr.step; } else { model_nr++; } write_pdbfile(out,out_title,&useatoms,fr.x,ePBC,fr.box,' ',model_nr,NULL,TRUE); break; case efG96: fr.title = out_title; fr.bTitle = (nframe == 0); fr.bAtoms = FALSE; fr.bStep = TRUE; fr.bTime = TRUE; write_g96_conf(out,&fr,-1,NULL); } break; } } nframe++; } while(read_next_frame(oenv,status,&fr)); if (bCountres) { fres= xvgropen(opt2fn("-cr",NFILE,fnm),"Number of frames in which the residues are aligned to","Residue","Number",oenv); for (i=0;i<ratoms.nres;i++) { fprintf(fres,"%10d %12d\n",countres[i].resnr,countres[i].count); } gmx_ffclose(fres); } gmx_ffclose(fo); gmx_ffclose(frc); fprintf(stderr,"\n"); close_trj(status); if (trxout != NULL) { close_trx(trxout); } else if (out != NULL) { gmx_ffclose(out); } view_all(oenv,NFILE, fnm); sfree(xr); if (bCountres) { sfree(countres); } free_t_atoms(&ratoms,TRUE); if (bTrjout) { if (outftp==efPDB || outftp==efGRO || outftp==efG96) { free_t_atoms(&useatoms,TRUE); } } gmx_thanx(stderr); return 0; }
int gmx_editconf(int argc, char *argv[]) { const char *desc[] = { "editconf converts generic structure format to [TT].gro[tt], [TT].g96[tt]", "or [TT].pdb[tt].", "[PAR]", "The box can be modified with options [TT]-box[tt], [TT]-d[tt] and", "[TT]-angles[tt]. Both [TT]-box[tt] and [TT]-d[tt]", "will center the system in the box, unless [TT]-noc[tt] is used.", "[PAR]", "Option [TT]-bt[tt] determines the box type: [TT]triclinic[tt] is a", "triclinic box, [TT]cubic[tt] is a rectangular box with all sides equal", "[TT]dodecahedron[tt] represents a rhombic dodecahedron and", "[TT]octahedron[tt] is a truncated octahedron.", "The last two are special cases of a triclinic box.", "The length of the three box vectors of the truncated octahedron is the", "shortest distance between two opposite hexagons.", "The volume of a dodecahedron is 0.71 and that of a truncated octahedron", "is 0.77 of that of a cubic box with the same periodic image distance.", "[PAR]", "Option [TT]-box[tt] requires only", "one value for a cubic box, dodecahedron and a truncated octahedron.", "[PAR]", "With [TT]-d[tt] and a [TT]triclinic[tt] box the size of the system in the x, y", "and z directions is used. With [TT]-d[tt] and [TT]cubic[tt],", "[TT]dodecahedron[tt] or [TT]octahedron[tt] boxes, the dimensions are set", "to the diameter of the system (largest distance between atoms) plus twice", "the specified distance.", "[PAR]", "Option [TT]-angles[tt] is only meaningful with option [TT]-box[tt] and", "a triclinic box and can not be used with option [TT]-d[tt].", "[PAR]", "When [TT]-n[tt] or [TT]-ndef[tt] is set, a group", "can be selected for calculating the size and the geometric center,", "otherwise the whole system is used.", "[PAR]", "[TT]-rotate[tt] rotates the coordinates and velocities.", "[PAR]", "[TT]-princ[tt] aligns the principal axes of the system along the", "coordinate axes, this may allow you to decrease the box volume,", "but beware that molecules can rotate significantly in a nanosecond.", "[PAR]", "Scaling is applied before any of the other operations are", "performed. Boxes and coordinates can be scaled to give a certain density (option", "[TT]-density[tt]). Note that this may be inaccurate in case a gro", "file is given as input. A special feature of the scaling option, when the", "factor -1 is given in one dimension, one obtains a mirror image,", "mirrored in one of the plains, when one uses -1 in three dimensions", "a point-mirror image is obtained.[PAR]", "Groups are selected after all operations have been applied.[PAR]", "Periodicity can be removed in a crude manner.", "It is important that the box sizes at the bottom of your input file", "are correct when the periodicity is to be removed.", "[PAR]", "When writing [TT].pdb[tt] files, B-factors can be", "added with the [TT]-bf[tt] option. B-factors are read", "from a file with with following format: first line states number of", "entries in the file, next lines state an index", "followed by a B-factor. The B-factors will be attached per residue", "unless an index is larger than the number of residues or unless the", "[TT]-atom[tt] option is set. Obviously, any type of numeric data can", "be added instead of B-factors. [TT]-legend[tt] will produce", "a row of CA atoms with B-factors ranging from the minimum to the", "maximum value found, effectively making a legend for viewing.", "[PAR]", "With the option -mead a special pdb (pqr) file for the MEAD electrostatics", "program (Poisson-Boltzmann solver) can be made. A further prerequisite", "is that the input file is a run input file.", "The B-factor field is then filled with the Van der Waals radius", "of the atoms while the occupancy field will hold the charge.", "[PAR]", "The option -grasp is similar, but it puts the charges in the B-factor", "and the radius in the occupancy.", "[PAR]", "Option [TT]-align[tt] allows alignment", "of the principal axis of a specified group against the given vector, ", "with an optional center of rotation specified by [TT]-aligncenter[tt].", "[PAR]", "Finally with option [TT]-label[tt] editconf can add a chain identifier", "to a pdb file, which can be useful for analysis with e.g. rasmol.", "[PAR]", "To convert a truncated octrahedron file produced by a package which uses", "a cubic box with the corners cut off (such as Gromos) use:[BR]", "[TT]editconf -f <in> -rotate 0 45 35.264 -bt o -box <veclen> -o <out>[tt][BR]", "where [TT]veclen[tt] is the size of the cubic box times sqrt(3)/2." }; const char *bugs[] = { "For complex molecules, the periodicity removal routine may break down, ", "in that case you can use trjconv." }; static real dist = 0.0, rbox = 0.0, to_diam = 0.0; static gmx_bool bNDEF = FALSE, bRMPBC = FALSE, bCenter = FALSE, bReadVDW = FALSE, bCONECT = FALSE; static gmx_bool peratom = FALSE, bLegend = FALSE, bOrient = FALSE, bMead = FALSE, bGrasp = FALSE, bSig56 = FALSE; static rvec scale = { 1, 1, 1 }, newbox = { 0, 0, 0 }, newang = { 90, 90, 90 }; static real rho = 1000.0, rvdw = 0.12; static rvec center = { 0, 0, 0 }, translation = { 0, 0, 0 }, rotangles = { 0, 0, 0 }, aligncenter = { 0, 0, 0 }, targetvec = { 0, 0, 0 }; static const char *btype[] = { NULL, "triclinic", "cubic", "dodecahedron", "octahedron", NULL }, *label = "A"; static rvec visbox = { 0, 0, 0 }; t_pargs pa[] = { { "-ndef", FALSE, etBOOL, { &bNDEF }, "Choose output from default index groups" }, { "-visbox", FALSE, etRVEC, { visbox }, "HIDDENVisualize a grid of boxes, -1 visualizes the 14 box images" }, { "-bt", FALSE, etENUM, { btype }, "Box type for -box and -d" }, { "-box", FALSE, etRVEC, { newbox }, "Box vector lengths (a,b,c)" }, { "-angles", FALSE, etRVEC, { newang }, "Angles between the box vectors (bc,ac,ab)" }, { "-d", FALSE, etREAL, { &dist }, "Distance between the solute and the box" }, { "-c", FALSE, etBOOL, { &bCenter }, "Center molecule in box (implied by -box and -d)" }, { "-center", FALSE, etRVEC, { center }, "Coordinates of geometrical center" }, { "-aligncenter", FALSE, etRVEC, { aligncenter }, "Center of rotation for alignment" }, { "-align", FALSE, etRVEC, { targetvec }, "Align to target vector" }, { "-translate", FALSE, etRVEC, { translation }, "Translation" }, { "-rotate", FALSE, etRVEC, { rotangles }, "Rotation around the X, Y and Z axes in degrees" }, { "-princ", FALSE, etBOOL, { &bOrient }, "Orient molecule(s) along their principal axes" }, { "-scale", FALSE, etRVEC, { scale }, "Scaling factor" }, { "-density", FALSE, etREAL, { &rho }, "Density (g/l) of the output box achieved by scaling" }, { "-pbc", FALSE, etBOOL, { &bRMPBC }, "Remove the periodicity (make molecule whole again)" }, { "-grasp", FALSE, etBOOL, { &bGrasp }, "Store the charge of the atom in the B-factor field and the radius of the atom in the occupancy field" }, { "-rvdw", FALSE, etREAL, { &rvdw }, "Default Van der Waals radius (in nm) if one can not be found in the database or if no parameters are present in the topology file" }, { "-sig56", FALSE, etREAL, { &bSig56 }, "Use rmin/2 (minimum in the Van der Waals potential) rather than sigma/2 " }, { "-vdwread", FALSE, etBOOL, { &bReadVDW }, "Read the Van der Waals radii from the file vdwradii.dat rather than computing the radii based on the force field" }, { "-atom", FALSE, etBOOL, { &peratom }, "Force B-factor attachment per atom" }, { "-legend", FALSE, etBOOL, { &bLegend }, "Make B-factor legend" }, { "-label", FALSE, etSTR, { &label }, "Add chain label for all residues" }, { "-conect", FALSE, etBOOL, { &bCONECT }, "Add CONECT records to a pdb file when written. Can only be done when a topology is present" } }; #define NPA asize(pa) FILE *out; const char *infile, *outfile; char title[STRLEN]; int outftp, inftp, natom, i, j, n_bfac, itype, ntype; double *bfac = NULL, c6, c12; int *bfac_nr = NULL; t_topology *top = NULL; t_atoms atoms; char *grpname, *sgrpname, *agrpname; int isize, ssize, tsize, asize; atom_id *index, *sindex, *tindex, *aindex; rvec *x, *v, gc, min, max, size; int ePBC; matrix box,rotmatrix,trans; rvec princd,tmpvec; gmx_bool bIndex, bSetSize, bSetAng, bCubic, bDist, bSetCenter, bAlign; gmx_bool bHaveV, bScale, bRho, bTranslate, bRotate, bCalcGeom, bCalcDiam; real xs, ys, zs, xcent, ycent, zcent, diam = 0, mass = 0, d, vdw; gmx_atomprop_t aps; gmx_conect conect; output_env_t oenv; t_filenm fnm[] = { { efSTX, "-f", NULL, ffREAD }, { efNDX, "-n", NULL, ffOPTRD }, { efSTO, NULL, NULL, ffOPTWR }, { efPQR, "-mead", "mead", ffOPTWR }, { efDAT, "-bf", "bfact", ffOPTRD } }; #define NFILE asize(fnm) CopyRight(stderr, argv[0]); parse_common_args(&argc, argv, PCA_CAN_VIEW, NFILE, fnm, NPA, pa, asize(desc), desc, asize(bugs), bugs, &oenv); bIndex = opt2bSet("-n", NFILE, fnm) || bNDEF; bMead = opt2bSet("-mead", NFILE, fnm); bSetSize = opt2parg_bSet("-box", NPA, pa); bSetAng = opt2parg_bSet("-angles", NPA, pa); bSetCenter = opt2parg_bSet("-center", NPA, pa); bDist = opt2parg_bSet("-d", NPA, pa); bAlign = opt2parg_bSet("-align", NPA, pa); /* Only automatically turn on centering without -noc */ if ((bDist || bSetSize || bSetCenter) && !opt2parg_bSet("-c", NPA, pa)) { bCenter = TRUE; } bScale = opt2parg_bSet("-scale", NPA, pa); bRho = opt2parg_bSet("-density", NPA, pa); bTranslate = opt2parg_bSet("-translate", NPA, pa); bRotate = opt2parg_bSet("-rotate", NPA, pa); if (bScale && bRho) fprintf(stderr, "WARNING: setting -density overrides -scale\n"); bScale = bScale || bRho; bCalcGeom = bCenter || bRotate || bOrient || bScale; bCalcDiam = btype[0][0] == 'c' || btype[0][0] == 'd' || btype[0][0] == 'o'; infile = ftp2fn(efSTX, NFILE, fnm); if (bMead) outfile = ftp2fn(efPQR, NFILE, fnm); else outfile = ftp2fn(efSTO, NFILE, fnm); outftp = fn2ftp(outfile); inftp = fn2ftp(infile); aps = gmx_atomprop_init(); if (bMead && bGrasp) { printf("Incompatible options -mead and -grasp. Turning off -grasp\n"); bGrasp = FALSE; } if (bGrasp && (outftp != efPDB)) gmx_fatal(FARGS, "Output file should be a .pdb file" " when using the -grasp option\n"); if ((bMead || bGrasp) && !((fn2ftp(infile) == efTPR) || (fn2ftp(infile) == efTPA) || (fn2ftp(infile) == efTPB))) gmx_fatal(FARGS,"Input file should be a .tp[abr] file" " when using the -mead option\n"); get_stx_coordnum(infile,&natom); init_t_atoms(&atoms,natom,TRUE); snew(x,natom); snew(v,natom); read_stx_conf(infile,title,&atoms,x,v,&ePBC,box); if (fn2ftp(infile) == efPDB) { get_pdb_atomnumber(&atoms,aps); } printf("Read %d atoms\n",atoms.nr); /* Get the element numbers if available in a pdb file */ if (fn2ftp(infile) == efPDB) get_pdb_atomnumber(&atoms,aps); if (ePBC != epbcNONE) { real vol = det(box); printf("Volume: %g nm^3, corresponds to roughly %d electrons\n", vol,100*((int)(vol*4.5))); } if (bMead || bGrasp || bCONECT) top = read_top(infile,NULL); if (bMead || bGrasp) { if (atoms.nr != top->atoms.nr) gmx_fatal(FARGS,"Atom numbers don't match (%d vs. %d)",atoms.nr,top->atoms.nr); snew(atoms.pdbinfo,top->atoms.nr); ntype = top->idef.atnr; for(i=0; (i<atoms.nr); i++) { /* Determine the Van der Waals radius from the force field */ if (bReadVDW) { if (!gmx_atomprop_query(aps,epropVDW, *top->atoms.resinfo[top->atoms.atom[i].resind].name, *top->atoms.atomname[i],&vdw)) vdw = rvdw; } else { itype = top->atoms.atom[i].type; c12 = top->idef.iparams[itype*ntype+itype].lj.c12; c6 = top->idef.iparams[itype*ntype+itype].lj.c6; if ((c6 != 0) && (c12 != 0)) { real sig6; if (bSig56) sig6 = 2*c12/c6; else sig6 = c12/c6; vdw = 0.5*pow(sig6,1.0/6.0); } else vdw = rvdw; } /* Factor of 10 for nm -> Angstroms */ vdw *= 10; if (bMead) { atoms.pdbinfo[i].occup = top->atoms.atom[i].q; atoms.pdbinfo[i].bfac = vdw; } else { atoms.pdbinfo[i].occup = vdw; atoms.pdbinfo[i].bfac = top->atoms.atom[i].q; } } } bHaveV=FALSE; for (i=0; (i<natom) && !bHaveV; i++) for (j=0; (j<DIM) && !bHaveV; j++) bHaveV=bHaveV || (v[i][j]!=0); printf("%selocities found\n",bHaveV?"V":"No v"); if (visbox[0] > 0) { if (bIndex) gmx_fatal(FARGS,"Sorry, can not visualize box with index groups"); if (outftp != efPDB) gmx_fatal(FARGS,"Sorry, can only visualize box with a pdb file"); } else if (visbox[0] == -1) visualize_images("images.pdb",ePBC,box); /* remove pbc */ if (bRMPBC) rm_gropbc(&atoms,x,box); if (bCalcGeom) { if (bIndex) { fprintf(stderr,"\nSelect a group for determining the system size:\n"); get_index(&atoms,ftp2fn_null(efNDX,NFILE,fnm), 1,&ssize,&sindex,&sgrpname); } else { ssize = atoms.nr; sindex = NULL; } diam=calc_geom(ssize,sindex,x,gc,min,max,bCalcDiam); rvec_sub(max, min, size); printf(" system size :%7.3f%7.3f%7.3f (nm)\n", size[XX], size[YY], size[ZZ]); if (bCalcDiam) printf(" diameter :%7.3f (nm)\n",diam); printf(" center :%7.3f%7.3f%7.3f (nm)\n", gc[XX], gc[YY], gc[ZZ]); printf(" box vectors :%7.3f%7.3f%7.3f (nm)\n", norm(box[XX]), norm(box[YY]), norm(box[ZZ])); printf(" box angles :%7.2f%7.2f%7.2f (degrees)\n", norm2(box[ZZ])==0 ? 0 : RAD2DEG*acos(cos_angle_no_table(box[YY],box[ZZ])), norm2(box[ZZ])==0 ? 0 : RAD2DEG*acos(cos_angle_no_table(box[XX],box[ZZ])), norm2(box[YY])==0 ? 0 : RAD2DEG*acos(cos_angle_no_table(box[XX],box[YY]))); printf(" box volume :%7.2f (nm^3)\n",det(box)); } if (bRho || bOrient || bAlign) mass = calc_mass(&atoms,!fn2bTPX(infile),aps); if (bOrient) { atom_id *index; char *grpnames; /* Get a group for principal component analysis */ fprintf(stderr,"\nSelect group for the determining the orientation\n"); get_index(&atoms,ftp2fn_null(efNDX,NFILE,fnm),1,&isize,&index,&grpnames); /* Orient the principal axes along the coordinate axes */ orient_princ(&atoms,isize,index,natom,x,bHaveV ? v : NULL, NULL); sfree(index); sfree(grpnames); } if ( bScale ) { /* scale coordinates and box */ if (bRho) { /* Compute scaling constant */ real vol,dens; vol = det(box); dens = (mass*AMU)/(vol*NANO*NANO*NANO); fprintf(stderr,"Volume of input %g (nm^3)\n",vol); fprintf(stderr,"Mass of input %g (a.m.u.)\n",mass); fprintf(stderr,"Density of input %g (g/l)\n",dens); if (vol==0 || mass==0) gmx_fatal(FARGS,"Cannot scale density with " "zero mass (%g) or volume (%g)\n",mass,vol); scale[XX] = scale[YY] = scale[ZZ] = pow(dens/rho,1.0/3.0); fprintf(stderr,"Scaling all box vectors by %g\n",scale[XX]); } scale_conf(atoms.nr,x,box,scale); } if (bAlign) { if (bIndex) { fprintf(stderr,"\nSelect a group that you want to align:\n"); get_index(&atoms,ftp2fn_null(efNDX,NFILE,fnm), 1,&asize,&aindex,&agrpname); } else { asize = atoms.nr; snew(aindex,asize); for (i=0;i<asize;i++) aindex[i]=i; } printf("Aligning %d atoms (out of %d) to %g %g %g, center of rotation %g %g %g\n",asize,natom, targetvec[XX],targetvec[YY],targetvec[ZZ], aligncenter[XX],aligncenter[YY],aligncenter[ZZ]); /*subtract out pivot point*/ for(i=0; i<asize; i++) rvec_dec(x[aindex[i]],aligncenter); /*now determine transform and rotate*/ /*will this work?*/ principal_comp(asize,aindex,atoms.atom,x, trans,princd); unitv(targetvec,targetvec); printf("Using %g %g %g as principal axis\n", trans[0][2],trans[1][2],trans[2][2]); tmpvec[XX]=trans[0][2]; tmpvec[YY]=trans[1][2]; tmpvec[ZZ]=trans[2][2]; calc_rotmatrix(tmpvec, targetvec, rotmatrix); /* rotmatrix finished */ for (i=0;i<asize;++i) { mvmul(rotmatrix,x[aindex[i]],tmpvec); copy_rvec(tmpvec,x[aindex[i]]); } /*add pivot point back*/ for(i=0; i<asize; i++) rvec_inc(x[aindex[i]],aligncenter); if (!bIndex) sfree(aindex); } if (bTranslate) { if (bIndex) { fprintf(stderr,"\nSelect a group that you want to translate:\n"); get_index(&atoms,ftp2fn_null(efNDX,NFILE,fnm), 1,&ssize,&sindex,&sgrpname); } else { ssize = atoms.nr; sindex = NULL; } printf("Translating %d atoms (out of %d) by %g %g %g nm\n",ssize,natom, translation[XX],translation[YY],translation[ZZ]); if (sindex) { for(i=0; i<ssize; i++) rvec_inc(x[sindex[i]],translation); } else { for(i=0; i<natom; i++) rvec_inc(x[i],translation); } } if (bRotate) { /* Rotate */ printf("Rotating %g, %g, %g degrees around the X, Y and Z axis respectively\n",rotangles[XX],rotangles[YY],rotangles[ZZ]); for(i=0; i<DIM; i++) rotangles[i] *= DEG2RAD; rotate_conf(natom,x,v,rotangles[XX],rotangles[YY],rotangles[ZZ]); } if (bCalcGeom) { /* recalc geometrical center and max and min coordinates and size */ calc_geom(ssize,sindex,x,gc,min,max,FALSE); rvec_sub(max, min, size); if (bScale || bOrient || bRotate) printf("new system size : %6.3f %6.3f %6.3f\n", size[XX],size[YY],size[ZZ]); } if (bSetSize || bDist || (btype[0][0]=='t' && bSetAng)) { ePBC = epbcXYZ; if (!(bSetSize || bDist)) for (i=0; i<DIM; i++) newbox[i] = norm(box[i]); clear_mat(box); /* calculate new boxsize */ switch(btype[0][0]){ case 't': if (bDist) for(i=0; i<DIM; i++) newbox[i] = size[i]+2*dist; if (!bSetAng) { box[XX][XX] = newbox[XX]; box[YY][YY] = newbox[YY]; box[ZZ][ZZ] = newbox[ZZ]; } else { matrix_convert(box,newbox,newang); } break; case 'c': case 'd': case 'o': if (bSetSize) d = newbox[0]; else d = diam+2*dist; if (btype[0][0] == 'c') for(i=0; i<DIM; i++) box[i][i] = d; else if (btype[0][0] == 'd') { box[XX][XX] = d; box[YY][YY] = d; box[ZZ][XX] = d/2; box[ZZ][YY] = d/2; box[ZZ][ZZ] = d*sqrt(2)/2; } else { box[XX][XX] = d; box[YY][XX] = d/3; box[YY][YY] = d*sqrt(2)*2/3; box[ZZ][XX] = -d/3; box[ZZ][YY] = d*sqrt(2)/3; box[ZZ][ZZ] = d*sqrt(6)/3; } break; } } /* calculate new coords for geometrical center */ if (!bSetCenter) calc_box_center(ecenterDEF,box,center); /* center molecule on 'center' */ if (bCenter) center_conf(natom,x,center,gc); /* print some */ if (bCalcGeom) { calc_geom(ssize,sindex,x, gc, min, max, FALSE); printf("new center :%7.3f%7.3f%7.3f (nm)\n",gc[XX],gc[YY],gc[ZZ]); } if (bOrient || bScale || bDist || bSetSize) { printf("new box vectors :%7.3f%7.3f%7.3f (nm)\n", norm(box[XX]), norm(box[YY]), norm(box[ZZ])); printf("new box angles :%7.2f%7.2f%7.2f (degrees)\n", norm2(box[ZZ])==0 ? 0 : RAD2DEG*acos(cos_angle_no_table(box[YY],box[ZZ])), norm2(box[ZZ])==0 ? 0 : RAD2DEG*acos(cos_angle_no_table(box[XX],box[ZZ])), norm2(box[YY])==0 ? 0 : RAD2DEG*acos(cos_angle_no_table(box[XX],box[YY]))); printf("new box volume :%7.2f (nm^3)\n",det(box)); } if (check_box(epbcXYZ,box)) printf("\nWARNING: %s\n",check_box(epbcXYZ,box)); if (bDist && btype[0][0]=='t') { if(TRICLINIC(box)) { printf("\nWARNING: Your box is triclinic with non-orthogonal axes. In this case, the\n" "distance from the solute to a box surface along the corresponding normal\n" "vector might be somewhat smaller than your specified value %f.\n" "You can check the actual value with g_mindist -pi\n",dist); } else { printf("\nWARNING: No boxtype specified - distance condition applied in each dimension.\n" "If the molecule rotates the actual distance will be smaller. You might want\n" "to use a cubic box instead, or why not try a dodecahedron today?\n"); } } if (bCONECT && (outftp == efPDB) && (inftp == efTPR)) conect = gmx_conect_generate(top); else conect = NULL; if (bIndex) { fprintf(stderr,"\nSelect a group for output:\n"); get_index(&atoms,opt2fn_null("-n",NFILE,fnm), 1,&isize,&index,&grpname); if (opt2parg_bSet("-label",NPA,pa)) { for(i=0; (i<atoms.nr); i++) atoms.resinfo[atoms.atom[i].resind].chainid=label[0]; } if (opt2bSet("-bf",NFILE,fnm) || bLegend) { gmx_fatal(FARGS,"Sorry, cannot do bfactors with an index group."); } if (outftp == efPDB) { out=ffopen(outfile,"w"); write_pdbfile_indexed(out,title,&atoms,x,ePBC,box,' ',1,isize,index,conect,TRUE); ffclose(out); } else { write_sto_conf_indexed(outfile,title,&atoms,x,bHaveV?v:NULL,ePBC,box,isize,index); } } else { if ((outftp == efPDB) || (outftp == efPQR)) { out=ffopen(outfile,"w"); if (bMead) { set_pdb_wide_format(TRUE); fprintf(out,"REMARK " "The B-factors in this file hold atomic radii\n"); fprintf(out,"REMARK " "The occupancy in this file hold atomic charges\n"); } else if (bGrasp) { fprintf(out,"GRASP PDB FILE\nFORMAT NUMBER=1\n"); fprintf(out,"REMARK " "The B-factors in this file hold atomic charges\n"); fprintf(out,"REMARK " "The occupancy in this file hold atomic radii\n"); } else if (opt2bSet("-bf",NFILE,fnm)) { read_bfac(opt2fn("-bf",NFILE,fnm),&n_bfac,&bfac,&bfac_nr); set_pdb_conf_bfac(atoms.nr,atoms.nres,&atoms, n_bfac,bfac,bfac_nr,peratom); } if (opt2parg_bSet("-label",NPA,pa)) { for(i=0; (i<atoms.nr); i++) atoms.resinfo[atoms.atom[i].resind].chainid=label[0]; } write_pdbfile(out,title,&atoms,x,ePBC,box,' ',-1,conect,TRUE); if (bLegend) pdb_legend(out,atoms.nr,atoms.nres,&atoms,x); if (visbox[0] > 0) visualize_box(out,bLegend ? atoms.nr+12 : atoms.nr, bLegend? atoms.nres=12 : atoms.nres,box,visbox); ffclose(out); } else write_sto_conf(outfile,title,&atoms,x,bHaveV?v:NULL,ePBC,box); } gmx_atomprop_destroy(aps); do_view(oenv,outfile,NULL); thanx(stderr); return 0; }
double do_tpi(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[], const output_env_t oenv, gmx_bool bVerbose, gmx_bool gmx_unused bCompact, int gmx_unused nstglobalcomm, gmx_vsite_t gmx_unused *vsite, gmx_constr_t gmx_unused constr, int gmx_unused stepout, t_inputrec *inputrec, gmx_mtop_t *top_global, t_fcdata *fcd, t_state *state, t_mdatoms *mdatoms, t_nrnb *nrnb, gmx_wallcycle_t wcycle, gmx_edsam_t gmx_unused ed, t_forcerec *fr, int gmx_unused repl_ex_nst, int gmx_unused repl_ex_nex, int gmx_unused repl_ex_seed, gmx_membed_t gmx_unused membed, real gmx_unused cpt_period, real gmx_unused max_hours, const char gmx_unused *deviceOptions, int gmx_unused imdport, unsigned long gmx_unused Flags, gmx_walltime_accounting_t walltime_accounting) { const char *TPI = "Test Particle Insertion"; gmx_localtop_t *top; gmx_groups_t *groups; gmx_enerdata_t *enerd; rvec *f; real lambda, t, temp, beta, drmax, epot; double embU, sum_embU, *sum_UgembU, V, V_all, VembU_all; t_trxstatus *status; t_trxframe rerun_fr; gmx_bool bDispCorr, bCharge, bRFExcl, bNotLastFrame, bStateChanged, bNS; tensor force_vir, shake_vir, vir, pres; int cg_tp, a_tp0, a_tp1, ngid, gid_tp, nener, e; rvec *x_mol; rvec mu_tot, x_init, dx, x_tp; int nnodes, frame; gmx_int64_t frame_step_prev, frame_step; gmx_int64_t nsteps, stepblocksize = 0, step; gmx_int64_t rnd_count_stride, rnd_count; gmx_int64_t seed; double rnd[4]; int i, start, end; FILE *fp_tpi = NULL; char *ptr, *dump_pdb, **leg, str[STRLEN], str2[STRLEN]; double dbl, dump_ener; gmx_bool bCavity; int nat_cavity = 0, d; real *mass_cavity = NULL, mass_tot; int nbin; double invbinw, *bin, refvolshift, logV, bUlogV; real dvdl, prescorr, enercorr, dvdlcorr; gmx_bool bEnergyOutOfBounds; const char *tpid_leg[2] = {"direct", "reweighted"}; /* Since there is no upper limit to the insertion energies, * we need to set an upper limit for the distribution output. */ real bU_bin_limit = 50; real bU_logV_bin_limit = bU_bin_limit + 10; nnodes = cr->nnodes; top = gmx_mtop_generate_local_top(top_global, inputrec); groups = &top_global->groups; bCavity = (inputrec->eI == eiTPIC); if (bCavity) { ptr = getenv("GMX_TPIC_MASSES"); if (ptr == NULL) { nat_cavity = 1; } else { /* Read (multiple) masses from env var GMX_TPIC_MASSES, * The center of mass of the last atoms is then used for TPIC. */ nat_cavity = 0; while (sscanf(ptr, "%lf%n", &dbl, &i) > 0) { srenew(mass_cavity, nat_cavity+1); mass_cavity[nat_cavity] = dbl; fprintf(fplog, "mass[%d] = %f\n", nat_cavity+1, mass_cavity[nat_cavity]); nat_cavity++; ptr += i; } if (nat_cavity == 0) { gmx_fatal(FARGS, "Found %d masses in GMX_TPIC_MASSES", nat_cavity); } } } /* init_em(fplog,TPI,inputrec,&lambda,nrnb,mu_tot, state->box,fr,mdatoms,top,cr,nfile,fnm,NULL,NULL);*/ /* We never need full pbc for TPI */ fr->ePBC = epbcXYZ; /* Determine the temperature for the Boltzmann weighting */ temp = inputrec->opts.ref_t[0]; if (fplog) { for (i = 1; (i < inputrec->opts.ngtc); i++) { if (inputrec->opts.ref_t[i] != temp) { fprintf(fplog, "\nWARNING: The temperatures of the different temperature coupling groups are not identical\n\n"); fprintf(stderr, "\nWARNING: The temperatures of the different temperature coupling groups are not identical\n\n"); } } fprintf(fplog, "\n The temperature for test particle insertion is %.3f K\n\n", temp); } beta = 1.0/(BOLTZ*temp); /* Number of insertions per frame */ nsteps = inputrec->nsteps; /* Use the same neighborlist with more insertions points * in a sphere of radius drmax around the initial point */ /* This should be a proper mdp parameter */ drmax = inputrec->rtpi; /* An environment variable can be set to dump all configurations * to pdb with an insertion energy <= this value. */ dump_pdb = getenv("GMX_TPI_DUMP"); dump_ener = 0; if (dump_pdb) { sscanf(dump_pdb, "%lf", &dump_ener); } atoms2md(top_global, inputrec, 0, NULL, top_global->natoms, mdatoms); update_mdatoms(mdatoms, inputrec->fepvals->init_lambda); snew(enerd, 1); init_enerdata(groups->grps[egcENER].nr, inputrec->fepvals->n_lambda, enerd); snew(f, top_global->natoms); /* Print to log file */ walltime_accounting_start(walltime_accounting); wallcycle_start(wcycle, ewcRUN); print_start(fplog, cr, walltime_accounting, "Test Particle Insertion"); /* The last charge group is the group to be inserted */ cg_tp = top->cgs.nr - 1; a_tp0 = top->cgs.index[cg_tp]; a_tp1 = top->cgs.index[cg_tp+1]; if (debug) { fprintf(debug, "TPI cg %d, atoms %d-%d\n", cg_tp, a_tp0, a_tp1); } if (a_tp1 - a_tp0 > 1 && (inputrec->rlist < inputrec->rcoulomb || inputrec->rlist < inputrec->rvdw)) { gmx_fatal(FARGS, "Can not do TPI for multi-atom molecule with a twin-range cut-off"); } snew(x_mol, a_tp1-a_tp0); bDispCorr = (inputrec->eDispCorr != edispcNO); bCharge = FALSE; for (i = a_tp0; i < a_tp1; i++) { /* Copy the coordinates of the molecule to be insterted */ copy_rvec(state->x[i], x_mol[i-a_tp0]); /* Check if we need to print electrostatic energies */ bCharge |= (mdatoms->chargeA[i] != 0 || (mdatoms->chargeB && mdatoms->chargeB[i] != 0)); } bRFExcl = (bCharge && EEL_RF(fr->eeltype) && fr->eeltype != eelRF_NEC); calc_cgcm(fplog, cg_tp, cg_tp+1, &(top->cgs), state->x, fr->cg_cm); if (bCavity) { if (norm(fr->cg_cm[cg_tp]) > 0.5*inputrec->rlist && fplog) { fprintf(fplog, "WARNING: Your TPI molecule is not centered at 0,0,0\n"); fprintf(stderr, "WARNING: Your TPI molecule is not centered at 0,0,0\n"); } } else { /* Center the molecule to be inserted at zero */ for (i = 0; i < a_tp1-a_tp0; i++) { rvec_dec(x_mol[i], fr->cg_cm[cg_tp]); } } if (fplog) { fprintf(fplog, "\nWill insert %d atoms %s partial charges\n", a_tp1-a_tp0, bCharge ? "with" : "without"); fprintf(fplog, "\nWill insert %d times in each frame of %s\n", (int)nsteps, opt2fn("-rerun", nfile, fnm)); } if (!bCavity) { if (inputrec->nstlist > 1) { if (drmax == 0 && a_tp1-a_tp0 == 1) { gmx_fatal(FARGS, "Re-using the neighborlist %d times for insertions of a single atom in a sphere of radius %f does not make sense", inputrec->nstlist, drmax); } if (fplog) { fprintf(fplog, "Will use the same neighborlist for %d insertions in a sphere of radius %f\n", inputrec->nstlist, drmax); } } } else { if (fplog) { fprintf(fplog, "Will insert randomly in a sphere of radius %f around the center of the cavity\n", drmax); } } ngid = groups->grps[egcENER].nr; gid_tp = GET_CGINFO_GID(fr->cginfo[cg_tp]); nener = 1 + ngid; if (bDispCorr) { nener += 1; } if (bCharge) { nener += ngid; if (bRFExcl) { nener += 1; } if (EEL_FULL(fr->eeltype)) { nener += 1; } } snew(sum_UgembU, nener); /* Copy the random seed set by the user */ seed = inputrec->ld_seed; /* We use the frame step number as one random counter. * The second counter use the insertion (step) count. But we * need multiple random numbers per insertion. This number is * not fixed, since we generate random locations in a sphere * by putting locations in a cube and some of these fail. * A count of 20 is already extremely unlikely, so 10000 is * a safe margin for random numbers per insertion. */ rnd_count_stride = 10000; if (MASTER(cr)) { fp_tpi = xvgropen(opt2fn("-tpi", nfile, fnm), "TPI energies", "Time (ps)", "(kJ mol\\S-1\\N) / (nm\\S3\\N)", oenv); xvgr_subtitle(fp_tpi, "f. are averages over one frame", oenv); snew(leg, 4+nener); e = 0; sprintf(str, "-kT log(<Ve\\S-\\betaU\\N>/<V>)"); leg[e++] = strdup(str); sprintf(str, "f. -kT log<e\\S-\\betaU\\N>"); leg[e++] = strdup(str); sprintf(str, "f. <e\\S-\\betaU\\N>"); leg[e++] = strdup(str); sprintf(str, "f. V"); leg[e++] = strdup(str); sprintf(str, "f. <Ue\\S-\\betaU\\N>"); leg[e++] = strdup(str); for (i = 0; i < ngid; i++) { sprintf(str, "f. <U\\sVdW %s\\Ne\\S-\\betaU\\N>", *(groups->grpname[groups->grps[egcENER].nm_ind[i]])); leg[e++] = strdup(str); } if (bDispCorr) { sprintf(str, "f. <U\\sdisp c\\Ne\\S-\\betaU\\N>"); leg[e++] = strdup(str); } if (bCharge) { for (i = 0; i < ngid; i++) { sprintf(str, "f. <U\\sCoul %s\\Ne\\S-\\betaU\\N>", *(groups->grpname[groups->grps[egcENER].nm_ind[i]])); leg[e++] = strdup(str); } if (bRFExcl) { sprintf(str, "f. <U\\sRF excl\\Ne\\S-\\betaU\\N>"); leg[e++] = strdup(str); } if (EEL_FULL(fr->eeltype)) { sprintf(str, "f. <U\\sCoul recip\\Ne\\S-\\betaU\\N>"); leg[e++] = strdup(str); } } xvgr_legend(fp_tpi, 4+nener, (const char**)leg, oenv); for (i = 0; i < 4+nener; i++) { sfree(leg[i]); } sfree(leg); } clear_rvec(x_init); V_all = 0; VembU_all = 0; invbinw = 10; nbin = 10; snew(bin, nbin); /* Avoid frame step numbers <= -1 */ frame_step_prev = -1; bNotLastFrame = read_first_frame(oenv, &status, opt2fn("-rerun", nfile, fnm), &rerun_fr, TRX_NEED_X); frame = 0; if (rerun_fr.natoms - (bCavity ? nat_cavity : 0) != mdatoms->nr - (a_tp1 - a_tp0)) { gmx_fatal(FARGS, "Number of atoms in trajectory (%d)%s " "is not equal the number in the run input file (%d) " "minus the number of atoms to insert (%d)\n", rerun_fr.natoms, bCavity ? " minus one" : "", mdatoms->nr, a_tp1-a_tp0); } refvolshift = log(det(rerun_fr.box)); switch (inputrec->eI) { case eiTPI: stepblocksize = inputrec->nstlist; break; case eiTPIC: stepblocksize = 1; break; default: gmx_fatal(FARGS, "Unknown integrator %s", ei_names[inputrec->eI]); } #ifdef GMX_SIMD /* Make sure we don't detect SIMD overflow generated before this point */ gmx_simd_check_and_reset_overflow(); #endif while (bNotLastFrame) { frame_step = rerun_fr.step; if (frame_step <= frame_step_prev) { /* We don't have step number in the trajectory file, * or we have constant or decreasing step numbers. * Ensure we have increasing step numbers, since we use * the step numbers as a counter for random numbers. */ frame_step = frame_step_prev + 1; } frame_step_prev = frame_step; lambda = rerun_fr.lambda; t = rerun_fr.time; sum_embU = 0; for (e = 0; e < nener; e++) { sum_UgembU[e] = 0; } /* Copy the coordinates from the input trajectory */ for (i = 0; i < rerun_fr.natoms; i++) { copy_rvec(rerun_fr.x[i], state->x[i]); } copy_mat(rerun_fr.box, state->box); V = det(state->box); logV = log(V); bStateChanged = TRUE; bNS = TRUE; step = cr->nodeid*stepblocksize; while (step < nsteps) { /* Initialize the second counter for random numbers using * the insertion step index. This ensures that we get * the same random numbers independently of how many * MPI ranks we use. Also for the same seed, we get * the same initial random sequence for different nsteps. */ rnd_count = step*rnd_count_stride; if (!bCavity) { /* Random insertion in the whole volume */ bNS = (step % inputrec->nstlist == 0); if (bNS) { /* Generate a random position in the box */ gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd); gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd+2); for (d = 0; d < DIM; d++) { x_init[d] = rnd[d]*state->box[d][d]; } } if (inputrec->nstlist == 1) { copy_rvec(x_init, x_tp); } else { /* Generate coordinates within |dx|=drmax of x_init */ do { gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd); gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd+2); for (d = 0; d < DIM; d++) { dx[d] = (2*rnd[d] - 1)*drmax; } } while (norm2(dx) > drmax*drmax); rvec_add(x_init, dx, x_tp); } } else { /* Random insertion around a cavity location * given by the last coordinate of the trajectory. */ if (step == 0) { if (nat_cavity == 1) { /* Copy the location of the cavity */ copy_rvec(rerun_fr.x[rerun_fr.natoms-1], x_init); } else { /* Determine the center of mass of the last molecule */ clear_rvec(x_init); mass_tot = 0; for (i = 0; i < nat_cavity; i++) { for (d = 0; d < DIM; d++) { x_init[d] += mass_cavity[i]*rerun_fr.x[rerun_fr.natoms-nat_cavity+i][d]; } mass_tot += mass_cavity[i]; } for (d = 0; d < DIM; d++) { x_init[d] /= mass_tot; } } } /* Generate coordinates within |dx|=drmax of x_init */ do { gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd); gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd+2); for (d = 0; d < DIM; d++) { dx[d] = (2*rnd[d] - 1)*drmax; } } while (norm2(dx) > drmax*drmax); rvec_add(x_init, dx, x_tp); } if (a_tp1 - a_tp0 == 1) { /* Insert a single atom, just copy the insertion location */ copy_rvec(x_tp, state->x[a_tp0]); } else { /* Copy the coordinates from the top file */ for (i = a_tp0; i < a_tp1; i++) { copy_rvec(x_mol[i-a_tp0], state->x[i]); } /* Rotate the molecule randomly */ gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd); gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd+2); rotate_conf(a_tp1-a_tp0, state->x+a_tp0, NULL, 2*M_PI*rnd[0], 2*M_PI*rnd[1], 2*M_PI*rnd[2]); /* Shift to the insertion location */ for (i = a_tp0; i < a_tp1; i++) { rvec_inc(state->x[i], x_tp); } } /* Clear some matrix variables */ clear_mat(force_vir); clear_mat(shake_vir); clear_mat(vir); clear_mat(pres); /* Set the charge group center of mass of the test particle */ copy_rvec(x_init, fr->cg_cm[top->cgs.nr-1]); /* Calc energy (no forces) on new positions. * Since we only need the intermolecular energy * and the RF exclusion terms of the inserted molecule occur * within a single charge group we can pass NULL for the graph. * This also avoids shifts that would move charge groups * out of the box. * * Some checks above ensure than we can not have * twin-range interactions together with nstlist > 1, * therefore we do not need to remember the LR energies. */ /* Make do_force do a single node force calculation */ cr->nnodes = 1; do_force(fplog, cr, inputrec, step, nrnb, wcycle, top, &top_global->groups, state->box, state->x, &state->hist, f, force_vir, mdatoms, enerd, fcd, state->lambda, NULL, fr, NULL, mu_tot, t, NULL, NULL, FALSE, GMX_FORCE_NONBONDED | GMX_FORCE_ENERGY | (bNS ? GMX_FORCE_DYNAMICBOX | GMX_FORCE_NS | GMX_FORCE_DO_LR : 0) | (bStateChanged ? GMX_FORCE_STATECHANGED : 0)); cr->nnodes = nnodes; bStateChanged = FALSE; bNS = FALSE; /* Calculate long range corrections to pressure and energy */ calc_dispcorr(fplog, inputrec, fr, step, top_global->natoms, state->box, lambda, pres, vir, &prescorr, &enercorr, &dvdlcorr); /* figure out how to rearrange the next 4 lines MRS 8/4/2009 */ enerd->term[F_DISPCORR] = enercorr; enerd->term[F_EPOT] += enercorr; enerd->term[F_PRES] += prescorr; enerd->term[F_DVDL_VDW] += dvdlcorr; epot = enerd->term[F_EPOT]; bEnergyOutOfBounds = FALSE; #ifdef GMX_SIMD_X86_SSE2_OR_HIGHER /* With SSE the energy can overflow, check for this */ if (gmx_mm_check_and_reset_overflow()) { if (debug) { fprintf(debug, "Found an SSE overflow, assuming the energy is out of bounds\n"); } bEnergyOutOfBounds = TRUE; } #endif /* If the compiler doesn't optimize this check away * we catch the NAN energies. * The epot>GMX_REAL_MAX check catches inf values, * which should nicely result in embU=0 through the exp below, * but it does not hurt to check anyhow. */ /* Non-bonded Interaction usually diverge at r=0. * With tabulated interaction functions the first few entries * should be capped in a consistent fashion between * repulsion, dispersion and Coulomb to avoid accidental * negative values in the total energy. * The table generation code in tables.c does this. * With user tbales the user should take care of this. */ if (epot != epot || epot > GMX_REAL_MAX) { bEnergyOutOfBounds = TRUE; } if (bEnergyOutOfBounds) { if (debug) { fprintf(debug, "\n time %.3f, step %d: non-finite energy %f, using exp(-bU)=0\n", t, (int)step, epot); } embU = 0; } else { embU = exp(-beta*epot); sum_embU += embU; /* Determine the weighted energy contributions of each energy group */ e = 0; sum_UgembU[e++] += epot*embU; if (fr->bBHAM) { for (i = 0; i < ngid; i++) { sum_UgembU[e++] += (enerd->grpp.ener[egBHAMSR][GID(i, gid_tp, ngid)] + enerd->grpp.ener[egBHAMLR][GID(i, gid_tp, ngid)])*embU; } } else { for (i = 0; i < ngid; i++) { sum_UgembU[e++] += (enerd->grpp.ener[egLJSR][GID(i, gid_tp, ngid)] + enerd->grpp.ener[egLJLR][GID(i, gid_tp, ngid)])*embU; } } if (bDispCorr) { sum_UgembU[e++] += enerd->term[F_DISPCORR]*embU; } if (bCharge) { for (i = 0; i < ngid; i++) { sum_UgembU[e++] += (enerd->grpp.ener[egCOULSR][GID(i, gid_tp, ngid)] + enerd->grpp.ener[egCOULLR][GID(i, gid_tp, ngid)])*embU; } if (bRFExcl) { sum_UgembU[e++] += enerd->term[F_RF_EXCL]*embU; } if (EEL_FULL(fr->eeltype)) { sum_UgembU[e++] += enerd->term[F_COUL_RECIP]*embU; } } } if (embU == 0 || beta*epot > bU_bin_limit) { bin[0]++; } else { i = (int)((bU_logV_bin_limit - (beta*epot - logV + refvolshift))*invbinw + 0.5); if (i < 0) { i = 0; } if (i >= nbin) { realloc_bins(&bin, &nbin, i+10); } bin[i]++; } if (debug) { fprintf(debug, "TPI %7d %12.5e %12.5f %12.5f %12.5f\n", (int)step, epot, x_tp[XX], x_tp[YY], x_tp[ZZ]); } if (dump_pdb && epot <= dump_ener) { sprintf(str, "t%g_step%d.pdb", t, (int)step); sprintf(str2, "t: %f step %d ener: %f", t, (int)step, epot); write_sto_conf_mtop(str, str2, top_global, state->x, state->v, inputrec->ePBC, state->box); } step++; if ((step/stepblocksize) % cr->nnodes != cr->nodeid) { /* Skip all steps assigned to the other MPI ranks */ step += (cr->nnodes - 1)*stepblocksize; } } if (PAR(cr)) { /* When running in parallel sum the energies over the processes */ gmx_sumd(1, &sum_embU, cr); gmx_sumd(nener, sum_UgembU, cr); } frame++; V_all += V; VembU_all += V*sum_embU/nsteps; if (fp_tpi) { if (bVerbose || frame%10 == 0 || frame < 10) { fprintf(stderr, "mu %10.3e <mu> %10.3e\n", -log(sum_embU/nsteps)/beta, -log(VembU_all/V_all)/beta); } fprintf(fp_tpi, "%10.3f %12.5e %12.5e %12.5e %12.5e", t, VembU_all == 0 ? 20/beta : -log(VembU_all/V_all)/beta, sum_embU == 0 ? 20/beta : -log(sum_embU/nsteps)/beta, sum_embU/nsteps, V); for (e = 0; e < nener; e++) { fprintf(fp_tpi, " %12.5e", sum_UgembU[e]/nsteps); } fprintf(fp_tpi, "\n"); fflush(fp_tpi); } bNotLastFrame = read_next_frame(oenv, status, &rerun_fr); } /* End of the loop */ walltime_accounting_end(walltime_accounting); close_trj(status); if (fp_tpi != NULL) { gmx_fio_fclose(fp_tpi); } if (fplog != NULL) { fprintf(fplog, "\n"); fprintf(fplog, " <V> = %12.5e nm^3\n", V_all/frame); fprintf(fplog, " <mu> = %12.5e kJ/mol\n", -log(VembU_all/V_all)/beta); } /* Write the Boltzmann factor histogram */ if (PAR(cr)) { /* When running in parallel sum the bins over the processes */ i = nbin; global_max(cr, &i); realloc_bins(&bin, &nbin, i); gmx_sumd(nbin, bin, cr); } if (MASTER(cr)) { fp_tpi = xvgropen(opt2fn("-tpid", nfile, fnm), "TPI energy distribution", "\\betaU - log(V/<V>)", "count", oenv); sprintf(str, "number \\betaU > %g: %9.3e", bU_bin_limit, bin[0]); xvgr_subtitle(fp_tpi, str, oenv); xvgr_legend(fp_tpi, 2, (const char **)tpid_leg, oenv); for (i = nbin-1; i > 0; i--) { bUlogV = -i/invbinw + bU_logV_bin_limit - refvolshift + log(V_all/frame); fprintf(fp_tpi, "%6.2f %10d %12.5e\n", bUlogV, (int)(bin[i]+0.5), bin[i]*exp(-bUlogV)*V_all/VembU_all); } gmx_fio_fclose(fp_tpi); } sfree(bin); sfree(sum_UgembU); walltime_accounting_set_nsteps_done(walltime_accounting, frame*inputrec->nsteps); return 0; }
static char *insert_mols(const char *mol_insrt, int nmol_insrt, int ntry, int seed, t_atoms *atoms, rvec **x, real **r, int ePBC, matrix box, gmx_atomprop_t aps, real r_distance, real r_scale, real rshell, const output_env_t oenv, const char* posfn, const rvec deltaR, int enum_rot, gmx_bool bCheckAllPairDist) { t_pbc pbc; static char *title_insrt; t_atoms atoms_insrt; rvec *x_insrt, *x_n; real *r_insrt; int ePBC_insrt; matrix box_insrt; int i, mol, onr, ncol; real alfa = 0., beta = 0., gamma = 0.; rvec offset_x; int trial; double **rpos; set_pbc(&pbc, ePBC, box); /* read number of atoms of insert molecules */ get_stx_coordnum(mol_insrt, &atoms_insrt.nr); if (atoms_insrt.nr == 0) { gmx_fatal(FARGS, "No molecule in %s, please check your input\n", mol_insrt); } /* allocate memory for atom coordinates of insert molecules */ snew(x_insrt, atoms_insrt.nr); snew(r_insrt, atoms_insrt.nr); snew(atoms_insrt.resinfo, atoms_insrt.nr); snew(atoms_insrt.atomname, atoms_insrt.nr); snew(atoms_insrt.atom, atoms_insrt.nr); atoms_insrt.pdbinfo = NULL; snew(x_n, atoms_insrt.nr); snew(title_insrt, STRLEN); /* read residue number, residue names, atomnames, coordinates etc. */ fprintf(stderr, "Reading molecule configuration \n"); read_stx_conf(mol_insrt, title_insrt, &atoms_insrt, x_insrt, NULL, &ePBC_insrt, box_insrt); fprintf(stderr, "%s\nContaining %d atoms in %d residue\n", title_insrt, atoms_insrt.nr, atoms_insrt.nres); srenew(atoms_insrt.resinfo, atoms_insrt.nres); /* initialise van der waals arrays of insert molecules */ mk_vdw(&atoms_insrt, r_insrt, aps, r_distance, r_scale); /* With -ip, take nmol_insrt from file posfn */ if (posfn != NULL) { nmol_insrt = read_xvg(posfn, &rpos, &ncol); if (ncol != 3) { gmx_fatal(FARGS, "Expected 3 columns (x/y/z coordinates) in file %s\n", ncol, posfn); } fprintf(stderr, "Read %d positions from file %s\n\n", nmol_insrt, posfn); } srenew(atoms->resinfo, (atoms->nres+nmol_insrt*atoms_insrt.nres)); srenew(atoms->atomname, (atoms->nr+atoms_insrt.nr*nmol_insrt)); srenew(atoms->atom, (atoms->nr+atoms_insrt.nr*nmol_insrt)); srenew(*x, (atoms->nr+atoms_insrt.nr*nmol_insrt)); srenew(*r, (atoms->nr+atoms_insrt.nr*nmol_insrt)); trial = mol = 0; while ((mol < nmol_insrt) && (trial < ntry*nmol_insrt)) { fprintf(stderr, "\rTry %d", trial++); for (i = 0; (i < atoms_insrt.nr); i++) { copy_rvec(x_insrt[i], x_n[i]); } switch (enum_rot) { case en_rotXYZ: alfa = 2*M_PI *rando(&seed); beta = 2*M_PI *rando(&seed); gamma = 2*M_PI *rando(&seed); break; case en_rotZ: alfa = beta = 0.; gamma = 2*M_PI*rando(&seed); break; case en_rotNone: alfa = beta = gamma = 0.; break; } if (enum_rot == en_rotXYZ || (enum_rot == en_rotZ)) { rotate_conf(atoms_insrt.nr, x_n, NULL, alfa, beta, gamma); } if (posfn == NULL) { /* insert at random positions */ offset_x[XX] = box[XX][XX]*rando(&seed); offset_x[YY] = box[YY][YY]*rando(&seed); offset_x[ZZ] = box[ZZ][ZZ]*rando(&seed); gen_box(0, atoms_insrt.nr, x_n, box_insrt, offset_x, TRUE); if (!in_box(&pbc, x_n[0]) || !in_box(&pbc, x_n[atoms_insrt.nr-1])) { continue; } } else { /* Insert at positions taken from option -ip file */ offset_x[XX] = rpos[XX][mol] + deltaR[XX]*(2*rando(&seed)-1); offset_x[YY] = rpos[YY][mol] + deltaR[YY]*(2*rando(&seed)-1); offset_x[ZZ] = rpos[ZZ][mol] + deltaR[ZZ]*(2*rando(&seed)-1); for (i = 0; i < atoms_insrt.nr; i++) { rvec_inc(x_n[i], offset_x); } } onr = atoms->nr; /* This is a (maybe) slow workaround to avoid too many calls of add_conf, which * leaks memory (status May 2012). If the momory leaks in add_conf() are fixed, * this check could be removed. Note, however, that allPairsDistOk is probably * even faster than add_conf() when inserting a small molecule into a moderately * small system. */ if (bCheckAllPairDist && !allPairsDistOk(atoms, *x, *r, ePBC, box, &atoms_insrt, x_n, r_insrt)) { continue; } add_conf(atoms, x, NULL, r, FALSE, ePBC, box, TRUE, &atoms_insrt, x_n, NULL, r_insrt, FALSE, rshell, 0, oenv); if (atoms->nr == (atoms_insrt.nr+onr)) { mol++; fprintf(stderr, " success (now %d atoms)!\n", atoms->nr); } } srenew(atoms->resinfo, atoms->nres); srenew(atoms->atomname, atoms->nr); srenew(atoms->atom, atoms->nr); srenew(*x, atoms->nr); srenew(*r, atoms->nr); fprintf(stderr, "\n"); /* print number of molecules added */ fprintf(stderr, "Added %d molecules (out of %d requested) of %s\n", mol, nmol_insrt, *atoms_insrt.resinfo[0].name); return title_insrt; }