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