source: XMLIO_V2/dev/dev_rv/src/XMLIO/NetCDF4_data_output.hpp @ 127

Last change on this file since 127 was 127, checked in by hozdoba, 14 years ago

suite du précédent commit

File size: 12.9 KB
Line 
1#ifndef __NETCDF4_DATA_OUTPUT__
2#define __NETCDF4_DATA_OUTPUT__
3
4#include <netcdfcpp.h>
5
6namespace XMLIOSERVER
7{
8
9   static const char* TimeName = "time";
10
11   class NetCDF4DataOutput : public AbstractDataOutput
12   {
13      public :
14
15         NetCDF4DataOutput(CFile* const _file)
16            : AbstractDataOutput(_file), dataFile(NULL)
17         { /* Ne rien faire de plus */ }
18
19         const NcFile* getDataFile(void) const { return (dataFile); }
20
21         void writeVarData(const string& id, const Array<float, 1>& vdata)
22         {
23            //if (!latVar->put(lats, NLAT))
24            //   return NC_ERR;
25         }
26
27         virtual ~NetCDF4DataOutput()
28         { if (dataFile != NULL) delete dataFile; }
29
30      protected :
31
32         Poco::HashMap<string, int> getAllLimitedDim(void) const
33         {
34            Poco::HashMap<string, int> dims;
35            const std::set<const CDomain*> sdom = this->getRelFile()->getEnabledDomains();
36            const std::set<const CAxis*>  saxis = this->getRelFile()->getEnabledAxis();
37
38            // std::cout << "Nombre de domaines disponibles pour le fichier : " << sdom.size()  << std::endl;
39            // std::cout << "Nombre d'axes disponibles pour le fichier : "      << saxis.size() << std::endl;
40
41            std::set<const CDomain*>::const_iterator itt;
42            std::set<const CAxis*>::const_iterator it;
43
44            for ( itt = sdom.begin() ; itt != sdom.end(); itt++ )
45            {
46               string domid = ((*itt)->name.hasValue()) ? (string)(*itt)->name : (*itt)->getId();
47               string lonid = string("lon_").append(domid);
48               string latid = string("lat_").append(domid);
49               dims[lonid]  = (*itt)->ni;
50               dims[latid]  = (*itt)->nj;
51            }
52
53            for ( it = saxis.begin() ; it != saxis.end(); it++ )
54            {
55               string axisid = ((*it)->name.hasValue()) ? (string)(*it)->name : (*it)->getId();
56               dims[axisid]  = (*it)->size;
57            }
58
59            return (dims);
60         }
61
62         std::string getFileName(void)
63         { return ((getRelFile()->name.hasValue()) ? string(getRelFile()->name): getRelFile()->name.getId()); }
64
65         std::string getTimeStamp(void)
66         {
67            const int buffer_size = 100;
68            time_t rawtime;
69            struct tm * timeinfo = NULL;
70            char buffer [buffer_size];
71
72            time ( &rawtime );
73            timeinfo = localtime ( &rawtime );
74            strftime (buffer, buffer_size, "%Y-%b-%d %H:%M:%S %Z", timeinfo);
75
76            return (string(buffer));
77         }
78
79         void writeCoords(const string& id, const Array<double, 1>& cdata)
80         {
81            NcVar *cVar = dataFile->get_var(id.c_str());
82
83            if (!cVar->put(cdata.dataFirst(), cdata.size()))
84               throw XMLIOUndefinedValueException("Impossible d'écrire les valeurs de coordonnées "+ id +" !");
85         }
86
87      protected : /* virtual */
88
89         virtual void initFile(void)
90         {
91            string filename = this->getFileName();
92
93            // Création du fichier ou remplacement si celui-ci existe déjà.
94            dataFile = new NcFile(filename.c_str(), NcFile::Replace);
95            if(!dataFile->is_valid())
96               throw XMLIOUndefinedValueException("Impossible d'ouvrir le fichier '"+ filename +"' pour l'écriture des données' !");
97
98            // Ajout de quelques attributs globaux.
99            dataFile->add_att("conventions", "CF-1.1");
100            dataFile->add_att("file_name"  , getFileName().c_str());
101            if (getRelFile()->description.hasValue())
102               dataFile->add_att("file_desc" , string(getRelFile()->description).c_str());
103            dataFile->add_att("production" , "An IPSL model");
104            dataFile->add_att("timeStamp"  , getTimeStamp().c_str()) ;
105         }
106
107         virtual void setDims(void)
108         {
109            bool withTime = true;
110            const Poco::HashMap<string, int>& allDim = this->getAllLimitedDim();
111            Poco::HashMap<string, int>::ConstIterator it;
112
113            // Ajout des dimensions limitées.
114            for (it = allDim.begin() ; it != allDim.end(); it++)
115               if (NULL == dataFile->add_dim((*it).first.c_str(), (*it).second))
116                  throw XMLIOUndefinedValueException("Impossible d'ajouter la dimension "+ (*it).first +" !");
117
118            // Ajout de la dimension temporelle non limitée.
119            if (withTime)
120               if (NULL == dataFile->add_dim(TimeName))
121                  throw XMLIOUndefinedValueException("Impossible d'ajouter la dimension temporelle !");
122         }
123
124         virtual void setCoords(void)
125         {
126            NcVar *latVar = NULL, // variable de latitude.
127                  *lonVar = NULL, // variable de longitude.
128                  *othvar = NULL; // toute autre variable.
129
130            Poco::HashMap<string, string> hm;
131
132            const std::set<const CDomain*> sdom = this->getRelFile()->getEnabledDomains();
133            const std::set<const CAxis*>  saxis = this->getRelFile()->getEnabledAxis();
134
135            std::set<const CDomain*>::const_iterator itt;
136            for ( itt = sdom.begin() ; itt != sdom.end(); itt++ )
137            {
138               string domid = ((*itt)->name.hasValue()) ? (string)(*itt)->name : (*itt)->getId();
139               string lonid = string("lon_").append(domid);
140               string latid = string("lat_").append(domid);
141
142               if (!(latVar = dataFile->add_var(latid.c_str(), ncFloat, dataFile->get_dim(latid.c_str()))))
143                  throw XMLIOUndefinedValueException("Impossible d'ajouter la variable de latitude !");
144
145               if (!(lonVar = dataFile->add_var(lonid.c_str(), ncFloat, dataFile->get_dim(lonid.c_str()))))
146                  throw XMLIOUndefinedValueException("Impossible d'ajouter la variable de longitude !");
147
148               // Attribut de latitude.
149               hm["axis"]          = "Y" ;
150               hm["standard_name"] = "latitude" ;
151               hm["units"]         = "degrees_north";
152               hm["long_name"]     = "Latitude" ;
153               this->addStringAttributesToVar(latVar, hm);
154               hm.clear();
155
156               // Attribut de longitude.
157               hm["axis"]           = "X" ;
158               hm["standard_name"]  = "longitude" ;
159               hm["units"]          = "degrees_east";
160               hm["long_name"]      = "Longitude" ;
161               this->addStringAttributesToVar(lonVar, hm);
162               hm.clear();
163
164               if ((*itt)->yvalue.hasValue())
165                  this->writeCoords(lonid, (*itt)->xvalue);
166               else throw XMLIOUndefinedValueException("Les coordonnées de longitude (xvalue) ne sont pas définies pour le domaine \""+domid+"\".");
167
168               if ((*itt)->xvalue.hasValue())
169                  this->writeCoords(latid, (*itt)->yvalue);
170               else throw XMLIOUndefinedValueException("Les coordonnées de latitude (yvalue) ne sont pas définies pour le domaine \""+domid+"\".");
171            }
172
173            // Attribut des autres coordonnées.
174            std::set<const CAxis*>::const_iterator it;
175            for ( it = saxis.begin() ; it != saxis.end(); it++ )
176            {
177               string axisid = ((*it)->name.hasValue()) ? (string)(*it)->name : (*it)->getId();
178               if (!(othvar = dataFile->add_var(axisid.c_str(), ncFloat, dataFile->get_dim(axisid.c_str()))))
179                  throw XMLIOUndefinedValueException("Impossible d'ajouter la variable "+ (*it)->getId() +" !");
180
181               hm["axis"] = "Z" ;
182               if ((*it)->standard_name.hasValue())hm["standard_name"] = (*it)->standard_name ;
183               if ((*it)->long_name.hasValue())    hm["long_name"]     = (*it)->long_name ;
184               if ((*it)->unit.hasValue())         hm["units"]         = (*it)->unit;
185               this->addStringAttributesToVar(othvar, hm);
186               hm.clear();
187
188               if ((*it)->value.hasValue())
189                  this->writeCoords(axisid, (*it)->value);
190               else throw XMLIOUndefinedValueException("Les coordonnées de l'axe \""+axisid+"\" (value) ne sont pas définies.");
191            }
192         }
193
194         virtual void setVars(void)
195         {
196            NcType tvar = ncFloat;
197            NcVar *var  = NULL;
198            Poco::HashMap<string, string> hm;
199            bool lonlat = false, wtime = true;
200            const std::vector<CField*>& enabledFields = getRelFile()->getEnabledFields();
201
202            std::vector<CField*>::const_iterator it;
203
204            for ( it = enabledFields.begin() ; it != enabledFields.end(); it++ )
205            {
206                     CField*  field = (*it);
207               const CField* bfield = (*it)->getBaseObject();
208               const CDomain*  rdom = field->getGrid()->getRelDomain();
209               const CAxis*   raxis = field->getGrid()->getRelAxis();
210
211               string fieldid = (field->name.hasValue()) ? (string)field->name : bfield->getId();
212               string domid   = (rdom ->name.hasValue()) ? (string)rdom ->name : rdom  ->getId();
213               string axisid  = (raxis->name.hasValue()) ? (string)raxis->name : raxis ->getId();
214
215               string lonid = string("lon_").append(domid); // Nom de la coordonnée longitudinale associée.
216               string latid = string("lat_").append(domid); // Nom de la coordonnée latitudinale  associée.
217
218               lonlat = !field->getGrid()->_hasAxis();
219
220               if (field->operation.hasValue())
221               { // Si une opération sur le champ est définie ...
222                  if (field->operation.getId().compare("once") == 0)
223                  { wtime = false; field->freq_op.setValue(NoneDu); }
224               }
225               else
226               { // Si aucune opération sur le champ n'est définie ...
227                  FieldOperation ope("inst");
228                  field->operation.setValue(ope);
229               }
230
231               // Si la fréquence d'opération n'est pas définie, on l'initialise à 0s.
232               // Une fréquence à 0s signifie que l'opération se fera à chaque écriture de données depuis la simulation.
233               if (!field->freq_op.hasValue())
234                  field->freq_op.setValue(NoneDu);
235               ((FieldOperation)field->operation).setFreqOp(Duration(field->freq_op));
236
237               tvar = ncFloat;
238               if (field->prec.hasValue())
239                  if (field->prec == 8) tvar = ncDouble;
240
241               if (wtime)
242               {
243                  if (lonlat) // 2D spatio + temps
244                  {
245                     if (!(var = dataFile->add_var(fieldid.c_str(), tvar,
246                        dataFile->get_dim(TimeName), dataFile->get_dim(latid.c_str()), dataFile->get_dim(lonid.c_str()))))
247                        throw XMLIOUndefinedValueException("Impossible d'ajouter le champ "+ field->getId() +" !");
248                  }
249                  else // 3D spatio + temps
250                  {
251                     if (!(var = dataFile->add_var(fieldid.c_str(), tvar,
252                        dataFile->get_dim(TimeName), dataFile->get_dim(axisid.c_str()),
253                        dataFile->get_dim(latid.c_str()), dataFile->get_dim(lonid.c_str()))))
254                        throw XMLIOUndefinedValueException("Impossible d'ajouter le champ "+ field->getId() +" !");
255                  }
256               }
257               else
258               {
259                  if (lonlat) // 2D spatio sans temps
260                  {
261                     if (!(var = dataFile->add_var(fieldid.c_str(), tvar,
262                        dataFile->get_dim(latid.c_str()), dataFile->get_dim(lonid.c_str()))))
263                        throw XMLIOUndefinedValueException("Impossible d'ajouter le champ "+ field->getId() +" !");
264                  }
265                  else // 3D spatio sans temps
266                  {
267                     if (!(var = dataFile->add_var(fieldid.c_str(), tvar, dataFile->get_dim(axisid.c_str()),
268                        dataFile->get_dim(latid.c_str()), dataFile->get_dim(lonid.c_str()))))
269                        throw XMLIOUndefinedValueException("Impossible d'ajouter le champ "+ field->getId() +" !");
270                  }
271               }
272
273               if (field->standard_name.hasValue())hm["standard_name"] = field->standard_name ;
274               if (field->long_name.hasValue())    hm["long_name"]     = field->long_name ;
275               if (field->unit.hasValue())         hm["units"]         = field->unit;
276               this->addStringAttributesToVar(var, hm);
277               hm.clear();
278            }
279         }
280
281      private :
282
283         void addStringAttributesToVar(NcVar * const var, const Poco::HashMap<string, string>& attr)
284         {
285            Poco::HashMap<string, string>::ConstIterator it;
286
287            for ( it = attr.begin() ; it != attr.end(); it++ )
288               if (!var->add_att((*it).first.c_str(), (*it).second.c_str()))
289                  throw XMLIOUndefinedValueException("Impossible d'ajouter l'attribut' "+ (*it).first +" à la variable "+ var->name() +" !");
290         }
291
292         NcFile* dataFile;
293
294   }; //class NetCDF4DataOutput
295
296}// namespace XMLIOSERVER
297
298#endif //__NETCDF4_DATA_OUTPUT__
Note: See TracBrowser for help on using the repository browser.