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