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