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 <netcdf.h>
46 #include <string.h>
47 
48 #include "nq_basic.h"
49 #include "nq_structure.h"
50 #include "nq_density.h"
51 #include <visu_tools.h>
52 #include <visu_basic.h>
53 #include <visu_dataatomic.h>
54 
55 #define NANOQUANTA_DESCRIPTION _("<span size=\"smaller\">" \
56 				 "This plug-in introduces support for\n" \
57 				 "<b>ETSF</b> file format defined by the\n" \
58 				 "European network <b>NANOQUANTA</b>.</span>")
59 #define NANOQUANTA_AUTHORS     _("Caliste Damien:\n   structure/density loading.")
60 
61 static gchar *iconPath;
62 
63 /* Required methods for a loadable module. */
etsfInit()64 gboolean etsfInit()
65 {
66   DBG_fprintf(stderr, "ETSF: loading plug-in 'nanoquanta'...\n");
67 
68   DBG_fprintf(stderr, "ETSF: declare a new rendering load method.\n");
69   visu_data_atomic_class_addLoader(visu_data_loader_ETSF_getStatic());
70 
71   iconPath = g_build_filename(V_SIM_PIXMAPS_DIR, "nanoquanta.png", NULL);
72 
73   DBG_fprintf(stderr, "ETSF: declare a new density load method.\n");
74   nqDensityInit();
75 
76   return TRUE;
77 }
78 
etsfGet_description()79 const char* etsfGet_description()
80 {
81   return NANOQUANTA_DESCRIPTION;
82 }
83 
etsfGet_authors()84 const char* etsfGet_authors()
85 {
86   return NANOQUANTA_AUTHORS;
87 }
88 
etsfGet_icon()89 const char* etsfGet_icon()
90 {
91   return iconPath;
92 }
93 
nqError_quark()94 GQuark nqError_quark()
95 {
96   return g_quark_from_static_string("nanoquanta");
97 }
98 
99 
100 
nqOpen_netcdfFile(const char * filename,int * netcdfId,GError ** error)101 gboolean nqOpen_netcdfFile(const char* filename, int *netcdfId, GError **error)
102 {
103   int status, i;
104   char *varsNames[3] = {"file_format", "file_format_version", "Conventions"};
105   nc_type varsType[3] = {NC_CHAR, NC_FLOAT, NC_CHAR};
106   nc_type altVarsType[3] = {NC_CHAR, NC_DOUBLE, NC_CHAR};
107   size_t varsLength[3] = {80, 1, 80};
108   nc_type readType;
109   size_t readLength[3];
110   char format[256];
111   float version;
112 
113   g_return_val_if_fail(error && *error == (GError*)0, FALSE);
114   g_return_val_if_fail(netcdfId && filename, FALSE);
115 
116   DBG_fprintf(stderr, "NQ Basic: opening file '%s' as a NetCDF file.\n", filename);
117   /* Open the file as a NETCDF file. */
118   status = nc_open(filename, NC_NOWRITE, netcdfId);
119   if (status != NC_NOERR)
120     {
121       DBG_fprintf(stderr, " | not a NetCDF file, can't open.\n");
122       *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_OPEN,
123 			   "%s", nc_strerror(status));
124       return FALSE;
125     }
126 
127   /* From here, the file is opened. */
128 
129   /* Grep the header variables to check that it is a NETCDF file
130      following rules of NANOQUANTA specifications. */
131   DBG_fprintf(stderr, "NQ Basic: checking header of file '%s'.\n", filename);
132   /* Check lengths and types. */
133   for (i = 0; i < 3; i++)
134     {
135       status = nc_inq_att(*netcdfId, NC_GLOBAL, varsNames[i], &readType, readLength + i);
136       if (status != NC_NOERR)
137         {
138           DBG_fprintf(stderr, " | cannot read header element %d (%s).\n", i, nc_strerror(status));
139           *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_HEADER,
140 			       "inquiring global attribute '%s' raises: %s",
141                                varsNames[i], nc_strerror(status));
142           nqClose_netcdfFile(*netcdfId);
143           return FALSE;
144         }
145       DBG_fprintf(stderr, " | header '%s' : type %d (%d), length %d (%d).\n",
146                   varsNames[i], (int)readType, (int)varsType[i],
147                   (int)readLength[i], (int)varsLength[i]);
148       if ((readType != varsType[i] && readType != altVarsType[i]) ||
149            readLength[i] > varsLength[i])
150         {
151           DBG_fprintf(stderr, " | header not valid.\n");
152           *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_HEADER,
153                                _("Global attribute '%s' has a wrong "
154                                  "length or type.\n"), varsNames[i]);
155           nqClose_netcdfFile(*netcdfId);
156           return FALSE;
157         }
158     }
159   /* Check values. */
160   status = nc_get_att_text(*netcdfId, NC_GLOBAL, varsNames[0], format);
161   if (status != NC_NOERR)
162     {
163       DBG_fprintf(stderr, " | cannot read format.\n");
164       *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_HEADER,
165 			   "reading global attribute '%s' raises: %s",
166                            varsNames[0], nc_strerror(status));
167       nqClose_netcdfFile(*netcdfId);
168       return FALSE;
169     }
170   format[readLength[0]] = '\0';
171   DBG_fprintf(stderr, " | header '%s' value '%s'.\n", varsNames[0], format);
172   if (strcmp(format, "ETSF Nanoquanta"))
173     {
174       DBG_fprintf(stderr, " | wrong format '%s'.\n", format);
175       *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_HEADER,
176 			   _("Variable 'file_format' should be "
177 			     "'ETSF Nanoquanta' but is '%s'.\n"), format);
178       nqClose_netcdfFile(*netcdfId);
179       return FALSE;
180     }
181   status = nc_get_att_float(*netcdfId, NC_GLOBAL, varsNames[1], &version);
182   if (status != NC_NOERR)
183     {
184       DBG_fprintf(stderr, " | cannot read version.\n");
185       *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_HEADER,
186 			   "reading global attribute '%s' raises: %s",
187                            varsNames[1], nc_strerror(status));
188       nqClose_netcdfFile(*netcdfId);
189       return FALSE;
190     }
191   DBG_fprintf(stderr, " | header '%s' value %f.\n", varsNames[1], version);
192   if (version < 1.2)
193     {
194       DBG_fprintf(stderr, " | version too small (%f).\n", version);
195       *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_HEADER,
196 			   _("Supported version are 1.2 and over but"
197 			     " this file is only %f.\n"), version);
198       nqClose_netcdfFile(*netcdfId);
199       return FALSE;
200     }
201 
202   return TRUE;
203 }
204 
nqClose_netcdfFile(int netcdfId)205 gboolean nqClose_netcdfFile(int netcdfId)
206 {
207   int status;
208 
209   status = nc_close(netcdfId);
210   if (status != NC_NOERR)
211     {
212       g_warning("%s", nc_strerror(status));
213       return FALSE;
214     }
215 
216   return TRUE;
217 }
218 
nqErrorReport(GError ** error,const char * message,...)219 static gboolean nqErrorReport(GError **error, const char *message, ...)
220 {
221   va_list args;
222   gchar *formatted;
223 
224   if (error)
225     {
226       va_start(args, message);
227       formatted = g_strdup_vprintf(message, args);
228       va_end(args);
229 
230       *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_FORMAT, "%s", formatted);
231 
232       g_free(formatted);
233     }
234 
235   return FALSE;
236 }
237 
nqGetDim(int netcdfId,GError ** error,char * name,int * varId,size_t * value)238 gboolean nqGetDim(int netcdfId, GError **error, char *name, int *varId, size_t *value)
239 {
240   int status;
241 
242   /* Grep the number of elements. */
243   status = nc_inq_dimid(netcdfId, name, varId);
244   if (status != NC_NOERR)
245     return nqErrorReport(error, _("Reading '%s': %s."),
246                          name, nc_strerror(status));
247   status = nc_inq_dimlen(netcdfId, *varId, value);
248   if (status != NC_NOERR)
249     return nqErrorReport(error, _("Retrieve value for variable '%s': %s."),
250                          name, nc_strerror(status));
251   return TRUE;
252 }
253 
nqCheckVar(int netcdfId,GError ** error,char * name,int * varId,nc_type ncType,int nbDims,size_t * nbEleDims)254 gboolean nqCheckVar(int netcdfId, GError **error, char *name, int *varId,
255 			              nc_type ncType, int nbDims, size_t *nbEleDims)
256 {
257   int status;
258   nc_type localType;
259   char *typeNames[] = {"NAT", "BYTE", "CHAR", "SHORT", "INT", "FLOAT", "DOUBLE"};
260   int localDims;
261   int *localNbDims;
262   int i;
263   size_t dimSize;
264 
265   status = nc_inq_varid(netcdfId, name, varId);
266   if (status != NC_NOERR)
267     return nqErrorReport(error, _("Reading '%s': %s."),
268 			    name, nc_strerror(status));
269   status = nc_inq_vartype(netcdfId, *varId, &localType);
270   if (status != NC_NOERR)
271     return nqErrorReport(error, _("Checking variable '%s': %s."),
272 			    name, nc_strerror(status));
273   if (localType != ncType)
274     return nqErrorReport(error, _("Variable '%s' should be of type '%s'."),
275 			    name, typeNames[ncType]);
276   status = nc_inq_varndims(netcdfId, *varId, &localDims);
277   if (status != NC_NOERR)
278     return nqErrorReport(error, _("Checking variable '%s': %s."),
279 			    name, nc_strerror(status));
280   if (localDims != nbDims)
281     return nqErrorReport(error,
282 			    _("Variable '%s' should be a %d dimension array."),
283 			    name, nbDims);
284   localNbDims = g_malloc(sizeof(int) * nbDims);
285   status = nc_inq_vardimid(netcdfId, *varId, localNbDims);
286   if (status != NC_NOERR)
287     {
288       g_free(localNbDims);
289       return nqErrorReport(error, _("Checking variable '%s': %s."),
290 			      name, nc_strerror(status));
291     }
292   for (i = 0; i< nbDims; i++)
293     {
294       status = nc_inq_dimlen(netcdfId, localNbDims[i], &dimSize);
295       if (status != NC_NOERR)
296 	{
297 	  g_free(localNbDims);
298 	  return nqErrorReport(error, _("Checking dimension ID %d: %s."),
299 				  localNbDims[i], nc_strerror(status));
300 	}
301       if (dimSize != nbEleDims[i])
302       {
303 	g_free(localNbDims);
304 	return nqErrorReport(error,
305 				_("Variable '%s' is not consistent with"
306 				  " declaration of dimensions."), name);
307       }
308     }
309   g_free(localNbDims);
310   return TRUE;
311 }
312 
313