Update copyright statements and change license to LGPL
[alexxy/gromacs.git] / src / ngmx / manager.c
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
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.
11  *
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.
16  *
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.
21  *
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.
26  *
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.
34  *
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.
37  */
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #include <sysstuff.h>
43 #include <string.h>
44 #include <smalloc.h>
45 #include <ctype.h>
46 #include <typedefs.h>
47 #include <smalloc.h>
48 #include <tpxio.h>
49 #include <macros.h>
50 #include <maths.h>
51 #include <atomprop.h>
52 #include <names.h>
53 #include "manager.h"
54 #include "futil.h"
55 #include "pbc.h"
56 #include "nmol.h"
57 #include "copyrite.h"
58 #include "gstat.h"
59 #include "vec.h"
60 #include "statutil.h"
61 #include "string2.h"
62
63 static void add_object(t_manager *man,eObject eO,atom_id ai,atom_id aj)
64 {
65   srenew(man->obj,++man->nobj);
66   man->obj[man->nobj-1].eO    = eO;
67   man->obj[man->nobj-1].eV    = eVNormal;
68   man->obj[man->nobj-1].color = WHITE;
69   man->obj[man->nobj-1].ai    = ai;
70   man->obj[man->nobj-1].aj    = aj;
71   man->obj[man->nobj-1].z     = 0.0;
72 }
73
74 static void add_bonds(t_manager *man,t_functype func[],
75                       t_ilist *b,gmx_bool bB[])
76 {
77   gmx_bool    *bH=man->bHydro;
78   t_iatom *ia;
79   t_iatom type,ai,aj,ak;
80   int     i,delta,ftype;
81   
82 #ifdef DEBUG
83   fprintf(stderr,"Going to make bonds from an ilist with %d entries\n",b->nr);
84 #endif
85   ia=b->iatoms;
86   for(i=0; (i<b->nr); ) {
87     type  = ia[0];
88     ai    = ia[1];
89     ftype = func[type];
90     delta = interaction_function[ftype].nratoms;
91     
92     if (ftype == F_SETTLE) {
93       aj = ia[2];
94       ak = ia[3];
95       bB[ai]=bB[aj]=bB[ak]=TRUE;
96       add_object(man,eOHBond,ai,aj);
97       add_object(man,eOHBond,ai,ak);
98     }
99     else if (IS_CHEMBOND(ftype)) {
100       aj=ia[2];
101 #ifdef DEBUG
102       fprintf(stderr,"Adding bond from %d to %d\n",ai,aj);
103 #endif
104       bB[ai]=bB[aj]=TRUE;
105       if (!(bH[ai] == bH[aj])) 
106         add_object(man,eOHBond,ai,aj);
107       else if (!bH[ai] && !bH[aj]) 
108         add_object(man,eOBond,ai,aj);
109     }
110 #ifdef DEBUG
111     fprintf(stderr,"Type: %5d, delta: %5d\n",type,delta);
112 #endif
113     ia += delta+1;
114     i  += delta+1;
115   }
116 }
117
118 static void add_bpl(t_manager *man,t_idef *idef,gmx_bool bB[])
119 {
120   int ftype;
121
122   for(ftype=0; ftype<F_NRE; ftype++)
123     if (IS_CHEMBOND(ftype) || ftype==F_SETTLE)
124       add_bonds(man,idef->functype,&idef->il[ftype],bB);
125 }
126  
127 static atom_id which_atom(t_manager *man,int x, int y)
128 {
129 #define DELTA 5
130   int i;
131   iv2 *ix=man->ix;
132
133   for(i=0; (i<man->natom); i++) {
134     if ((abs(ix[i][XX]-x) < DELTA) && (abs(ix[i][YY]-y) < DELTA)) {
135       if (man->bVis[i]) 
136         return (atom_id) i;
137     }
138   }
139   return NO_ATID;
140 }
141
142 static void do_label(t_x11 *x11,t_manager *man,int x,int y,gmx_bool bSet)
143 {
144   atom_id ai;
145   unsigned long   col;
146
147   if ((ai=which_atom(man,x,y)) != NO_ATID) {
148     x=man->ix[ai][XX];
149     y=man->ix[ai][YY];
150     if (bSet && !man->bLabel[ai]) {
151       col=WHITE;
152       man->bLabel[ai]=TRUE;
153     }
154     else if (!bSet && man->bLabel[ai]) {
155       col=BLUE;
156       man->bLabel[ai]=FALSE;
157     }
158     else
159       return;
160     XSetForeground(x11->disp,x11->gc,col);
161     XDrawString(x11->disp,man->molw->wd.self,x11->gc,x+2,y-2,man->szLab[ai],
162                 strlen(man->szLab[ai]));
163     XSetForeground(x11->disp,x11->gc,x11->fg);
164   }
165 }
166
167 static void show_label(t_x11 *x11,t_manager *man,int x,int y)
168 {
169   do_label(x11,man,x,y,TRUE);
170 }
171
172 static void hide_label(t_x11 *x11,t_manager *man,int x,int y)
173 {
174   do_label(x11,man,x,y,FALSE);
175 }
176
177 void set_file(t_x11 *x11,t_manager *man,const char *trajectory,
178               const char *status)
179 {
180   gmx_atomprop_t aps;
181   char         buf[256],quote[256];
182   t_tpxheader  sh;
183   t_atoms      *at;
184   gmx_bool         *bB;
185   int          i,idum;
186
187   read_tpxheader(status,&sh,TRUE,NULL,NULL);
188   snew(man->ix,sh.natoms);
189   snew(man->zz,sh.natoms);
190   snew(man->col,sh.natoms);
191   snew(man->size,sh.natoms);
192   snew(man->vdw,sh.natoms);
193   snew(man->bLabel,sh.natoms);
194   snew(man->bVis,sh.natoms);
195   for(i=0; (i<sh.natoms); i++)
196     man->bVis[i]=FALSE;
197
198   man->bPbc=FALSE;
199
200   snew(man->szLab,sh.natoms);
201   snew(man->bHydro,sh.natoms);
202   snew(bB,sh.natoms);
203   read_tpx_top(status,NULL,man->box,&man->natom,NULL,NULL,NULL,&man->top);
204   man->gpbc = gmx_rmpbc_init(&man->top.idef,-1,man->natom,man->box);
205   
206   man->natom=
207     read_first_x(man->oenv,&man->status,trajectory,&(man->time),&(man->x),
208                  man->box);
209   man->trajfile=strdup(trajectory);
210   if (man->natom > man->top.atoms.nr)
211     gmx_fatal(FARGS,"Topology %s (%d atoms) and trajectory %s (%d atoms) "
212                 "do not match",status,man->top.atoms.nr,
213                 trajectory,man->natom);
214  
215   cool_quote(quote,255,NULL);
216   sprintf(buf,"%s: %s",*man->top.name,quote);
217   man->title.text = strdup(buf);
218   man->view       = init_view(man->box);
219   at  = &(man->top.atoms);
220   aps = gmx_atomprop_init();
221   for(i=0; (i<man->natom); i++) {
222     char *aname=*(at->atomname[i]);
223     t_resinfo *ri=&at->resinfo[at->atom[i].resind];
224
225     man->col[i]=Type2Color(aname);
226     snew(man->szLab[i],20);
227     if (ri->ic != ' ') {
228       sprintf(man->szLab[i],"%s%d%c, %s",*ri->name,ri->nr,ri->ic,aname);
229     } else {
230       sprintf(man->szLab[i],"%s%d, %s",*ri->name,ri->nr,aname);
231     }
232     man->bHydro[i]=(toupper(aname[0])=='H');
233     if ( man->bHydro[i] )
234       man->vdw[i]=0;
235     else if (!gmx_atomprop_query(aps,epropVDW,*ri->name,aname,&(man->vdw[i])))
236       man->vdw[i] = 0;
237   }
238   gmx_atomprop_destroy(aps);
239   add_bpl(man,&(man->top.idef),bB);
240   for(i=0; (i<man->natom); i++)
241     if (!bB[i]) 
242       add_object(man,eOSingle,(atom_id) i,0);
243   sfree(bB);
244
245   ExposeWin(x11->disp,man->molw->wd.self);
246 }
247
248 void step_message(t_x11 *x11,t_manager *man)
249 {
250   XEvent letter;
251
252   letter.type=ClientMessage;
253   letter.xclient.display=x11->disp;
254   letter.xclient.window=man->wd.self;
255   letter.xclient.message_type=0;
256   letter.xclient.format=32;
257   letter.xclient.data.l[0]=IDSTEP;
258   letter.xclient.data.l[1]=Button1;
259   XSendEvent(x11->disp,letter.xclient.window,True,0,&letter);
260 }
261
262 gmx_bool ReadMonfile(char *fn,int *nbars, int *bars)
263 {
264   FILE *fp;
265   if ((fp = fopen(fn,"r"))==NULL) 
266     return(FALSE);
267   else {
268     for((*nbars)=0; fscanf(fp,"%d",&bars[*nbars])>0; (*nbars)++)
269       ;
270     fclose(fp);
271     return (TRUE);
272   }
273 }
274
275 static void reset_mols(t_block *mols,matrix box,rvec x[])
276 {
277   int  i,m0,m1,j,m;
278   rvec xcm,icm;
279   real ix,iy,iz;
280   
281   for(i=0; (i<mols->nr); i++) {
282     m0=mols->index[i];
283     m1=mols->index[i+1];
284     
285     clear_rvec(xcm);
286     clear_rvec(icm);
287     
288     for(j=m0; (j<m1); j++) {
289       rvec_inc(xcm,x[j]);
290     }
291     for(m=0; (m<DIM); m++)
292       xcm[m]/=(m1-m0);
293     for(m=0; (m<DIM); m++) {
294       if (xcm[m] < 0) 
295         icm[m]=box[m][m];
296       else if (xcm[m] >= box[m][m]) 
297         icm[m]=-box[m][m];
298     }
299     ix=icm[XX],iy=icm[YY],iz=icm[ZZ];
300     
301     if ((ix != 0) || (iy != 0) || (iz != 0)) {
302       for(j=m0; (j<m1); j++) {
303         x[j][XX]+=ix;
304         x[j][YY]+=iy;
305         x[j][ZZ]+=iz;
306       }
307     }
308   }
309 }
310
311 static gmx_bool step_man(t_manager *man,int *nat)
312 {
313   static int  ncount=0;
314   static gmx_bool bWarn = FALSE;
315   gmx_bool        bEof;
316   int         dum;
317   const char *warn;
318
319   if (!man->natom) {
320     fprintf(stderr,"Not initiated yet!");
321     exit(1);
322   }
323   bEof=read_next_x(man->oenv,man->status,&man->time,man->natom,man->x,man->box);
324   *nat=man->natom;
325   if (ncount == man->nSkip) {
326     switch (man->molw->boxtype) {
327     case esbTri:
328       put_atoms_in_triclinic_unitcell(ecenterDEF,man->box,man->natom,man->x);
329       break;
330     case esbTrunc:
331       warn = put_atoms_in_compact_unitcell(man->molw->ePBC,ecenterDEF,man->box,
332                                            man->natom,man->x);
333       if (warn && !bWarn) {
334         fprintf(stderr,"\n%s\n",warn);
335         bWarn = TRUE;
336       }
337       break;
338     case esbRect:
339     case esbNone:
340     default:
341       break;
342     }
343     if (man->bPbc) {
344       gmx_rmpbc(man->gpbc,man->natom,man->box,man->x);
345       reset_mols(&(man->top.mols),man->box,man->x);
346     }
347     ncount=0;
348   }
349   else {
350     if (man->nSkip > 0) {
351       ncount++;
352       return step_man(man,nat);
353     }
354   }
355
356   return bEof;
357 }
358
359 static void HandleClient(t_x11 *x11,t_manager *man,long data[])
360 {
361   int  ID,button,x,y;
362   gmx_bool bPos;
363   real fac;
364
365   ID=data[0];
366   button=data[1];
367   x=data[2];
368   y=data[3];
369   bPos=(button==Button1);
370   switch (ID) {
371   case IDROTX:
372   case IDROTY:
373   case IDROTZ:
374     rotate_3d(man->view,ID-IDROTX,bPos);
375     draw_mol(x11,man);
376     break;
377   case IDZOOM:
378     if (bPos)
379       fac=0.8; /* Reduce distance between eye and origin */
380     else
381       fac=1.25;
382     
383     /*  zoom changed to scale by Berk Hess 3-7-96
384     if (zoom_3d(man->view,fac))
385       draw_mol(x11,man); */
386     man->view->sc_x/=fac;
387     man->view->sc_y/=fac;
388     draw_mol(x11,man);
389     break;
390   case IDTRANSX:
391   case IDTRANSY:
392   case IDTRANSZ:
393     translate_view(man->view,ID-IDTRANSX,bPos);
394     draw_mol(x11,man);
395     break;
396   case IDREWIND:
397     if (man->status) {
398       rewind_trj(man->status);
399       read_next_x(man->oenv,man->status,&(man->time),man->natom,man->x,
400                   man->box);
401       man->bEof=FALSE;
402       draw_mol(x11,man);
403     }
404     break;
405   case IDSTEP: {
406     int      nat;
407
408     nat=0;
409     if (!step_man(man,&nat)) {
410       man->bEof=TRUE;
411       man->bStop=TRUE;
412     }
413     else {
414       if (nat > 0) {
415         draw_mol(x11,man);
416         usleep(man->nWait*1000);
417       }
418     }
419     break;
420   }
421   case IDFF:
422     man->bStop=FALSE;
423     break;
424   case IDSTOP_ANI:
425     man->bStop=TRUE;
426     break;
427   case IDDRAWMOL:
428     draw_mol(x11,man);
429     break;
430   case IDLABEL:
431     switch (button) {
432     case Button1:
433     case Button2:
434       show_label(x11,man,x,y);
435       break;
436     case Button3:
437       hide_label(x11,man,x,y);
438       break;
439     }
440     break;
441   default:
442     break;
443   }
444   if (man->bAnimate && !man->bEof && !man->bStop)
445     step_message(x11,man);
446 }
447
448 static gmx_bool TitleCallBack(t_x11 *x11,XEvent *event, Window w, void *data)
449 {
450   t_windata *wd;
451
452   wd=(t_windata *)data;
453   switch (event->type) {
454   case Expose:
455     if (wd->text && (wd->width > 10)) {
456       XSetForeground(x11->disp,x11->gc,WHITE);
457       TextInWin(x11,wd,wd->text,eXCenter,eYCenter);
458       XDrawLine(x11->disp,wd->self,x11->gc,0,wd->height,
459                 wd->width,wd->height);
460     }
461     break;
462   case ConfigureNotify:
463     wd->width=event->xconfigure.width;
464     wd->height=event->xconfigure.height;
465     break;
466   }
467   return FALSE;
468 }
469
470 static gmx_bool ManCallBack(t_x11 *x11,XEvent *event, Window w, void *data)
471 {
472   t_manager *man;
473   int       width,height;
474
475   man=(t_manager *)data;
476   switch(event->type) {
477   case ConfigureNotify:
478     width=event->xconfigure.width;
479     height=event->xconfigure.height;
480     if ((width!=man->wd.width) || (height!=man->wd.height))
481       move_man(x11,man,width,height);
482     break;
483   case ClientMessage:
484     HandleClient(x11,man,event->xclient.data.l);
485     break;
486   default:
487     break;
488   }
489   return FALSE;
490 }
491
492 void no_labels(t_x11 *x11,t_manager *man)
493 {
494   int i;
495
496   for(i=0; (i<man->natom); i++)
497     man->bLabel[i]=FALSE;
498   draw_mol(x11,man);
499 }
500
501 void move_man(t_x11 *x11,t_manager *man,int width,int height)
502 {
503   int x0,y0,mw,mh,hb;
504   int th;
505   
506 #ifdef DEBUG
507   fprintf(stderr,"Move manager %dx%d\n",width,height);
508 #endif
509   man->wd.width=width;
510   man->wd.height=height;
511
512   /* Move all subwindows, resize only Mol window */
513   x0=width-EWIDTH-AIR-4*BORDER;               /* Starting of ewin etc. */
514   y0=AIR;
515   
516   /* Mol Window */
517   mw=x0-2*AIR-4*BORDER;
518   mh=height-y0-AIR-2*BORDER;
519   XMoveResizeWindow(x11->disp,man->molw->wd.self,AIR,y0,mw,mh);
520
521   /* Title Window */
522   th=XTextHeight(x11->font);
523   XMoveResizeWindow(x11->disp,man->title.self,0,0,mw,th+AIR);
524   
525   /* Legend Window */
526   XMoveResizeWindow(x11->disp,man->legw->wd.self,x0,y0,EWIDTH,LEGHEIGHT);
527   y0+=LEGHEIGHT+AIR+2*BORDER;
528
529   if (y0 > height) 
530     printf("Error: Windows falling out of main window!\n");
531
532   /* Button Box */
533   hb=height-y0-AIR-2*BORDER;
534   XMoveResizeWindow(x11->disp,man->bbox->wd.self,x0,y0,EWIDTH,hb);
535   
536   /* Video Box */
537   x0=(mw-man->vbox->wd.width)/2;
538   y0=(mh-2-AIR-man->vbox->wd.height);
539   XMoveWindow(x11->disp,man->vbox->wd.self,x0,y0);
540 }
541
542 void map_man(t_x11 *x11,t_manager *man)
543 {
544   XMapWindow(x11->disp,man->wd.self);
545   map_mw(x11,man->molw);
546   XMapWindow(x11->disp,man->title.self);
547   map_legw(x11,man->legw);
548   show_but(x11,man->bbox);
549 }
550
551 gmx_bool toggle_animate (t_x11 *x11,t_manager *man)
552
553   if (man->status) {
554     man->bAnimate=!man->bAnimate;
555     man->bStop=TRUE;
556     man->bEof=FALSE;
557     if (man->bAnimate)
558       show_but(x11,man->vbox);
559     else
560       hide_but(x11,man->vbox);
561   }
562   return man->bAnimate;
563 }
564
565 gmx_bool toggle_pbc (t_manager *man)
566 {
567   man->bPbc=!man->bPbc;
568   
569   return man->bPbc;
570 }
571
572
573 t_manager *init_man(t_x11 *x11,Window Parent,
574                     int x,int y,int width,int height,
575                     unsigned long fg,unsigned long bg,
576                     int ePBC,matrix box,
577                     const output_env_t oenv)
578 {
579   t_manager *man;
580
581   snew(man,1);
582   man->status=NULL;
583   man->bPlus=TRUE;
584   man->bSort=TRUE;
585   man->oenv=oenv;
586   InitWin(&(man->wd),x,y,width,height,0,"Manager");
587   man->wd.self=XCreateSimpleWindow(x11->disp,Parent,man->wd.x, man->wd.y, 
588                                    man->wd.width,man->wd.height,
589                                    man->wd.bwidth,fg,bg);
590   x11->RegisterCallback(x11,man->wd.self,Parent,ManCallBack,man);
591   x11->SetInputMask(x11,man->wd.self,StructureNotifyMask | 
592                     ExposureMask | ButtonPressMask);
593
594   /* The order of creating windows is important for the stacking order */
595   /* Mol Window */
596   man->molw=init_mw(x11,man->wd.self,0,0,1,1,WHITE,BLUE,ePBC,box);
597
598   /* Title Window */
599   InitWin(&(man->title),0,0,1,1,0,NULL);
600   man->title.self=XCreateSimpleWindow(x11->disp,man->molw->wd.self,
601                                       man->title.x,man->title.y,
602                                       man->title.width,man->title.height,
603                                       man->title.bwidth,WHITE,BLUE);
604   x11->RegisterCallback(x11,man->title.self,man->molw->wd.self,
605                         TitleCallBack,&(man->title));
606   x11->SetInputMask(x11,man->title.self,ExposureMask | StructureNotifyMask);
607   
608   /* Button box */
609   man->bbox=init_bbox(x11,man->wd.self,man->wd.self,1,WHITE,BLUE);
610   
611   /* Legend Window */
612   man->legw=init_legw(x11,man->wd.self,0,0,EWIDTH,LEGHEIGHT,WHITE,BLUE);
613
614   /* Video Box */
615   man->vbox=init_vbox(x11,man->molw->wd.self,man->wd.self,WHITE,BLUE);
616   
617   return man;
618 }
619
620 void done_man(t_x11 *x11,t_manager *man)
621 {
622   done_bbox(x11,man->vbox);
623   done_bbox(x11,man->bbox);
624   done_mw(x11,man->molw);
625   done_legw(x11,man->legw);
626   x11->UnRegisterCallback(x11,man->title.self);
627   x11->UnRegisterCallback(x11,man->wd.self);
628   sfree(man->x);
629   sfree(man->obj);
630   sfree(man->bHydro);
631   sfree(man->bLabel);
632   sfree(man->szLab);
633   sfree(man->col);
634   sfree(man);
635 }
636
637 void do_filter(t_x11 *x11,t_manager *man,t_filter *filter)
638 {
639   int      i;
640   atom_id  j;
641
642   for(i=0; (i<man->natom); i++)
643     man->bVis[i]=FALSE;
644   for(i=0; (i<filter->grps->nr); i++) {
645     if (filter->bShow[i])
646       for(j=filter->grps->index[i]; (j<filter->grps->index[i+1]); j++)
647         man->bVis[filter->grps->a[j]]=TRUE;
648   }
649
650   ExposeWin(x11->disp,man->wd.self);
651 }