SYCL: Avoid using no_init read accessor in rocFFT
[alexxy/gromacs.git] / src / programs / view / nmol.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-2013, 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.
11  *
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.
16  *
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.
21  *
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.
26  *
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.
34  *
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.
37  */
38 #include "gmxpre.h"
39
40 #include "nmol.h"
41
42 #include <cstdio>
43 #include <cstdlib>
44 #include <cstring>
45
46 #include "gromacs/math/vec.h"
47 #include "gromacs/math/vecdump.h"
48 #include "gromacs/pbcutil/pbc.h"
49 #include "gromacs/utility/fatalerror.h"
50 #include "gromacs/utility/smalloc.h"
51
52 #include "3dview.h"
53 #include "buttons.h"
54 #include "manager.h"
55 #include "xutil.h"
56
57 #define MSIZE 4
58
59 static bool MWCallBack(t_x11* x11, XEvent* event, Window /*w*/, void* data)
60 {
61     t_molwin* mw;
62     Window    To;
63     XEvent    letter;
64
65     mw                          = static_cast<t_molwin*>(data);
66     To                          = mw->wd.Parent;
67     letter.type                 = ClientMessage;
68     letter.xclient.display      = x11->disp;
69     letter.xclient.window       = To;
70     letter.xclient.message_type = 0;
71     letter.xclient.format       = 32;
72     switch (event->type)
73     {
74         case Expose:
75             /* Do Not draw anything, but signal parent instead, he will
76              * coordinate drawing.
77              */
78             letter.xclient.data.l[0] = IDDRAWMOL;
79             letter.xclient.data.l[1] = Button1;
80             XSendEvent(x11->disp, To, True, 0, &letter);
81             break;
82         case ButtonPress:
83 #ifdef DEBUG
84             std::printf("Molwindow: Buttonpress\n");
85 #endif
86             letter.xclient.data.l[0] = IDLABEL;
87             letter.xclient.data.l[1] = (long)event->xbutton.button;
88             letter.xclient.data.l[2] = event->xbutton.x;
89             letter.xclient.data.l[3] = event->xbutton.y;
90             XSendEvent(x11->disp, To, True, 0, &letter);
91             break;
92         case ConfigureNotify:
93             mw->wd.width  = event->xconfigure.width;
94             mw->wd.height = event->xconfigure.height;
95             break;
96         default: break;
97     }
98     return false;
99 }
100
101 static void set_def(t_molwin* mw, PbcType pbcType, matrix box)
102 {
103     mw->bShowHydrogen = true;
104     mw->bond_type     = eBFat;
105     mw->pbcType       = pbcType;
106     mw->boxtype       = esbRect;
107     mw->realbox       = TRICLINIC(box) ? esbTri : esbRect;
108 }
109
110 t_molwin* init_mw(t_x11*        x11,
111                   Window        Parent,
112                   int           x,
113                   int           y,
114                   int           width,
115                   int           height,
116                   unsigned long fg,
117                   unsigned long bg,
118                   PbcType       pbcType,
119                   matrix        box)
120 {
121     t_molwin* mw;
122
123     snew(mw, 1);
124     set_def(mw, pbcType, box);
125
126     InitWin(&mw->wd, x, y, width, height, 1, "Mol Window");
127
128     mw->wd.Parent = Parent;
129     mw->wd.self   = XCreateSimpleWindow(x11->disp, Parent, x, y, width, height, 1, fg, bg);
130     x11->RegisterCallback(x11, mw->wd.self, Parent, MWCallBack, mw);
131     x11->SetInputMask(x11, mw->wd.self, ExposureMask | StructureNotifyMask | ButtonPressMask);
132     return mw;
133 }
134
135 void map_mw(t_x11* x11, t_molwin* mw)
136 {
137     XMapWindow(x11->disp, mw->wd.self);
138 }
139
140 bool toggle_hydrogen(t_x11* x11, t_molwin* mw)
141 {
142     mw->bShowHydrogen = !mw->bShowHydrogen;
143     ExposeWin(x11->disp, mw->wd.self);
144
145     return mw->bShowHydrogen;
146 }
147
148 void set_bond_type(t_x11* x11, t_molwin* mw, int bt)
149 {
150     if (bt != mw->bond_type)
151     {
152         mw->bond_type = bt;
153         ExposeWin(x11->disp, mw->wd.self);
154     }
155 }
156
157 void set_box_type(t_x11* x11, t_molwin* mw, int bt)
158 {
159 #ifdef DEBUG
160     std::fprintf(stderr, "mw->boxtype = %d, bt = %d\n", mw->boxtype, bt);
161 #endif
162     if (bt != mw->boxtype)
163     {
164         if ((bt == esbTrunc && mw->realbox == esbTri) || bt == esbTri || bt == esbNone)
165         {
166             mw->boxtype = bt;
167             ExposeWin(x11->disp, mw->wd.self);
168         }
169         else
170         {
171             std::fprintf(stderr, "Can not change rectangular box to truncated octahedron\n");
172         }
173     }
174 }
175
176 void done_mw(t_x11* x11, t_molwin* mw)
177 {
178     x11->UnRegisterCallback(x11, mw->wd.self);
179     sfree(mw);
180 }
181
182 static void
183 draw_atom(Display* disp, Window w, GC gc, int ai, iv2 vec2[], unsigned long col[], int size[], bool bBall, bool bPlus)
184 {
185     int xi, yi;
186
187     xi = vec2[ai][XX];
188     yi = vec2[ai][YY];
189     XSetForeground(disp, gc, col[ai]);
190     if (bBall)
191     {
192         XFillCircle(disp, w, gc, xi, yi, size[ai] - 1);
193         XSetForeground(disp, gc, BLACK);
194         XDrawCircle(disp, w, gc, xi, yi, size[ai]);
195         /*    XSetForeground(disp,gc,WHITE);
196            XFillCircle(disp,w,gc,xi+4,yi-4,4); */
197     }
198     else if (bPlus)
199     {
200         XDrawLine(disp, w, gc, xi - MSIZE, yi, xi + MSIZE + 1, yi);
201         XDrawLine(disp, w, gc, xi, yi - MSIZE, xi, yi + MSIZE + 1);
202     }
203     else
204     {
205         XDrawLine(disp, w, gc, xi - 1, yi, xi + 1, yi);
206     }
207 }
208
209 /* Global variables */
210 static rvec gl_fbox, gl_hbox, gl_mhbox;
211
212 static void my_init_pbc(matrix box)
213 {
214     int i;
215
216     for (i = 0; (i < DIM); i++)
217     {
218         gl_fbox[i]  = box[i][i];
219         gl_hbox[i]  = gl_fbox[i] * 0.5;
220         gl_mhbox[i] = -gl_hbox[i];
221     }
222 }
223
224 static bool local_pbc_dx(rvec x1, rvec x2)
225 {
226     int  i;
227     real dx;
228
229     for (i = 0; (i < DIM); i++)
230     {
231         dx = x1[i] - x2[i];
232         if (dx > gl_hbox[i])
233         {
234             return false;
235         }
236         else if (dx <= gl_mhbox[i])
237         {
238             return false;
239         }
240     }
241     return true;
242 }
243
244 static void
245 draw_bond(Display* disp, Window w, GC gc, int ai, int aj, iv2 vec2[], rvec x[], unsigned long col[], int size[], bool bBalls)
246 {
247     unsigned long ic, jc;
248     int           xi, yi, xj, yj;
249     int           xm, ym;
250
251     if (bBalls)
252     {
253         draw_atom(disp, w, gc, ai, vec2, col, size, true, false);
254         draw_atom(disp, w, gc, aj, vec2, col, size, true, false);
255     }
256     else
257     {
258         if (local_pbc_dx(x[ai], x[aj]))
259         {
260             ic = col[ai];
261             jc = col[aj];
262             xi = vec2[ai][XX];
263             yi = vec2[ai][YY];
264             xj = vec2[aj][XX];
265             yj = vec2[aj][YY];
266
267             if (ic != jc)
268             {
269                 xm = (xi + xj) >> 1;
270                 ym = (yi + yj) >> 1;
271
272                 XSetForeground(disp, gc, ic);
273                 XDrawLine(disp, w, gc, xi, yi, xm, ym);
274                 XSetForeground(disp, gc, jc);
275                 XDrawLine(disp, w, gc, xm, ym, xj, yj);
276             }
277             else
278             {
279                 XSetForeground(disp, gc, ic);
280                 XDrawLine(disp, w, gc, xi, yi, xj, yj);
281             }
282         }
283     }
284 }
285
286 int compare_obj(const void* a, const void* b)
287 {
288     const t_object *oa, *ob;
289     real            z;
290
291     oa = static_cast<const t_object*>(a);
292     ob = static_cast<const t_object*>(b);
293
294     z = oa->z - ob->z;
295
296     if (z < 0)
297     {
298         return 1;
299     }
300     else if (z > 0)
301     {
302         return -1;
303     }
304     else
305     {
306         return 0;
307     }
308 }
309
310 void z_fill(t_manager* man, real* zz)
311 {
312     t_object* obj;
313     int       i;
314
315     for (i = 0, obj = man->obj; (i < man->nobj); i++, obj++)
316     {
317         switch (obj->eO)
318         {
319             case eOSingle: obj->z = zz[obj->ai]; break;
320             case eOBond:
321             case eOHBond: obj->z = (zz[obj->ai] + zz[obj->aj]) * 0.5; break;
322             default: break;
323         }
324     }
325 }
326
327 int filter_vis(t_manager* man)
328 {
329     int       i, nobj, nvis, nhide;
330     int       ai;
331     bool      bAdd, *bVis;
332     t_object* obj;
333     t_object* newobj;
334
335     nobj = man->nobj;
336     snew(newobj, nobj);
337     obj   = man->obj;
338     bVis  = man->bVis;
339     nvis  = 0;
340     nhide = nobj - 1;
341     for (i = 0; (i < nobj); i++, obj++)
342     {
343         ai   = obj->ai;
344         bAdd = bVis[ai];
345         if (bAdd)
346         {
347             if (obj->eO != eOSingle)
348             {
349                 bAdd = bVis[obj->aj];
350             }
351         }
352         if (bAdd)
353         {
354             newobj[nvis++] = *obj;
355         }
356         else
357         {
358             newobj[nhide--] = *obj;
359         }
360     }
361     sfree(man->obj);
362     man->obj = newobj;
363
364     return nvis;
365 }
366
367 static void draw_objects(Display*      disp,
368                          Window        w,
369                          GC            gc,
370                          int           nobj,
371                          t_object      objs[],
372                          iv2           vec2[],
373                          rvec          x[],
374                          unsigned long col[],
375                          int           size[],
376                          bool          bShowHydro,
377                          int           bond_type,
378                          bool          bPlus)
379 {
380     bool      bBalls;
381     int       i;
382     t_object* obj;
383
384     bBalls = false;
385     switch (bond_type)
386     {
387         case eBThin: XSetLineAttributes(disp, gc, 1, LineSolid, CapNotLast, JoinRound); break;
388         case eBFat: XSetLineAttributes(disp, gc, 3, LineSolid, CapNotLast, JoinRound); break;
389         case eBVeryFat: XSetLineAttributes(disp, gc, 5, LineSolid, CapNotLast, JoinRound); break;
390         case eBSpheres:
391             bBalls = true;
392             bPlus  = false;
393             break;
394         default: gmx_fatal(FARGS, "Invalid bond_type selected: %d\n", bond_type); break;
395     }
396     for (i = 0; (i < nobj); i++)
397     {
398         obj = &(objs[i]);
399         switch (obj->eO)
400         {
401             case eOSingle: draw_atom(disp, w, gc, obj->ai, vec2, col, size, bBalls, bPlus); break;
402             case eOBond:
403                 draw_bond(disp, w, gc, obj->ai, obj->aj, vec2, x, col, size, bBalls);
404                 break;
405             case eOHBond:
406                 if (bShowHydro)
407                 {
408                     draw_bond(disp, w, gc, obj->ai, obj->aj, vec2, x, col, size, bBalls);
409                 }
410                 break;
411             default: break;
412         }
413     }
414     XSetLineAttributes(disp, gc, 1, LineSolid, CapNotLast, JoinRound);
415 }
416
417 static void v4_to_iv2(vec4 x4, iv2 v2, int x0, int y0, real sx, real sy)
418 {
419     real inv_z;
420
421     inv_z  = 1.0 / x4[ZZ];
422     v2[XX] = x0 + sx * x4[XX] * inv_z;
423     v2[YY] = y0 - sy * x4[YY] * inv_z;
424 }
425
426 static void draw_box(t_x11* x11, Window w, t_3dview* view, matrix box, int x0, int y0, real sx, real sy, int boxtype)
427 {
428     rvec        rect_tri[8]     = { { 0, 0, 0 }, { 1, 0, 0 }, { 1, 1, 0 }, { 0, 1, 0 },
429                          { 0, 0, 1 }, { 1, 0, 1 }, { 1, 1, 1 }, { 0, 1, 1 } };
430     int         tr_bonds[12][2] = { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 0 }, { 4, 5 }, { 5, 6 },
431                             { 6, 7 }, { 7, 4 }, { 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 } };
432     static int* edge            = nullptr;
433     int         i, j, k, i0, i1;
434     rvec        corner[NCUCEDGE], box_center;
435     vec4        x4;
436     iv2         vec2[NCUCEDGE];
437
438     calc_box_center(view->ecenter, box, box_center);
439     if (boxtype == esbTrunc)
440     {
441         calc_compact_unitcell_vertices(view->ecenter, box, corner);
442         if (edge == nullptr)
443         {
444             edge = compact_unitcell_edges();
445         }
446
447         for (i = 0; (i < NCUCEDGE); i++)
448         {
449             gmx_mat4_transform_point(view->proj, corner[i], x4);
450             v4_to_iv2(x4, vec2[i], x0, y0, sx, sy);
451         }
452         XSetForeground(x11->disp, x11->gc, YELLOW);
453         for (i = 0; i < NCUCEDGE; i++)
454         {
455             i0 = edge[2 * i];
456             i1 = edge[2 * i + 1];
457             XDrawLine(x11->disp, w, x11->gc, vec2[i0][XX], vec2[i0][YY], vec2[i1][XX], vec2[i1][YY]);
458         }
459     }
460     else
461     {
462         if (boxtype == esbRect)
463         {
464             for (j = 0; (j < DIM); j++)
465             {
466                 box_center[j] -= 0.5 * box[j][j];
467             }
468         }
469         else
470         {
471             for (i = 0; (i < DIM); i++)
472             {
473                 for (j = 0; (j < DIM); j++)
474                 {
475                     box_center[j] -= 0.5 * box[i][j];
476                 }
477             }
478         }
479         for (i = 0; (i < 8); i++)
480         {
481             clear_rvec(corner[i]);
482             for (j = 0; (j < DIM); j++)
483             {
484                 if (boxtype == esbTri)
485                 {
486                     for (k = 0; (k < DIM); k++)
487                     {
488                         corner[i][k] += rect_tri[i][j] * box[j][k];
489                     }
490                 }
491                 else
492                 {
493                     corner[i][j] = rect_tri[i][j] * box[j][j];
494                 }
495             }
496             rvec_inc(corner[i], box_center);
497             gmx_mat4_transform_point(view->proj, corner[i], x4);
498             v4_to_iv2(x4, vec2[i], x0, y0, sx, sy);
499         }
500         if (debug)
501         {
502             pr_rvecs(debug, 0, "box", box, DIM);
503             pr_rvecs(debug, 0, "corner", corner, 8);
504         }
505         XSetForeground(x11->disp, x11->gc, YELLOW);
506         for (i = 0; (i < 12); i++)
507         {
508             i0 = tr_bonds[i][0];
509             i1 = tr_bonds[i][1];
510             XDrawLine(x11->disp, w, x11->gc, vec2[i0][XX], vec2[i0][YY], vec2[i1][XX], vec2[i1][YY]);
511         }
512     }
513 }
514
515 void set_sizes(t_manager* man)
516 {
517     for (int i = 0; i < man->natom; i++)
518     {
519         if (man->bVis[i])
520         {
521             man->size[i] = 180 * man->vdw[i];
522         }
523     }
524 }
525
526 void draw_mol(t_x11* x11, t_manager* man)
527 {
528     static char tstr[2][20];
529     static int  ntime = 0;
530     t_windata*  win;
531     t_3dview*   view;
532     t_molwin*   mw;
533     int         i, x0, y0, nvis;
534     iv2*        vec2;
535     real        sx, sy;
536     vec4        x4;
537
538     if (!man->status)
539     {
540         return;
541     }
542
543     view = man->view;
544     mw   = man->molw;
545
546     win = &(mw->wd);
547
548     vec2 = man->ix;
549     x0   = win->width / 2;
550     y0   = win->height / 2;
551     sx   = win->width / 2 * view->sc_x;
552     sy   = win->height / 2 * view->sc_y;
553
554     my_init_pbc(man->box);
555
556     for (i = 0; (i < man->natom); i++)
557     {
558         if (man->bVis[i])
559         {
560             gmx_mat4_transform_point(view->proj, man->x[i], x4);
561             man->zz[i] = x4[ZZ];
562             v4_to_iv2(x4, vec2[i], x0, y0, sx, sy);
563         }
564     }
565     set_sizes(man);
566
567     z_fill(man, man->zz);
568
569     /* Start drawing */
570     XClearWindow(x11->disp, win->self);
571
572     /* Draw Time */
573     std::sprintf(tstr[ntime], "Time: %.3f ps", man->time);
574     if (std::strcmp(tstr[ntime], tstr[1 - ntime]) != 0)
575     {
576         set_vbtime(x11, man->vbox, tstr[ntime]);
577         ntime = 1 - ntime;
578     }
579
580     if (mw->boxtype != esbNone)
581     {
582         draw_box(x11, win->self, view, man->box, x0, y0, sx, sy, mw->boxtype);
583     }
584
585     /* Should sort on Z-Coordinates here! */
586     nvis = filter_vis(man);
587     if (nvis && man->bSort)
588     {
589         std::qsort(man->obj, nvis, sizeof(man->obj[0]), compare_obj);
590     }
591
592     /* Draw the objects */
593     draw_objects(x11->disp,
594                  win->self,
595                  x11->gc,
596                  nvis,
597                  man->obj,
598                  man->ix,
599                  man->x,
600                  man->col,
601                  man->size,
602                  mw->bShowHydrogen,
603                  mw->bond_type,
604                  man->bPlus);
605
606     /* Draw the labels */
607     XSetForeground(x11->disp, x11->gc, WHITE);
608     for (i = 0; (i < man->natom); i++)
609     {
610         if (man->bLabel[i] && man->bVis[i])
611         {
612             XDrawString(x11->disp,
613                         win->self,
614                         x11->gc,
615                         vec2[i][XX] + 2,
616                         vec2[i][YY] - 2,
617                         man->szLab[i],
618                         std::strlen(man->szLab[i]));
619         }
620     }
621
622     XSetForeground(x11->disp, x11->gc, x11->fg);
623 }