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