2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team,
6 * check out http://www.gromacs.org for more information.
7 * Copyright (c) 2012, by the GROMACS development team, led by
8 * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9 * others, as listed in the AUTHORS file in the top-level source
10 * directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
41 #include "gmx_header_config.h"
71 enum { euSel,euRect, euTric, euCompact, euNR};
74 static void calc_pbc_cluster(int ecenter,int nrefat,t_topology *top,int ePBC,
75 rvec x[],atom_id index[],
76 rvec clust_com,matrix box, rvec clustercenter)
78 int m,i,j,j0,j1,jj,ai,aj;
81 rvec dx,xtest,box_center;
93 calc_box_center(ecenter,box,box_center);
95 /* Initiate the pbc structure */
96 memset(&pbc,0,sizeof(pbc));
97 set_pbc(&pbc,ePBC,box);
99 /* Convert atom index to molecular */
101 molind = top->mols.index;
107 snew(bTmp,top->atoms.nr);
109 for(i=0; (i<nrefat); i++) {
110 /* Mark all molecules in the index */
113 /* Binary search assuming the molecules are sorted */
117 if (ai < molind[j0+1])
119 else if (ai >= molind[j1])
123 if (ai < molind[jj+1])
131 /* Double check whether all atoms in all molecules that are marked are part
132 * of the cluster. Simultaneously compute the center of geometry.
134 min_dist2 = 10*sqr(trace(box));
137 for(i=0; i<nmol; i++)
139 for(j=molind[i]; j<molind[i+1]; j++)
141 if (bMol[i] && !bTmp[j])
143 gmx_fatal(FARGS,"Molecule %d marked for clustering but not atom %d in it - check your index!",i+1,j+1);
145 else if (!bMol[i] && bTmp[j])
147 gmx_fatal(FARGS,"Atom %d marked for clustering but not molecule %d - this is an internal error...",j+1,i+1);
151 /* Make molecule whole, move 2nd and higher atom to same periodicity as 1st atom in molecule */
154 pbc_dx(&pbc,x[j],x[j-1],dx);
155 rvec_add(x[j-1],dx,x[j]);
157 /* Compute center of geometry of molecule - m_com[i] was zeroed when we did snew() on it! */
158 rvec_inc(m_com[i],x[j]);
163 /* Normalize center of geometry */
164 fac = 1.0/(molind[i+1]-molind[i]);
165 for(m=0; (m<DIM); m++)
167 /* Determine which molecule is closest to the center of the box */
168 pbc_dx(&pbc,box_center,m_com[i],dx);
171 if (tmp_r2 < min_dist2)
176 cluster[ncluster++]=i;
183 fprintf(stderr,"No molecules selected in the cluster\n");
186 else if (imol_center == -1)
188 fprintf(stderr,"No central molecules could be found\n");
193 added[nadded++] = imol_center;
194 bMol[imol_center] = FALSE;
196 while (nadded<ncluster)
198 /* Find min distance between cluster molecules and those remaining to be added */
199 min_dist2 = 10*sqr(trace(box));
202 /* Loop over added mols */
203 for(i=0;i<nadded;i++)
206 /* Loop over all mols */
207 for(j=0;j<ncluster;j++)
210 /* check those remaining to be added */
213 pbc_dx(&pbc,m_com[aj],m_com[ai],dx);
215 if (tmp_r2 < min_dist2)
225 /* Add the best molecule */
226 added[nadded++] = jmin;
228 /* Calculate the shift from the ai molecule */
229 pbc_dx(&pbc,m_com[jmin],m_com[imin],dx);
230 rvec_add(m_com[imin],dx,xtest);
231 rvec_sub(xtest,m_com[jmin],m_shift[jmin]);
232 rvec_inc(m_com[jmin],m_shift[jmin]);
234 for(j=molind[jmin]; j<molind[jmin+1]; j++)
236 rvec_inc(x[j],m_shift[jmin]);
238 fprintf(stdout,"\rClustering iteration %d of %d...",nadded,ncluster);
248 fprintf(stdout,"\n");
251 static void put_molecule_com_in_box(int unitcell_enum,int ecenter,
253 int natoms,t_atom atom[],
254 int ePBC,matrix box,rvec x[])
258 rvec com,new_com,shift,dx,box_center;
263 calc_box_center(ecenter,box,box_center);
264 set_pbc(&pbc,ePBC,box);
266 gmx_fatal(FARGS,"There are no molecule descriptions. I need a .tpr file for this pbc option.");
267 for(i=0; (i<mols->nr); i++) {
271 for(j=mols->index[i]; (j<mols->index[i+1] && j<natoms); j++) {
277 /* calculate final COM */
278 svmul(1.0/mtot, com, com);
280 /* check if COM is outside box */
281 copy_rvec(com,new_com);
282 switch (unitcell_enum) {
284 put_atoms_in_box(ePBC,box,1,&new_com);
287 put_atoms_in_triclinic_unitcell(ecenter,box,1,&new_com);
290 put_atoms_in_compact_unitcell(ePBC,ecenter,box,1,&new_com);
293 rvec_sub(new_com,com,shift);
294 if (norm2(shift) > 0) {
296 fprintf (debug,"\nShifting position of molecule %d "
297 "by %8.3f %8.3f %8.3f\n", i+1, PR_VEC(shift));
298 for(j=mols->index[i]; (j<mols->index[i+1] && j<natoms); j++) {
299 rvec_inc(x[j],shift);
305 static void put_residue_com_in_box(int unitcell_enum,int ecenter,
306 int natoms,t_atom atom[],
307 int ePBC,matrix box,rvec x[])
309 atom_id i, j, res_start, res_end, res_nat;
313 rvec box_center,com,new_com,shift;
315 calc_box_center(ecenter,box,box_center);
321 for(i=0; i<natoms+1; i++) {
322 if (i == natoms || (presnr != atom[i].resind && presnr != NOTSET)) {
323 /* calculate final COM */
325 res_nat = res_end - res_start;
326 svmul(1.0/mtot, com, com);
328 /* check if COM is outside box */
329 copy_rvec(com,new_com);
330 switch (unitcell_enum) {
332 put_atoms_in_box(ePBC,box,1,&new_com);
335 put_atoms_in_triclinic_unitcell(ecenter,box,1,&new_com);
338 put_atoms_in_compact_unitcell(ePBC,ecenter,box,1,&new_com);
341 rvec_sub(new_com,com,shift);
344 fprintf (debug,"\nShifting position of residue %d (atoms %u-%u) "
345 "by %g,%g,%g\n", atom[res_start].resind+1,
346 res_start+1, res_end+1, PR_VEC(shift));
347 for(j=res_start; j<res_end; j++)
348 rvec_inc(x[j],shift);
353 /* remember start of new residue */
363 presnr = atom[i].resind;
368 static void center_x(int ecenter,rvec x[],matrix box,int n,int nc,atom_id ci[])
371 rvec cmin,cmax,box_center,dx;
374 copy_rvec(x[ci[0]],cmin);
375 copy_rvec(x[ci[0]],cmax);
376 for(i=0; i<nc; i++) {
378 for(m=0; m<DIM; m++) {
379 if (x[ai][m] < cmin[m])
381 else if (x[ai][m] > cmax[m])
385 calc_box_center(ecenter,box,box_center);
387 dx[m] = box_center[m]-(cmin[m]+cmax[m])*0.5;
394 static void mk_filenm(char *base,const char *ext,int ndigit,int file_nr,
400 strcpy(out_file,base);
408 strncat(out_file,"00000000000",ndigit-nd);
409 sprintf(nbuf,"%d.",file_nr);
410 strcat(out_file,nbuf);
411 strcat(out_file,ext);
414 void check_trn(const char *fn)
416 if ((fn2ftp(fn) != efTRJ) && (fn2ftp(fn) != efTRR))
417 gmx_fatal(FARGS,"%s is not a trajectory file, exiting\n",fn);
420 #ifndef GMX_NATIVE_WINDOWS
421 void do_trunc(const char *fn, real t0)
433 gmx_fatal(FARGS,"You forgot to set the truncation time");
435 /* Check whether this is a .trj file */
438 in = open_trn(fn,"r");
439 fp = gmx_fio_getfp(in);
441 fprintf(stderr,"Sorry, can not trunc %s, truncation of this filetype is not supported\n",fn);
445 fpos = gmx_fio_ftell(in);
447 while (!bStop && fread_trnheader(in,&sh,&bOK)) {
448 fread_htrn(in,&sh,NULL,NULL,NULL,NULL);
452 gmx_fseek(fp, fpos, SEEK_SET);
457 fprintf(stderr,"Do you REALLY want to truncate this trajectory (%s) at:\n"
458 "frame %d, time %g, bytes %ld ??? (type YES if so)\n",
459 fn,j,t,(long int)fpos);
460 if(1 != scanf("%s",yesno))
462 gmx_fatal(FARGS,"Error reading user input");
464 if (strcmp(yesno,"YES") == 0) {
465 fprintf(stderr,"Once again, I'm gonna DO this...\n");
467 if(0 != truncate(fn,fpos))
469 gmx_fatal(FARGS,"Error truncating file %s",fn);
473 fprintf(stderr,"Ok, I'll forget about it\n");
477 fprintf(stderr,"Already at end of file (t=%g)...\n",t);
484 int gmx_trjconv(int argc,char *argv[])
486 const char *desc[] = {
487 "[TT]trjconv[tt] can convert trajectory files in many ways:[BR]",
488 "[BB]1.[bb] from one format to another[BR]",
489 "[BB]2.[bb] select a subset of atoms[BR]",
490 "[BB]3.[bb] change the periodicity representation[BR]",
491 "[BB]4.[bb] keep multimeric molecules together[BR]",
492 "[BB]5.[bb] center atoms in the box[BR]",
493 "[BB]6.[bb] fit atoms to reference structure[BR]",
494 "[BB]7.[bb] reduce the number of frames[BR]",
495 "[BB]8.[bb] change the timestamps of the frames ",
496 "([TT]-t0[tt] and [TT]-timestep[tt])[BR]",
497 "[BB]9.[bb] cut the trajectory in small subtrajectories according",
498 "to information in an index file. This allows subsequent analysis of",
499 "the subtrajectories that could, for example, be the result of a",
500 "cluster analysis. Use option [TT]-sub[tt].",
501 "This assumes that the entries in the index file are frame numbers and",
502 "dumps each group in the index file to a separate trajectory file.[BR]",
503 "[BB]10.[bb] select frames within a certain range of a quantity given",
504 "in an [TT].xvg[tt] file.[PAR]",
506 "The program [TT]trjcat[tt] is better suited for concatenating multiple trajectory files.",
509 "Currently seven formats are supported for input and output:",
510 "[TT].xtc[tt], [TT].trr[tt], [TT].trj[tt], [TT].gro[tt], [TT].g96[tt],",
511 "[TT].pdb[tt] and [TT].g87[tt].",
512 "The file formats are detected from the file extension.",
513 "The precision of [TT].xtc[tt] and [TT].gro[tt] output is taken from the",
514 "input file for [TT].xtc[tt], [TT].gro[tt] and [TT].pdb[tt],",
515 "and from the [TT]-ndec[tt] option for other input formats. The precision",
516 "is always taken from [TT]-ndec[tt], when this option is set.",
517 "All other formats have fixed precision. [TT].trr[tt] and [TT].trj[tt]",
518 "output can be single or double precision, depending on the precision",
519 "of the [TT]trjconv[tt] binary.",
520 "Note that velocities are only supported in",
521 "[TT].trr[tt], [TT].trj[tt], [TT].gro[tt] and [TT].g96[tt] files.[PAR]",
523 "Option [TT]-app[tt] can be used to",
524 "append output to an existing trajectory file.",
525 "No checks are performed to ensure integrity",
526 "of the resulting combined trajectory file.[PAR]",
528 "Option [TT]-sep[tt] can be used to write every frame to a separate",
529 "[TT].gro, .g96[tt] or [TT].pdb[tt] file. By default, all frames all written to one file.",
530 "[TT].pdb[tt] files with all frames concatenated can be viewed with",
531 "[TT]rasmol -nmrpdb[tt].[PAR]",
533 "It is possible to select part of your trajectory and write it out",
534 "to a new trajectory file in order to save disk space, e.g. for leaving",
535 "out the water from a trajectory of a protein in water.",
536 "[BB]ALWAYS[bb] put the original trajectory on tape!",
537 "We recommend to use the portable [TT].xtc[tt] format for your analysis",
538 "to save disk space and to have portable files.[PAR]",
540 "There are two options for fitting the trajectory to a reference",
541 "either for essential dynamics analysis, etc.",
542 "The first option is just plain fitting to a reference structure",
543 "in the structure file. The second option is a progressive fit",
544 "in which the first timeframe is fitted to the reference structure ",
545 "in the structure file to obtain and each subsequent timeframe is ",
546 "fitted to the previously fitted structure. This way a continuous",
547 "trajectory is generated, which might not be the case when using the",
548 "regular fit method, e.g. when your protein undergoes large",
549 "conformational transitions.[PAR]",
551 "Option [TT]-pbc[tt] sets the type of periodic boundary condition",
553 "[TT]* mol[tt] puts the center of mass of molecules in the box,",
554 "and requires a run input file to be supplied with [TT]-s[tt].[BR]",
555 "[TT]* res[tt] puts the center of mass of residues in the box.[BR]",
556 "[TT]* atom[tt] puts all the atoms in the box.[BR]",
557 "[TT]* nojump[tt] checks if atoms jump across the box and then puts",
558 "them back. This has the effect that all molecules",
559 "will remain whole (provided they were whole in the initial",
560 "conformation). [BB]Note[bb] that this ensures a continuous trajectory but",
561 "molecules may diffuse out of the box. The starting configuration",
562 "for this procedure is taken from the structure file, if one is",
563 "supplied, otherwise it is the first frame.[BR]",
564 "[TT]* cluster[tt] clusters all the atoms in the selected index",
565 "such that they are all closest to the center of mass of the cluster,",
566 "which is iteratively updated. [BB]Note[bb] that this will only give meaningful",
567 "results if you in fact have a cluster. Luckily that can be checked",
568 "afterwards using a trajectory viewer. Note also that if your molecules",
569 "are broken this will not work either.[BR]",
570 "The separate option [TT]-clustercenter[tt] can be used to specify an",
571 "approximate center for the cluster. This is useful e.g. if you have",
572 "two big vesicles, and you want to maintain their relative positions.[BR]",
573 "[TT]* whole[tt] only makes broken molecules whole.[PAR]",
575 "Option [TT]-ur[tt] sets the unit cell representation for options",
576 "[TT]mol[tt], [TT]res[tt] and [TT]atom[tt] of [TT]-pbc[tt].",
577 "All three options give different results for triclinic boxes and",
578 "identical results for rectangular boxes.",
579 "[TT]rect[tt] is the ordinary brick shape.",
580 "[TT]tric[tt] is the triclinic unit cell.",
581 "[TT]compact[tt] puts all atoms at the closest distance from the center",
582 "of the box. This can be useful for visualizing e.g. truncated octahedra",
583 "or rhombic dodecahedra. The center for options [TT]tric[tt] and [TT]compact[tt]",
584 "is [TT]tric[tt] (see below), unless the option [TT]-boxcenter[tt]",
585 "is set differently.[PAR]",
587 "Option [TT]-center[tt] centers the system in the box. The user can",
588 "select the group which is used to determine the geometrical center.",
589 "Option [TT]-boxcenter[tt] sets the location of the center of the box",
590 "for options [TT]-pbc[tt] and [TT]-center[tt]. The center options are:",
591 "[TT]tric[tt]: half of the sum of the box vectors,",
592 "[TT]rect[tt]: half of the box diagonal,",
593 "[TT]zero[tt]: zero.",
594 "Use option [TT]-pbc mol[tt] in addition to [TT]-center[tt] when you",
595 "want all molecules in the box after the centering.[PAR]",
597 "It is not always possible to use combinations of [TT]-pbc[tt],",
598 "[TT]-fit[tt], [TT]-ur[tt] and [TT]-center[tt] to do exactly what",
599 "you want in one call to [TT]trjconv[tt]. Consider using multiple",
600 "calls, and check out the GROMACS website for suggestions.[PAR]",
602 "With [TT]-dt[tt], it is possible to reduce the number of ",
603 "frames in the output. This option relies on the accuracy of the times",
604 "in your input trajectory, so if these are inaccurate use the",
605 "[TT]-timestep[tt] option to modify the time (this can be done",
606 "simultaneously). For making smooth movies, the program [TT]g_filter[tt]",
607 "can reduce the number of frames while using low-pass frequency",
608 "filtering, this reduces aliasing of high frequency motions.[PAR]",
610 "Using [TT]-trunc[tt] [TT]trjconv[tt] can truncate [TT].trj[tt] in place, i.e.",
611 "without copying the file. This is useful when a run has crashed",
612 "during disk I/O (i.e. full disk), or when two contiguous",
613 "trajectories must be concatenated without having double frames.[PAR]",
615 "Option [TT]-dump[tt] can be used to extract a frame at or near",
616 "one specific time from your trajectory.[PAR]",
618 "Option [TT]-drop[tt] reads an [TT].xvg[tt] file with times and values.",
619 "When options [TT]-dropunder[tt] and/or [TT]-dropover[tt] are set,",
620 "frames with a value below and above the value of the respective options",
621 "will not be written."
637 const char *pbc_opt[epNR + 1] =
638 { NULL, "none", "mol", "res", "atom", "nojump", "cluster", "whole",
642 const char *unitcell_opt[euNR+1] =
643 { NULL, "rect", "tric", "compact", NULL };
646 { ecSel, ecTric, ecRect, ecZero, ecNR};
647 const char *center_opt[ecNR+1] =
648 { NULL, "tric", "rect", "zero", NULL };
654 efSel, efNone, efFit, efFitXY, efReset, efResetXY, efPFit, efNR
656 const char *fit[efNR + 1] =
657 { NULL, "none", "rot+trans", "rotxy+transxy", "translation", "transxy",
658 "progressive", NULL };
660 static gmx_bool bAppend=FALSE,bSeparate=FALSE,bVels=TRUE,bForce=FALSE,bCONECT=FALSE;
661 static gmx_bool bCenter=FALSE;
662 static int skip_nr=1,ndec=3,nzero=0;
663 static real tzero=0,delta_t=0,timestep=0,ttrunc=-1,tdump=-1,split_t=0;
664 static rvec newbox = {0,0,0}, shift = {0,0,0}, trans = {0,0,0};
665 static char *exec_command=NULL;
666 static real dropunder=0,dropover=0;
667 static gmx_bool bRound=FALSE;
668 static rvec clustercenter = {0,0,0};
673 { "-skip", FALSE, etINT,
674 { &skip_nr }, "Only write every nr-th frame" },
675 { "-dt", FALSE, etTIME,
677 "Only write frame when t MOD dt = first time (%t)" },
678 { "-round", FALSE, etBOOL,
679 { &bRound }, "Round measurements to nearest picosecond"
681 { "-dump", FALSE, etTIME,
682 { &tdump }, "Dump frame nearest specified time (%t)" },
683 { "-t0", FALSE, etTIME,
685 "Starting time (%t) (default: don't change)" },
686 { "-timestep", FALSE, etTIME,
688 "Change time step between input frames (%t)" },
689 { "-pbc", FALSE, etENUM,
691 "PBC treatment (see help text for full description)" },
692 { "-ur", FALSE, etENUM,
693 { unitcell_opt }, "Unit-cell representation" },
694 { "-center", FALSE, etBOOL,
695 { &bCenter }, "Center atoms in box" },
696 { "-boxcenter", FALSE, etENUM,
697 { center_opt }, "Center for -pbc and -center" },
698 { "-box", FALSE, etRVEC,
700 "Size for new cubic box (default: read from input)" },
701 { "-clustercenter", FALSE, etRVEC,
703 "Optional starting point for pbc cluster option" },
704 { "-trans", FALSE, etRVEC,
706 "All coordinates will be translated by trans. This "
707 "can advantageously be combined with -pbc mol -ur "
709 { "-shift", FALSE, etRVEC,
711 "All coordinates will be shifted by framenr*shift" },
712 { "-fit", FALSE, etENUM,
714 "Fit molecule to ref structure in the structure file" },
715 { "-ndec", FALSE, etINT,
717 "Precision for .xtc and .gro writing in number of "
719 { "-vel", FALSE, etBOOL,
720 { &bVels }, "Read and write velocities if possible" },
721 { "-force", FALSE, etBOOL,
722 { &bForce }, "Read and write forces if possible" },
723 #ifndef GMX_NATIVE_WINDOWS
724 { "-trunc", FALSE, etTIME,
726 "Truncate input trajectory file after this time (%t)" },
728 { "-exec", FALSE, etSTR,
730 "Execute command for every output frame with the "
731 "frame number as argument" },
732 { "-app", FALSE, etBOOL,
733 { &bAppend }, "Append output" },
734 { "-split", FALSE, etTIME,
736 "Start writing new file when t MOD split = first "
738 { "-sep", FALSE, etBOOL,
740 "Write each frame to a separate .gro, .g96 or .pdb "
742 { "-nzero", FALSE, etINT,
744 "If the -sep flag is set, use these many digits "
745 "for the file numbers and prepend zeros as needed" },
746 { "-dropunder", FALSE, etREAL,
747 { &dropunder }, "Drop all frames below this value" },
748 { "-dropover", FALSE, etREAL,
749 { &dropover }, "Drop all frames above this value" },
750 { "-conect", FALSE, etBOOL,
752 "Add conect records when writing [TT].pdb[tt] files. Useful "
753 "for visualization of non-standard molecules, e.g. "
754 "coarse grained ones" } };
755 #define NPA asize(pa)
758 t_trxstatus *trxout=NULL;
760 int ftp,ftpin=0,file_nr;
763 rvec *xmem=NULL,*vmem=NULL,*fmem=NULL;
764 rvec *xp=NULL,x_shift,hbox,box_center,dx;
765 real xtcpr, lambda,*w_rls=NULL;
766 int m,i,d,frame,outframe,natoms,nout,ncent,nre,newstep=0,model_nr;
771 t_atoms *atoms=NULL,useatoms;
773 atom_id *index,*cindex;
777 int ifit,irms,my_clust=-1;
778 atom_id *ind_fit,*ind_rms;
779 char *gn_fit,*gn_rms;
780 t_cluster_ndx *clust=NULL;
781 t_trxstatus **clust_status=NULL;
782 int *clust_status_id=NULL;
785 int ndrop=0,ncol,drop0=0,drop1=0,dropuse=0;
787 real tshift=0,t0=-1,dt=0.001,prec;
788 gmx_bool bFit,bFitXY,bPFit,bReset;
790 gmx_rmpbc_t gpbc=NULL;
791 gmx_bool bRmPBC,bPBCWhole,bPBCcomRes,bPBCcomMol,bPBCcomAtom,bPBC,bNoJump,bCluster;
792 gmx_bool bCopy,bDoIt,bIndex,bTDump,bSetTime,bTPS=FALSE,bDTset=FALSE;
793 gmx_bool bExec,bTimeStep=FALSE,bDumpFrame=FALSE,bSetPrec,bNeedPrec;
794 gmx_bool bHaveFirstFrame,bHaveNextFrame,bSetBox,bSetUR,bSplit=FALSE;
795 gmx_bool bSubTraj=FALSE,bDropUnder=FALSE,bDropOver=FALSE,bTrans=FALSE;
796 gmx_bool bWriteFrame,bSplitHere;
797 const char *top_file,*in_file,*out_file=NULL;
798 char out_file2[256],*charpt;
799 char *outf_base=NULL;
800 const char *outf_ext=NULL;
801 char top_title[256],title[256],command[256],filemode[5];
803 gmx_bool bWarnCompact=FALSE;
808 { efTRX, "-f", NULL, ffREAD },
809 { efTRO, "-o", NULL, ffWRITE },
810 { efTPS, NULL, NULL, ffOPTRD },
811 { efNDX, NULL, NULL, ffOPTRD },
812 { efNDX, "-fr", "frames", ffOPTRD },
813 { efNDX, "-sub", "cluster", ffOPTRD },
814 { efXVG, "-drop","drop", ffOPTRD }
816 #define NFILE asize(fnm)
818 CopyRight(stderr,argv[0]);
819 parse_common_args(&argc,argv,
820 PCA_CAN_BEGIN | PCA_CAN_END | PCA_CAN_VIEW |
821 PCA_TIME_UNIT | PCA_BE_NICE,
822 NFILE,fnm,NPA,pa,asize(desc),desc,
825 top_file = ftp2fn(efTPS,NFILE,fnm);
828 /* Check command line */
829 in_file=opt2fn("-f",NFILE,fnm);
832 #ifndef GMX_NATIVE_WINDOWS
833 do_trunc(in_file,ttrunc);
837 /* mark active cmdline options */
838 bSetBox = opt2parg_bSet("-box", NPA, pa);
839 bSetTime = opt2parg_bSet("-t0", NPA, pa);
840 bSetPrec = opt2parg_bSet("-ndec", NPA, pa);
841 bSetUR = opt2parg_bSet("-ur", NPA, pa);
842 bExec = opt2parg_bSet("-exec", NPA, pa);
843 bTimeStep = opt2parg_bSet("-timestep", NPA, pa);
844 bTDump = opt2parg_bSet("-dump", NPA, pa);
845 bDropUnder= opt2parg_bSet("-dropunder", NPA, pa);
846 bDropOver = opt2parg_bSet("-dropover", NPA, pa);
847 bTrans = opt2parg_bSet("-trans",NPA,pa);
848 bSplit = (split_t != 0);
850 /* parse enum options */
851 fit_enum = nenum(fit);
852 bFit = (fit_enum==efFit || fit_enum==efFitXY);
853 bFitXY = fit_enum==efFitXY;
854 bReset = (fit_enum==efReset || fit_enum==efResetXY);
855 bPFit = fit_enum==efPFit;
856 pbc_enum = nenum(pbc_opt);
857 bPBCWhole = pbc_enum==epWhole;
858 bPBCcomRes = pbc_enum==epComRes;
859 bPBCcomMol = pbc_enum==epComMol;
860 bPBCcomAtom= pbc_enum==epComAtom;
861 bNoJump = pbc_enum==epNojump;
862 bCluster = pbc_enum==epCluster;
863 bPBC = pbc_enum!=epNone;
864 unitcell_enum = nenum(unitcell_opt);
865 ecenter = nenum(center_opt) - ecTric;
867 /* set and check option dependencies */
868 if (bPFit) bFit = TRUE; /* for pfit, fit *must* be set */
869 if (bFit) bReset = TRUE; /* for fit, reset *must* be set */
872 nfitdim = (fit_enum==efFitXY || fit_enum==efResetXY) ? 2 : 3;
873 bRmPBC = bFit || bPBCWhole || bPBCcomRes || bPBCcomMol;
876 if (!(bPBCcomRes || bPBCcomMol || bPBCcomAtom)) {
878 "WARNING: Option for unitcell representation (-ur %s)\n"
879 " only has effect in combination with -pbc %s, %s or %s.\n"
880 " Ingoring unitcell representation.\n\n",
881 unitcell_opt[0],pbc_opt[2],pbc_opt[3],pbc_opt[4]);
886 gmx_fatal(FARGS,"PBC condition treatment does not work together with rotational fit.\n"
887 "Please do the PBC condition treatment first and then run trjconv in a second step\n"
888 "for the rotational fit.\n"
889 "First doing the rotational fit and then doing the PBC treatment gives incorrect\n"
893 /* ndec is in nr of decimal places, prec is a multiplication factor: */
895 for (i=0; i<ndec; i++)
898 bIndex=ftp2bSet(efNDX,NFILE,fnm);
901 /* Determine output type */
902 out_file=opt2fn("-o",NFILE,fnm);
903 ftp=fn2ftp(out_file);
904 fprintf(stderr,"Will write %s: %s\n",ftp2ext(ftp),ftp2desc(ftp));
905 bNeedPrec = (ftp==efXTC || ftp==efGRO);
907 /* check if velocities are possible in input and output files */
908 ftpin=fn2ftp(in_file);
909 bVels= (ftp==efTRR || ftp==efTRJ || ftp==efGRO || ftp==efG96)
910 && (ftpin==efTRR || ftpin==efTRJ || ftpin==efGRO || ftpin==efG96 ||
913 if (bSeparate || bSplit) {
914 outf_ext = strrchr(out_file,'.');
915 if (outf_ext == NULL)
916 gmx_fatal(FARGS,"Output file name '%s' does not contain a '.'",out_file);
917 outf_base = strdup(out_file);
918 outf_base[outf_ext - out_file] = '\0';
921 bSubTraj = opt2bSet("-sub",NFILE,fnm);
923 if ((ftp != efXTC) && (ftp != efTRN))
924 gmx_fatal(FARGS,"Can only use the sub option with output file types "
926 clust = cluster_index(NULL,opt2fn("-sub",NFILE,fnm));
928 /* Check for number of files disabled, as FOPEN_MAX is not the correct
929 * number to check for. In my linux box it is only 16.
931 if (0 && (clust->clust->nr > FOPEN_MAX-4))
932 gmx_fatal(FARGS,"Can not open enough (%d) files to write all the"
933 " trajectories.\ntry splitting the index file in %d parts.\n"
935 clust->clust->nr,1+clust->clust->nr/FOPEN_MAX,FOPEN_MAX);
936 gmx_warning("The -sub option could require as many open output files as there are\n"
937 "index groups in the file (%d). If you get I/O errors opening new files,\n"
938 "try reducing the number of index groups in the file, and perhaps\n"
939 "using trjconv -sub several times on different chunks of your index file.\n",
942 snew(clust_status,clust->clust->nr);
943 snew(clust_status_id,clust->clust->nr);
944 snew(nfwritten,clust->clust->nr);
945 for(i=0; (i<clust->clust->nr); i++)
947 clust_status[i] = NULL;
948 clust_status_id[i] = -1;
950 bSeparate = bSplit = FALSE;
956 /* Determine whether to read a topology */
957 bTPS = (ftp2bSet(efTPS,NFILE,fnm) ||
958 bRmPBC || bReset || bPBCcomMol || bCluster ||
959 (ftp == efGRO) || (ftp == efPDB) || bCONECT);
961 /* Determine if when can read index groups */
962 bIndex = (bIndex || bTPS);
965 read_tps_conf(top_file,top_title,&top,&ePBC,&xp,NULL,top_box,
966 bReset || bPBCcomRes);
969 if (0 == top.mols.nr && (bCluster || bPBCcomMol))
971 gmx_fatal(FARGS,"Option -pbc %s requires a .tpr file for the -s option",pbc_opt[pbc_enum]);
974 /* top_title is only used for gro and pdb,
975 * the header in such a file is top_title t= ...
976 * to prevent a double t=, remove it from top_title
978 if ((charpt=strstr(top_title," t= ")))
982 gc = gmx_conect_generate(&top);
984 gpbc = gmx_rmpbc_init(&top.idef,ePBC,top.atoms.nr,top_box);
987 /* get frame number index */
989 if (opt2bSet("-fr",NFILE,fnm)) {
990 printf("Select groups of frame number indices:\n");
991 rd_index(opt2fn("-fr",NFILE,fnm),1,&nrfri,(atom_id **)&frindex,&frname);
993 for(i=0; i<nrfri; i++)
994 fprintf(debug,"frindex[%4d]=%4d\n",i,frindex[i]);
997 /* get index groups etc. */
999 printf("Select group for %s fit\n",
1000 bFit?"least squares":"translational");
1001 get_index(atoms,ftp2fn_null(efNDX,NFILE,fnm),
1002 1,&ifit,&ind_fit,&gn_fit);
1006 gmx_fatal(FARGS,"Need at least 2 atoms to fit!\n");
1008 fprintf(stderr,"WARNING: fitting with only 2 atoms is not unique\n");
1011 else if (bCluster) {
1012 printf("Select group for clustering\n");
1013 get_index(atoms,ftp2fn_null(efNDX,NFILE,fnm),
1014 1,&ifit,&ind_fit,&gn_fit);
1019 printf("Select group for centering\n");
1020 get_index(atoms,ftp2fn_null(efNDX,NFILE,fnm),
1021 1,&ncent,&cindex,&grpnm);
1023 printf("Select group for output\n");
1024 get_index(atoms,ftp2fn_null(efNDX,NFILE,fnm),
1025 1,&nout,&index,&grpnm);
1027 /* no index file, so read natoms from TRX */
1028 if (!read_first_frame(oenv,&status,in_file,&fr,TRX_DONT_SKIP))
1029 gmx_fatal(FARGS,"Could not read a frame from %s",in_file);
1034 for(i=0;i<natoms;i++)
1044 snew(w_rls,atoms->nr);
1045 for(i=0; (i<ifit); i++)
1046 w_rls[ind_fit[i]]=atoms->atom[ind_fit[i]].m;
1048 /* Restore reference structure and set to origin,
1049 store original location (to put structure back) */
1051 gmx_rmpbc(gpbc,top.atoms.nr,top_box,xp);
1052 copy_rvec(xp[index[0]],x_shift);
1053 reset_x_ndim(nfitdim,ifit,ind_fit,atoms->nr,NULL,xp,w_rls);
1054 rvec_dec(x_shift,xp[index[0]]);
1056 clear_rvec(x_shift);
1058 if (bDropUnder || bDropOver) {
1059 /* Read the .xvg file with the drop values */
1060 fprintf(stderr,"\nReading drop file ...");
1061 ndrop = read_xvg(opt2fn("-drop",NFILE,fnm),&dropval,&ncol);
1062 fprintf(stderr," %d time points\n",ndrop);
1063 if (ndrop == 0 || ncol < 2)
1064 gmx_fatal(FARGS,"Found no data points in %s",
1065 opt2fn("-drop",NFILE,fnm));
1070 /* Make atoms struct for output in GRO or PDB files */
1071 if ((ftp == efGRO) || ((ftp == efG96) && bTPS) || (ftp == efPDB)) {
1072 /* get memory for stuff to go in .pdb file */
1073 init_t_atoms(&useatoms,atoms->nr,FALSE);
1074 sfree(useatoms.resinfo);
1075 useatoms.resinfo = atoms->resinfo;
1076 for(i=0;(i<nout);i++) {
1077 useatoms.atomname[i]=atoms->atomname[index[i]];
1078 useatoms.atom[i]=atoms->atom[index[i]];
1079 useatoms.nres=max(useatoms.nres,useatoms.atom[i].resind+1);
1083 /* select what to read */
1084 if (ftp==efTRR || ftp==efTRJ)
1089 flags = flags | TRX_READ_V;
1091 flags = flags | TRX_READ_F;
1093 /* open trx file for reading */
1094 bHaveFirstFrame = read_first_frame(oenv,&status,in_file,&fr,flags);
1096 fprintf(stderr,"\nPrecision of %s is %g (nm)\n",in_file,1/fr.prec);
1098 if (bSetPrec || !fr.bPrec)
1099 fprintf(stderr,"\nSetting output precision to %g (nm)\n",1/prec);
1101 fprintf(stderr,"Using output precision of %g (nm)\n",1/prec);
1104 if (bHaveFirstFrame) {
1105 set_trxframe_ePBC(&fr,ePBC);
1110 tshift=tzero-fr.time;
1114 /* open output for writing */
1115 if ((bAppend) && (gmx_fexist(out_file))) {
1116 strcpy(filemode,"a");
1117 fprintf(stderr,"APPENDING to existing file %s\n",out_file);
1119 strcpy(filemode,"w");
1126 if (!bSplit && !bSubTraj)
1127 trxout = open_trx(out_file,filemode);
1132 if (( !bSeparate && !bSplit ) && !bSubTraj)
1133 out=ffopen(out_file,filemode);
1139 /* check if index is meaningful */
1140 for(i=0; i<nout; i++) {
1141 if (index[i] >= natoms)
1143 "Index[%d] %d is larger than the number of atoms in the\n"
1144 "trajectory file (%d). There is a mismatch in the contents\n"
1145 "of your -f, -s and/or -n files.",i,index[i]+1,natoms);
1146 bCopy = bCopy || (i != index[i]);
1159 fprintf(gmx_fio_getfp(trx_get_fileio(trxout)),
1160 "Generated by %s. #atoms=%d, a BOX is"
1161 " stored in this file.\n",Program(),nout);
1163 /* Start the big loop over frames */
1170 /* Main loop over frames */
1178 /*if (frame >= clust->clust->nra)
1179 gmx_fatal(FARGS,"There are more frames in the trajectory than in the cluster index file\n");*/
1180 if (frame > clust->maxframe)
1183 my_clust = clust->inv_clust[frame];
1184 if ((my_clust < 0) || (my_clust >= clust->clust->nr) ||
1185 (my_clust == NO_ATID))
1190 /* generate new box */
1192 for (m=0; m<DIM; m++)
1193 fr.box[m][m] = newbox[m];
1197 for(i=0; i<natoms; i++)
1198 rvec_inc(fr.x[i],trans);
1202 /* determine timestep */
1211 /* This is not very elegant, as one can not dump a frame after
1212 * a timestep with is more than twice as small as the first one. */
1213 bDumpFrame = (fr.time > tdump-0.5*dt) && (fr.time <= tdump+0.5*dt);
1217 /* determine if an atom jumped across the box and reset it if so */
1218 if (bNoJump && (bTPS || frame!=0)) {
1219 for(d=0; d<DIM; d++)
1220 hbox[d] = 0.5*fr.box[d][d];
1221 for(i=0; i<natoms; i++) {
1223 rvec_dec(fr.x[i],x_shift);
1224 for(m=DIM-1; m>=0; m--)
1226 while (fr.x[i][m]-xp[i][m] <= -hbox[m])
1228 fr.x[i][d] += fr.box[m][d];
1229 while (fr.x[i][m]-xp[i][m] > hbox[m])
1231 fr.x[i][d] -= fr.box[m][d];
1235 else if (bCluster) {
1238 calc_pbc_cluster(ecenter,ifit,&top,ePBC,fr.x,ind_fit,com,fr.box,clustercenter);
1242 /* Now modify the coords according to the flags,
1243 for normal fit, this is only done for output frames */
1245 gmx_rmpbc_trxfr(gpbc,&fr);
1247 reset_x_ndim(nfitdim,ifit,ind_fit,natoms,NULL,fr.x,w_rls);
1248 do_fit(natoms,w_rls,xp,fr.x);
1251 /* store this set of coordinates for future use */
1252 if (bPFit || bNoJump) {
1255 for(i=0; (i<natoms); i++) {
1256 copy_rvec(fr.x[i],xp[i]);
1257 rvec_inc(fr.x[i],x_shift);
1262 /* see if we have a frame from the frame index group */
1263 for(i=0; i<nrfri && !bDumpFrame; i++)
1264 bDumpFrame = frame == frindex[i];
1265 if (debug && bDumpFrame)
1266 fprintf(debug,"dumping %d\n",frame);
1269 ( ( !bTDump && !frindex && frame % skip_nr == 0 ) || bDumpFrame );
1271 if (bWriteFrame && (bDropUnder || bDropOver)) {
1272 while (dropval[0][drop1]<fr.time && drop1+1<ndrop) {
1276 if (fabs(dropval[0][drop0] - fr.time)
1277 < fabs(dropval[0][drop1] - fr.time)) {
1282 if ((bDropUnder && dropval[1][dropuse] < dropunder) ||
1283 (bDropOver && dropval[1][dropuse] > dropover))
1284 bWriteFrame = FALSE;
1291 fr.time = tzero+frame*timestep;
1297 fprintf(stderr,"\nDumping frame at t= %g %s\n",
1298 output_env_conv_time(oenv,fr.time),output_env_get_time_unit(oenv));
1300 /* check for writing at each delta_t */
1301 bDoIt=(delta_t == 0);
1305 bDoIt=bRmod(fr.time,tzero, delta_t);
1307 /* round() is not C89 compatible, so we do this: */
1308 bDoIt=bRmod(floor(fr.time+0.5),floor(tzero+0.5),
1309 floor(delta_t+0.5));
1312 if (bDoIt || bTDump) {
1313 /* print sometimes */
1314 if ( ((outframe % SKIP) == 0) || (outframe < SKIP) )
1315 fprintf(stderr," -> frame %6d time %8.3f \r",
1316 outframe,output_env_conv_time(oenv,fr.time));
1319 /* Now modify the coords according to the flags,
1320 for PFit we did this already! */
1323 gmx_rmpbc_trxfr(gpbc,&fr);
1326 reset_x_ndim(nfitdim,ifit,ind_fit,natoms,NULL,fr.x,w_rls);
1328 do_fit_ndim(nfitdim,natoms,w_rls,xp,fr.x);
1330 for(i=0; i<natoms; i++)
1331 rvec_inc(fr.x[i],x_shift);
1335 center_x(ecenter,fr.x,fr.box,natoms,ncent,cindex);
1339 switch (unitcell_enum) {
1341 put_atoms_in_box(ePBC,fr.box,natoms,fr.x);
1344 put_atoms_in_triclinic_unitcell(ecenter,fr.box,natoms,fr.x);
1347 warn = put_atoms_in_compact_unitcell(ePBC,ecenter,fr.box,
1349 if (warn && !bWarnCompact) {
1350 fprintf(stderr,"\n%s\n",warn);
1351 bWarnCompact = TRUE;
1357 put_residue_com_in_box(unitcell_enum,ecenter,
1358 natoms,atoms->atom,ePBC,fr.box,fr.x);
1361 put_molecule_com_in_box(unitcell_enum,ecenter,
1363 natoms,atoms->atom,ePBC,fr.box,fr.x);
1365 /* Copy the input trxframe struct to the output trxframe struct */
1367 frout.bV = (frout.bV && bVels);
1368 frout.bF = (frout.bF && bForce);
1369 frout.natoms = nout;
1370 if (bNeedPrec && (bSetPrec || !fr.bPrec)) {
1382 for(i=0; i<nout; i++) {
1383 copy_rvec(fr.x[index[i]],frout.x[i]);
1385 copy_rvec(fr.v[index[i]],frout.v[i]);
1388 copy_rvec(fr.f[index[i]],frout.f[i]);
1393 if (opt2parg_bSet("-shift",NPA,pa))
1394 for(i=0; i<nout; i++)
1395 for (d=0; d<DIM; d++)
1396 frout.x[i][d] += outframe*shift[d];
1399 bSplitHere = bSplit && bRmod(fr.time,tzero, split_t);
1402 /* round() is not C89 compatible, so we do this: */
1403 bSplitHere = bSplit && bRmod(floor(fr.time+0.5),
1405 floor(split_t+0.5));
1407 if (bSeparate || bSplitHere)
1408 mk_filenm(outf_base,ftp2ext(ftp),nzero,file_nr,out_file2);
1418 trxout = open_trx(out_file2,filemode);
1421 if (my_clust != -1) {
1423 if (clust_status_id[my_clust] == -1) {
1424 sprintf(buf,"%s.%s",clust->grpname[my_clust],ftp2ext(ftp));
1425 clust_status[my_clust] = open_trx(buf,"w");
1426 clust_status_id[my_clust] = 1;
1429 else if (clust_status_id[my_clust] == -2)
1430 gmx_fatal(FARGS,"File %s.xtc should still be open (%d open .xtc files)\n""in order to write frame %d. my_clust = %d",
1431 clust->grpname[my_clust],ntrxopen,frame,
1433 write_trxframe(clust_status[my_clust],&frout,gc);
1434 nfwritten[my_clust]++;
1435 if (nfwritten[my_clust] ==
1436 (clust->clust->index[my_clust+1]-
1437 clust->clust->index[my_clust])) {
1438 close_trx(clust_status[my_clust]);
1439 clust_status[my_clust] = NULL;
1440 clust_status_id[my_clust] = -2;
1443 gmx_fatal(FARGS,"Less than zero open .xtc files!");
1448 write_trxframe(trxout,&frout,gc);
1453 sprintf(title,"Generated by trjconv : %s t= %9.5f",
1455 if (bSeparate || bSplitHere)
1456 out=ffopen(out_file2,"w");
1459 write_hconf_p(out,title,&useatoms,prec2ndec(frout.prec),
1460 frout.x,frout.bV?frout.v:NULL,frout.box);
1463 fprintf(out,"REMARK GENERATED BY TRJCONV\n");
1464 sprintf(title,"%s t= %9.5f",top_title,frout.time);
1465 /* if reading from pdb, we want to keep the original
1466 model numbering else we write the output frame
1467 number plus one, because model 0 is not allowed in pdb */
1468 if (ftpin==efPDB && fr.bStep && fr.step > model_nr)
1472 write_pdbfile(out,title,&useatoms,frout.x,
1473 frout.ePBC,frout.box,' ',model_nr,gc,TRUE);
1476 frout.title = title;
1477 if (bSeparate || bTDump) {
1478 frout.bTitle = TRUE;
1480 frout.bAtoms = TRUE;
1481 frout.atoms = &useatoms;
1482 frout.bStep = FALSE;
1483 frout.bTime = FALSE;
1485 frout.bTitle = (outframe == 0);
1486 frout.bAtoms = FALSE;
1490 write_g96_conf(out,&frout,-1,NULL);
1498 gmx_fatal(FARGS,"DHE, ftp=%d\n",ftp);
1500 if (bSeparate || bSplitHere)
1503 /* execute command */
1506 sprintf(c,"%s %d",exec_command,file_nr-1);
1507 /*fprintf(stderr,"Executing '%s'\n",c);*/
1508 #ifdef GMX_NO_SYSTEM
1509 printf("Warning-- No calls to system(3) supported on this platform.");
1510 printf("Warning-- Skipping execution of 'system(\"%s\")'.", c);
1514 gmx_fatal(FARGS,"Error executing command: %s",c);
1522 bHaveNextFrame=read_next_frame(oenv,status,&fr);
1523 } while (!(bTDump && bDumpFrame) && bHaveNextFrame);
1526 if (!bHaveFirstFrame || (bTDump && !bDumpFrame))
1527 fprintf(stderr,"\nWARNING no output, "
1528 "last frame read at t=%g\n",fr.time);
1529 fprintf(stderr,"\n");
1535 gmx_rmpbc_done(gpbc);
1539 else if (out != NULL)
1542 for(i=0; (i<clust->clust->nr); i++)
1543 if (clust_status[i] )
1544 close_trx(clust_status[i]);
1548 do_view(oenv,out_file,NULL);