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

Last change on this file since 431 was 431, checked in by ymipsl, 9 years ago

Bug fix : Solve problem in splitting date
Enhancement : Add file attribute split_freq_format to manage the suffix added in splitted file

File size: 16.5 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(const CAttributeMap * const parent)
361   {
362      SuperClassAttribute::setAttributes(parent);
363      this->getVirtualFieldGroup()->solveDescInheritance(NULL);
364   }
365
366   //----------------------------------------------------------------
367
368   void CFile::solveFieldRefInheritance(void)
369   {
370      // Résolution des héritages par référence de chacun des champs contenus dans le fichier.
371      std::vector<CField*> allF = this->getAllFields();
372      for (unsigned int i = 0; i < allF.size(); i++)
373         allF[i]->solveRefInheritance();
374   }
375
376   //----------------------------------------------------------------
377
378   void CFile::solveEFGridRef(void)
379   {
380      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
381         this->enabledFields[i]->solveGridReference();
382   }
383
384   //----------------------------------------------------------------
385
386   void CFile::solveEFOperation(void)
387   {
388      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
389         this->enabledFields[i]->solveOperation();
390   }
391   
392   //---------------------------------------------------------------
393/*
394   void CFile::toBinary  (StdOStream & os) const
395   {
396      ENodeType genum = CFileGroup::GetType();
397      bool hasVFG = (this->getVirtualFieldGroup() != NULL);
398      SuperClass::toBinary(os);
399     
400      os.write (reinterpret_cast<const char*>(&genum) , sizeof(ENodeType));
401      os.write (reinterpret_cast<const char*>(&hasVFG) , sizeof(bool));
402     
403      if (hasVFG)this->getVirtualFieldGroup()->toBinary(os);
404         
405   }
406   
407   //----------------------------------------------------------------
408   
409   void CFile::fromBinary(StdIStream & is)
410   {
411      ENodeType renum = Unknown;
412      bool hasVFG = false;
413      SuperClass::fromBinary(is);
414     
415      is.read (reinterpret_cast<char*>(&renum), sizeof(ENodeType));
416      is.read (reinterpret_cast<char*>(&hasVFG), sizeof(bool));
417     
418      if (renum != CFileGroup::GetType())
419         ERROR("CFile::fromBinary(StdIStream & is)",
420               << "[ renum = " << renum << "] Bad type !");
421     
422//      this->setVirtualFieldGroup(this->getId());
423      if (hasVFG)this->getVirtualFieldGroup()->fromBinary(is);
424     
425   }
426*/
427
428   CField* CFile::addField(const string& id)
429   {
430     return vFieldGroup->createChild(id) ;
431   }
432
433   CFieldGroup* CFile::addFieldGroup(const string& id)
434   {
435     return vFieldGroup->createChildGroup(id) ;
436   }
437   
438 
439   void CFile::sendAddField(const string& id)
440   {
441    CContext* context=CContext::getCurrent() ;
442   
443    if (! context->hasServer )
444    {
445       CContextClient* client=context->client ;
446
447       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD) ;   
448       if (client->isServerLeader())
449       {
450         CMessage msg ;
451         msg<<this->getId() ;
452         msg<<id ;
453         event.push(client->getServerLeader(),1,msg) ;
454         client->sendEvent(event) ;
455       }
456       else client->sendEvent(event) ;
457    }
458     
459   }
460   
461   void CFile::sendAddFieldGroup(const string& id)
462   {
463    CContext* context=CContext::getCurrent() ;
464    if (! context->hasServer )
465    {
466       CContextClient* client=context->client ;
467
468       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP) ;   
469       if (client->isServerLeader())
470       {
471         CMessage msg ;
472         msg<<this->getId() ;
473         msg<<id ;
474         event.push(client->getServerLeader(),1,msg) ;
475         client->sendEvent(event) ;
476       }
477       else client->sendEvent(event) ;
478    }
479     
480   }
481   
482   void CFile::recvAddField(CEventServer& event)
483   {
484     
485      CBufferIn* buffer=event.subEvents.begin()->buffer;
486      string id;
487      *buffer>>id ;
488      get(id)->recvAddField(*buffer) ;
489   }
490   
491   
492   void CFile::recvAddField(CBufferIn& buffer)
493   {
494      string id ;
495      buffer>>id ;
496      addField(id) ;
497   }
498
499   void CFile::recvAddFieldGroup(CEventServer& event)
500   {
501     
502      CBufferIn* buffer=event.subEvents.begin()->buffer;
503      string id;
504      *buffer>>id ;
505      get(id)->recvAddFieldGroup(*buffer) ;
506   }
507   
508   
509   void CFile::recvAddFieldGroup(CBufferIn& buffer)
510   {
511      string id ;
512      buffer>>id ;
513      addFieldGroup(id) ;
514   }
515   
516
517   bool CFile::dispatchEvent(CEventServer& event)
518   {
519      if (SuperClass::dispatchEvent(event)) return true ;
520      else
521      {
522        switch(event.type)
523        {
524           case EVENT_ID_ADD_FIELD :
525             recvAddField(event) ;
526             return true ;
527             break ;
528         
529           case EVENT_ID_ADD_FIELD_GROUP :
530             recvAddFieldGroup(event) ;
531             return true ;
532             break ;       
533         
534           default :
535              ERROR("bool CFile::dispatchEvent(CEventServer& event)", <<"Unknown Event") ;
536           return false ;
537        }
538      }
539   }
540   
541   
542   
543   
544   ///---------------------------------------------------------------
545
546} // namespace xios
Note: See TracBrowser for help on using the repository browser.