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.
52 # include <unistd.h> // for usleep()
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"
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;
87 t_iatom type, ai, aj, ak;
91 std::fprintf(stderr, "Going to make bonds from an ilist with %d entries\n", b->nr);
94 for (i = 0; (i < b->nr);)
99 delta = interaction_function[ftype].nratoms;
101 if (ftype == F_SETTLE)
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))
113 std::fprintf(stderr, "Adding bond from %d to %d\n", ai, aj);
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);
126 std::fprintf(stderr, "Type: %5d, delta: %5d\n", type, delta);
133 static void add_bpl(t_manager* man, t_idef* idef, bool bB[])
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)
152 for (i = 0; (i < man->natom); i++)
154 if ((std::abs(ix[i][XX] - x) < DELTA) && (std::abs(ix[i][YY] - y) < DELTA))
165 static void do_label(t_x11* x11, t_manager* man, int x, int y, bool bSet)
170 if ((ai = which_atom(man, x, y)) != -1)
174 if (bSet && !man->bLabel[ai])
177 man->bLabel[ai] = true;
179 else if (!bSet && man->bLabel[ai])
182 man->bLabel[ai] = false;
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)
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;
226 snew(man->szLab, sh.natoms);
227 snew(man->bHydro, 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, -1, 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)
237 "Topology %s (%d atoms) and trajectory %s (%d atoms) "
239 status, man->top.atoms.nr, trajectory, man->natom);
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);
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);
256 std::sprintf(man->szLab[i], "%s%d%c, %s", *ri->name, ri->nr, ri->ic, aname);
260 std::sprintf(man->szLab[i], "%s%d, %s", *ri->name, ri->nr, aname);
262 man->bHydro[i] = (toupper(aname[0]) == 'H');
267 else if (!aps.setAtomProperty(epropVDW, *ri->name, aname, &(man->vdw[i])))
272 add_bpl(man, &(man->top.idef), bB);
273 for (i = 0; (i < man->natom); i++)
277 add_object(man, eOSingle, i, 0);
282 ExposeWin(x11->disp, man->molw->wd.self);
285 void step_message(t_x11* x11, t_manager* man)
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[])
305 for (i = 0; (i < mols->nr); i++)
308 m1 = mols->index[i + 1];
313 for (j = m0; (j < m1); j++)
317 for (m = 0; (m < DIM); m++)
321 for (m = 0; (m < DIM); m++)
327 else if (xcm[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++)
346 static bool step_man(t_manager* man, int* nat)
348 static int ncount = 0;
353 std::fprintf(stderr, "Not initiated yet!");
356 bEof = read_next_x(man->oenv, man->status, &man->time, man->x, man->box);
358 if (ncount == man->nSkip)
360 auto atomsArrayRef = gmx::arrayRefFromArray(reinterpret_cast<gmx::RVec*>(man->x), man->natom);
361 switch (man->molw->boxtype)
364 put_atoms_in_triclinic_unitcell(ecenterDEF, man->box, atomsArrayRef);
367 put_atoms_in_compact_unitcell(man->molw->ePBC, ecenterDEF, man->box, atomsArrayRef);
375 gmx_rmpbc(man->gpbc, man->natom, man->box, man->x);
376 reset_mols(&(man->top.mols), man->box, man->x);
385 return step_man(man, nat);
392 static void HandleClient(t_x11* x11, t_manager* man, const long data[])
394 int ID, button, x, y;
402 bPos = (button == Button1);
408 rotate_3d(man->view, ID - IDROTX, bPos);
414 fac = 0.8; /* Reduce distance between eye and origin */
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;
431 translate_view(man->view, ID - IDTRANSX, bPos);
437 rewind_trj(man->status);
438 read_next_x(man->oenv, man->status, &(man->time), man->x, man->box);
448 if (!step_man(man, &nat))
458 usleep(man->nWait * 1000);
463 case IDFF: man->bStop = false; break;
464 case IDSTOP_ANI: man->bStop = true; break;
465 case IDDRAWMOL: draw_mol(x11, man); break;
470 case Button2: show_label(x11, man, x, y); break;
471 case Button3: hide_label(x11, man, x, y); 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)
486 wd = static_cast<t_windata*>(data);
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);
497 case ConfigureNotify:
498 wd->width = event->xconfigure.width;
499 wd->height = event->xconfigure.height;
505 static bool ManCallBack(t_x11* x11, XEvent* event, Window /*w*/, void* data)
510 man = static_cast<t_manager*>(data);
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);
521 case ClientMessage: HandleClient(x11, man, event->xclient.data.l); break;
527 void no_labels(t_x11* x11, t_manager* man)
531 for (i = 0; (i < man->natom); i++)
533 man->bLabel[i] = false;
538 void move_man(t_x11* x11, t_manager* man, int width, int height)
540 int x0, y0, mw, mh, hb;
544 std::fprintf(stderr, "Move manager %dx%d\n", width, height);
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. */
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);
559 th = XTextHeight(x11->font);
560 XMoveResizeWindow(x11->disp, man->title.self, 0, 0, mw, th + AIR);
563 XMoveResizeWindow(x11->disp, man->legw->wd.self, x0, y0, EWIDTH, LEGHEIGHT);
564 y0 += LEGHEIGHT + AIR + 2 * BORDER;
568 std::printf("Error: Windows falling out of main window!\n");
572 hb = height - y0 - AIR - 2 * BORDER;
573 XMoveResizeWindow(x11->disp, man->bbox->wd.self, x0, y0, EWIDTH, hb);
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)
594 man->bAnimate = !man->bAnimate;
599 show_but(x11, man->vbox);
603 hide_but(x11, man->vbox);
606 return man->bAnimate;
609 bool toggle_pbc(t_manager* man)
611 man->bPbc = !man->bPbc;
617 t_manager* init_man(t_x11* x11,
627 gmx_output_env_t* oenv)
632 man->status = nullptr;
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 */
644 man->molw = init_mw(x11, man->wd.self, 0, 0, 1, 1, WHITE, BLUE, ePBC, box);
647 InitWin(&(man->title), 0, 0, 1, 1, 0, nullptr);
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);
655 man->bbox = init_bbox(x11, man->wd.self, man->wd.self, 1, WHITE, BLUE);
658 man->legw = init_legw(x11, man->wd.self, 0, 0, EWIDTH, LEGHEIGHT, WHITE, BLUE);
661 man->vbox = init_vbox(x11, man->molw->wd.self, man->wd.self, WHITE, BLUE);
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);
683 void do_filter(t_x11* x11, t_manager* man, t_filter* filter)
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);