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(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(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 != efTRN))
923 gmx_fatal(FARGS,"Can only use the sub option with output file types "
925 clust = cluster_index(NULL,opt2fn("-sub",NFILE,fnm));
927 /* Check for number of files disabled, as FOPEN_MAX is not the correct
928 * number to check for. In my linux box it is only 16.
930 if (0 && (clust->clust->nr > FOPEN_MAX-4))
931 gmx_fatal(FARGS,"Can not open enough (%d) files to write all the"
932 " trajectories.\ntry splitting the index file in %d parts.\n"
934 clust->clust->nr,1+clust->clust->nr/FOPEN_MAX,FOPEN_MAX);
935 gmx_warning("The -sub option could require as many open output files as there are\n"
936 "index groups in the file (%d). If you get I/O errors opening new files,\n"
937 "try reducing the number of index groups in the file, and perhaps\n"
938 "using trjconv -sub several times on different chunks of your index file.\n",
941 snew(clust_status,clust->clust->nr);
942 snew(clust_status_id,clust->clust->nr);
943 snew(nfwritten,clust->clust->nr);
944 for(i=0; (i<clust->clust->nr); i++)
946 clust_status[i] = NULL;
947 clust_status_id[i] = -1;
949 bSeparate = bSplit = FALSE;
955 /* Determine whether to read a topology */
956 bTPS = (ftp2bSet(efTPS,NFILE,fnm) ||
957 bRmPBC || bReset || bPBCcomMol || bCluster ||
958 (ftp == efGRO) || (ftp == efPDB) || bCONECT);
960 /* Determine if when can read index groups */
961 bIndex = (bIndex || bTPS);
964 read_tps_conf(top_file,top_title,&top,&ePBC,&xp,NULL,top_box,
965 bReset || bPBCcomRes);
968 if (0 == top.mols.nr && (bCluster || bPBCcomMol))
970 gmx_fatal(FARGS,"Option -pbc %s requires a .tpr file for the -s option",pbc_opt[pbc_enum]);
973 /* top_title is only used for gro and pdb,
974 * the header in such a file is top_title t= ...
975 * to prevent a double t=, remove it from top_title
977 if ((charpt=strstr(top_title," t= ")))
981 gc = gmx_conect_generate(&top);
983 gpbc = gmx_rmpbc_init(&top.idef,ePBC,top.atoms.nr,top_box);
986 /* get frame number index */
988 if (opt2bSet("-fr",NFILE,fnm)) {
989 printf("Select groups of frame number indices:\n");
990 rd_index(opt2fn("-fr",NFILE,fnm),1,&nrfri,(atom_id **)&frindex,&frname);
992 for(i=0; i<nrfri; i++)
993 fprintf(debug,"frindex[%4d]=%4d\n",i,frindex[i]);
996 /* get index groups etc. */
998 printf("Select group for %s fit\n",
999 bFit?"least squares":"translational");
1000 get_index(atoms,ftp2fn_null(efNDX,NFILE,fnm),
1001 1,&ifit,&ind_fit,&gn_fit);
1005 gmx_fatal(FARGS,"Need at least 2 atoms to fit!\n");
1007 fprintf(stderr,"WARNING: fitting with only 2 atoms is not unique\n");
1010 else if (bCluster) {
1011 printf("Select group for clustering\n");
1012 get_index(atoms,ftp2fn_null(efNDX,NFILE,fnm),
1013 1,&ifit,&ind_fit,&gn_fit);
1018 printf("Select group for centering\n");
1019 get_index(atoms,ftp2fn_null(efNDX,NFILE,fnm),
1020 1,&ncent,&cindex,&grpnm);
1022 printf("Select group for output\n");
1023 get_index(atoms,ftp2fn_null(efNDX,NFILE,fnm),
1024 1,&nout,&index,&grpnm);
1026 /* no index file, so read natoms from TRX */
1027 if (!read_first_frame(oenv,&status,in_file,&fr,TRX_DONT_SKIP))
1028 gmx_fatal(FARGS,"Could not read a frame from %s",in_file);
1033 for(i=0;i<natoms;i++)
1043 snew(w_rls,atoms->nr);
1044 for(i=0; (i<ifit); i++)
1045 w_rls[ind_fit[i]]=atoms->atom[ind_fit[i]].m;
1047 /* Restore reference structure and set to origin,
1048 store original location (to put structure back) */
1050 gmx_rmpbc(gpbc,top.atoms.nr,top_box,xp);
1051 copy_rvec(xp[index[0]],x_shift);
1052 reset_x_ndim(nfitdim,ifit,ind_fit,atoms->nr,NULL,xp,w_rls);
1053 rvec_dec(x_shift,xp[index[0]]);
1055 clear_rvec(x_shift);
1057 if (bDropUnder || bDropOver) {
1058 /* Read the .xvg file with the drop values */
1059 fprintf(stderr,"\nReading drop file ...");
1060 ndrop = read_xvg(opt2fn("-drop",NFILE,fnm),&dropval,&ncol);
1061 fprintf(stderr," %d time points\n",ndrop);
1062 if (ndrop == 0 || ncol < 2)
1063 gmx_fatal(FARGS,"Found no data points in %s",
1064 opt2fn("-drop",NFILE,fnm));
1069 /* Make atoms struct for output in GRO or PDB files */
1070 if ((ftp == efGRO) || ((ftp == efG96) && bTPS) || (ftp == efPDB)) {
1071 /* get memory for stuff to go in .pdb file */
1072 init_t_atoms(&useatoms,atoms->nr,FALSE);
1073 sfree(useatoms.resinfo);
1074 useatoms.resinfo = atoms->resinfo;
1075 for(i=0;(i<nout);i++) {
1076 useatoms.atomname[i]=atoms->atomname[index[i]];
1077 useatoms.atom[i]=atoms->atom[index[i]];
1078 useatoms.nres=max(useatoms.nres,useatoms.atom[i].resind+1);
1082 /* select what to read */
1083 if (ftp==efTRR || ftp==efTRJ)
1088 flags = flags | TRX_READ_V;
1090 flags = flags | TRX_READ_F;
1092 /* open trx file for reading */
1093 bHaveFirstFrame = read_first_frame(oenv,&status,in_file,&fr,flags);
1095 fprintf(stderr,"\nPrecision of %s is %g (nm)\n",in_file,1/fr.prec);
1097 if (bSetPrec || !fr.bPrec)
1098 fprintf(stderr,"\nSetting output precision to %g (nm)\n",1/prec);
1100 fprintf(stderr,"Using output precision of %g (nm)\n",1/prec);
1103 if (bHaveFirstFrame) {
1104 set_trxframe_ePBC(&fr,ePBC);
1109 tshift=tzero-fr.time;
1113 /* open output for writing */
1114 if ((bAppend) && (gmx_fexist(out_file))) {
1115 strcpy(filemode,"a");
1116 fprintf(stderr,"APPENDING to existing file %s\n",out_file);
1118 strcpy(filemode,"w");
1125 if (!bSplit && !bSubTraj)
1126 trxout = open_trx(out_file,filemode);
1131 if (( !bSeparate && !bSplit ) && !bSubTraj)
1132 out=ffopen(out_file,filemode);
1138 /* check if index is meaningful */
1139 for(i=0; i<nout; i++) {
1140 if (index[i] >= natoms)
1142 "Index[%d] %d is larger than the number of atoms in the\n"
1143 "trajectory file (%d). There is a mismatch in the contents\n"
1144 "of your -f, -s and/or -n files.",i,index[i]+1,natoms);
1145 bCopy = bCopy || (i != index[i]);
1158 fprintf(gmx_fio_getfp(trx_get_fileio(trxout)),
1159 "Generated by %s. #atoms=%d, a BOX is"
1160 " stored in this file.\n",Program(),nout);
1162 /* Start the big loop over frames */
1169 /* Main loop over frames */
1177 /*if (frame >= clust->clust->nra)
1178 gmx_fatal(FARGS,"There are more frames in the trajectory than in the cluster index file\n");*/
1179 if (frame > clust->maxframe)
1182 my_clust = clust->inv_clust[frame];
1183 if ((my_clust < 0) || (my_clust >= clust->clust->nr) ||
1184 (my_clust == NO_ATID))
1189 /* generate new box */
1191 for (m=0; m<DIM; m++)
1192 fr.box[m][m] = newbox[m];
1196 for(i=0; i<natoms; i++)
1197 rvec_inc(fr.x[i],trans);
1201 /* determine timestep */
1210 /* This is not very elegant, as one can not dump a frame after
1211 * a timestep with is more than twice as small as the first one. */
1212 bDumpFrame = (fr.time > tdump-0.5*dt) && (fr.time <= tdump+0.5*dt);
1216 /* determine if an atom jumped across the box and reset it if so */
1217 if (bNoJump && (bTPS || frame!=0)) {
1218 for(d=0; d<DIM; d++)
1219 hbox[d] = 0.5*fr.box[d][d];
1220 for(i=0; i<natoms; i++) {
1222 rvec_dec(fr.x[i],x_shift);
1223 for(m=DIM-1; m>=0; m--)
1225 while (fr.x[i][m]-xp[i][m] <= -hbox[m])
1227 fr.x[i][d] += fr.box[m][d];
1228 while (fr.x[i][m]-xp[i][m] > hbox[m])
1230 fr.x[i][d] -= fr.box[m][d];
1234 else if (bCluster) {
1237 calc_pbc_cluster(ecenter,ifit,&top,ePBC,fr.x,ind_fit,com,fr.box,clustercenter);
1241 /* Now modify the coords according to the flags,
1242 for normal fit, this is only done for output frames */
1244 gmx_rmpbc_trxfr(gpbc,&fr);
1246 reset_x_ndim(nfitdim,ifit,ind_fit,natoms,NULL,fr.x,w_rls);
1247 do_fit(natoms,w_rls,xp,fr.x);
1250 /* store this set of coordinates for future use */
1251 if (bPFit || bNoJump) {
1254 for(i=0; (i<natoms); i++) {
1255 copy_rvec(fr.x[i],xp[i]);
1256 rvec_inc(fr.x[i],x_shift);
1261 /* see if we have a frame from the frame index group */
1262 for(i=0; i<nrfri && !bDumpFrame; i++)
1263 bDumpFrame = frame == frindex[i];
1264 if (debug && bDumpFrame)
1265 fprintf(debug,"dumping %d\n",frame);
1268 ( ( !bTDump && !frindex && frame % skip_nr == 0 ) || bDumpFrame );
1270 if (bWriteFrame && (bDropUnder || bDropOver)) {
1271 while (dropval[0][drop1]<fr.time && drop1+1<ndrop) {
1275 if (fabs(dropval[0][drop0] - fr.time)
1276 < fabs(dropval[0][drop1] - fr.time)) {
1281 if ((bDropUnder && dropval[1][dropuse] < dropunder) ||
1282 (bDropOver && dropval[1][dropuse] > dropover))
1283 bWriteFrame = FALSE;
1290 fr.time = tzero+frame*timestep;
1296 fprintf(stderr,"\nDumping frame at t= %g %s\n",
1297 output_env_conv_time(oenv,fr.time),output_env_get_time_unit(oenv));
1299 /* check for writing at each delta_t */
1300 bDoIt=(delta_t == 0);
1304 bDoIt=bRmod(fr.time,tzero, delta_t);
1306 /* round() is not C89 compatible, so we do this: */
1307 bDoIt=bRmod(floor(fr.time+0.5),floor(tzero+0.5),
1308 floor(delta_t+0.5));
1311 if (bDoIt || bTDump) {
1312 /* print sometimes */
1313 if ( ((outframe % SKIP) == 0) || (outframe < SKIP) )
1314 fprintf(stderr," -> frame %6d time %8.3f \r",
1315 outframe,output_env_conv_time(oenv,fr.time));
1318 /* Now modify the coords according to the flags,
1319 for PFit we did this already! */
1322 gmx_rmpbc_trxfr(gpbc,&fr);
1325 reset_x_ndim(nfitdim,ifit,ind_fit,natoms,NULL,fr.x,w_rls);
1327 do_fit_ndim(nfitdim,natoms,w_rls,xp,fr.x);
1329 for(i=0; i<natoms; i++)
1330 rvec_inc(fr.x[i],x_shift);
1334 center_x(ecenter,fr.x,fr.box,natoms,ncent,cindex);
1338 switch (unitcell_enum) {
1340 put_atoms_in_box(fr.box,natoms,fr.x);
1343 put_atoms_in_triclinic_unitcell(ecenter,fr.box,natoms,fr.x);
1346 warn = put_atoms_in_compact_unitcell(ePBC,ecenter,fr.box,
1348 if (warn && !bWarnCompact) {
1349 fprintf(stderr,"\n%s\n",warn);
1350 bWarnCompact = TRUE;
1356 put_residue_com_in_box(unitcell_enum,ecenter,
1357 natoms,atoms->atom,ePBC,fr.box,fr.x);
1360 put_molecule_com_in_box(unitcell_enum,ecenter,
1362 natoms,atoms->atom,ePBC,fr.box,fr.x);
1364 /* Copy the input trxframe struct to the output trxframe struct */
1366 frout.bV = (frout.bV && bVels);
1367 frout.bF = (frout.bF && bForce);
1368 frout.natoms = nout;
1369 if (bNeedPrec && (bSetPrec || !fr.bPrec)) {
1381 for(i=0; i<nout; i++) {
1382 copy_rvec(fr.x[index[i]],frout.x[i]);
1384 copy_rvec(fr.v[index[i]],frout.v[i]);
1387 copy_rvec(fr.f[index[i]],frout.f[i]);
1392 if (opt2parg_bSet("-shift",NPA,pa))
1393 for(i=0; i<nout; i++)
1394 for (d=0; d<DIM; d++)
1395 frout.x[i][d] += outframe*shift[d];
1398 bSplitHere = bSplit && bRmod(fr.time,tzero, split_t);
1401 /* round() is not C89 compatible, so we do this: */
1402 bSplitHere = bSplit && bRmod(floor(fr.time+0.5),
1404 floor(split_t+0.5));
1406 if (bSeparate || bSplitHere)
1407 mk_filenm(outf_base,ftp2ext(ftp),nzero,file_nr,out_file2);
1417 trxout = open_trx(out_file2,filemode);
1420 if (my_clust != -1) {
1422 if (clust_status_id[my_clust] == -1) {
1423 sprintf(buf,"%s.%s",clust->grpname[my_clust],ftp2ext(ftp));
1424 clust_status[my_clust] = open_trx(buf,"w");
1425 clust_status_id[my_clust] = 1;
1428 else if (clust_status_id[my_clust] == -2)
1429 gmx_fatal(FARGS,"File %s.xtc should still be open (%d open .xtc files)\n""in order to write frame %d. my_clust = %d",
1430 clust->grpname[my_clust],ntrxopen,frame,
1432 write_trxframe(clust_status[my_clust],&frout,gc);
1433 nfwritten[my_clust]++;
1434 if (nfwritten[my_clust] ==
1435 (clust->clust->index[my_clust+1]-
1436 clust->clust->index[my_clust])) {
1437 close_trx(clust_status[my_clust]);
1438 clust_status[my_clust] = NULL;
1439 clust_status_id[my_clust] = -2;
1442 gmx_fatal(FARGS,"Less than zero open .xtc files!");
1447 write_trxframe(trxout,&frout,gc);
1452 sprintf(title,"Generated by trjconv : %s t= %9.5f",
1454 if (bSeparate || bSplitHere)
1455 out=ffopen(out_file2,"w");
1458 write_hconf_p(out,title,&useatoms,prec2ndec(frout.prec),
1459 frout.x,frout.bV?frout.v:NULL,frout.box);
1462 fprintf(out,"REMARK GENERATED BY TRJCONV\n");
1463 sprintf(title,"%s t= %9.5f",top_title,frout.time);
1464 /* if reading from pdb, we want to keep the original
1465 model numbering else we write the output frame
1466 number plus one, because model 0 is not allowed in pdb */
1467 if (ftpin==efPDB && fr.bStep && fr.step > model_nr)
1471 write_pdbfile(out,title,&useatoms,frout.x,
1472 frout.ePBC,frout.box,' ',model_nr,gc,TRUE);
1475 frout.title = title;
1476 if (bSeparate || bTDump) {
1477 frout.bTitle = TRUE;
1479 frout.bAtoms = TRUE;
1480 frout.atoms = &useatoms;
1481 frout.bStep = FALSE;
1482 frout.bTime = FALSE;
1484 frout.bTitle = (outframe == 0);
1485 frout.bAtoms = FALSE;
1489 write_g96_conf(out,&frout,-1,NULL);
1497 gmx_fatal(FARGS,"DHE, ftp=%d\n",ftp);
1499 if (bSeparate || bSplitHere)
1502 /* execute command */
1505 sprintf(c,"%s %d",exec_command,file_nr-1);
1506 /*fprintf(stderr,"Executing '%s'\n",c);*/
1507 #ifdef GMX_NO_SYSTEM
1508 printf("Warning-- No calls to system(3) supported on this platform.");
1509 printf("Warning-- Skipping execution of 'system(\"%s\")'.", c);
1513 gmx_fatal(FARGS,"Error executing command: %s",c);
1521 bHaveNextFrame=read_next_frame(oenv,status,&fr);
1522 } while (!(bTDump && bDumpFrame) && bHaveNextFrame);
1525 if (!bHaveFirstFrame || (bTDump && !bDumpFrame))
1526 fprintf(stderr,"\nWARNING no output, "
1527 "last frame read at t=%g\n",fr.time);
1528 fprintf(stderr,"\n");
1534 gmx_rmpbc_done(gpbc);
1538 else if (out != NULL)
1541 for(i=0; (i<clust->clust->nr); i++)
1542 if (clust_status[i] )
1543 close_trx(clust_status[i]);
1547 do_view(oenv,out_file,NULL);