source: XIOS/trunk/src/node/file.cpp @ 459

Last change on this file since 459 was 459, checked in by ymipsl, 10 years ago

Add new parsing expression functionnalities
(modified files)

YM

File size: 16.1 KB
Line 
1#include "file.hpp"
2
3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6#include "object_factory.hpp"
7#include "data_output.hpp"
8#include "context.hpp"
9#include "context_server.hpp"
10#include "nc4_data_output.hpp"
11#include "calendar_util.hpp"
12#include "date.hpp"
13#include "message.hpp"
14#include "type.hpp"
15#include "xmlioserver_spl.hpp"
16#include "context_client.hpp"
17#include "mpi.hpp"
18
19namespace xios {
20   
21   /// ////////////////////// Définitions ////////////////////// ///
22
23   CFile::CFile(void)
24      : CObjectTemplate<CFile>(), CFileAttributes()
25      , vFieldGroup(), data_out(), enabledFields(), fileComm(MPI_COMM_NULL)
26   { setVirtualFieldGroup() ;}
27
28   CFile::CFile(const StdString & id)
29      : CObjectTemplate<CFile>(id), CFileAttributes()
30      , vFieldGroup(), data_out(), enabledFields(), fileComm(MPI_COMM_NULL)
31   { setVirtualFieldGroup() ;}
32
33   CFile::~CFile(void)
34   { /* Ne rien faire de plus */ }
35
36   ///---------------------------------------------------------------
37
38   StdString CFile::GetName(void)   { return (StdString("file")); }
39   StdString CFile::GetDefName(void){ return (CFile::GetName()); }
40   ENodeType CFile::GetType(void)   { return (eFile); }
41
42   //----------------------------------------------------------------
43
44   boost::shared_ptr<CDataOutput> CFile::getDataOutput(void) const
45   {
46      return (data_out);
47   }
48
49   CFieldGroup* CFile::getVirtualFieldGroup(void) const
50   {
51      return (this->vFieldGroup);
52   }
53
54   std::vector<CField*> CFile::getAllFields(void) const
55   {
56      return (this->vFieldGroup->getAllChildren());
57   }
58
59   //----------------------------------------------------------------
60
61   std::vector<CField*> CFile::getEnabledFields(int default_outputlevel, 
62                                                int default_level,
63                                                bool default_enabled)
64   {
65      if (!this->enabledFields.empty())
66         return (this->enabledFields);
67
68      const int _outputlevel =
69         (!output_level.isEmpty()) ? output_level.getValue() : default_outputlevel;
70      std::vector<CField*>::iterator it;
71      this->enabledFields = this->getAllFields();
72
73      std::vector<CField*> newEnabledFields;
74     
75      for ( it = this->enabledFields.begin() ; it != this->enabledFields.end(); it++ )
76      {
77         if (!(*it)->enabled.isEmpty()) // Si l'attribut 'enabled' est défini ...
78         {
79            if (! (*it)->enabled.getValue()) continue;
80//            { it--; this->enabledFields.erase(it+1); continue; }
81         }
82         else // Si l'attribut 'enabled' n'est pas défini ...
83         {
84            if (!default_enabled) continue ;
85//            { it--; this->enabledFields.erase(it+1); continue; }
86         }
87
88         if (!(*it)->level.isEmpty()) // Si l'attribut 'level' est défini ...
89         {
90            if ((*it)->level.getValue() > _outputlevel) continue ;
91//            { it--; this->enabledFields.erase(it+1); continue; }
92         }
93         else // Si l'attribut 'level' n'est pas défini ...
94         {
95            if (default_level > _outputlevel) continue ;
96//            { it--; this->enabledFields.erase(it+1); continue; }
97         }
98 
99//         CField* field_tmp=(*it).get() ;
100//         shared_ptr<CField> sptfield=*it ;
101//         field_tmp->refObject.push_back(sptfield) ;
102         newEnabledFields.push_back(*it) ;
103         // Le champ est finalement actif, on y ajoute sa propre reference.
104//         (*it)->refObject.push_back(*it);
105         // Le champ est finalement actif, on y ajoute la référence au champ de base.
106         (*it)->setRelFile(CFile::get(this));
107//         (*it)->baseRefObject->refObject.push_back(*it);
108         // A faire, ajouter les references intermediaires...
109      }
110      enabledFields=newEnabledFields ;
111
112      return (this->enabledFields);
113   }
114
115   //----------------------------------------------------------------
116
117   void CFile::setVirtualFieldGroup(CFieldGroup* newVFieldGroup)
118   { 
119      this->vFieldGroup = newVFieldGroup; 
120   }
121
122   //----------------------------------------------------------------
123
124   void CFile::setVirtualFieldGroup(void)
125   {
126      this->setVirtualFieldGroup(CFieldGroup::create());
127   }
128
129   //----------------------------------------------------------------
130   bool CFile::isSyncTime(void)
131   {
132     CContext* context = CContext::getCurrent() ;
133     CDate& currentDate=context->calendar->getCurrentDate() ;
134     if (! sync_freq.isEmpty())
135     {
136       if (*lastSync+syncFreq < currentDate)
137       {
138         *lastSync=currentDate ;
139         return true ;
140        }
141      }
142      return false ;
143    }
144   
145   void CFile::initFile(void)
146   {
147      CContext* context = CContext::getCurrent() ;
148      CDate& currentDate=context->calendar->getCurrentDate() ;
149      CContextServer* server=context->server ;
150           
151      if (! sync_freq.isEmpty()) syncFreq = CDuration::FromString(sync_freq.getValue());
152      if (! split_freq.isEmpty()) splitFreq = CDuration::FromString(split_freq.getValue());
153      if (! output_freq.isEmpty()) outputFreq = CDuration::FromString(output_freq.getValue());
154      lastSync=new CDate(currentDate) ;
155      lastSplit=new CDate(currentDate) ;
156      isOpen=false ;
157
158      allDomainEmpty=true ;
159      set<CDomain*> setDomain ;
160
161      std::vector<CField*>::iterator it, end = this->enabledFields.end();
162      for (it = this->enabledFields.begin() ;it != end; it++)
163      {
164         CField* field = *it;
165         allDomainEmpty&=field->grid->domain->isEmpty() ;
166         setDomain.insert(field->grid->domain) ;
167      }
168      nbDomain=setDomain.size() ;
169
170      // create sub communicator for file 
171      int color=allDomainEmpty?0:1 ;
172      MPI_Comm_split(server->intraComm,color,server->intraCommRank,&fileComm) ;
173      if (allDomainEmpty) MPI_Comm_free(&fileComm) ;
174      //
175     
176    }
177   
178    void CFile::checkFile(void)
179    {
180      if (!isOpen) createHeader() ;
181      checkSync() ;
182      checkSplit() ;
183    }
184     
185     
186   bool CFile::checkSync(void)
187   {
188     CContext* context = CContext::getCurrent() ;
189     CDate& currentDate=context->calendar->getCurrentDate() ;
190     if (! sync_freq.isEmpty())
191     {
192       if (*lastSync+syncFreq <= currentDate)
193       {
194         *lastSync=currentDate ;
195         data_out->syncFile() ;
196         return true ;
197        }
198      }
199      return false ;
200    }
201   
202   
203    bool CFile::checkSplit(void)
204    {
205      CContext* context = CContext::getCurrent() ;
206      CDate& currentDate=context->calendar->getCurrentDate() ;
207      if (! split_freq.isEmpty())
208      {
209        if (currentDate > *lastSplit+splitFreq)
210        {
211          *lastSplit=*lastSplit+splitFreq ;   
212          std::vector<CField*>::iterator it, end = this->enabledFields.end();
213          for (it = this->enabledFields.begin() ;it != end; it++)  (*it)->resetNStep() ;
214          createHeader() ;
215          return true ;
216        }
217      }
218      return false ;
219    }
220   
221   void CFile::createHeader(void)
222   {
223      CContext* context = CContext::getCurrent() ;
224      CContextServer* server=context->server ;
225     
226      if (!allDomainEmpty)
227      {
228         StdString filename = (!name.isEmpty()) ?   name.getValue() : getId();
229         StdOStringStream oss;
230         oss << filename;
231         if (!name_suffix.isEmpty()) oss << name_suffix.getValue();
232//         if (!split_freq.isEmpty()) oss<<"_"<<lastSplit->getStryyyymmdd()<<"-"<< (*lastSplit+(splitFreq-1*Second)).getStryyyymmdd();
233//         if (!split_freq.isEmpty()) oss<<"_"<<lastSplit->getStr("%y_%mo_%d")<<"-"<< (*lastSplit+(splitFreq-1*Second)).getStr("%y_%mo_%d");
234         if (!split_freq.isEmpty())
235         {
236           string splitFormat ;
237           if (split_freq_format.isEmpty())
238           {
239             if (splitFreq.second!=0) splitFormat="%y%mo%d%h%mi%s";
240             else if (splitFreq.minute!=0) splitFormat="%y%mo%d%h%mi";
241             else if (splitFreq.hour!=0) splitFormat="%y%mo%d%h";
242             else if (splitFreq.day!=0) splitFormat="%y%mo%d";
243             else if (splitFreq.month!=0) splitFormat="%y%mo";
244             else splitFormat="%y";
245           }
246           else splitFormat=split_freq_format ;
247           oss<<"_"<<lastSplit->getStr(splitFormat)<<"-"<< (*lastSplit+(splitFreq-1*Second)).getStr(splitFormat);
248         }
249           
250         bool multifile=true ;
251         if (!type.isEmpty())
252         {
253           if (type==type_attr::one_file) multifile=false ;
254           else if (type==type_attr::multiple_file) multifile=true ;
255
256         } 
257#ifndef USING_NETCDF_PAR
258         if (!multifile)
259         {
260            info(0)<<"!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : "<<filename<<" ..."<<endl ;
261            multifile=true ;
262          }
263#endif
264         if (multifile) 
265         {
266            int commSize, commRank ;
267            MPI_Comm_size(fileComm,&commSize) ;
268            MPI_Comm_rank(fileComm,&commRank) ;
269           
270            if (server->intraCommSize > 1) 
271            {
272              oss << "_"  ;
273              int width=0 ; int n=commSize-1 ;
274              while(n != 0) { n=n/10 ; width++ ;}
275              if (!min_digits.isEmpty()) 
276                if (width<min_digits) width=min_digits ;
277              oss.width(width) ;
278              oss.fill('0') ;
279              oss<<right<< commRank;
280            }
281         }
282         oss << ".nc";
283
284         if (isOpen) data_out->closeFile() ;
285         bool isCollective=true ;
286         if (!par_access.isEmpty())
287         {
288           if (par_access.getValue()=="independent") isCollective=false ;
289           else if (par_access.getValue()=="collective") isCollective=true ;
290           else 
291           {
292             ERROR("void Context::createDataOutput(void)",
293                        "incorrect file <par_access> attribut : must be <collective> or <indepedent>, "
294                        <<"having : <"<<type.getValue()<<">") ;
295           }
296         }
297         data_out=shared_ptr<CDataOutput>(new CNc4DataOutput(oss.str(), false, fileComm, multifile, isCollective));
298         isOpen=true ;
299
300         data_out->writeFile(CFile::get(this));
301         std::vector<CField*>::iterator it, end = this->enabledFields.end();
302         for (it = this->enabledFields.begin() ;it != end; it++)
303         {
304            CField* field = *it;
305            this->data_out->writeFieldGrid(field);
306         }
307         this->data_out->writeTimeDimension();
308         
309         for (it = this->enabledFields.begin() ;it != end; it++)
310         {
311            CField* field = *it;
312            this->data_out->writeField(field);
313         }
314         
315         this->data_out->definition_end();
316      }
317   }
318
319   void CFile::close(void)
320   {
321     delete lastSync ;
322     delete lastSplit ;
323     if (!allDomainEmpty)
324       if (isOpen) 
325       {
326         this->data_out->closeFile();
327       }
328      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm) ;
329   }
330   //----------------------------------------------------------------
331
332   void CFile::parse(xml::CXMLNode & node)
333   {
334      SuperClass::parse(node);
335      if (node.goToChildElement() & this->hasId())
336      { // Si la définition du fichier intégre des champs et si le fichier est identifié.
337         node.goToParentElement();
338//         this->setVirtualFieldGroup(this->getId());
339         this->getVirtualFieldGroup()->parse(node, false);
340      }
341   }
342   //----------------------------------------------------------------
343
344   StdString CFile::toString(void) const
345   {
346      StdOStringStream oss;
347
348      oss << "<" << CFile::GetName() << " ";
349      if (this->hasId())
350         oss << " id=\"" << this->getId() << "\" ";
351      oss << SuperClassAttribute::toString() << ">" << std::endl;
352      if (this->getVirtualFieldGroup() != NULL)
353         oss << *this->getVirtualFieldGroup() << std::endl;
354      oss << "</" << CFile::GetName() << " >";
355      return (oss.str());
356   }
357
358   //----------------------------------------------------------------
359   
360   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
361   {
362      SuperClassAttribute::setAttributes(parent,apply);
363      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL);
364   }
365
366   //----------------------------------------------------------------
367
368   void CFile::processEnabledFile(void)
369   {
370     if (output_freq.isEmpty()) ERROR("void CFile::processEnabledFile(void)",
371                                       <<"File attribute <<output_freq>> is undefined"); 
372     solveFieldRefInheritance(true) ;
373     getEnabledFields() ;
374     processEnabledFields() ;
375   }
376   
377   void CFile::processEnabledFields(void)
378   {
379      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
380      {
381        this->enabledFields[i]->processEnabledField() ;
382      }
383    }
384   
385   void CFile::solveFieldRefInheritance(bool apply)
386   {
387      // Résolution des héritages par référence de chacun des champs contenus dans le fichier.
388      std::vector<CField*> allF = this->getAllFields();
389      for (unsigned int i = 0; i < allF.size(); i++)
390         allF[i]->solveRefInheritance(apply);
391   }
392
393   //----------------------------------------------------------------
394
395   void CFile::solveEFGridRef(void)
396   {
397      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
398         this->enabledFields[i]->solveGridReference();
399   }
400
401   //----------------------------------------------------------------
402
403   void CFile::solveEFOperation(void)
404   {
405      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
406         this->enabledFields[i]->solveOperation();
407   }
408 
409   void CFile::solveEFExpression(void)
410   {
411      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
412         this->enabledFields[i]->buildExpression();
413   }   
414 
415
416   CField* CFile::addField(const string& id)
417   {
418     return vFieldGroup->createChild(id) ;
419   }
420
421   CFieldGroup* CFile::addFieldGroup(const string& id)
422   {
423     return vFieldGroup->createChildGroup(id) ;
424   }
425   
426 
427   void CFile::sendAddField(const string& id)
428   {
429    CContext* context=CContext::getCurrent() ;
430   
431    if (! context->hasServer )
432    {
433       CContextClient* client=context->client ;
434
435       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD) ;   
436       if (client->isServerLeader())
437       {
438         CMessage msg ;
439         msg<<this->getId() ;
440         msg<<id ;
441         event.push(client->getServerLeader(),1,msg) ;
442         client->sendEvent(event) ;
443       }
444       else client->sendEvent(event) ;
445    }
446     
447   }
448   
449   void CFile::sendAddFieldGroup(const string& id)
450   {
451    CContext* context=CContext::getCurrent() ;
452    if (! context->hasServer )
453    {
454       CContextClient* client=context->client ;
455
456       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP) ;   
457       if (client->isServerLeader())
458       {
459         CMessage msg ;
460         msg<<this->getId() ;
461         msg<<id ;
462         event.push(client->getServerLeader(),1,msg) ;
463         client->sendEvent(event) ;
464       }
465       else client->sendEvent(event) ;
466    }
467     
468   }
469   
470   void CFile::recvAddField(CEventServer& event)
471   {
472     
473      CBufferIn* buffer=event.subEvents.begin()->buffer;
474      string id;
475      *buffer>>id ;
476      get(id)->recvAddField(*buffer) ;
477   }
478   
479   
480   void CFile::recvAddField(CBufferIn& buffer)
481   {
482      string id ;
483      buffer>>id ;
484      addField(id) ;
485   }
486
487   void CFile::recvAddFieldGroup(CEventServer& event)
488   {
489     
490      CBufferIn* buffer=event.subEvents.begin()->buffer;
491      string id;
492      *buffer>>id ;
493      get(id)->recvAddFieldGroup(*buffer) ;
494   }
495   
496   
497   void CFile::recvAddFieldGroup(CBufferIn& buffer)
498   {
499      string id ;
500      buffer>>id ;
501      addFieldGroup(id) ;
502   }
503   
504
505   bool CFile::dispatchEvent(CEventServer& event)
506   {
507      if (SuperClass::dispatchEvent(event)) return true ;
508      else
509      {
510        switch(event.type)
511        {
512           case EVENT_ID_ADD_FIELD :
513             recvAddField(event) ;
514             return true ;
515             break ;
516         
517           case EVENT_ID_ADD_FIELD_GROUP :
518             recvAddFieldGroup(event) ;
519             return true ;
520             break ;       
521         
522           default :
523              ERROR("bool CFile::dispatchEvent(CEventServer& event)", <<"Unknown Event") ;
524           return false ;
525        }
526      }
527   }
528   
529   
530   
531   
532   ///---------------------------------------------------------------
533
534} // namespace xios
Note: See TracBrowser for help on using the repository browser.