1 /*   EXTRAITS DE LA LICENCE
2 	Copyright CEA, contributeurs : Damien
3 	CALISTE, laboratoire L_Sim, (2016)
4 
5 	Adresse mèl :
6 	CALISTE, damien P caliste AT cea P fr.
7 
8 	Ce logiciel est un programme informatique servant à visualiser des
9 	structures atomiques dans un rendu pseudo-3D.
10 
11 	Ce logiciel est régi par la licence CeCILL soumise au droit français et
12 	respectant les principes de diffusion des logiciels libres. Vous pouvez
13 	utiliser, modifier et/ou redistribuer ce programme sous les conditions
14 	de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
15 	sur le site "http://www.cecill.info".
16 
17 	Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
18 	pris connaissance de la licence CeCILL, et que vous en avez accepté les
19 	termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
20 */
21 
22 /*   LICENCE SUM UP
23 	Copyright CEA, contributors : Damien
24 	CALISTE, laboratoire L_Sim, (2016)
25 
26 	E-mail address:
27 	CALISTE, damien P caliste AT cea P fr.
28 
29 	This software is a computer program whose purpose is to visualize atomic
30 	configurations in 3D.
31 
32 	This software is governed by the CeCILL  license under French law and
33 	abiding by the rules of distribution of free software.  You can  use,
34 	modify and/ or redistribute the software under the terms of the CeCILL
35 	license as circulated by CEA, CNRS and INRIA at the following URL
36 	"http://www.cecill.info".
37 
38 	The fact that you are presently reading this means that you have had
39 	knowledge of the CeCILL license and that you accept its terms. You can
40 	find a copy of this licence shipped with this software at Documentation/licence.en.txt.
41 */
42 
43 #include "visu_dataspin.h"
44 
45 #include "coreTools/toolFortran.h"
46 
47 /**
48  * SECTION: visu_dataspin
49  * @short_description: a class of nodes representing spin data and
50  * providing associated loading methods.
51  *
52  * <para>This class provides #VisuDataLoader for spin data representation.</para>
53  */
54 
55 #define SPIN_PROP_ID _("Spin (\316\270, \317\206, mod.)")
56 #define SPIN_MAX_MOD_ID "spin_max_modulus_id"
57 
58 enum
59   {
60     PROP_0,
61     PROP_FILE,
62     PROP_FORMAT,
63     N_PROP,
64     PROP_LABEL,
65     N_PROP_TOT
66   };
67 static GParamSpec *_properties[N_PROP];
68 
69 struct _VisuDataSpinPrivate
70 {
71   gchar *file;
72   VisuDataLoader *format;
73 
74   /* These are cached pointers to the values. */
75   GArray *maxModulus;
76   VisuNodeValuesVector *spin;
77 };
78 
79 static GList *_spinFormats = NULL;
80 
81 
82 static void visu_data_spin_finalize    (GObject* obj);
83 static void visu_data_spin_get_property(GObject* obj, guint property_id,
84                                         GValue *value, GParamSpec *pspec);
85 static void visu_data_spin_set_property(GObject* obj, guint property_id,
86                                         const GValue *value, GParamSpec *pspec);
87 static const gchar* visu_data_spin_getFilename(const VisuDataLoadable *self,
88                                                guint fileType);
89 static gboolean visu_data_spin_load(VisuDataLoadable *self, guint iSet,
90                                     GCancellable *cancel, GError **error);
91 
92 static gboolean read_spin_file(VisuDataLoader *loader, VisuDataLoadable *data,
93                                guint type, guint nSet,
94                                GCancellable *cancel, GError **error);
95 static gboolean read_binary_file(VisuDataLoader *loader, VisuDataLoadable *data,
96                                  guint type, guint nSet,
97                                  GCancellable *cancel, GError **error);
98 
_initSpinFormats(void)99 static void _initSpinFormats(void)
100 {
101   const gchar *typeSpin[] = {"*.spin", "*.sp", NULL};
102   const gchar *typeBinary[] = {"*.bspin", "*.bsp", NULL};
103 
104   visu_data_spin_class_addLoader(visu_data_loader_new
105                                  (_("Ascii spin files"), typeSpin, FALSE,
106                                   read_spin_file, 100));
107   visu_data_spin_class_addLoader(visu_data_loader_new
108                                  (_("Binary spin files"), typeBinary, FALSE,
109                                   read_binary_file, 10));
110 }
111 
112 /* Local methods. */
113 
G_DEFINE_TYPE_WITH_CODE(VisuDataSpin,visu_data_spin,VISU_TYPE_DATA_ATOMIC,G_ADD_PRIVATE (VisuDataSpin))114 G_DEFINE_TYPE_WITH_CODE(VisuDataSpin, visu_data_spin, VISU_TYPE_DATA_ATOMIC,
115                         G_ADD_PRIVATE(VisuDataSpin))
116 
117 static void visu_data_spin_class_init(VisuDataSpinClass *klass)
118 {
119   /* Connect the overloading methods. */
120   G_OBJECT_CLASS(klass)->finalize     = visu_data_spin_finalize;
121   G_OBJECT_CLASS(klass)->get_property = visu_data_spin_get_property;
122   G_OBJECT_CLASS(klass)->set_property = visu_data_spin_set_property;
123   VISU_DATA_LOADABLE_CLASS(klass)->load = visu_data_spin_load;
124   VISU_DATA_LOADABLE_CLASS(klass)->getFilename = visu_data_spin_getFilename;
125 
126   g_object_class_override_property(G_OBJECT_CLASS(klass), PROP_LABEL, "label");
127 
128   /**
129    * VisuDataAtomic::spin-filename:
130    *
131    * The path to the source filename.
132    *
133    * Since: 3.8
134    */
135   _properties[PROP_FILE] =
136     g_param_spec_string("spin-filename", "Spin filename", "source filename",
137                         (gchar*)0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
138   /**
139    * VisuDataAtomic::spin-format:
140    *
141    * The format of the source filename, if known.
142    *
143    * Since: 3.8
144    */
145   _properties[PROP_FORMAT] =
146     g_param_spec_object("spin-format", "Spin format", "source format",
147                         VISU_TYPE_DATA_LOADER, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
148   g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties);
149 
150   _initSpinFormats();
151 }
visu_data_spin_init(VisuDataSpin * obj)152 static void visu_data_spin_init(VisuDataSpin *obj)
153 {
154   obj->priv = visu_data_spin_get_instance_private(obj);
155 
156   /* Private data. */
157   obj->priv->file    = (gchar*)0;
158   obj->priv->format  = (VisuDataLoader*)0;
159 }
visu_data_spin_finalize(GObject * obj)160 static void visu_data_spin_finalize(GObject* obj)
161 {
162   VisuDataSpin *data;
163 
164   data = VISU_DATA_SPIN(obj);
165 
166   g_free(data->priv->file);
167 
168   /* Chain up to the parent class */
169   G_OBJECT_CLASS(visu_data_spin_parent_class)->finalize(obj);
170 }
visu_data_spin_get_property(GObject * obj,guint property_id,GValue * value,GParamSpec * pspec)171 static void visu_data_spin_get_property(GObject* obj, guint property_id,
172                                           GValue *value, GParamSpec *pspec)
173 {
174   gchar *at, *sp;
175   VisuDataSpin *self = VISU_DATA_SPIN(obj);
176 
177   switch (property_id)
178     {
179     case PROP_LABEL:
180       at = g_path_get_basename(visu_data_atomic_getFile(VISU_DATA_ATOMIC(self),
181                                                         (VisuDataLoader**)0));
182       sp = g_path_get_basename(self->priv->file);
183       g_value_take_string(value, g_strdup_printf("%s \302\240\342\200\224 %s", at, sp));
184       g_free(at);
185       g_free(sp);
186       break;
187     case PROP_FILE:
188       g_value_set_string(value, self->priv->file);
189       break;
190     case PROP_FORMAT:
191       g_value_set_object(value, self->priv->format);
192       break;
193     default:
194       /* We don't have any other property... */
195       G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
196       break;
197     }
198 }
visu_data_spin_set_property(GObject * obj,guint property_id,const GValue * value,GParamSpec * pspec)199 static void visu_data_spin_set_property(GObject* obj, guint property_id,
200                                         const GValue *value, GParamSpec *pspec)
201 {
202   VisuDataSpin *self = VISU_DATA_SPIN(obj);
203 
204   switch (property_id)
205     {
206     case PROP_FILE:
207       self->priv->file = tool_path_normalize(g_value_get_string(value));
208       break;
209     case PROP_FORMAT:
210       self->priv->format = g_value_get_object(value);
211       break;
212     default:
213       /* We don't have any other property... */
214       G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
215       break;
216     }
217 }
218 
219 /**
220  * visu_data_spin_new:
221  * @atomic: a filename.
222  * @spin: a filename.
223  * @atomicFormat: (allow-none): a #VisuDataLoader format, if known.
224  * @spinFormat: (allow-none): a #VisuDataLoader format, if known.
225  *
226  * Creates a #VisuDataSpin object and set @atomic as its atomic file
227  * source and @file for the spin source.
228  *
229  * Since: 3.8
230  *
231  * Returns: a newly allocated #VisuDataSpin object.
232  **/
visu_data_spin_new(const gchar * atomic,const gchar * spin,VisuDataLoader * atomicFormat,VisuDataLoader * spinFormat)233 VisuDataSpin* visu_data_spin_new(const gchar *atomic, const gchar *spin,
234                                  VisuDataLoader *atomicFormat,
235                                  VisuDataLoader *spinFormat)
236 {
237   return g_object_new(VISU_TYPE_DATA_SPIN, "n-files", 2,
238                       "atomic-filename", atomic, "spin-filename", spin,
239                       "atomic-format", atomicFormat, "spin-format", spinFormat, NULL);
240 }
241 
242 /**
243  * visu_data_spin_class_addLoader:
244  * @loader: (transfer full): a #VisuDataSpin object.
245  *
246  * Add @loader to the list of #VisuDataLoader to be used when
247  * visu_data_loadable_load() is called.
248  *
249  * Since: 3.8
250  **/
visu_data_spin_class_addLoader(VisuDataLoader * loader)251 void visu_data_spin_class_addLoader(VisuDataLoader *loader)
252 {
253   if (g_list_find(_spinFormats, loader))
254     return;
255 
256   _spinFormats = g_list_prepend(_spinFormats, loader);
257   _spinFormats = g_list_sort(_spinFormats,
258                                (GCompareFunc)visu_data_loader_comparePriority);
259 }
260 
261 /**
262  * visu_data_spin_class_getLoaders:
263  *
264  * Returns a list of available #VisuDataLoader.
265  *
266  * Since: 3.8
267  *
268  * Returns: (transfer none) (element-type VisuDataLoader): a list of
269  * #VisuDataLoader owned by V_Sim.
270  **/
visu_data_spin_class_getLoaders(void)271 GList* visu_data_spin_class_getLoaders(void)
272 {
273   return _spinFormats;
274 }
275 /**
276  * visu_data_spin_class_getFileDescription:
277  *
278  * Returns a translated string describing what is files loaded by
279  * #VisuDataSpin objects.
280  *
281  * Since: 3.8
282  *
283  * Returns: a string owned by V_Sim.
284  **/
visu_data_spin_class_getFileDescription(void)285 const gchar* visu_data_spin_class_getFileDescription(void)
286 {
287   return _("Spin files");
288 }
289 /**
290  * visu_data_spin_class_finalize:
291  *
292  * Empty the list of known loaders.
293  *
294  * Since: 3.8
295  **/
visu_data_spin_class_finalize(void)296 void visu_data_spin_class_finalize(void)
297 {
298   g_list_free_full(_spinFormats, (GDestroyNotify)g_object_unref);
299   _spinFormats = (GList*)0;
300 }
301 
visu_data_spin_getFilename(const VisuDataLoadable * self,guint fileType)302 static const gchar* visu_data_spin_getFilename(const VisuDataLoadable *self,
303                                                guint fileType)
304 {
305   g_return_val_if_fail(VISU_IS_DATA_SPIN(self) && fileType < 2, (const gchar*)0);
306 
307   if (fileType == 1)
308     return visu_data_spin_getFile(VISU_DATA_SPIN(self), (VisuDataLoader**)0);
309   else
310     return visu_data_atomic_getFile(VISU_DATA_ATOMIC(self), (VisuDataLoader**)0);
311 }
312 /**
313  * visu_data_spin_getFile:
314  * @data: a #VisuDataSpin object.
315  * @format: (out caller-allocates): a location to store the format.
316  *
317  * Retrieve the spin filename. Optionally provides also the format of
318  * this file. If the file has been parsed this is the detected
319  * format. If not, this is the supposed format, as proposed by user.
320  *
321  * Since: 3.8
322  *
323  * Returns: a filename.
324  **/
visu_data_spin_getFile(VisuDataSpin * data,VisuDataLoader ** format)325 const gchar* visu_data_spin_getFile(VisuDataSpin *data, VisuDataLoader **format)
326 {
327   g_return_val_if_fail(VISU_IS_DATA_SPIN(data), (const gchar*)0);
328 
329   if (format)
330     *format = data->priv->format;
331   return data->priv->file;
332 }
333 
visu_data_spin_load(VisuDataLoadable * self,guint iSet,GCancellable * cancel,GError ** error)334 static gboolean visu_data_spin_load(VisuDataLoadable *self, guint iSet,
335                                     GCancellable *cancel, GError **error)
336 {
337   VisuDataSpin *data;
338   GList *lst;
339   VisuDataLoader *loader;
340 
341   g_return_val_if_fail(VISU_IS_DATA_SPIN(self), FALSE);
342 
343   if (!VISU_DATA_LOADABLE_CLASS(visu_data_spin_parent_class)->load(self, iSet,
344                                                                    cancel, error))
345     return FALSE;
346 
347   data = VISU_DATA_SPIN(self);
348 
349   if (!visu_data_loadable_checkFile(self, 1, error))
350     return FALSE;
351 
352   for (lst = _spinFormats; lst; lst = g_list_next(lst))
353     {
354       loader = VISU_DATA_LOADER(lst->data);
355 
356       /* Each load may set error even if the format is not recognise
357 	 and loadOK is FALSE, then we need to free the error. */
358       g_clear_error(error);
359 
360       if (!data->priv->format || loader == data->priv->format)
361 	{
362 	  DBG_fprintf(stderr,"Data Spin: testing '%s' with format: %s.\n",
363 		      data->priv->file, tool_file_format_getName(TOOL_FILE_FORMAT(loader)));
364 	  if (visu_data_loader_load(loader, self, 1, iSet, cancel, error))
365             return TRUE;
366           if (*error && (*error)->domain == G_FILE_ERROR)
367             return FALSE;
368         }
369     }
370   g_clear_error(error);
371   g_set_error(error, VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_UNKNOWN,
372               _("Impossible to load '%s', unrecognised format.\n"), data->priv->file);
373   return FALSE;
374 }
375 
initMaxModulus(VisuElement * ele _U_,GValue * val)376 static void initMaxModulus(VisuElement *ele _U_, GValue *val)
377 {
378   DBG_fprintf(stderr, " | init max modulus of val %p.\n", (gpointer)val);
379   g_value_init(val, G_TYPE_FLOAT);
380   g_value_set_float(val, -G_MAXFLOAT);
381 }
382 
383 /**
384  * visu_data_spin_get:
385  * @dataObj: a #VisuDataSpin object.
386  *
387  * Retrieve the #VisuNodeValuesVector object stroing the spin
388  * components per #VisuNode.
389  *
390  * Since: 3.8
391  *
392  * Returns: (transfer none): the #VisuNodeValuesVector storing the spi
393  * components of @dataObj.
394  **/
visu_data_spin_get(const VisuDataSpin * dataObj)395 const VisuNodeValuesVector* visu_data_spin_get(const VisuDataSpin *dataObj)
396 {
397   return VISU_NODE_VALUES_VECTOR(visu_data_getNodeProperties(VISU_DATA(dataObj),
398                                                              SPIN_PROP_ID));
399 }
400 
401 /**
402  * visu_data_spin_setAt:
403  * @dataObj: a #VisuDataSpin object.
404  * @node: a #VisuNode object.
405  * @vals: (array fixed-size=3): a vector in cartesian coordinates.
406  *
407  * Store @vals as the spin representation for @node in @dataObj.
408  *
409  * Since: 3.8
410  **/
visu_data_spin_setAt(VisuDataSpin * dataObj,const VisuNode * node,const gfloat vals[3])411 void visu_data_spin_setAt(VisuDataSpin *dataObj,
412                           const VisuNode *node, const gfloat vals[3])
413 {
414   GValue *val;
415   const gfloat* sph;
416 
417   g_return_if_fail(VISU_IS_DATA_SPIN(dataObj));
418 
419   if (!dataObj->priv->spin)
420     {
421       dataObj->priv->spin = visu_node_values_vector_new(VISU_NODE_ARRAY(dataObj),
422                                                         SPIN_PROP_ID);
423       visu_data_addNodeProperties(VISU_DATA(dataObj),
424                                   VISU_NODE_VALUES(dataObj->priv->spin));
425     }
426   visu_node_values_vector_setAt(dataObj->priv->spin, node, vals);
427   sph = visu_node_values_vector_getAtSpherical(dataObj->priv->spin, node);
428   if (!dataObj->priv->maxModulus)
429     dataObj->priv->maxModulus = visu_node_array_setElementProperty
430       (VISU_NODE_ARRAY(dataObj), SPIN_MAX_MOD_ID, initMaxModulus);
431   val = &g_array_index(dataObj->priv->maxModulus, GValue, node->posElement);
432   g_value_set_float(val, MAX(sph[TOOL_MATRIX_SPHERICAL_MODULUS],
433                              g_value_get_float(val)));
434 }
435 /**
436  * visu_data_spin_setAtSpherical:
437  * @dataObj: a #VisuDataSpin object.
438  * @node: a #VisuNode object.
439  * @vals: (array fixed-size=3): a vector in spherical coordinates.
440  *
441  * Store @vals as the spin representation for @node in @dataObj.
442  *
443  * Since: 3.8
444  **/
visu_data_spin_setAtSpherical(VisuDataSpin * dataObj,const VisuNode * node,const gfloat vals[3])445 void visu_data_spin_setAtSpherical(VisuDataSpin *dataObj, const VisuNode *node,
446                                    const gfloat vals[3])
447 {
448   GValue *val;
449 
450   g_return_if_fail(VISU_IS_DATA_SPIN(dataObj));
451 
452   if (!dataObj->priv->spin)
453     {
454       dataObj->priv->spin = visu_node_values_vector_new(VISU_NODE_ARRAY(dataObj),
455                                                         SPIN_PROP_ID);
456       visu_data_addNodeProperties(VISU_DATA(dataObj),
457                                   VISU_NODE_VALUES(dataObj->priv->spin));
458     }
459   visu_node_values_vector_setAtSpherical(dataObj->priv->spin, node, vals);
460   if (!dataObj->priv->maxModulus)
461     dataObj->priv->maxModulus = visu_node_array_setElementProperty
462       (VISU_NODE_ARRAY(dataObj), SPIN_MAX_MOD_ID, initMaxModulus);
463   val = &g_array_index(dataObj->priv->maxModulus, GValue, node->posElement);
464   g_value_set_float(val, MAX(vals[TOOL_MATRIX_SPHERICAL_MODULUS],
465                              g_value_get_float(val)));
466 }
467 
468 /**
469  * visu_data_spin_getMaxModulus:
470  * @dataObj: a #VisuDataSpin object.
471  * @iElement: an integer.
472  *
473  * Inquires the max spin modulous from @dataObj for the given
474  * #VisuElement represented by @iElement.
475  *
476  * Since: 3.8
477  *
478  * Returns: a positive float.
479  **/
visu_data_spin_getMaxModulus(const VisuDataSpin * dataObj,guint iElement)480 gfloat visu_data_spin_getMaxModulus(const VisuDataSpin *dataObj, guint iElement)
481 {
482   GValue *val;
483 
484   g_return_val_if_fail(VISU_IS_DATA_SPIN(dataObj), 1.f);
485 
486   g_return_val_if_fail(dataObj->priv->maxModulus &&
487                        iElement < dataObj->priv->maxModulus->len, 1.f);
488 
489   val = &g_array_index(dataObj->priv->maxModulus, GValue, iElement);
490   return g_value_get_float(val);
491 }
492 
493 /*****************************************************************************/
494 /*                                                                           */
495 /*****************************************************************************/
496 /* The following are the methods responsible of dealing with the reading of files. */
497 /*****************************************************************************/
498 /*                                                                           */
499 /*****************************************************************************/
500 
501 /* This is the method associated to the reading of supported spin files. */
read_spin_file(VisuDataLoader * loader _U_,VisuDataLoadable * data,guint type,guint nSet _U_,GCancellable * cancel _U_,GError ** error)502 static gboolean read_spin_file(VisuDataLoader *loader _U_, VisuDataLoadable *data,
503                                guint type, guint nSet _U_,
504                                GCancellable *cancel _U_, GError **error)
505 {
506   char line[TOOL_MAX_LINE_LENGTH] = "\0";
507   float vals[3];
508   int itrash, iLine;
509   VisuNodeArrayIter iter;
510   FILE *readFrom;
511   gboolean readContinue;
512 
513   g_return_val_if_fail(error && *error == (GError*)0, FALSE);
514 
515   readFrom = fopen(visu_data_loadable_getFilename(data, type), "r");
516   if (!readFrom)
517     {
518       *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FILE,
519 			   _("impossible to open this spin file.\n"));
520       return FALSE;
521     }
522   iLine = 1;
523 
524   /* The first line is a commentry. */
525   if(!fgets(line, TOOL_MAX_LINE_LENGTH, readFrom) || feof(readFrom))
526     {
527       *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT,
528 			   _("spin file should have one line at least.\n"));
529       fclose(readFrom);
530       return FALSE;
531     }
532   iLine += 1;
533 
534   readContinue = TRUE;
535   visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter);
536   for(visu_node_array_iterStartNumber(VISU_NODE_ARRAY(data), &iter); iter.node;
537       visu_node_array_iterNextNodeNumber(VISU_NODE_ARRAY(data), &iter))
538     {
539       if (readContinue)
540 	{
541 	  if(!fgets(line, TOOL_MAX_LINE_LENGTH, readFrom) || feof(readFrom))
542 	    readContinue = FALSE;
543 	  else
544 	    {
545 	      if(sscanf(line, "%d %f %f %f", &itrash, vals + TOOL_MATRIX_SPHERICAL_MODULUS,
546 			vals + TOOL_MATRIX_SPHERICAL_THETA, vals + TOOL_MATRIX_SPHERICAL_PHI) != 4)
547 		{
548 		  g_warning("line number #%d is invalid."
549 			    " Setting node parameters to default ones...", iLine);
550 		  vals[TOOL_MATRIX_SPHERICAL_THETA]   = 0.f;
551 		  vals[TOOL_MATRIX_SPHERICAL_PHI]     = 0.f;
552 		  vals[TOOL_MATRIX_SPHERICAL_MODULUS] = 0.f;
553 		}
554 	    }
555 	  iLine += 1;
556 	}
557       else
558 	{
559 	  vals[TOOL_MATRIX_SPHERICAL_THETA]   = 0.f;
560 	  vals[TOOL_MATRIX_SPHERICAL_PHI]     = 0.f;
561 	  vals[TOOL_MATRIX_SPHERICAL_MODULUS] = 0.f;
562 	}
563       visu_data_spin_setAtSpherical(VISU_DATA_SPIN(data), iter.node, vals);
564     }
565   fclose(readFrom);
566 
567   return TRUE;
568 }
569 
570 /* This is the method associated to the reading of binary spin files. */
read_binary_file(VisuDataLoader * loader _U_,VisuDataLoadable * data,guint type,guint nSet _U_,GCancellable * cancel _U_,GError ** error)571 static gboolean read_binary_file(VisuDataLoader *loader _U_, VisuDataLoadable *data,
572                                  guint type, guint nSet _U_,
573                                  GCancellable *cancel _U_, GError **error)
574 {
575   ToolFiles *readFrom;
576   gboolean valid;
577   ToolFortranEndianId endian;
578   guint nspins;
579   GArray *mods, *thetas, *phis;
580   int i;
581   float vals[3];
582   VisuNodeArrayIter iter;
583 
584   g_return_val_if_fail(error && *error == (GError*)0, FALSE);
585 
586   readFrom = tool_files_new();
587   if (!tool_files_fortran_open(readFrom, visu_data_loadable_getFilename(data, type), error))
588     return FALSE;
589 
590   /* Try to find the endianness. */
591   if (!tool_files_fortran_testEndianness(readFrom, 4, &endian))
592     {
593       g_object_unref(readFrom);
594       return FALSE;
595     }
596 
597   /* Try to the number of spins. */
598   if (!tool_files_fortran_readInteger(readFrom, (gint*)&nspins, endian, error))
599     {
600       g_object_unref(readFrom);
601       return FALSE;
602     }
603   if (!tool_files_fortran_checkFlag(readFrom, 4, endian, error))
604     {
605       g_object_unref(readFrom);
606       return FALSE;
607     }
608 
609   /* From now on, we consider to a have valid spin file. */
610   visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter);
611   if (nspins != iter.nAllStoredNodes)
612     {
613       g_set_error(error, VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT,
614                   _("number of spin differs from number of nodes.\n"));
615       g_object_unref(readFrom);
616       return TRUE;
617     }
618 
619   /* Read module. */
620   valid = tool_files_fortran_readDoubleArray(readFrom, &mods,
621                                              nspins, endian, TRUE, error);
622   if (!valid)
623     {
624       g_object_unref(readFrom);
625       return TRUE;
626     }
627   /* Read theta. */
628   valid = tool_files_fortran_readDoubleArray(readFrom, &thetas,
629                                              nspins, endian, TRUE, error);
630   if (!valid)
631     {
632       g_array_unref(mods);
633       g_object_unref(readFrom);
634       return TRUE;
635     }
636   /* Read phi. */
637   valid = tool_files_fortran_readDoubleArray(readFrom, &phis,
638                                              nspins, endian, TRUE, error);
639   if (!valid)
640     {
641       g_array_unref(mods);
642       g_array_unref(thetas);
643       g_object_unref(readFrom);
644       return TRUE;
645     }
646   /* Close the file. */
647   g_object_unref(readFrom);
648 
649   for(visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter), i = 0; iter.node;
650       visu_node_array_iterNext(VISU_NODE_ARRAY(data), &iter), i++)
651     {
652       vals[TOOL_MATRIX_SPHERICAL_MODULUS] = g_array_index(mods, double, i);
653       vals[TOOL_MATRIX_SPHERICAL_THETA]   = g_array_index(thetas, double, i);
654       vals[TOOL_MATRIX_SPHERICAL_PHI]     = g_array_index(phis, double, i);
655       visu_data_spin_setAtSpherical(VISU_DATA_SPIN(data), iter.node, vals);
656     }
657 
658   g_array_unref(mods);
659   g_array_unref(thetas);
660   g_array_unref(phis);
661   return TRUE;
662 }
663