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.
70 enum { euSel,euRect, euTric, euCompact, euNR};
73 static void calc_pbc_cluster(int ecenter,int nrefat,t_topology *top,int ePBC,
74 rvec x[],atom_id index[],
75 rvec clust_com,matrix box, rvec clustercenter)
77 int m,i,j,j0,j1,jj,ai,aj;
80 rvec dx,xtest,box_center;
92 calc_box_center(ecenter,box,box_center);
94 /* Initiate the pbc structure */
95 memset(&pbc,0,sizeof(pbc));
96 set_pbc(&pbc,ePBC,box);
98 /* Convert atom index to molecular */
100 molind = top->mols.index;
106 snew(bTmp,top->atoms.nr);
108 for(i=0; (i<nrefat); i++) {
109 /* Mark all molecules in the index */
112 /* Binary search assuming the molecules are sorted */
116 if (ai < molind[j0+1])
118 else if (ai >= molind[j1])
122 if (ai < molind[jj+1])
130 /* Double check whether all atoms in all molecules that are marked are part
131 * of the cluster. Simultaneously compute the center of geometry.
133 min_dist2 = 10*sqr(trace(box));
136 for(i=0; i<nmol; i++)
138 for(j=molind[i]; j<molind[i+1]; j++)
140 if (bMol[i] && !bTmp[j])
142 gmx_fatal(FARGS,"Molecule %d marked for clustering but not atom %d in it - check your index!",i+1,j+1);
144 else if (!bMol[i] && bTmp[j])
146 gmx_fatal(FARGS,"Atom %d marked for clustering but not molecule %d - this is an internal error...",j+1,i+1);
150 /* Make molecule whole, move 2nd and higher atom to same periodicity as 1st atom in molecule */
153 pbc_dx(&pbc,x[j],x[j-1],dx);
154 rvec_add(x[j-1],dx,x[j]);
156 /* Compute center of geometry of molecule - m_com[i] was zeroed when we did snew() on it! */
157 rvec_inc(m_com[i],x[j]);
162 /* Normalize center of geometry */
163 fac = 1.0/(molind[i+1]-molind[i]);
164 for(m=0; (m<DIM); m++)
166 /* Determine which molecule is closest to the center of the box */
167 pbc_dx(&pbc,box_center,m_com[i],dx);
170 if (tmp_r2 < min_dist2)
175 cluster[ncluster++]=i;
182 fprintf(stderr,"No molecules selected in the cluster\n");
185 else if (imol_center == -1)
187 fprintf(stderr,"No central molecules could be found\n");
192 added[nadded++] = imol_center;
193 bMol[imol_center] = FALSE;
195 while (nadded<ncluster)
197 /* Find min distance between cluster molecules and those remaining to be added */
198 min_dist2 = 10*sqr(trace(box));
201 /* Loop over added mols */
202 for(i=0;i<nadded;i++)
205 /* Loop over all mols */
206 for(j=0;j<ncluster;j++)
209 /* check those remaining to be added */
212 pbc_dx(&pbc,m_com[aj],m_com[ai],dx);
214 if (tmp_r2 < min_dist2)
224 /* Add the best molecule */
225 added[nadded++] = jmin;
227 /* Calculate the shift from the ai molecule */
228 pbc_dx(&pbc,m_com[jmin],m_com[imin],dx);
229 rvec_add(m_com[imin],dx,xtest);
230 rvec_sub(xtest,m_com[jmin],m_shift[jmin]);
231 rvec_inc(m_com[jmin],m_shift[jmin]);
233 for(j=molind[jmin]; j<molind[jmin+1]; j++)
235 rvec_inc(x[j],m_shift[jmin]);
237 fprintf(stdout,"\rClustering iteration %d of %d...",nadded,ncluster);
247 fprintf(stdout,"\n");
250 static void put_molecule_com_in_box(int unitcell_enum,int ecenter,
252 int natoms,t_atom atom[],
253 int ePBC,matrix box,rvec x[])
257 rvec com,new_com,shift,dx,box_center;
262 calc_box_center(ecenter,box,box_center);
263 set_pbc(&pbc,ePBC,box);
265 gmx_fatal(FARGS,"There are no molecule descriptions. I need a .tpr file for this pbc option.");
266 for(i=0; (i<mols->nr); i++) {
270 for(j=mols->index[i]; (j<mols->index[i+1] && j<natoms); j++) {
276 /* calculate final COM */
277 svmul(1.0/mtot, com, com);
279 /* check if COM is outside box */
280 copy_rvec(com,new_com);
281 switch (unitcell_enum) {
283 put_atoms_in_box(ePBC,box,1,&new_com);
286 put_atoms_in_triclinic_unitcell(ecenter,box,1,&new_com);
289 put_atoms_in_compact_unitcell(ePBC,ecenter,box,1,&new_com);
292 rvec_sub(new_com,com,shift);
293 if (norm2(shift) > 0) {
295 fprintf (debug,"\nShifting position of molecule %d "
296 "by %8.3f %8.3f %8.3f\n", i+1, PR_VEC(shift));
297 for(j=mols->index[i]; (j<mols->index[i+1] && j<natoms); j++) {
298 rvec_inc(x[j],shift);
304 static void put_residue_com_in_box(int unitcell_enum,int ecenter,
305 int natoms,t_atom atom[],
306 int ePBC,matrix box,rvec x[])
308 atom_id i, j, res_start, res_end, res_nat;
312 rvec box_center,com,new_com,shift;
314 calc_box_center(ecenter,box,box_center);
320 for(i=0; i<natoms+1; i++) {
321 if (i == natoms || (presnr != atom[i].resind && presnr != NOTSET)) {
322 /* calculate final COM */
324 res_nat = res_end - res_start;
325 svmul(1.0/mtot, com, com);
327 /* check if COM is outside box */
328 copy_rvec(com,new_com);
329 switch (unitcell_enum) {
331 put_atoms_in_box(ePBC,box,1,&new_com);
334 put_atoms_in_triclinic_unitcell(ecenter,box,1,&new_com);
337 put_atoms_in_compact_unitcell(ePBC,ecenter,box,1,&new_com);
340 rvec_sub(new_com,com,shift);
343 fprintf (debug,"\nShifting position of residue %d (atoms %u-%u) "
344 "by %g,%g,%g\n", atom[res_start].resind+1,
345 res_start+1, res_end+1, PR_VEC(shift));
346 for(j=res_start; j<res_end; j++)
347 rvec_inc(x[j],shift);
352 /* remember start of new residue */
362 presnr = atom[i].resind;
367 static void center_x(int ecenter,rvec x[],matrix box,int n,int nc,atom_id ci[])
370 rvec cmin,cmax,box_center,dx;
373 copy_rvec(x[ci[0]],cmin);
374 copy_rvec(x[ci[0]],cmax);
375 for(i=0; i<nc; i++) {
377 for(m=0; m<DIM; m++) {
378 if (x[ai][m] < cmin[m])
380 else if (x[ai][m] > cmax[m])
384 calc_box_center(ecenter,box,box_center);
386 dx[m] = box_center[m]-(cmin[m]+cmax[m])*0.5;
393 static void mk_filenm(char *base,const char *ext,int ndigit,int file_nr,
399 strcpy(out_file,base);
407 strncat(out_file,"00000000000",ndigit-nd);
408 sprintf(nbuf,"%d.",file_nr);
409 strcat(out_file,nbuf);
410 strcat(out_file,ext);
413 void check_trn(const char *fn)
415 if ((fn2ftp(fn) != efTRJ) && (fn2ftp(fn) != efTRR))
416 gmx_fatal(FARGS,"%s is not a trajectory file, exiting\n",fn);
419 #ifndef GMX_NATIVE_WINDOWS
420 void do_trunc(const char *fn, real t0)
432 gmx_fatal(FARGS,"You forgot to set the truncation time");
434 /* Check whether this is a .trj file */
437 in = open_trn(fn,"r");
438 fp = gmx_fio_getfp(in);
440 fprintf(stderr,"Sorry, can not trunc %s, truncation of this filetype is not supported\n",fn);
444 fpos = gmx_fio_ftell(in);
446 while (!bStop && fread_trnheader(in,&sh,&bOK)) {
447 fread_htrn(in,&sh,NULL,NULL,NULL,NULL);
451 gmx_fseek(fp, fpos, SEEK_SET);
456 fprintf(stderr,"Do you REALLY want to truncate this trajectory (%s) at:\n"
457 "frame %d, time %g, bytes %ld ??? (type YES if so)\n",
458 fn,j,t,(long int)fpos);
459 if(1 != scanf("%s",yesno))
461 gmx_fatal(FARGS,"Error reading user input");
463 if (strcmp(yesno,"YES") == 0) {
464 fprintf(stderr,"Once again, I'm gonna DO this...\n");
466 if(0 != truncate(fn,fpos))
468 gmx_fatal(FARGS,"Error truncating file %s",fn);
472 fprintf(stderr,"Ok, I'll forget about it\n");
476 fprintf(stderr,"Already at end of file (t=%g)...\n",t);
483 int gmx_trjconv(int argc,char *argv[])
485 const char *desc[] = {
486 "[TT]trjconv[tt] can convert trajectory files in many ways:[BR]",
487 "[BB]1.[bb] from one format to another[BR]",
488 "[BB]2.[bb] select a subset of atoms[BR]",
489 "[BB]3.[bb] change the periodicity representation[BR]",
490 "[BB]4.[bb] keep multimeric molecules together[BR]",
491 "[BB]5.[bb] center atoms in the box[BR]",
492 "[BB]6.[bb] fit atoms to reference structure[BR]",
493 "[BB]7.[bb] reduce the number of frames[BR]",
494 "[BB]8.[bb] change the timestamps of the frames ",
495 "([TT]-t0[tt] and [TT]-timestep[tt])[BR]",
496 "[BB]9.[bb] cut the trajectory in small subtrajectories according",
497 "to information in an index file. This allows subsequent analysis of",
498 "the subtrajectories that could, for example, be the result of a",
499 "cluster analysis. Use option [TT]-sub[tt].",
500 "This assumes that the entries in the index file are frame numbers and",
501 "dumps each group in the index file to a separate trajectory file.[BR]",
502 "[BB]10.[bb] select frames within a certain range of a quantity given",
503 "in an [TT].xvg[tt] file.[PAR]",
505 "The program [TT]trjcat[tt] is better suited for concatenating multiple trajectory files.",
508 "Currently seven formats are supported for input and output:",
509 "[TT].xtc[tt], [TT].trr[tt], [TT].trj[tt], [TT].gro[tt], [TT].g96[tt],",
510 "[TT].pdb[tt] and [TT].g87[tt].",
511 "The file formats are detected from the file extension.",
512 "The precision of [TT].xtc[tt] and [TT].gro[tt] output is taken from the",
513 "input file for [TT].xtc[tt], [TT].gro[tt] and [TT].pdb[tt],",
514 "and from the [TT]-ndec[tt] option for other input formats. The precision",
515 "is always taken from [TT]-ndec[tt], when this option is set.",
516 "All other formats have fixed precision. [TT].trr[tt] and [TT].trj[tt]",
517 "output can be single or double precision, depending on the precision",
518 "of the [TT]trjconv[tt] binary.",
519 "Note that velocities are only supported in",
520 "[TT].trr[tt], [TT].trj[tt], [TT].gro[tt] and [TT].g96[tt] files.[PAR]",
522 "Option [TT]-app[tt] can be used to",
523 "append output to an existing trajectory file.",
524 "No checks are performed to ensure integrity",
525 "of the resulting combined trajectory file.[PAR]",
527 "Option [TT]-sep[tt] can be used to write every frame to a separate",
528 "[TT].gro, .g96[tt] or [TT].pdb[tt] file. By default, all frames all written to one file.",
529 "[TT].pdb[tt] files with all frames concatenated can be viewed with",
530 "[TT]rasmol -nmrpdb[tt].[PAR]",
532 "It is possible to select part of your trajectory and write it out",
533 "to a new trajectory file in order to save disk space, e.g. for leaving",
534 "out the water from a trajectory of a protein in water.",
535 "[BB]ALWAYS[bb] put the original trajectory on tape!",
536 "We recommend to use the portable [TT].xtc[tt] format for your analysis",
537 "to save disk space and to have portable files.[PAR]",
539 "There are two options for fitting the trajectory to a reference",
540 "either for essential dynamics analysis, etc.",
541 "The first option is just plain fitting to a reference structure",
542 "in the structure file. The second option is a progressive fit",
543 "in which the first timeframe is fitted to the reference structure ",
544 "in the structure file to obtain and each subsequent timeframe is ",
545 "fitted to the previously fitted structure. This way a continuous",
546 "trajectory is generated, which might not be the case when using the",
547 "regular fit method, e.g. when your protein undergoes large",
548 "conformational transitions.[PAR]",
550 "Option [TT]-pbc[tt] sets the type of periodic boundary condition",
552 "[TT]* mol[tt] puts the center of mass of molecules in the box,",
553 "and requires a run input file to be supplied with [TT]-s[tt].[BR]",
554 "[TT]* res[tt] puts the center of mass of residues in the box.[BR]",
555 "[TT]* atom[tt] puts all the atoms in the box.[BR]",
556 "[TT]* nojump[tt] checks if atoms jump across the box and then puts",
557 "them back. This has the effect that all molecules",
558 "will remain whole (provided they were whole in the initial",
559 "conformation). [BB]Note[bb] that this ensures a continuous trajectory but",
560 "molecules may diffuse out of the box. The starting configuration",
561 "for this procedure is taken from the structure file, if one is",
562 "supplied, otherwise it is the first frame.[BR]",
563 "[TT]* cluster[tt] clusters all the atoms in the selected index",
564 "such that they are all closest to the center of mass of the cluster,",
565 "which is iteratively updated. [BB]Note[bb] that this will only give meaningful",
566 "results if you in fact have a cluster. Luckily that can be checked",
567 "afterwards using a trajectory viewer. Note also that if your molecules",
568 "are broken this will not work either.[BR]",
569 "The separate option [TT]-clustercenter[tt] can be used to specify an",
570 "approximate center for the cluster. This is useful e.g. if you have",
571 "two big vesicles, and you want to maintain their relative positions.[BR]",
572 "[TT]* whole[tt] only makes broken molecules whole.[PAR]",
574 "Option [TT]-ur[tt] sets the unit cell representation for options",
575 "[TT]mol[tt], [TT]res[tt] and [TT]atom[tt] of [TT]-pbc[tt].",
576 "All three options give different results for triclinic boxes and",
577 "identical results for rectangular boxes.",
578 "[TT]rect[tt] is the ordinary brick shape.",
579 "[TT]tric[tt] is the triclinic unit cell.",
580 "[TT]compact[tt] puts all atoms at the closest distance from the center",
581 "of the box. This can be useful for visualizing e.g. truncated octahedra",
582 "or rhombic dodecahedra. The center for options [TT]tric[tt] and [TT]compact[tt]",
583 "is [TT]tric[tt] (see below), unless the option [TT]-boxcenter[tt]",
584 "is set differently.[PAR]",
586 "Option [TT]-center[tt] centers the system in the box. The user can",
587 "select the group which is used to determine the geometrical center.",
588 "Option [TT]-boxcenter[tt] sets the location of the center of the box",
589 "for options [TT]-pbc[tt] and [TT]-center[tt]. The center options are:",
590 "[TT]tric[tt]: half of the sum of the box vectors,",
591 "[TT]rect[tt]: half of the box diagonal,",
592 "[TT]zero[tt]: zero.",
593 "Use option [TT]-pbc mol[tt] in addition to [TT]-center[tt] when you",
594 "want all molecules in the box after the centering.[PAR]",
596 "It is not always possible to use combinations of [TT]-pbc[tt],",
597 "[TT]-fit[tt], [TT]-ur[tt] and [TT]-center[tt] to do exactly what",
598 "you want in one call to [TT]trjconv[tt]. Consider using multiple",
599 "calls, and check out the GROMACS website for suggestions.[PAR]",
601 "With [TT]-dt[tt], it is possible to reduce the number of ",
602 "frames in the output. This option relies on the accuracy of the times",
603 "in your input trajectory, so if these are inaccurate use the",
604 "[TT]-timestep[tt] option to modify the time (this can be done",
605 "simultaneously). For making smooth movies, the program [TT]g_filter[tt]",
606 "can reduce the number of frames while using low-pass frequency",
607 "filtering, this reduces aliasing of high frequency motions.[PAR]",
609 "Using [TT]-trunc[tt] [TT]trjconv[tt] can truncate [TT].trj[tt] in place, i.e.",
610 "without copying the file. This is useful when a run has crashed",
611 "during disk I/O (i.e. full disk), or when two contiguous",
612 "trajectories must be concatenated without having double frames.[PAR]",
614 "Option [TT]-dump[tt] can be used to extract a frame at or near",
615 "one specific time from your trajectory.[PAR]",
617 "Option [TT]-drop[tt] reads an [TT].xvg[tt] file with times and values.",
618 "When options [TT]-dropunder[tt] and/or [TT]-dropover[tt] are set,",
619 "frames with a value below and above the value of the respective options",
620 "will not be written."
636 const char *pbc_opt[epNR + 1] =
637 { NULL, "none", "mol", "res", "atom", "nojump", "cluster", "whole",
641 const char *unitcell_opt[euNR+1] =
642 { NULL, "rect", "tric", "compact", NULL };
645 { ecSel, ecTric, ecRect, ecZero, ecNR};
646 const char *center_opt[ecNR+1] =
647 { NULL, "tric", "rect", "zero", NULL };
653 efSel, efNone, efFit, efFitXY, efReset, efResetXY, efPFit, efNR
655 const char *fit[efNR + 1] =
656 { NULL, "none", "rot+trans", "rotxy+transxy", "translation", "transxy",
657 "progressive", NULL };
659 static gmx_bool bAppend=FALSE,bSeparate=FALSE,bVels=TRUE,bForce=FALSE,bCONECT=FALSE;
660 static gmx_bool bCenter=FALSE;
661 static int skip_nr=1,ndec=3,nzero=0;
662 static real tzero=0,delta_t=0,timestep=0,ttrunc=-1,tdump=-1,split_t=0;
663 static rvec newbox = {0,0,0}, shift = {0,0,0}, trans = {0,0,0};
664 static char *exec_command=NULL;
665 static real dropunder=0,dropover=0;
666 static gmx_bool bRound=FALSE;
667 static rvec clustercenter = {0,0,0};
672 { "-skip", FALSE, etINT,
673 { &skip_nr }, "Only write every nr-th frame" },
674 { "-dt", FALSE, etTIME,
676 "Only write frame when t MOD dt = first time (%t)" },
677 { "-round", FALSE, etBOOL,
678 { &bRound }, "Round measurements to nearest picosecond"
680 { "-dump", FALSE, etTIME,
681 { &tdump }, "Dump frame nearest specified time (%t)" },
682 { "-t0", FALSE, etTIME,
684 "Starting time (%t) (default: don't change)" },
685 { "-timestep", FALSE, etTIME,
687 "Change time step between input frames (%t)" },
688 { "-pbc", FALSE, etENUM,
690 "PBC treatment (see help text for full description)" },
691 { "-ur", FALSE, etENUM,
692 { unitcell_opt }, "Unit-cell representation" },
693 { "-center", FALSE, etBOOL,
694 { &bCenter }, "Center atoms in box" },
695 { "-boxcenter", FALSE, etENUM,
696 { center_opt }, "Center for -pbc and -center" },
697 { "-box", FALSE, etRVEC,
699 "Size for new cubic box (default: read from input)" },
700 { "-clustercenter", FALSE, etRVEC,
702 "Optional starting point for pbc cluster option" },
703 { "-trans", FALSE, etRVEC,
705 "All coordinates will be translated by trans. This "
706 "can advantageously be combined with -pbc mol -ur "
708 { "-shift", FALSE, etRVEC,
710 "All coordinates will be shifted by framenr*shift" },
711 { "-fit", FALSE, etENUM,
713 "Fit molecule to ref structure in the structure file" },
714 { "-ndec", FALSE, etINT,
716 "Precision for .xtc and .gro writing in number of "
718 { "-vel", FALSE, etBOOL,
719 { &bVels }, "Read and write velocities if possible" },
720 { "-force", FALSE, etBOOL,
721 { &bForce }, "Read and write forces if possible" },
722 #ifndef GMX_NATIVE_WINDOWS
723 { "-trunc", FALSE, etTIME,
725 "Truncate input trajectory file after this time (%t)" },
727 { "-exec", FALSE, etSTR,
729 "Execute command for every output frame with the "
730 "frame number as argument" },
731 { "-app", FALSE, etBOOL,
732 { &bAppend }, "Append output" },
733 { "-split", FALSE, etTIME,
735 "Start writing new file when t MOD split = first "
737 { "-sep", FALSE, etBOOL,
739 "Write each frame to a separate .gro, .g96 or .pdb "
741 { "-nzero", FALSE, etINT,
743 "If the -sep flag is set, use these many digits "
744 "for the file numbers and prepend zeros as needed" },
745 { "-dropunder", FALSE, etREAL,
746 { &dropunder }, "Drop all frames below this value" },
747 { "-dropover", FALSE, etREAL,
748 { &dropover }, "Drop all frames above this value" },
749 { "-conect", FALSE, etBOOL,
751 "Add conect records when writing [TT].pdb[tt] files. Useful "
752 "for visualization of non-standard molecules, e.g. "
753 "coarse grained ones" } };
754 #define NPA asize(pa)
757 t_trxstatus *trxout=NULL;
759 int ftp,ftpin=0,file_nr;
762 rvec *xmem=NULL,*vmem=NULL,*fmem=NULL;
763 rvec *xp=NULL,x_shift,hbox,box_center,dx;
764 real xtcpr, lambda,*w_rls=NULL;
765 int m,i,d,frame,outframe,natoms,nout,ncent,nre,newstep=0,model_nr;
770 t_atoms *atoms=NULL,useatoms;
772 atom_id *index,*cindex;
776 int ifit,irms,my_clust=-1;
777 atom_id *ind_fit,*ind_rms;
778 char *gn_fit,*gn_rms;
779 t_cluster_ndx *clust=NULL;
780 t_trxstatus **clust_status=NULL;
781 int *clust_status_id=NULL;
784 int ndrop=0,ncol,drop0=0,drop1=0,dropuse=0;
786 real tshift=0,t0=-1,dt=0.001,prec;
787 gmx_bool bFit,bFitXY,bPFit,bReset;
789 gmx_rmpbc_t gpbc=NULL;
790 gmx_bool bRmPBC,bPBCWhole,bPBCcomRes,bPBCcomMol,bPBCcomAtom,bPBC,bNoJump,bCluster;
791 gmx_bool bCopy,bDoIt,bIndex,bTDump,bSetTime,bTPS=FALSE,bDTset=FALSE;
792 gmx_bool bExec,bTimeStep=FALSE,bDumpFrame=FALSE,bSetPrec,bNeedPrec;
793 gmx_bool bHaveFirstFrame,bHaveNextFrame,bSetBox,bSetUR,bSplit=FALSE;
794 gmx_bool bSubTraj=FALSE,bDropUnder=FALSE,bDropOver=FALSE,bTrans=FALSE;
795 gmx_bool bWriteFrame,bSplitHere;
796 const char *top_file,*in_file,*out_file=NULL;
797 char out_file2[256],*charpt;
798 char *outf_base=NULL;
799 const char *outf_ext=NULL;
800 char top_title[256],title[256],command[256],filemode[5];
802 gmx_bool bWarnCompact=FALSE;
807 { efTRX, "-f", NULL, ffREAD },
808 { efTRO, "-o", NULL, ffWRITE },
809 { efTPS, NULL, NULL, ffOPTRD },
810 { efNDX, NULL, NULL, ffOPTRD },
811 { efNDX, "-fr", "frames", ffOPTRD },
812 { efNDX, "-sub", "cluster", ffOPTRD },
813 { efXVG, "-drop","drop", ffOPTRD }
815 #define NFILE asize(fnm)
817 CopyRight(stderr,argv[0]);
818 parse_common_args(&argc,argv,
819 PCA_CAN_BEGIN | PCA_CAN_END | PCA_CAN_VIEW |
820 PCA_TIME_UNIT | PCA_BE_NICE,
821 NFILE,fnm,NPA,pa,asize(desc),desc,
824 top_file = ftp2fn(efTPS,NFILE,fnm);
827 /* Check command line */
828 in_file=opt2fn("-f",NFILE,fnm);
831 #ifndef GMX_NATIVE_WINDOWS
832 do_trunc(in_file,ttrunc);
836 /* mark active cmdline options */
837 bSetBox = opt2parg_bSet("-box", NPA, pa);
838 bSetTime = opt2parg_bSet("-t0", NPA, pa);
839 bSetPrec = opt2parg_bSet("-ndec", NPA, pa);
840 bSetUR = opt2parg_bSet("-ur", NPA, pa);
841 bExec = opt2parg_bSet("-exec", NPA, pa);
842 bTimeStep = opt2parg_bSet("-timestep", NPA, pa);
843 bTDump = opt2parg_bSet("-dump", NPA, pa);
844 bDropUnder= opt2parg_bSet("-dropunder", NPA, pa);
845 bDropOver = opt2parg_bSet("-dropover", NPA, pa);
846 bTrans = opt2parg_bSet("-trans",NPA,pa);
847 bSplit = (split_t != 0);
849 /* parse enum options */
850 fit_enum = nenum(fit);
851 bFit = (fit_enum==efFit || fit_enum==efFitXY);
852 bFitXY = fit_enum==efFitXY;
853 bReset = (fit_enum==efReset || fit_enum==efResetXY);
854 bPFit = fit_enum==efPFit;
855 pbc_enum = nenum(pbc_opt);
856 bPBCWhole = pbc_enum==epWhole;
857 bPBCcomRes = pbc_enum==epComRes;
858 bPBCcomMol = pbc_enum==epComMol;
859 bPBCcomAtom= pbc_enum==epComAtom;
860 bNoJump = pbc_enum==epNojump;
861 bCluster = pbc_enum==epCluster;
862 bPBC = pbc_enum!=epNone;
863 unitcell_enum = nenum(unitcell_opt);
864 ecenter = nenum(center_opt) - ecTric;
866 /* set and check option dependencies */
867 if (bPFit) bFit = TRUE; /* for pfit, fit *must* be set */
868 if (bFit) bReset = TRUE; /* for fit, reset *must* be set */
871 nfitdim = (fit_enum==efFitXY || fit_enum==efResetXY) ? 2 : 3;
872 bRmPBC = bFit || bPBCWhole || bPBCcomRes || bPBCcomMol;
875 if (!(bPBCcomRes || bPBCcomMol || bPBCcomAtom)) {
877 "WARNING: Option for unitcell representation (-ur %s)\n"
878 " only has effect in combination with -pbc %s, %s or %s.\n"
879 " Ingoring unitcell representation.\n\n",
880 unitcell_opt[0],pbc_opt[2],pbc_opt[3],pbc_opt[4]);
885 gmx_fatal(FARGS,"PBC condition treatment does not work together with rotational fit.\n"
886 "Please do the PBC condition treatment first and then run trjconv in a second step\n"
887 "for the rotational fit.\n"
888 "First doing the rotational fit and then doing the PBC treatment gives incorrect\n"
892 /* ndec is in nr of decimal places, prec is a multiplication factor: */
894 for (i=0; i<ndec; i++)
897 bIndex=ftp2bSet(efNDX,NFILE,fnm);
900 /* Determine output type */
901 out_file=opt2fn("-o",NFILE,fnm);
902 ftp=fn2ftp(out_file);
903 fprintf(stderr,"Will write %s: %s\n",ftp2ext(ftp),ftp2desc(ftp));
904 bNeedPrec = (ftp==efXTC || ftp==efGRO);
906 /* check if velocities are possible in input and output files */
907 ftpin=fn2ftp(in_file);
908 bVels= (ftp==efTRR || ftp==efTRJ || ftp==efGRO || ftp==efG96)
909 && (ftpin==efTRR || ftpin==efTRJ || ftpin==efGRO || ftpin==efG96 ||
912 if (bSeparate || bSplit) {
913 outf_ext = strrchr(out_file,'.');
914 if (outf_ext == NULL)
915 gmx_fatal(FARGS,"Output file name '%s' does not contain a '.'",out_file);
916 outf_base = strdup(out_file);
917 outf_base[outf_ext - out_file] = '\0';
920 bSubTraj = opt2bSet("-sub",NFILE,fnm);
922 if ((ftp != efXTC) && (ftp != efTRR))
923 /* It seems likely that other trajectory file types
924 * could work here. */
925 gmx_fatal(FARGS,"Can only use the sub option with output file types "
927 clust = cluster_index(NULL,opt2fn("-sub",NFILE,fnm));
929 /* Check for number of files disabled, as FOPEN_MAX is not the correct
930 * number to check for. In my linux box it is only 16.
932 if (0 && (clust->clust->nr > FOPEN_MAX-4))
933 gmx_fatal(FARGS,"Can not open enough (%d) files to write all the"
934 " trajectories.\ntry splitting the index file in %d parts.\n"
936 clust->clust->nr,1+clust->clust->nr/FOPEN_MAX,FOPEN_MAX);
937 gmx_warning("The -sub option could require as many open output files as there are\n"
938 "index groups in the file (%d). If you get I/O errors opening new files,\n"
939 "try reducing the number of index groups in the file, and perhaps\n"
940 "using trjconv -sub several times on different chunks of your index file.\n",
943 snew(clust_status,clust->clust->nr);
944 snew(clust_status_id,clust->clust->nr);
945 snew(nfwritten,clust->clust->nr);
946 for(i=0; (i<clust->clust->nr); i++)
948 clust_status[i] = NULL;
949 clust_status_id[i] = -1;
951 bSeparate = bSplit = FALSE;
957 /* Determine whether to read a topology */
958 bTPS = (ftp2bSet(efTPS,NFILE,fnm) ||
959 bRmPBC || bReset || bPBCcomMol || bCluster ||
960 (ftp == efGRO) || (ftp == efPDB) || bCONECT);
962 /* Determine if when can read index groups */
963 bIndex = (bIndex || bTPS);
966 read_tps_conf(top_file,top_title,&top,&ePBC,&xp,NULL,top_box,
967 bReset || bPBCcomRes);
970 if (0 == top.mols.nr && (bCluster || bPBCcomMol))
972 gmx_fatal(FARGS,"Option -pbc %s requires a .tpr file for the -s option",pbc_opt[pbc_enum]);
975 /* top_title is only used for gro and pdb,
976 * the header in such a file is top_title t= ...
977 * to prevent a double t=, remove it from top_title
979 if ((charpt=strstr(top_title," t= ")))
983 gc = gmx_conect_generate(&top);
985 gpbc = gmx_rmpbc_init(&top.idef,ePBC,top.atoms.nr,top_box);
988 /* get frame number index */
990 if (opt2bSet("-fr",NFILE,fnm)) {
991 printf("Select groups of frame number indices:\n");
992 rd_index(opt2fn("-fr",NFILE,fnm),1,&nrfri,(atom_id **)&frindex,&frname);
994 for(i=0; i<nrfri; i++)
995 fprintf(debug,"frindex[%4d]=%4d\n",i,frindex[i]);
998 /* get index groups etc. */
1000 printf("Select group for %s fit\n",
1001 bFit?"least squares":"translational");
1002 get_index(atoms,ftp2fn_null(efNDX,NFILE,fnm),
1003 1,&ifit,&ind_fit,&gn_fit);
1007 gmx_fatal(FARGS,"Need at least 2 atoms to fit!\n");
1009 fprintf(stderr,"WARNING: fitting with only 2 atoms is not unique\n");
1012 else if (bCluster) {
1013 printf("Select group for clustering\n");
1014 get_index(atoms,ftp2fn_null(efNDX,NFILE,fnm),
1015 1,&ifit,&ind_fit,&gn_fit);
1020 printf("Select group for centering\n");
1021 get_index(atoms,ftp2fn_null(efNDX,NFILE,fnm),
1022 1,&ncent,&cindex,&grpnm);
1024 printf("Select group for output\n");
1025 get_index(atoms,ftp2fn_null(efNDX,NFILE,fnm),
1026 1,&nout,&index,&grpnm);
1028 /* no index file, so read natoms from TRX */
1029 if (!read_first_frame(oenv,&status,in_file,&fr,TRX_DONT_SKIP))
1030 gmx_fatal(FARGS,"Could not read a frame from %s",in_file);
1035 for(i=0;i<natoms;i++)
1045 snew(w_rls,atoms->nr);
1046 for(i=0; (i<ifit); i++)
1047 w_rls[ind_fit[i]]=atoms->atom[ind_fit[i]].m;
1049 /* Restore reference structure and set to origin,
1050 store original location (to put structure back) */
1052 gmx_rmpbc(gpbc,top.atoms.nr,top_box,xp);
1053 copy_rvec(xp[index[0]],x_shift);
1054 reset_x_ndim(nfitdim,ifit,ind_fit,atoms->nr,NULL,xp,w_rls);
1055 rvec_dec(x_shift,xp[index[0]]);
1057 clear_rvec(x_shift);
1059 if (bDropUnder || bDropOver) {
1060 /* Read the .xvg file with the drop values */
1061 fprintf(stderr,"\nReading drop file ...");
1062 ndrop = read_xvg(opt2fn("-drop",NFILE,fnm),&dropval,&ncol);
1063 fprintf(stderr," %d time points\n",ndrop);
1064 if (ndrop == 0 || ncol < 2)
1065 gmx_fatal(FARGS,"Found no data points in %s",
1066 opt2fn("-drop",NFILE,fnm));
1071 /* Make atoms struct for output in GRO or PDB files */
1072 if ((ftp == efGRO) || ((ftp == efG96) && bTPS) || (ftp == efPDB)) {
1073 /* get memory for stuff to go in .pdb file */
1074 init_t_atoms(&useatoms,atoms->nr,FALSE);
1075 sfree(useatoms.resinfo);
1076 useatoms.resinfo = atoms->resinfo;
1077 for(i=0;(i<nout);i++) {
1078 useatoms.atomname[i]=atoms->atomname[index[i]];
1079 useatoms.atom[i]=atoms->atom[index[i]];
1080 useatoms.nres=max(useatoms.nres,useatoms.atom[i].resind+1);
1084 /* select what to read */
1085 if (ftp==efTRR || ftp==efTRJ)
1090 flags = flags | TRX_READ_V;
1092 flags = flags | TRX_READ_F;
1094 /* open trx file for reading */
1095 bHaveFirstFrame = read_first_frame(oenv,&status,in_file,&fr,flags);
1097 fprintf(stderr,"\nPrecision of %s is %g (nm)\n",in_file,1/fr.prec);
1099 if (bSetPrec || !fr.bPrec)
1100 fprintf(stderr,"\nSetting output precision to %g (nm)\n",1/prec);
1102 fprintf(stderr,"Using output precision of %g (nm)\n",1/prec);
1105 if (bHaveFirstFrame) {
1106 set_trxframe_ePBC(&fr,ePBC);
1111 tshift=tzero-fr.time;
1115 /* open output for writing */
1116 if ((bAppend) && (gmx_fexist(out_file))) {
1117 strcpy(filemode,"a");
1118 fprintf(stderr,"APPENDING to existing file %s\n",out_file);
1120 strcpy(filemode,"w");
1127 if (!bSplit && !bSubTraj)
1128 trxout = open_trx(out_file,filemode);
1133 if (( !bSeparate && !bSplit ) && !bSubTraj)
1134 out=ffopen(out_file,filemode);
1140 /* check if index is meaningful */
1141 for(i=0; i<nout; i++) {
1142 if (index[i] >= natoms)
1144 "Index[%d] %d is larger than the number of atoms in the\n"
1145 "trajectory file (%d). There is a mismatch in the contents\n"
1146 "of your -f, -s and/or -n files.",i,index[i]+1,natoms);
1147 bCopy = bCopy || (i != index[i]);
1160 fprintf(gmx_fio_getfp(trx_get_fileio(trxout)),
1161 "Generated by %s. #atoms=%d, a BOX is"
1162 " stored in this file.\n",Program(),nout);
1164 /* Start the big loop over frames */
1171 /* Main loop over frames */
1179 /*if (frame >= clust->clust->nra)
1180 gmx_fatal(FARGS,"There are more frames in the trajectory than in the cluster index file\n");*/
1181 if (frame > clust->maxframe)
1184 my_clust = clust->inv_clust[frame];
1185 if ((my_clust < 0) || (my_clust >= clust->clust->nr) ||
1186 (my_clust == NO_ATID))
1191 /* generate new box */
1193 for (m=0; m<DIM; m++)
1194 fr.box[m][m] = newbox[m];
1198 for(i=0; i<natoms; i++)
1199 rvec_inc(fr.x[i],trans);
1203 /* determine timestep */
1212 /* This is not very elegant, as one can not dump a frame after
1213 * a timestep with is more than twice as small as the first one. */
1214 bDumpFrame = (fr.time > tdump-0.5*dt) && (fr.time <= tdump+0.5*dt);
1218 /* determine if an atom jumped across the box and reset it if so */
1219 if (bNoJump && (bTPS || frame!=0)) {
1220 for(d=0; d<DIM; d++)
1221 hbox[d] = 0.5*fr.box[d][d];
1222 for(i=0; i<natoms; i++) {
1224 rvec_dec(fr.x[i],x_shift);
1225 for(m=DIM-1; m>=0; m--)
1227 while (fr.x[i][m]-xp[i][m] <= -hbox[m])
1229 fr.x[i][d] += fr.box[m][d];
1230 while (fr.x[i][m]-xp[i][m] > hbox[m])
1232 fr.x[i][d] -= fr.box[m][d];
1236 else if (bCluster) {
1239 calc_pbc_cluster(ecenter,ifit,&top,ePBC,fr.x,ind_fit,com,fr.box,clustercenter);
1243 /* Now modify the coords according to the flags,
1244 for normal fit, this is only done for output frames */
1246 gmx_rmpbc_trxfr(gpbc,&fr);
1248 reset_x_ndim(nfitdim,ifit,ind_fit,natoms,NULL,fr.x,w_rls);
1249 do_fit(natoms,w_rls,xp,fr.x);
1252 /* store this set of coordinates for future use */
1253 if (bPFit || bNoJump) {
1256 for(i=0; (i<natoms); i++) {
1257 copy_rvec(fr.x[i],xp[i]);
1258 rvec_inc(fr.x[i],x_shift);
1263 /* see if we have a frame from the frame index group */
1264 for(i=0; i<nrfri && !bDumpFrame; i++)
1265 bDumpFrame = frame == frindex[i];
1266 if (debug && bDumpFrame)
1267 fprintf(debug,"dumping %d\n",frame);
1270 ( ( !bTDump && !frindex && frame % skip_nr == 0 ) || bDumpFrame );
1272 if (bWriteFrame && (bDropUnder || bDropOver)) {
1273 while (dropval[0][drop1]<fr.time && drop1+1<ndrop) {
1277 if (fabs(dropval[0][drop0] - fr.time)
1278 < fabs(dropval[0][drop1] - fr.time)) {
1283 if ((bDropUnder && dropval[1][dropuse] < dropunder) ||
1284 (bDropOver && dropval[1][dropuse] > dropover))
1285 bWriteFrame = FALSE;
1292 fr.time = tzero+frame*timestep;
1298 fprintf(stderr,"\nDumping frame at t= %g %s\n",
1299 output_env_conv_time(oenv,fr.time),output_env_get_time_unit(oenv));
1301 /* check for writing at each delta_t */
1302 bDoIt=(delta_t == 0);
1306 bDoIt=bRmod(fr.time,tzero, delta_t);
1308 /* round() is not C89 compatible, so we do this: */
1309 bDoIt=bRmod(floor(fr.time+0.5),floor(tzero+0.5),
1310 floor(delta_t+0.5));
1313 if (bDoIt || bTDump) {
1314 /* print sometimes */
1315 if ( ((outframe % SKIP) == 0) || (outframe < SKIP) )
1316 fprintf(stderr," -> frame %6d time %8.3f \r",
1317 outframe,output_env_conv_time(oenv,fr.time));
1320 /* Now modify the coords according to the flags,
1321 for PFit we did this already! */
1324 gmx_rmpbc_trxfr(gpbc,&fr);
1327 reset_x_ndim(nfitdim,ifit,ind_fit,natoms,NULL,fr.x,w_rls);
1329 do_fit_ndim(nfitdim,natoms,w_rls,xp,fr.x);
1331 for(i=0; i<natoms; i++)
1332 rvec_inc(fr.x[i],x_shift);
1336 center_x(ecenter,fr.x,fr.box,natoms,ncent,cindex);
1340 switch (unitcell_enum) {
1342 put_atoms_in_box(ePBC,fr.box,natoms,fr.x);
1345 put_atoms_in_triclinic_unitcell(ecenter,fr.box,natoms,fr.x);
1348 warn = put_atoms_in_compact_unitcell(ePBC,ecenter,fr.box,
1350 if (warn && !bWarnCompact) {
1351 fprintf(stderr,"\n%s\n",warn);
1352 bWarnCompact = TRUE;
1358 put_residue_com_in_box(unitcell_enum,ecenter,
1359 natoms,atoms->atom,ePBC,fr.box,fr.x);
1362 put_molecule_com_in_box(unitcell_enum,ecenter,
1364 natoms,atoms->atom,ePBC,fr.box,fr.x);
1366 /* Copy the input trxframe struct to the output trxframe struct */
1368 frout.bV = (frout.bV && bVels);
1369 frout.bF = (frout.bF && bForce);
1370 frout.natoms = nout;
1371 if (bNeedPrec && (bSetPrec || !fr.bPrec)) {
1383 for(i=0; i<nout; i++) {
1384 copy_rvec(fr.x[index[i]],frout.x[i]);
1386 copy_rvec(fr.v[index[i]],frout.v[i]);
1389 copy_rvec(fr.f[index[i]],frout.f[i]);
1394 if (opt2parg_bSet("-shift",NPA,pa))
1395 for(i=0; i<nout; i++)
1396 for (d=0; d<DIM; d++)
1397 frout.x[i][d] += outframe*shift[d];
1400 bSplitHere = bSplit && bRmod(fr.time,tzero, split_t);
1403 /* round() is not C89 compatible, so we do this: */
1404 bSplitHere = bSplit && bRmod(floor(fr.time+0.5),
1406 floor(split_t+0.5));
1408 if (bSeparate || bSplitHere)
1409 mk_filenm(outf_base,ftp2ext(ftp),nzero,file_nr,out_file2);
1419 trxout = open_trx(out_file2,filemode);
1422 if (my_clust != -1) {
1424 if (clust_status_id[my_clust] == -1) {
1425 sprintf(buf,"%s.%s",clust->grpname[my_clust],ftp2ext(ftp));
1426 clust_status[my_clust] = open_trx(buf,"w");
1427 clust_status_id[my_clust] = 1;
1430 else if (clust_status_id[my_clust] == -2)
1431 gmx_fatal(FARGS,"File %s.xtc should still be open (%d open .xtc files)\n""in order to write frame %d. my_clust = %d",
1432 clust->grpname[my_clust],ntrxopen,frame,
1434 write_trxframe(clust_status[my_clust],&frout,gc);
1435 nfwritten[my_clust]++;
1436 if (nfwritten[my_clust] ==
1437 (clust->clust->index[my_clust+1]-
1438 clust->clust->index[my_clust])) {
1439 close_trx(clust_status[my_clust]);
1440 clust_status[my_clust] = NULL;
1441 clust_status_id[my_clust] = -2;
1444 gmx_fatal(FARGS,"Less than zero open .xtc files!");
1449 write_trxframe(trxout,&frout,gc);
1454 sprintf(title,"Generated by trjconv : %s t= %9.5f",
1456 if (bSeparate || bSplitHere)
1457 out=ffopen(out_file2,"w");
1460 write_hconf_p(out,title,&useatoms,prec2ndec(frout.prec),
1461 frout.x,frout.bV?frout.v:NULL,frout.box);
1464 fprintf(out,"REMARK GENERATED BY TRJCONV\n");
1465 sprintf(title,"%s t= %9.5f",top_title,frout.time);
1466 /* if reading from pdb, we want to keep the original
1467 model numbering else we write the output frame
1468 number plus one, because model 0 is not allowed in pdb */
1469 if (ftpin==efPDB && fr.bStep && fr.step > model_nr)
1473 write_pdbfile(out,title,&useatoms,frout.x,
1474 frout.ePBC,frout.box,' ',model_nr,gc,TRUE);
1477 frout.title = title;
1478 if (bSeparate || bTDump) {
1479 frout.bTitle = TRUE;
1481 frout.bAtoms = TRUE;
1482 frout.atoms = &useatoms;
1483 frout.bStep = FALSE;
1484 frout.bTime = FALSE;
1486 frout.bTitle = (outframe == 0);
1487 frout.bAtoms = FALSE;
1491 write_g96_conf(out,&frout,-1,NULL);
1499 gmx_fatal(FARGS,"DHE, ftp=%d\n",ftp);
1501 if (bSeparate || bSplitHere)
1504 /* execute command */
1507 sprintf(c,"%s %d",exec_command,file_nr-1);
1508 /*fprintf(stderr,"Executing '%s'\n",c);*/
1509 #ifdef GMX_NO_SYSTEM
1510 printf("Warning-- No calls to system(3) supported on this platform.");
1511 printf("Warning-- Skipping execution of 'system(\"%s\")'.", c);
1515 gmx_fatal(FARGS,"Error executing command: %s",c);
1523 bHaveNextFrame=read_next_frame(oenv,status,&fr);
1524 } while (!(bTDump && bDumpFrame) && bHaveNextFrame);
1527 if (!bHaveFirstFrame || (bTDump && !bDumpFrame))
1528 fprintf(stderr,"\nWARNING no output, "
1529 "last frame read at t=%g\n",fr.time);
1530 fprintf(stderr,"\n");
1536 gmx_rmpbc_done(gpbc);
1540 else if (out != NULL)
1543 for(i=0; (i<clust->clust->nr); i++)
1544 if (clust_status_id[i] >= 0 )
1545 close_trx(clust_status[i]);
1549 do_view(oenv,out_file,NULL);