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