3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
10 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12 * Copyright (c) 2001-2004, The GROMACS development team,
13 * check out http://www.gromacs.org for more information.
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * If you want to redistribute modifications, please consider that
21 * scientific software is very special. Version control is crucial -
22 * bugs must be traceable. We will be happy to consider code for
23 * inclusion in the official distribution, but derived work must not
24 * be called official GROMACS. Details are found in the README & COPYING
25 * files - if they are missing, get the official version at www.gromacs.org.
27 * To help us fund GROMACS development, we humbly ask that you cite
28 * the papers on the package - you can find them in the top README file.
30 * For more info, check our website at http://www.gromacs.org
33 * Green Red Orange Magenta Azure Cyan Skyblue
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 parse_common_args(&argc,argv,
818 PCA_CAN_BEGIN | PCA_CAN_END | PCA_CAN_VIEW |
819 PCA_TIME_UNIT | PCA_BE_NICE,
820 NFILE,fnm,NPA,pa,asize(desc),desc,
823 top_file = ftp2fn(efTPS,NFILE,fnm);
826 /* Check command line */
827 in_file=opt2fn("-f",NFILE,fnm);
830 #ifndef GMX_NATIVE_WINDOWS
831 do_trunc(in_file,ttrunc);
835 /* mark active cmdline options */
836 bSetBox = opt2parg_bSet("-box", NPA, pa);
837 bSetTime = opt2parg_bSet("-t0", NPA, pa);
838 bSetPrec = opt2parg_bSet("-ndec", NPA, pa);
839 bSetUR = opt2parg_bSet("-ur", NPA, pa);
840 bExec = opt2parg_bSet("-exec", NPA, pa);
841 bTimeStep = opt2parg_bSet("-timestep", NPA, pa);
842 bTDump = opt2parg_bSet("-dump", NPA, pa);
843 bDropUnder= opt2parg_bSet("-dropunder", NPA, pa);
844 bDropOver = opt2parg_bSet("-dropover", NPA, pa);
845 bTrans = opt2parg_bSet("-trans",NPA,pa);
846 bSplit = (split_t != 0);
848 /* parse enum options */
849 fit_enum = nenum(fit);
850 bFit = (fit_enum==efFit || fit_enum==efFitXY);
851 bFitXY = fit_enum==efFitXY;
852 bReset = (fit_enum==efReset || fit_enum==efResetXY);
853 bPFit = fit_enum==efPFit;
854 pbc_enum = nenum(pbc_opt);
855 bPBCWhole = pbc_enum==epWhole;
856 bPBCcomRes = pbc_enum==epComRes;
857 bPBCcomMol = pbc_enum==epComMol;
858 bPBCcomAtom= pbc_enum==epComAtom;
859 bNoJump = pbc_enum==epNojump;
860 bCluster = pbc_enum==epCluster;
861 bPBC = pbc_enum!=epNone;
862 unitcell_enum = nenum(unitcell_opt);
863 ecenter = nenum(center_opt) - ecTric;
865 /* set and check option dependencies */
866 if (bPFit) bFit = TRUE; /* for pfit, fit *must* be set */
867 if (bFit) bReset = TRUE; /* for fit, reset *must* be set */
870 nfitdim = (fit_enum==efFitXY || fit_enum==efResetXY) ? 2 : 3;
871 bRmPBC = bFit || bPBCWhole || bPBCcomRes || bPBCcomMol;
874 if (!(bPBCcomRes || bPBCcomMol || bPBCcomAtom)) {
876 "WARNING: Option for unitcell representation (-ur %s)\n"
877 " only has effect in combination with -pbc %s, %s or %s.\n"
878 " Ingoring unitcell representation.\n\n",
879 unitcell_opt[0],pbc_opt[2],pbc_opt[3],pbc_opt[4]);
884 gmx_fatal(FARGS,"PBC condition treatment does not work together with rotational fit.\n"
885 "Please do the PBC condition treatment first and then run trjconv in a second step\n"
886 "for the rotational fit.\n"
887 "First doing the rotational fit and then doing the PBC treatment gives incorrect\n"
891 /* ndec is in nr of decimal places, prec is a multiplication factor: */
893 for (i=0; i<ndec; i++)
896 bIndex=ftp2bSet(efNDX,NFILE,fnm);
899 /* Determine output type */
900 out_file=opt2fn("-o",NFILE,fnm);
901 ftp=fn2ftp(out_file);
902 fprintf(stderr,"Will write %s: %s\n",ftp2ext(ftp),ftp2desc(ftp));
903 bNeedPrec = (ftp==efXTC || ftp==efGRO);
905 /* check if velocities are possible in input and output files */
906 ftpin=fn2ftp(in_file);
907 bVels= (ftp==efTRR || ftp==efTRJ || ftp==efGRO || ftp==efG96)
908 && (ftpin==efTRR || ftpin==efTRJ || ftpin==efGRO || ftpin==efG96 ||
911 if (bSeparate || bSplit) {
912 outf_ext = strrchr(out_file,'.');
913 if (outf_ext == NULL)
914 gmx_fatal(FARGS,"Output file name '%s' does not contain a '.'",out_file);
915 outf_base = strdup(out_file);
916 outf_base[outf_ext - out_file] = '\0';
919 bSubTraj = opt2bSet("-sub",NFILE,fnm);
921 if ((ftp != efXTC) && (ftp != efTRR))
922 /* It seems likely that other trajectory file types
923 * could work here. */
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_id[i] >= 0 )
1544 close_trx(clust_status[i]);
1548 do_view(oenv,out_file,NULL);