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