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
, 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
)
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
->pbcType
, 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
, pbcType
, 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
);