Update instructions in containers.rst
[gromacs.git] / src / programs / view / manager.cpp
blobd5fbd842f365399b8f8365728134d6093229a1e5
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
7 * Copyright (c) 2019,2020, by the GROMACS development team, led by
8 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9 * and including many others, as listed in the AUTHORS file in the
10 * top-level source directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
38 #include "gmxpre.h"
40 #include "manager.h"
42 #include "config.h"
44 #include <cctype>
45 #include <cstdio>
46 #include <cstdlib>
47 #include <cstring>
49 #include <string>
51 #ifdef HAVE_UNISTD_H
52 # include <unistd.h> // for usleep()
53 #endif
55 #include "gromacs/fileio/tpxio.h"
56 #include "gromacs/math/utilities.h"
57 #include "gromacs/math/vec.h"
58 #include "gromacs/mdtypes/md_enums.h"
59 #include "gromacs/pbcutil/pbc.h"
60 #include "gromacs/topology/atomprop.h"
61 #include "gromacs/topology/ifunc.h"
62 #include "gromacs/utility/coolstuff.h"
63 #include "gromacs/utility/cstringutil.h"
64 #include "gromacs/utility/fatalerror.h"
65 #include "gromacs/utility/futil.h"
66 #include "gromacs/utility/smalloc.h"
67 #include "gromacs/utility/stringutil.h"
69 #include "3dview.h"
70 #include "nmol.h"
72 static void add_object(t_manager* man, eObject eO, int ai, int aj)
74 srenew(man->obj, ++man->nobj);
75 man->obj[man->nobj - 1].eO = eO;
76 man->obj[man->nobj - 1].eV = eVNormal;
77 man->obj[man->nobj - 1].color = WHITE;
78 man->obj[man->nobj - 1].ai = ai;
79 man->obj[man->nobj - 1].aj = aj;
80 man->obj[man->nobj - 1].z = 0.0;
83 static void add_bonds(t_manager* man, const t_functype func[], t_ilist* b, bool bB[])
85 bool* bH = man->bHydro;
86 t_iatom* ia;
87 t_iatom type, ai, aj, ak;
88 int i, delta, ftype;
90 #ifdef DEBUG
91 std::fprintf(stderr, "Going to make bonds from an ilist with %d entries\n", b->nr);
92 #endif
93 ia = b->iatoms;
94 for (i = 0; (i < b->nr);)
96 type = ia[0];
97 ai = ia[1];
98 ftype = func[type];
99 delta = interaction_function[ftype].nratoms;
101 if (ftype == F_SETTLE)
103 aj = ia[2];
104 ak = ia[3];
105 bB[ai] = bB[aj] = bB[ak] = true;
106 add_object(man, eOHBond, ai, aj);
107 add_object(man, eOHBond, ai, ak);
109 else if (IS_CHEMBOND(ftype))
111 aj = ia[2];
112 #ifdef DEBUG
113 std::fprintf(stderr, "Adding bond from %d to %d\n", ai, aj);
114 #endif
115 bB[ai] = bB[aj] = true;
116 if (!(bH[ai] == bH[aj]))
118 add_object(man, eOHBond, ai, aj);
120 else if (!bH[ai] && !bH[aj])
122 add_object(man, eOBond, ai, aj);
125 #ifdef DEBUG
126 std::fprintf(stderr, "Type: %5d, delta: %5d\n", type, delta);
127 #endif
128 ia += delta + 1;
129 i += delta + 1;
133 static void add_bpl(t_manager* man, t_idef* idef, bool bB[])
135 int ftype;
137 for (ftype = 0; ftype < F_NRE; ftype++)
139 if (IS_CHEMBOND(ftype) || ftype == F_SETTLE)
141 add_bonds(man, idef->functype, &idef->il[ftype], bB);
146 static int which_atom(t_manager* man, int x, int y)
148 #define DELTA 5
149 int i;
150 iv2* ix = man->ix;
152 for (i = 0; (i < man->natom); i++)
154 if ((std::abs(ix[i][XX] - x) < DELTA) && (std::abs(ix[i][YY] - y) < DELTA))
156 if (man->bVis[i])
158 return i;
162 return -1;
165 static void do_label(t_x11* x11, t_manager* man, int x, int y, bool bSet)
167 int ai;
168 unsigned long col;
170 if ((ai = which_atom(man, x, y)) != -1)
172 x = man->ix[ai][XX];
173 y = man->ix[ai][YY];
174 if (bSet && !man->bLabel[ai])
176 col = WHITE;
177 man->bLabel[ai] = true;
179 else if (!bSet && man->bLabel[ai])
181 col = BLUE;
182 man->bLabel[ai] = false;
184 else
186 return;
188 XSetForeground(x11->disp, x11->gc, col);
189 XDrawString(x11->disp, man->molw->wd.self, x11->gc, x + 2, y - 2, man->szLab[ai],
190 std::strlen(man->szLab[ai]));
191 XSetForeground(x11->disp, x11->gc, x11->fg);
195 static void show_label(t_x11* x11, t_manager* man, int x, int y)
197 do_label(x11, man, x, y, true);
200 static void hide_label(t_x11* x11, t_manager* man, int x, int y)
202 do_label(x11, man, x, y, false);
205 void set_file(t_x11* x11, t_manager* man, const char* trajectory, const char* status)
207 t_atoms* at;
208 bool* bB;
209 int i;
211 TpxFileHeader sh = readTpxHeader(status, true);
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++)
221 man->bVis[i] = false;
224 man->bPbc = false;
226 snew(man->szLab, sh.natoms);
227 snew(man->bHydro, sh.natoms);
228 snew(bB, sh.natoms);
229 read_tpx_top(status, nullptr, man->box, &man->natom, nullptr, nullptr, &man->top);
230 man->gpbc = gmx_rmpbc_init(&man->top.idef, PbcType::Unset, man->natom);
232 man->natom = read_first_x(man->oenv, &man->status, trajectory, &(man->time), &(man->x), man->box);
233 man->trajfile = gmx_strdup(trajectory);
234 if (man->natom > man->top.atoms.nr)
236 gmx_fatal(FARGS,
237 "Topology %s (%d atoms) and trajectory %s (%d atoms) "
238 "do not match",
239 status, man->top.atoms.nr, trajectory, man->natom);
242 man->title.text =
243 gmx_strdup(gmx::formatString("%s: %s", *man->top.name, gmx::getCoolQuote().c_str()).c_str());
244 man->view = init_view(man->box);
245 at = &(man->top.atoms);
246 AtomProperties aps;
247 for (i = 0; (i < man->natom); i++)
249 char* aname = *(at->atomname[i]);
250 t_resinfo* ri = &at->resinfo[at->atom[i].resind];
252 man->col[i] = Type2Color(aname);
253 snew(man->szLab[i], 20);
254 if (ri->ic != ' ')
256 std::sprintf(man->szLab[i], "%s%d%c, %s", *ri->name, ri->nr, ri->ic, aname);
258 else
260 std::sprintf(man->szLab[i], "%s%d, %s", *ri->name, ri->nr, aname);
262 man->bHydro[i] = (toupper(aname[0]) == 'H');
263 if (man->bHydro[i])
265 man->vdw[i] = 0;
267 else if (!aps.setAtomProperty(epropVDW, *ri->name, aname, &(man->vdw[i])))
269 man->vdw[i] = 0;
272 add_bpl(man, &(man->top.idef), bB);
273 for (i = 0; (i < man->natom); i++)
275 if (!bB[i])
277 add_object(man, eOSingle, i, 0);
280 sfree(bB);
282 ExposeWin(x11->disp, man->molw->wd.self);
285 void step_message(t_x11* x11, t_manager* man)
287 XEvent letter;
289 letter.type = ClientMessage;
290 letter.xclient.display = x11->disp;
291 letter.xclient.window = man->wd.self;
292 letter.xclient.message_type = 0;
293 letter.xclient.format = 32;
294 letter.xclient.data.l[0] = IDSTEP;
295 letter.xclient.data.l[1] = Button1;
296 XSendEvent(x11->disp, letter.xclient.window, True, 0, &letter);
299 static void reset_mols(t_block* mols, matrix box, rvec x[])
301 int i, m0, m1, j, m;
302 rvec xcm, icm;
303 real ix, iy, iz;
305 for (i = 0; (i < mols->nr); i++)
307 m0 = mols->index[i];
308 m1 = mols->index[i + 1];
310 clear_rvec(xcm);
311 clear_rvec(icm);
313 for (j = m0; (j < m1); j++)
315 rvec_inc(xcm, x[j]);
317 for (m = 0; (m < DIM); m++)
319 xcm[m] /= (m1 - m0);
321 for (m = 0; (m < DIM); m++)
323 if (xcm[m] < 0)
325 icm[m] = box[m][m];
327 else if (xcm[m] >= box[m][m])
329 icm[m] = -box[m][m];
332 ix = icm[XX], iy = icm[YY], iz = icm[ZZ];
334 if ((ix != 0) || (iy != 0) || (iz != 0))
336 for (j = m0; (j < m1); j++)
338 x[j][XX] += ix;
339 x[j][YY] += iy;
340 x[j][ZZ] += iz;
346 static bool step_man(t_manager* man, int* nat)
348 static int ncount = 0;
349 bool bEof;
351 if (!man->natom)
353 std::fprintf(stderr, "Not initiated yet!");
354 std::exit(1);
356 bEof = read_next_x(man->oenv, man->status, &man->time, man->x, man->box);
357 *nat = man->natom;
358 if (ncount == man->nSkip)
360 auto atomsArrayRef = gmx::arrayRefFromArray(reinterpret_cast<gmx::RVec*>(man->x), man->natom);
361 switch (man->molw->boxtype)
363 case esbTri:
364 put_atoms_in_triclinic_unitcell(ecenterDEF, man->box, atomsArrayRef);
365 break;
366 case esbTrunc:
367 put_atoms_in_compact_unitcell(man->molw->pbcType, ecenterDEF, man->box, atomsArrayRef);
368 break;
369 case esbRect:
370 case esbNone:
371 default: break;
373 if (man->bPbc)
375 gmx_rmpbc(man->gpbc, man->natom, man->box, man->x);
376 reset_mols(&(man->top.mols), man->box, man->x);
378 ncount = 0;
380 else
382 if (man->nSkip > 0)
384 ncount++;
385 return step_man(man, nat);
389 return bEof;
392 static void HandleClient(t_x11* x11, t_manager* man, const long data[])
394 int ID, button, x, y;
395 bool bPos;
396 real fac;
398 ID = data[0];
399 button = data[1];
400 x = data[2];
401 y = data[3];
402 bPos = (button == Button1);
403 switch (ID)
405 case IDROTX:
406 case IDROTY:
407 case IDROTZ:
408 rotate_3d(man->view, ID - IDROTX, bPos);
409 draw_mol(x11, man);
410 break;
411 case IDZOOM:
412 if (bPos)
414 fac = 0.8; /* Reduce distance between eye and origin */
416 else
418 fac = 1.25;
421 /* zoom changed to scale by Berk Hess 3-7-96
422 if (zoom_3d(man->view,fac))
423 draw_mol(x11,man); */
424 man->view->sc_x /= fac;
425 man->view->sc_y /= fac;
426 draw_mol(x11, man);
427 break;
428 case IDTRANSX:
429 case IDTRANSY:
430 case IDTRANSZ:
431 translate_view(man->view, ID - IDTRANSX, bPos);
432 draw_mol(x11, man);
433 break;
434 case IDREWIND:
435 if (man->status)
437 rewind_trj(man->status);
438 read_next_x(man->oenv, man->status, &(man->time), man->x, man->box);
439 man->bEof = false;
440 draw_mol(x11, man);
442 break;
443 case IDSTEP:
445 int nat;
447 nat = 0;
448 if (!step_man(man, &nat))
450 man->bEof = true;
451 man->bStop = true;
453 else
455 if (nat > 0)
457 draw_mol(x11, man);
458 usleep(man->nWait * 1000);
461 break;
463 case IDFF: man->bStop = false; break;
464 case IDSTOP_ANI: man->bStop = true; break;
465 case IDDRAWMOL: draw_mol(x11, man); break;
466 case IDLABEL:
467 switch (button)
469 case Button1:
470 case Button2: show_label(x11, man, x, y); break;
471 case Button3: hide_label(x11, man, x, y); break;
473 break;
474 default: break;
476 if (man->bAnimate && !man->bEof && !man->bStop)
478 step_message(x11, man);
482 static bool TitleCallBack(t_x11* x11, XEvent* event, Window /*w*/, void* data)
484 t_windata* wd;
486 wd = static_cast<t_windata*>(data);
487 switch (event->type)
489 case Expose:
490 if (wd->text && (wd->width > 10))
492 XSetForeground(x11->disp, x11->gc, WHITE);
493 TextInWin(x11, wd, wd->text, eXCenter, eYCenter);
494 XDrawLine(x11->disp, wd->self, x11->gc, 0, wd->height, wd->width, wd->height);
496 break;
497 case ConfigureNotify:
498 wd->width = event->xconfigure.width;
499 wd->height = event->xconfigure.height;
500 break;
502 return false;
505 static bool ManCallBack(t_x11* x11, XEvent* event, Window /*w*/, void* data)
507 t_manager* man;
508 int width, height;
510 man = static_cast<t_manager*>(data);
511 switch (event->type)
513 case ConfigureNotify:
514 width = event->xconfigure.width;
515 height = event->xconfigure.height;
516 if ((width != man->wd.width) || (height != man->wd.height))
518 move_man(x11, man, width, height);
520 break;
521 case ClientMessage: HandleClient(x11, man, event->xclient.data.l); break;
522 default: break;
524 return false;
527 void no_labels(t_x11* x11, t_manager* man)
529 int i;
531 for (i = 0; (i < man->natom); i++)
533 man->bLabel[i] = false;
535 draw_mol(x11, man);
538 void move_man(t_x11* x11, t_manager* man, int width, int height)
540 int x0, y0, mw, mh, hb;
541 int th;
543 #ifdef DEBUG
544 std::fprintf(stderr, "Move manager %dx%d\n", width, height);
545 #endif
546 man->wd.width = width;
547 man->wd.height = height;
549 /* Move all subwindows, resize only Mol window */
550 x0 = width - EWIDTH - AIR - 4 * BORDER; /* Starting of ewin etc. */
551 y0 = AIR;
553 /* Mol Window */
554 mw = x0 - 2 * AIR - 4 * BORDER;
555 mh = height - y0 - AIR - 2 * BORDER;
556 XMoveResizeWindow(x11->disp, man->molw->wd.self, AIR, y0, mw, mh);
558 /* Title Window */
559 th = XTextHeight(x11->font);
560 XMoveResizeWindow(x11->disp, man->title.self, 0, 0, mw, th + AIR);
562 /* Legend Window */
563 XMoveResizeWindow(x11->disp, man->legw->wd.self, x0, y0, EWIDTH, LEGHEIGHT);
564 y0 += LEGHEIGHT + AIR + 2 * BORDER;
566 if (y0 > height)
568 std::printf("Error: Windows falling out of main window!\n");
571 /* Button Box */
572 hb = height - y0 - AIR - 2 * BORDER;
573 XMoveResizeWindow(x11->disp, man->bbox->wd.self, x0, y0, EWIDTH, hb);
575 /* Video Box */
576 x0 = (mw - man->vbox->wd.width) / 2;
577 y0 = (mh - 2 - AIR - man->vbox->wd.height);
578 XMoveWindow(x11->disp, man->vbox->wd.self, x0, y0);
581 void map_man(t_x11* x11, t_manager* man)
583 XMapWindow(x11->disp, man->wd.self);
584 map_mw(x11, man->molw);
585 XMapWindow(x11->disp, man->title.self);
586 map_legw(x11, man->legw);
587 show_but(x11, man->bbox);
590 bool toggle_animate(t_x11* x11, t_manager* man)
592 if (man->status)
594 man->bAnimate = !man->bAnimate;
595 man->bStop = true;
596 man->bEof = false;
597 if (man->bAnimate)
599 show_but(x11, man->vbox);
601 else
603 hide_but(x11, man->vbox);
606 return man->bAnimate;
609 bool toggle_pbc(t_manager* man)
611 man->bPbc = !man->bPbc;
613 return man->bPbc;
617 t_manager* init_man(t_x11* x11,
618 Window Parent,
619 int x,
620 int y,
621 int width,
622 int height,
623 unsigned long fg,
624 unsigned long bg,
625 PbcType pbcType,
626 matrix box,
627 gmx_output_env_t* oenv)
629 t_manager* man;
631 snew(man, 1);
632 man->status = nullptr;
633 man->bPlus = true;
634 man->bSort = true;
635 man->oenv = oenv;
636 InitWin(&(man->wd), x, y, width, height, 0, "Manager");
637 man->wd.self = XCreateSimpleWindow(x11->disp, Parent, man->wd.x, man->wd.y, man->wd.width,
638 man->wd.height, man->wd.bwidth, fg, bg);
639 x11->RegisterCallback(x11, man->wd.self, Parent, ManCallBack, man);
640 x11->SetInputMask(x11, man->wd.self, StructureNotifyMask | ExposureMask | ButtonPressMask);
642 /* The order of creating windows is important for the stacking order */
643 /* Mol Window */
644 man->molw = init_mw(x11, man->wd.self, 0, 0, 1, 1, WHITE, BLUE, pbcType, box);
646 /* Title Window */
647 InitWin(&(man->title), 0, 0, 1, 1, 0, nullptr);
648 man->title.self =
649 XCreateSimpleWindow(x11->disp, man->molw->wd.self, man->title.x, man->title.y,
650 man->title.width, man->title.height, man->title.bwidth, WHITE, BLUE);
651 x11->RegisterCallback(x11, man->title.self, man->molw->wd.self, TitleCallBack, &(man->title));
652 x11->SetInputMask(x11, man->title.self, ExposureMask | StructureNotifyMask);
654 /* Button box */
655 man->bbox = init_bbox(x11, man->wd.self, man->wd.self, 1, WHITE, BLUE);
657 /* Legend Window */
658 man->legw = init_legw(x11, man->wd.self, 0, 0, EWIDTH, LEGHEIGHT, WHITE, BLUE);
660 /* Video Box */
661 man->vbox = init_vbox(x11, man->molw->wd.self, man->wd.self, WHITE, BLUE);
663 return man;
666 void done_man(t_x11* x11, t_manager* man)
668 done_bbox(x11, man->vbox);
669 done_bbox(x11, man->bbox);
670 done_mw(x11, man->molw);
671 done_legw(x11, man->legw);
672 x11->UnRegisterCallback(x11, man->title.self);
673 x11->UnRegisterCallback(x11, man->wd.self);
674 sfree(man->x);
675 sfree(man->obj);
676 sfree(man->bHydro);
677 sfree(man->bLabel);
678 sfree(man->szLab);
679 sfree(man->col);
680 sfree(man);
683 void do_filter(t_x11* x11, t_manager* man, t_filter* filter)
685 int i;
686 int j;
688 for (i = 0; (i < man->natom); i++)
690 man->bVis[i] = false;
692 for (i = 0; (i < filter->grps->nr); i++)
694 if (filter->bShow[i])
696 for (j = filter->grps->index[i]; (j < filter->grps->index[i + 1]); j++)
698 man->bVis[filter->grps->a[j]] = true;
703 ExposeWin(x11->disp, man->wd.self);