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

Last change on this file since 382 was 382, checked in by ymipsl, 12 years ago

embed MPI header to avoid some porting problem

YM

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