1 /*   EXTRAITS DE LA LICENCE
2      Copyright CEA, contributeurs : Luc BILLARD et Damien
3      CALISTE, laboratoire L_Sim, (2001-2005)
4 
5      Adresse m�l :
6      BILLARD, non joignable par m�l ;
7      CALISTE, damien P caliste AT cea P fr.
8 
9      Ce logiciel est un programme informatique servant � visualiser des
10      structures atomiques dans un rendu pseudo-3D.
11 
12      Ce logiciel est r�gi par la licence CeCILL soumise au droit fran�ais et
13      respectant les principes de diffusion des logiciels libres. Vous pouvez
14      utiliser, modifier et/ou redistribuer ce programme sous les conditions
15      de la licence CeCILL telle que diffus�e par le CEA, le CNRS et l'INRIA
16      sur le site "http://www.cecill.info".
17 
18      Le fait que vous puissiez acc�der � cet en-t�te signifie que vous avez
19      pris connaissance de la licence CeCILL, et que vous en avez accept� les
20      termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
21 */
22 
23 /*   LICENCE SUM UP
24      Copyright CEA, contributors : Luc BILLARD et Damien
25      CALISTE, laboratoire L_Sim, (2001-2005)
26 
27      E-mail address:
28      BILLARD, not reachable any more ;
29      CALISTE, damien P caliste AT cea P fr.
30 
31      This software is a computer program whose purpose is to visualize atomic
32      configurations in 3D.
33 
34      This software is governed by the CeCILL  license under French law and
35      abiding by the rules of distribution of free software.  You can  use,
36      modify and/ or redistribute the software under the terms of the CeCILL
37      license as circulated by CEA, CNRS and INRIA at the following URL
38      "http://www.cecill.info".
39 
40      The fact that you are presently reading this means that you have had
41      knowledge of the CeCILL license and that you accept its terms. You can
42      find a copy of this licence shipped with this software at Documentation/licence.en.txt.
43 */
44 
45 #include <gtk/gtk.h>
46 #include <math.h>
47 
48 #include <abinit.h>
49 
50 #include <support.h>
51 #include <visu_gtk.h>
52 #include <gtk_main.h>
53 #include <gtk_interactive.h>
54 #include <gtk_renderingWindowWidget.h>
55 #include <extensions/marks.h>
56 #include <openGLFunctions/interactive.h>
57 
58 #include "abinit.h"
59 
60 #define ABINIT_SYMMETRIES_INFO \
61   _("left-button\t\t: select one atom to get the equivalent ones\n"	\
62     "right-button\t\t: switch to observe")
63 
64 enum
65   {
66     SYM_ID,
67     SYM_MATRIX_00,
68     SYM_MATRIX_01,
69     SYM_MATRIX_02,
70     SYM_MATRIX_10,
71     SYM_MATRIX_11,
72     SYM_MATRIX_12,
73     SYM_MATRIX_20,
74     SYM_MATRIX_21,
75     SYM_MATRIX_22,
76     SYM_TRANS_0,
77     SYM_TRANS_1,
78     SYM_TRANS_2,
79     SYM_COMMENT,
80     SYM_N_COLS
81   };
82 
83 static gulong onSpin_id;
84 static AbSymmetry *sym;
85 static GtkWidget *lblSymName, *lblSymId, *lblSymWarning, *spinTol;
86 static GtkWidget *spinNode, *vbox, *vboxSym;
87 static guint timeout = 0;
88 static VisuInteractive *inter;
89 static GtkListStore *symList;
90 
91 static void onSelection(VisuInteractive *inter, VisuInteractivePick pick,
92                         VisuNodeArray *array, VisuNode *node0,
93                         VisuNode *node1, VisuNode *node2, gpointer data);
94 static void onSymmetryToggled(GtkToggleButton *toggle, gpointer data);
95 static void onSymmetryClicked(GtkButton *button, gpointer data);
96 static void onTolChanged(GtkSpinButton *spin, gpointer data);
97 static void onVisuDataChanged(VisuUiMain *visu, VisuData *dataObj, gpointer data);
98 static void onSpinNode(GtkSpinButton *button, gpointer data);
99 
100 static gchar* symAnalyse(AbSymmetry *sym, int iSym);
101 static void getEquivalents(VisuData *dataObj, VisuNode *node);
102 static void updateSymmetries(VisuData *dataObj, gdouble tol);
103 static void formatSymOperators(GtkTreeViewColumn *column, GtkCellRenderer *cell,
104                                GtkTreeModel *model, GtkTreeIter *iter, gpointer data);
105 
buildTab(VisuUiMain * main,gchar ** label,gchar ** help,GtkWidget ** radio)106 GtkWidget* buildTab(VisuUiMain *main, gchar **label,
107 		    gchar **help, GtkWidget **radio)
108 {
109   GtkWidget *wd, *hbox, *bt, *scroll;
110   VisuData *data;
111   VisuUiRenderingWindow *window;
112   VisuGlNodeScene *scene;
113   GtkCellRenderer *renderer;
114   GtkTreeViewColumn *column;
115 
116   window = visu_ui_main_class_getDefaultRendering();
117   scene = visu_ui_rendering_window_getGlScene(window);
118   data = visu_gl_node_scene_getData(scene);
119   g_return_val_if_fail(data, (GtkWidget*)0);
120 
121   inter = visu_interactive_new(interactive_pick);
122   g_signal_connect_swapped(G_OBJECT(inter), "stop",
123                            G_CALLBACK(visu_ui_interactive_toggle), (gpointer)0);
124   g_signal_connect(G_OBJECT(inter), "node-selection",
125 		   G_CALLBACK(onSelection), (gpointer)0);
126 
127   *label = _("Symmetries");
128   *help  = g_strdup(ABINIT_SYMMETRIES_INFO);
129 
130   symList = gtk_list_store_new(SYM_N_COLS, G_TYPE_INT,
131                                G_TYPE_INT, G_TYPE_INT, G_TYPE_INT,
132                                G_TYPE_INT, G_TYPE_INT, G_TYPE_INT,
133                                G_TYPE_INT, G_TYPE_INT, G_TYPE_INT,
134                                G_TYPE_FLOAT, G_TYPE_FLOAT, G_TYPE_FLOAT,
135                                G_TYPE_STRING);
136 
137   vbox = gtk_vbox_new(FALSE, 0);
138   g_signal_connect_swapped(vbox, "destroy", G_CALLBACK(g_object_unref), inter);
139 
140   sym = (AbSymmetry*)0;
141 
142   hbox = gtk_hbox_new(FALSE, 0);
143   gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
144 
145   *radio = gtk_radio_button_new_with_mnemonic
146     (NULL, _("Analyse the symmetries"));
147   gtk_box_pack_start(GTK_BOX(hbox), *radio, FALSE, FALSE, 0);
148   gtk_widget_set_name(*radio, "message_radio");
149   g_signal_connect(G_OBJECT(*radio), "toggled",
150 		   G_CALLBACK(onSymmetryToggled), (gpointer)0);
151   wd = gtk_button_new_with_mnemonic(_("Compute symmetries"));
152   bt = wd;
153   gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0);
154   wd = gtk_label_new(") ");
155   gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0);
156   wd = gtk_spin_button_new_with_range(-10, -2, 1);
157   gtk_entry_set_width_chars(GTK_ENTRY(wd), 2);
158   gtk_spin_button_set_value(GTK_SPIN_BUTTON(wd), -6);
159   g_signal_connect(G_OBJECT(wd), "value-changed",
160 		   G_CALLBACK(onTolChanged), (gpointer)0);
161   g_signal_connect(G_OBJECT(bt), "clicked",
162 		   G_CALLBACK(onSymmetryClicked), (gpointer)wd);
163   gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0);
164   spinTol = wd;
165   wd = gtk_label_new("(tolsym = 10^");
166   gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0);
167 
168   vboxSym = gtk_vbox_new(FALSE, 0);
169   gtk_widget_set_sensitive(vboxSym, FALSE);
170   gtk_box_pack_start(GTK_BOX(vbox), vboxSym, TRUE, TRUE, 0);
171 
172   /* A message for ABINIT. */
173   wd = gtk_label_new(_("<span size=\"smaller\">The symmetry routines"
174 		       " are provided by ABINIT ("
175 		       "<span font_desc=\"courier\" color=\"blue\">"
176 		       "http://www.abinit.org</span>).</span>"));
177   gtk_widget_set_halign(wd, 1.0);
178   gtk_label_set_use_markup(GTK_LABEL(wd), TRUE);
179   gtk_box_pack_end(GTK_BOX(vbox), wd, FALSE, FALSE, 5);
180 
181   /* The labels showing the symmetry. */
182   hbox = gtk_hbox_new(FALSE, 0);
183   gtk_box_pack_start(GTK_BOX(vboxSym), hbox, FALSE, FALSE, 10);
184   wd = gtk_label_new(_("<b>Space group:</b>"));
185   gtk_label_set_use_markup(GTK_LABEL(wd), TRUE);
186   gtk_widget_set_margin_start(wd, 10);
187   gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0);
188   wd = gtk_label_new(_("<span font_desc=\"courier\" color=\"blue\">"
189 		       "http://en.wikipedia.org/wiki/Space_group</span>"));
190   gtk_label_set_selectable(GTK_LABEL(wd), TRUE);
191   gtk_label_set_use_markup(GTK_LABEL(wd), TRUE);
192   gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 10);
193   wd = gtk_image_new_from_icon_name("help-browser", GTK_ICON_SIZE_MENU);
194   gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0);
195   hbox = gtk_hbox_new(FALSE, 0);
196   gtk_box_pack_start(GTK_BOX(vboxSym), hbox, FALSE, FALSE, 0);
197   wd = gtk_label_new(_("Crystal system:"));
198   gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0);
199   lblSymName = gtk_label_new("");
200   gtk_widget_set_halign(lblSymName, 0.);
201   gtk_box_pack_start(GTK_BOX(hbox), lblSymName, TRUE, TRUE, 5);
202   wd = gtk_label_new(_("space group:"));
203   gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0);
204   lblSymId = gtk_label_new("");
205   gtk_label_set_use_markup(GTK_LABEL(lblSymId), TRUE);
206   gtk_widget_set_halign(lblSymId, 0.);
207   gtk_box_pack_start(GTK_BOX(hbox), lblSymId, TRUE, TRUE, 5);
208   lblSymWarning = gtk_label_new(_("<span color=\"red\">Warning:</span> the Bravais lattice determined from the primitive vectors is more symmetric than the real one obtained from coordinates (printed)."));
209   gtk_label_set_use_markup(GTK_LABEL(lblSymWarning), TRUE);
210   gtk_label_set_line_wrap(GTK_LABEL(lblSymWarning), TRUE);
211   gtk_label_set_line_wrap_mode(GTK_LABEL(lblSymWarning), PANGO_WRAP_WORD);
212   gtk_box_pack_start(GTK_BOX(vboxSym), lblSymWarning, FALSE, FALSE, 0);
213   wd = gtk_label_new(_("List of symmetry operations:"));
214   gtk_widget_set_halign(wd, 0.);
215   gtk_box_pack_start(GTK_BOX(vboxSym), wd, FALSE, FALSE, 3);
216   scroll = gtk_scrolled_window_new(NULL, NULL);
217   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
218 				 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
219   gtk_box_pack_start(GTK_BOX(vboxSym), scroll, TRUE, TRUE, 0);
220   wd = gtk_tree_view_new_with_model(GTK_TREE_MODEL(symList));
221   gtk_container_add(GTK_CONTAINER(scroll), wd);
222   renderer = gtk_cell_renderer_text_new();
223   column = gtk_tree_view_column_new_with_attributes(_("Id"), renderer,
224 						    "text", SYM_ID, NULL);
225   gtk_tree_view_append_column(GTK_TREE_VIEW(wd), column);
226   renderer = gtk_cell_renderer_text_new ();
227   column = gtk_tree_view_column_new();
228   gtk_tree_view_column_set_title(column, _("operation"));
229   gtk_tree_view_column_pack_start(column, renderer, TRUE);
230   gtk_tree_view_column_set_cell_data_func
231     (column, renderer, formatSymOperators,
232      GINT_TO_POINTER(SYM_MATRIX_00), (GDestroyNotify)0);
233   gtk_tree_view_append_column(GTK_TREE_VIEW(wd), column);
234   renderer = gtk_cell_renderer_text_new ();
235   column = gtk_tree_view_column_new();
236   gtk_tree_view_column_set_title(column, _("translation"));
237   gtk_tree_view_column_pack_start(column, renderer, TRUE);
238   gtk_tree_view_column_set_cell_data_func
239     (column, renderer, formatSymOperators,
240      GINT_TO_POINTER(SYM_TRANS_0), (GDestroyNotify)0);
241   gtk_tree_view_append_column(GTK_TREE_VIEW(wd), column);
242   renderer = gtk_cell_renderer_text_new();
243   column = gtk_tree_view_column_new_with_attributes(_("comment"), renderer,
244 						    "text", SYM_COMMENT, NULL);
245   gtk_tree_view_append_column(GTK_TREE_VIEW(wd), column);
246 
247   /* The interface to choose one atom to select. */
248   wd = gtk_label_new(_("<b>Equivalent atoms:</b>"));
249   gtk_label_set_use_markup(GTK_LABEL(wd), TRUE);
250   gtk_widget_set_halign(wd, 0.);
251   gtk_widget_set_margin_start(wd, 10);
252   gtk_box_pack_start(GTK_BOX(vboxSym), wd, FALSE, FALSE, 10);
253   hbox = gtk_hbox_new(FALSE, 0);
254   gtk_box_pack_start(GTK_BOX(vboxSym), hbox, FALSE, FALSE, 0);
255   wd = gtk_label_new(_("Visualise the equivalent nodes of node:"));
256   gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0);
257   spinNode = gtk_spin_button_new_with_range(0, 1, 1);
258   onSpin_id = g_signal_connect(G_OBJECT(spinNode), "value-changed",
259 			       G_CALLBACK(onSpinNode), (gpointer)0);
260   gtk_box_pack_start(GTK_BOX(hbox), spinNode, FALSE, FALSE, 5);
261   wd = gtk_label_new(_(" or pick directly."));
262   gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0);
263 
264   gtk_widget_show_all(vbox);
265   gtk_widget_hide(lblSymWarning);
266 
267   g_signal_connect(main, "DataFocused", G_CALLBACK(onVisuDataChanged), (gpointer)0);
268   onVisuDataChanged((VisuUiMain*)0, data, (gpointer)0);
269 
270   return vbox;
271 }
formatSymOperators(GtkTreeViewColumn * column _U_,GtkCellRenderer * cell,GtkTreeModel * model,GtkTreeIter * iter,gpointer data)272 static void formatSymOperators(GtkTreeViewColumn *column _U_, GtkCellRenderer *cell,
273                                GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
274 {
275   gchar *str;
276   gfloat valf[3];
277   gint vali[9];
278 
279   str = (gchar*)0;
280   if (GPOINTER_TO_INT(data) == SYM_MATRIX_00)
281     {
282       gtk_tree_model_get(model, iter, SYM_MATRIX_00, vali,
283                          SYM_MATRIX_01, vali + 1,
284                          SYM_MATRIX_02, vali + 2,
285                          SYM_MATRIX_10, vali + 3,
286                          SYM_MATRIX_11, vali + 4,
287                          SYM_MATRIX_12, vali + 5,
288                          SYM_MATRIX_20, vali + 6,
289                          SYM_MATRIX_21, vali + 7,
290                          SYM_MATRIX_22, vali + 8,
291                          -1);
292       str = g_strdup_printf("[ %2d %2d %2d\n"
293                             "  %2d %2d %2d\n"
294                             "  %2d %2d %2d ]", vali[0], vali[1], vali[2],
295                             vali[3], vali[4], vali[5], vali[6], vali[7], vali[8]);
296     }
297   else if (GPOINTER_TO_INT(data) == SYM_TRANS_0)
298     {
299       gtk_tree_model_get(model, iter, SYM_TRANS_0, valf,
300                          SYM_TRANS_1, valf + 1,
301                          SYM_TRANS_2, valf + 2,
302                          -1);
303       str = g_strdup_printf("[ %2f\n"
304                             "  %2f\n"
305                             "  %2f ]", valf[0], valf[1], valf[2]);
306     }
307   if (str)
308     {
309       g_object_set(G_OBJECT(cell), "text", str, NULL);
310       g_free(str);
311     }
312 }
313 
startSelect(VisuUiRenderingWindow * window)314 void startSelect(VisuUiRenderingWindow *window)
315 {
316   visu_ui_rendering_window_pushInteractive(window, inter);
317 }
stopSelect(VisuUiRenderingWindow * window)318 void stopSelect(VisuUiRenderingWindow *window)
319 {
320   visu_ui_rendering_window_popInteractive(window, inter);
321 }
322 
onSelection(VisuInteractive * inter _U_,VisuInteractivePick pick _U_,VisuNodeArray * array,VisuNode * node0,VisuNode * node1 _U_,VisuNode * node2 _U_,gpointer data _U_)323 static void onSelection(VisuInteractive *inter _U_, VisuInteractivePick pick _U_,
324                         VisuNodeArray *array, VisuNode *node0,
325                         VisuNode *node1 _U_, VisuNode *node2 _U_, gpointer data _U_)
326 {
327   getEquivalents(VISU_DATA(array), node0);
328   g_signal_handler_block(G_OBJECT(spinNode), onSpin_id);
329   gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinNode), node0->number + 1);
330   g_signal_handler_unblock(G_OBJECT(spinNode), onSpin_id);
331 }
332 
onSymmetryToggled(GtkToggleButton * toggle _U_,gpointer data _U_)333 static void onSymmetryToggled(GtkToggleButton *toggle _U_, gpointer data _U_)
334 {
335 }
onSymmetryClicked(GtkButton * button _U_,gpointer spin)336 static void onSymmetryClicked(GtkButton *button _U_, gpointer spin)
337 {
338   VisuData *dataObj;
339 
340   /* Get the current VisuData object. */
341   dataObj = visu_gl_node_scene_getData(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()));
342 
343   updateSymmetries(dataObj, gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)));
344 }
onTolChanged(GtkSpinButton * spin,gpointer data _U_)345 static void onTolChanged(GtkSpinButton *spin, gpointer data _U_)
346 {
347   VisuData *dataObj;
348 
349   /* Get the current VisuData object. */
350   dataObj = visu_gl_node_scene_getData(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()));
351 
352   updateSymmetries(dataObj, gtk_spin_button_get_value(spin));
353 }
onVisuDataChanged(VisuUiMain * visu _U_,VisuData * dataObj,gpointer data _U_)354 static void onVisuDataChanged(VisuUiMain *visu _U_, VisuData *dataObj,
355 			      gpointer data _U_)
356 {
357   VisuNodeArrayIter iter;
358 
359   gtk_widget_set_sensitive(vbox, (dataObj !=(VisuData*)0));
360 
361   updateSymmetries((VisuData*)0, 0);
362 
363   if (dataObj)
364     {
365       visu_node_array_iter_new(VISU_NODE_ARRAY(dataObj), &iter);
366       gtk_spin_button_set_range(GTK_SPIN_BUTTON(spinNode), 0, iter.idMax + 1);
367     }
368 }
onSpinNode(GtkSpinButton * button,gpointer data _U_)369 static void onSpinNode(GtkSpinButton *button, gpointer data _U_)
370 {
371   VisuData *dataObj;
372   VisuNode *node;
373 
374   if (gtk_spin_button_get_value(button) == 0)
375     return;
376 
377   /* Get the current VisuData object. */
378   dataObj = visu_gl_node_scene_getData(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()));
379   node = visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj),
380                                    (int)gtk_spin_button_get_value(button) - 1);
381 
382   getEquivalents(dataObj, node);
383 }
onRemoveEquivalents(gpointer data _U_)384 static gboolean onRemoveEquivalents(gpointer data _U_)
385 {
386   timeout = 0;
387   return FALSE;
388 }
389 
removeEquivalents(gpointer data)390 static void removeEquivalents(gpointer data)
391 {
392   VisuGlExtMarks *marks;
393   GArray *ids;
394 
395   ids = (GArray*)data;
396 
397   /* Get the current VisuData object. */
398   marks = visu_gl_node_scene_getMarks(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()));
399 
400   visu_gl_ext_marks_setHighlight(marks, ids, MARKS_STATUS_TOGGLE);
401   g_array_unref(ids);
402 }
getEquivalents(VisuData * dataObj,VisuNode * node)403 static void getEquivalents(VisuData *dataObj, VisuNode *node)
404 {
405   guint j;
406   int i, nSym;
407   int *nodes;
408   GArray *ids;
409   gboolean found;
410 #if GLIB_MINOR_VERSION > 13
411 #define fact 1
412 #define G_TIMEOUT_ADD_FULL g_timeout_add_seconds_full
413 #else
414 #define fact 1000
415 #define G_TIMEOUT_ADD_FULL g_timeout_add_full
416 #endif
417 
418   if (!sym)
419     updateSymmetries(dataObj, gtk_spin_button_get_value(GTK_SPIN_BUTTON(spinTol)));
420   g_return_if_fail(sym);
421 
422   if (ab_symmetry_get_equivalent_atom(sym, &nodes, &nSym, node->number + 1) ==
423       AB_NO_ERROR)
424     {
425       ids = g_array_new(FALSE, FALSE, sizeof(guint));
426       for (i = 0; i < nSym; i++)
427 	{
428 	  found = FALSE;
429 	  for ( j = 0; j < ids->len && !found; j++)
430 	    found = (nodes[i * 4 + 3] == g_array_index(ids, int, j) + 1);
431 	  if (!found)
432             {
433               j = nodes[i * 4 + 3] - 1;
434               g_array_append_val(ids, j);
435             }
436 	}
437       g_free(nodes);
438 
439       /* We remove possible earlier timeout. */
440       if (timeout > 0)
441 	g_source_remove(timeout);
442 
443       /* Set the new highlights. */
444       visu_gl_ext_marks_setHighlight
445 	(visu_gl_node_scene_getMarks(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering())),
446 	 ids, MARKS_STATUS_SET);
447 
448       /* Add the new timeout. */
449       timeout = G_TIMEOUT_ADD_FULL(G_PRIORITY_DEFAULT, 3 * fact,
450 				   onRemoveEquivalents, ids, removeEquivalents);
451       /* ids will be freed in the timeout. */
452     }
453 }
454 
startThreadSymmetry(gpointer data _U_)455 gpointer startThreadSymmetry(gpointer data _U_)
456 {
457   float xred0[3], xyz[3];
458   char *spGrp;
459   double box[3][3], genAfm[3], *xred;
460   int i, *typat, grpId, grpMagnId;
461   AbError error;
462   VisuNodeArrayIter iter;
463 
464   AbinitData *dt;
465 
466   DBG_fprintf(stderr, "AB symmetry(%p): starting symmetry detection.\n",
467               (gpointer)g_thread_self());
468   dt = abinit_getDt();
469 
470   visu_box_getCellMatrix(visu_boxed_getBox(VISU_BOXED(dt->data)), box);
471   ab_symmetry_set_lattice(dt->sym, box);
472 
473   visu_node_array_iter_new(VISU_NODE_ARRAY(dt->data), &iter);
474   i = 0;
475   typat = g_malloc(sizeof(int) * iter.nAllStoredNodes);
476   xred = g_malloc(sizeof(double) * 3 * iter.nAllStoredNodes);
477   for (visu_node_array_iterStart(VISU_NODE_ARRAY(dt->data), &iter); iter.node;
478        visu_node_array_iterNext(VISU_NODE_ARRAY(dt->data), &iter))
479     {
480       typat[i] = iter.iElement;
481       visu_data_getNodePosition(dt->data, iter.node, xyz);
482       visu_box_convertXYZtoBoxCoordinates(visu_boxed_getBox(VISU_BOXED(dt->data)), xred0, xyz);
483       xred[3 * i + 0] = (double)xred0[0];
484       xred[3 * i + 1] = (double)xred0[1];
485       xred[3 * i + 2] = (double)xred0[2];
486       i += 1;
487     }
488   ab_symmetry_set_structure(dt->sym, iter.nAllStoredNodes, typat, xred);
489   g_free(typat);
490   g_free(xred);
491 
492   /* Ask for the calculation of the symmetries. */
493   DBG_fprintf(stderr, "AB symmetry(%p): Ready to get symmetries from ABINIT.\n",
494               (gpointer)g_thread_self());
495   error = ab_symmetry_get_group(dt->sym, &spGrp, &grpId,
496 				 &grpMagnId, genAfm);
497   DBG_fprintf(stderr, "AB symmetry(%p): return from ABINIT (%d).\n",
498               (gpointer)g_thread_self(), error);
499   if (error == AB_NO_ERROR || errno == AB_ERROR_SYM_BRAVAIS_XRED)
500     g_free(spGrp);
501   else if (error != AB_ERROR_SYM_NOT_PRIMITIVE)
502     dt->error = g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_METHOD,
503                             "An error occured in ABINIT plug-in.");
504   abinit_mutexUnlock();
505 
506   return (gpointer)0;
507 }
508 
updateSymmetries(VisuData * dataObj,gdouble tol)509 static void updateSymmetries(VisuData *dataObj, gdouble tol)
510 {
511   double genAfm[3];
512   int grpId, grpMagnId, centerId, nbrv;
513   char *spGrp;
514   gchar *str;
515   AbSymmetryMat *brvSyms;
516   int brvMat[3][3];
517   gchar *bravais[7] = {"triclinic", "monoclinic", "orthorhombic",
518 		       "tetragonal", "trigonal", "hexagonal", "cubic"};
519   gchar *center[7] = {"F", "F", "I", "P", "A", "B", "C"};
520   AbError error;
521 #ifdef G_THREADS_ENABLED
522   GThread *ld_thread;
523 #endif
524   int nSym, *amf, iSym;
525   AbSymmetryMat *symOps;
526   AbSymmetryTrans *trans;
527   GtkTreeIter iter;
528 
529   AbinitData *dt;
530 
531   DBG_fprintf(stderr, "Abinit: upadte symmetries from %p.\n", (gpointer)dataObj);
532 
533   if (sym)
534     ab_symmetry_free(sym);
535   sym = (AbSymmetry*)0;
536   gtk_list_store_clear(symList);
537 
538   if (dataObj)
539     {
540       dt = abinit_getDirectDt();
541       dt->data = dataObj;
542       dt->sym = ab_symmetry_new();
543       dt->getMessages = FALSE;
544       dt->useSignals  = FALSE;
545       DBG_fprintf(stderr, "AB symmetry: set tolerance to 10^%g.\n", tol);
546       ab_symmetry_set_tolerance(dt->sym, pow(10., tol));
547 #ifdef G_THREADS_ENABLED
548       abinit_mutexInit();
549       dt->error = (GError*)0;
550 #if GLIB_MINOR_VERSION < 32
551       ld_thread = g_thread_create(startThreadSymmetry, (gpointer)0,
552 				  TRUE, &(dt->error));
553 #else
554       ld_thread = g_thread_new(NULL, startThreadSymmetry, (gpointer)0);
555 #endif
556       DBG_fprintf(stderr, "AB symmetry: run ABINIT symmetry into a thread (%p).\n",
557                   (gpointer)ld_thread);
558       if (ld_thread)
559 	g_thread_join(ld_thread);
560       else
561 	g_warning("Can't run thread for ABINIT symmetry.");
562       abinit_mutexRelease();
563 #else
564       startThreadSymmetry((gpointer)(&dt));
565 #endif
566       DBG_fprintf(stderr, "AB symmetry: return after thread exec (%p).\n",
567                   (gpointer)dt->error);
568       if (!dt->error)
569 	{
570 	  sym = dt->sym;
571 
572 	  /* We get then the space group. */
573           DBG_fprintf(stderr, "AB symmetry: get group.\n");
574 	  error = ab_symmetry_get_group(sym, &spGrp, &grpId,
575 					 &grpMagnId, genAfm);
576 	  if (error == AB_NO_ERROR || errno == AB_ERROR_SYM_BRAVAIS_XRED)
577 	    {
578 	      str = g_strdup_printf("%s (#%d)", spGrp, grpId);
579 	      gtk_label_set_text(GTK_LABEL(lblSymId), str);
580 	      g_free(str);
581 	      g_free(spGrp);
582 
583               DBG_fprintf(stderr, "AB symmetry: get matrices.\n");
584               if (ab_symmetry_get_matrices(sym, &nSym, &symOps, &trans, &amf) ==
585                   AB_NO_ERROR)
586                 {
587                   for (iSym = 0; iSym < nSym; iSym++)
588                     {
589                       str = symAnalyse(dt->sym, iSym + 1);
590                       gtk_list_store_append(symList, &iter);
591                       gtk_list_store_set(symList, &iter, SYM_ID, iSym + 1,
592                                          SYM_MATRIX_00, symOps[iSym].mat[0][0],
593                                          SYM_MATRIX_01, symOps[iSym].mat[0][1],
594                                          SYM_MATRIX_02, symOps[iSym].mat[0][2],
595                                          SYM_MATRIX_10, symOps[iSym].mat[1][0],
596                                          SYM_MATRIX_11, symOps[iSym].mat[1][1],
597                                          SYM_MATRIX_12, symOps[iSym].mat[1][2],
598                                          SYM_MATRIX_20, symOps[iSym].mat[2][0],
599                                          SYM_MATRIX_21, symOps[iSym].mat[2][1],
600                                          SYM_MATRIX_22, symOps[iSym].mat[2][2],
601                                          SYM_TRANS_0, trans[iSym].vect[0],
602                                          SYM_TRANS_1, trans[iSym].vect[1],
603                                          SYM_TRANS_2, trans[iSym].vect[2],
604                                          SYM_COMMENT, str,
605                                          -1);
606                       g_free(str);
607                     }
608                   g_free(symOps);
609                   g_free(trans);
610                   g_free(amf);
611                 }
612 	    }
613 	  else
614 	    {
615 	      gtk_label_set_markup(GTK_LABEL(lblSymId), _("<i>not primitive</i>"));
616 	    }
617           DBG_fprintf(stderr, "AB symmetry: get bravais.\n");
618 	  if (ab_symmetry_get_bravais(sym, brvMat, &grpId,
619 				       &centerId, &nbrv, &brvSyms) == AB_NO_ERROR)
620 	    {
621 	      g_free(brvSyms);
622 	      str = g_strdup_printf("%s (%s)", _(bravais[grpId - 1]),
623 				    center[centerId+3]);
624 	      gtk_label_set_text(GTK_LABEL(lblSymName), str);
625 	      g_free(str);
626 	    }
627 	  else
628 	    gtk_label_set_text(GTK_LABEL(lblSymName), "!");
629 
630 	  /* If the bravais lattice doesn't match with the xred bravais
631 	     lattice, we print a message. */
632 	  if (error == AB_ERROR_SYM_BRAVAIS_XRED)
633 	    gtk_widget_show(lblSymWarning);
634 	  else
635 	    gtk_widget_hide(lblSymWarning);
636 
637 	  gtk_widget_set_sensitive(vboxSym, (dataObj != (VisuData*)0));
638 	}
639       else
640 	{
641 	  visu_ui_raiseWarning(_("ABINIT symmetry calculation"),
642 			       dt->error->message, (GtkWindow*)0);
643 	  g_error_free(dt->error);
644 	  ab_symmetry_free(dt->sym);
645 	  sym = (AbSymmetry*)0;
646 
647 	  gtk_widget_set_sensitive(vboxSym, FALSE);
648 	}
649     }
650   else
651     {
652       gtk_label_set_text(GTK_LABEL(lblSymName), "");
653       gtk_label_set_text(GTK_LABEL(lblSymId), "");
654     }
655 }
656 
symAnalyse(AbSymmetry * sym,int iSym)657 static gchar* symAnalyse(AbSymmetry *sym, int iSym)
658 {
659   AbError error;
660   int type;
661   gchar *label;
662 
663 
664   error = ab_symmetry_get_type(sym, &type, &label, iSym);
665   if (error == AB_NO_ERROR)
666     return label;
667   else
668     return g_strdup(_("Unknown symmetry"));
669 }
670