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

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

-Add min_digits attribute
-Add global attribute to be compatible with IOIPSL rebuild

YM

File size: 15.7 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 (*lastSplit+splitFreq < currentDate)
210        {
211          *lastSplit=currentDate-outputFreq ;
212       
213          std::vector<CField*>::iterator it, end = this->enabledFields.end();
214          for (it = this->enabledFields.begin() ;it != end; it++)  (*it)->resetNStep() ;
215          createHeader() ;
216          return true ;
217        }
218      }
219      return false ;
220    }
221   
222   void CFile::createHeader(void)
223   {
224      CContext* context = CContext::getCurrent() ;
225      CContextServer* server=context->server ;
226     
227      if (!allDomainEmpty)
228      {
229         StdString filename = (!name.isEmpty()) ?   name.getValue() : getId();
230         StdOStringStream oss;
231         oss << filename;
232         if (!name_suffix.isEmpty()) oss << name_suffix.getValue();
233         if (!split_freq.isEmpty()) oss<<"_"<<lastSplit->getStryyyymmdd()<<"-"<< (*lastSplit+(splitFreq-1*Second)).getStryyyymmdd();
234         bool multifile=true ;
235         if (!type.isEmpty())
236         {
237           if (type==type_attr::one_file) multifile=false ;
238           else if (type==type_attr::multiple_file) multifile=true ;
239
240         } 
241#ifndef USING_NETCDF_PAR
242         if (!multifile)
243         {
244            info(0)<<"!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : "<<filename<<" ..."<<endl ;
245            multifile=true ;
246          }
247#endif
248         if (multifile) 
249         {
250            int commSize, commRank ;
251            MPI_Comm_size(fileComm,&commSize) ;
252            MPI_Comm_rank(fileComm,&commRank) ;
253           
254            if (server->intraCommSize > 1) 
255            {
256              oss << "_"  ;
257              int width=0 ; int n=commSize-1 ;
258              while(n != 0) { n=n/10 ; width++ ;}
259              if (!min_digits.isEmpty()) 
260                if (width<min_digits) width=min_digits ;
261              oss.width(width) ;
262              oss.fill('0') ;
263              oss<<right<< commRank;
264            }
265         }
266         oss << ".nc";
267
268         if (isOpen) data_out->closeFile() ;
269         bool isCollective=true ;
270         if (!par_access.isEmpty())
271         {
272           if (par_access.getValue()=="independent") isCollective=false ;
273           else if (par_access.getValue()=="collective") isCollective=true ;
274           else 
275           {
276             ERROR("void Context::createDataOutput(void)",
277                        "incorrect file <par_access> attribut : must be <collective> or <indepedent>, "
278                        <<"having : <"<<type.getValue()<<">") ;
279           }
280         }
281         data_out=shared_ptr<CDataOutput>(new CNc4DataOutput(oss.str(), false, fileComm, multifile, isCollective));
282         isOpen=true ;
283
284         data_out->writeFile(CFile::get(this));
285         std::vector<CField*>::iterator it, end = this->enabledFields.end();
286         for (it = this->enabledFields.begin() ;it != end; it++)
287         {
288            CField* field = *it;
289            this->data_out->writeFieldGrid(field);
290         }
291         this->data_out->writeTimeDimension();
292         
293         for (it = this->enabledFields.begin() ;it != end; it++)
294         {
295            CField* field = *it;
296            this->data_out->writeField(field);
297         }
298         
299         this->data_out->definition_end();
300      }
301   }
302
303   void CFile::close(void)
304   {
305     delete lastSync ;
306     delete lastSplit ;
307     if (!allDomainEmpty)
308       if (isOpen) 
309       {
310         this->data_out->closeFile();
311       }
312      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm) ;
313   }
314   //----------------------------------------------------------------
315
316   void CFile::parse(xml::CXMLNode & node)
317   {
318      SuperClass::parse(node);
319      if (node.goToChildElement() & this->hasId())
320      { // Si la définition du fichier intégre des champs et si le fichier est identifié.
321         node.goToParentElement();
322//         this->setVirtualFieldGroup(this->getId());
323         this->getVirtualFieldGroup()->parse(node, false);
324      }
325   }
326   //----------------------------------------------------------------
327
328   StdString CFile::toString(void) const
329   {
330      StdOStringStream oss;
331
332      oss << "<" << CFile::GetName() << " ";
333      if (this->hasId())
334         oss << " id=\"" << this->getId() << "\" ";
335      oss << SuperClassAttribute::toString() << ">" << std::endl;
336      if (this->getVirtualFieldGroup() != NULL)
337         oss << *this->getVirtualFieldGroup() << std::endl;
338      oss << "</" << CFile::GetName() << " >";
339      return (oss.str());
340   }
341
342   //----------------------------------------------------------------
343   
344   void CFile::solveDescInheritance(const CAttributeMap * const parent)
345   {
346      SuperClassAttribute::setAttributes(parent);
347      this->getVirtualFieldGroup()->solveDescInheritance(NULL);
348   }
349
350   //----------------------------------------------------------------
351
352   void CFile::solveFieldRefInheritance(void)
353   {
354      // Résolution des héritages par référence de chacun des champs contenus dans le fichier.
355      std::vector<CField*> allF = this->getAllFields();
356      for (unsigned int i = 0; i < allF.size(); i++)
357         allF[i]->solveRefInheritance();
358   }
359
360   //----------------------------------------------------------------
361
362   void CFile::solveEFGridRef(void)
363   {
364      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
365         this->enabledFields[i]->solveGridReference();
366   }
367
368   //----------------------------------------------------------------
369
370   void CFile::solveEFOperation(void)
371   {
372      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
373         this->enabledFields[i]->solveOperation();
374   }
375   
376   //---------------------------------------------------------------
377/*
378   void CFile::toBinary  (StdOStream & os) const
379   {
380      ENodeType genum = CFileGroup::GetType();
381      bool hasVFG = (this->getVirtualFieldGroup() != NULL);
382      SuperClass::toBinary(os);
383     
384      os.write (reinterpret_cast<const char*>(&genum) , sizeof(ENodeType));
385      os.write (reinterpret_cast<const char*>(&hasVFG) , sizeof(bool));
386     
387      if (hasVFG)this->getVirtualFieldGroup()->toBinary(os);
388         
389   }
390   
391   //----------------------------------------------------------------
392   
393   void CFile::fromBinary(StdIStream & is)
394   {
395      ENodeType renum = Unknown;
396      bool hasVFG = false;
397      SuperClass::fromBinary(is);
398     
399      is.read (reinterpret_cast<char*>(&renum), sizeof(ENodeType));
400      is.read (reinterpret_cast<char*>(&hasVFG), sizeof(bool));
401     
402      if (renum != CFileGroup::GetType())
403         ERROR("CFile::fromBinary(StdIStream & is)",
404               << "[ renum = " << renum << "] Bad type !");
405     
406//      this->setVirtualFieldGroup(this->getId());
407      if (hasVFG)this->getVirtualFieldGroup()->fromBinary(is);
408     
409   }
410*/
411
412   CField* CFile::addField(const string& id)
413   {
414     return vFieldGroup->createChild(id) ;
415   }
416
417   CFieldGroup* CFile::addFieldGroup(const string& id)
418   {
419     return vFieldGroup->createChildGroup(id) ;
420   }
421   
422 
423   void CFile::sendAddField(const string& id)
424   {
425    CContext* context=CContext::getCurrent() ;
426   
427    if (! context->hasServer )
428    {
429       CContextClient* client=context->client ;
430
431       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD) ;   
432       if (client->isServerLeader())
433       {
434         CMessage msg ;
435         msg<<this->getId() ;
436         msg<<id ;
437         event.push(client->getServerLeader(),1,msg) ;
438         client->sendEvent(event) ;
439       }
440       else client->sendEvent(event) ;
441    }
442     
443   }
444   
445   void CFile::sendAddFieldGroup(const string& id)
446   {
447    CContext* context=CContext::getCurrent() ;
448    if (! context->hasServer )
449    {
450       CContextClient* client=context->client ;
451
452       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP) ;   
453       if (client->isServerLeader())
454       {
455         CMessage msg ;
456         msg<<this->getId() ;
457         msg<<id ;
458         event.push(client->getServerLeader(),1,msg) ;
459         client->sendEvent(event) ;
460       }
461       else client->sendEvent(event) ;
462    }
463     
464   }
465   
466   void CFile::recvAddField(CEventServer& event)
467   {
468     
469      CBufferIn* buffer=event.subEvents.begin()->buffer;
470      string id;
471      *buffer>>id ;
472      get(id)->recvAddField(*buffer) ;
473   }
474   
475   
476   void CFile::recvAddField(CBufferIn& buffer)
477   {
478      string id ;
479      buffer>>id ;
480      addField(id) ;
481   }
482
483   void CFile::recvAddFieldGroup(CEventServer& event)
484   {
485     
486      CBufferIn* buffer=event.subEvents.begin()->buffer;
487      string id;
488      *buffer>>id ;
489      get(id)->recvAddFieldGroup(*buffer) ;
490   }
491   
492   
493   void CFile::recvAddFieldGroup(CBufferIn& buffer)
494   {
495      string id ;
496      buffer>>id ;
497      addFieldGroup(id) ;
498   }
499   
500
501   bool CFile::dispatchEvent(CEventServer& event)
502   {
503      if (SuperClass::dispatchEvent(event)) return true ;
504      else
505      {
506        switch(event.type)
507        {
508           case EVENT_ID_ADD_FIELD :
509             recvAddField(event) ;
510             return true ;
511             break ;
512         
513           case EVENT_ID_ADD_FIELD_GROUP :
514             recvAddFieldGroup(event) ;
515             return true ;
516             break ;       
517         
518           default :
519              ERROR("bool CFile::dispatchEvent(CEventServer& event)", <<"Unknown Event") ;
520           return false ;
521        }
522      }
523   }
524   
525   
526   
527   
528   ///---------------------------------------------------------------
529
530} // namespace xios
Note: See TracBrowser for help on using the repository browser.