source: XIOS/branchs/xios-1.0/src/node/file.cpp @ 798

Last change on this file since 798 was 798, checked in by rlacroix, 8 years ago

Append mode

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
File size: 19.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   { 
27     setVirtualFieldGroup() ;
28     setVirtualVariableGroup() ;
29   }
30
31   CFile::CFile(const StdString & id)
32      : CObjectTemplate<CFile>(id), CFileAttributes()
33      , vFieldGroup(), data_out(), enabledFields(), fileComm(MPI_COMM_NULL)
34    { 
35      setVirtualFieldGroup() ;
36      setVirtualVariableGroup() ;
37    }
38
39   CFile::~CFile(void)
40   { /* Ne rien faire de plus */ }
41
42   ///---------------------------------------------------------------
43
44   StdString CFile::GetName(void)   { return (StdString("file")); }
45   StdString CFile::GetDefName(void){ return (CFile::GetName()); }
46   ENodeType CFile::GetType(void)   { return (eFile); }
47
48   //----------------------------------------------------------------
49
50   boost::shared_ptr<CDataOutput> CFile::getDataOutput(void) const
51   {
52      return (data_out);
53   }
54
55   CFieldGroup* CFile::getVirtualFieldGroup(void) const
56   {
57      return (this->vFieldGroup);
58   }
59
60   CVariableGroup* CFile::getVirtualVariableGroup(void) const
61   {
62      return (this->vVariableGroup);
63   }
64
65   std::vector<CField*> CFile::getAllFields(void) const
66   {
67      return (this->vFieldGroup->getAllChildren());
68   }
69 
70   std::vector<CVariable*> CFile::getAllVariables(void) const
71   {
72      return (this->vVariableGroup->getAllChildren());
73   }
74
75   //----------------------------------------------------------------
76
77   std::vector<CField*> CFile::getEnabledFields(int default_outputlevel, 
78                                                int default_level,
79                                                bool default_enabled)
80   {
81      if (!this->enabledFields.empty())
82         return (this->enabledFields);
83
84      const int _outputlevel =
85         (!output_level.isEmpty()) ? output_level.getValue() : default_outputlevel;
86      std::vector<CField*>::iterator it;
87      this->enabledFields = this->getAllFields();
88
89      std::vector<CField*> newEnabledFields;
90     
91      for ( it = this->enabledFields.begin() ; it != this->enabledFields.end(); it++ )
92      {
93         if (!(*it)->enabled.isEmpty()) // Si l'attribut 'enabled' est défini ...
94         {
95            if (! (*it)->enabled.getValue()) continue;
96//            { it--; this->enabledFields.erase(it+1); continue; }
97         }
98         else // Si l'attribut 'enabled' n'est pas défini ...
99         {
100            if (!default_enabled) continue ;
101//            { it--; this->enabledFields.erase(it+1); continue; }
102         }
103
104         if (!(*it)->level.isEmpty()) // Si l'attribut 'level' est défini ...
105         {
106            if ((*it)->level.getValue() > _outputlevel) continue ;
107//            { it--; this->enabledFields.erase(it+1); continue; }
108         }
109         else // Si l'attribut 'level' n'est pas défini ...
110         {
111            if (default_level > _outputlevel) continue ;
112//            { it--; this->enabledFields.erase(it+1); continue; }
113         }
114 
115//         CField* field_tmp=(*it).get() ;
116//         shared_ptr<CField> sptfield=*it ;
117//         field_tmp->refObject.push_back(sptfield) ;
118         newEnabledFields.push_back(*it) ;
119         // Le champ est finalement actif, on y ajoute sa propre reference.
120//         (*it)->refObject.push_back(*it);
121         // Le champ est finalement actif, on y ajoute la référence au champ de base.
122         (*it)->setRelFile(CFile::get(this));
123//         (*it)->baseRefObject->refObject.push_back(*it);
124         // A faire, ajouter les references intermediaires...
125      }
126      enabledFields=newEnabledFields ;
127
128      return (this->enabledFields);
129   }
130
131   //----------------------------------------------------------------
132
133   void CFile::setVirtualFieldGroup(CFieldGroup* newVFieldGroup)
134   { 
135      this->vFieldGroup = newVFieldGroup; 
136   }
137
138   void CFile::setVirtualVariableGroup(CVariableGroup* newVVariableGroup)
139   { 
140      this->vVariableGroup = newVVariableGroup; 
141   }
142
143   //----------------------------------------------------------------
144
145   void CFile::setVirtualFieldGroup(void)
146   {
147      this->setVirtualFieldGroup(CFieldGroup::create());
148   }
149
150   void CFile::setVirtualVariableGroup(void)
151   {
152      this->setVirtualVariableGroup(CVariableGroup::create());
153   }
154
155   //----------------------------------------------------------------
156   bool CFile::isSyncTime(void)
157   {
158     CContext* context = CContext::getCurrent() ;
159     CDate& currentDate=context->calendar->getCurrentDate() ;
160     if (! sync_freq.isEmpty())
161     {
162       if (*lastSync+syncFreq < currentDate)
163       {
164         *lastSync=currentDate ;
165         return true ;
166        }
167      }
168      return false ;
169    }
170   
171   void CFile::initFile(void)
172   {
173      CContext* context = CContext::getCurrent() ;
174      CDate& currentDate=context->calendar->getCurrentDate() ;
175      CContextServer* server=context->server ;
176           
177      if (! sync_freq.isEmpty()) syncFreq = CDuration::FromString(sync_freq.getValue());
178      if (! split_freq.isEmpty()) splitFreq = CDuration::FromString(split_freq.getValue());
179      if (! output_freq.isEmpty()) outputFreq = CDuration::FromString(output_freq.getValue());
180      lastSync=new CDate(currentDate) ;
181      lastSplit=new CDate(currentDate) ;
182      isOpen=false ;
183
184      allDomainEmpty=true ;
185      set<CAxis*> setAxis;
186      set<CDomain*> setDomains;
187
188      std::vector<CField*>::iterator it, end = this->enabledFields.end();
189      for (it = this->enabledFields.begin(); it != end; it++)
190      {
191         CField* field = *it;
192         allDomainEmpty&=field->grid->domain->isEmpty();
193         setAxis.insert(field->grid->axis);
194         setDomains.insert(field->grid->domain);
195      }
196      nbAxis = setAxis.size();
197      nbDomains = setDomains.size();
198
199      // create sub communicator for file 
200      int color=allDomainEmpty?0:1 ;
201      MPI_Comm_split(server->intraComm,color,server->intraCommRank,&fileComm) ;
202      if (allDomainEmpty) MPI_Comm_free(&fileComm) ;
203
204      if (time_counter.isEmpty()) time_counter.setValue(time_counter_attr::centered);
205    }
206   
207    void CFile::checkFile(void)
208    {
209      if (!isOpen) createHeader() ;
210      checkSync() ;
211      checkSplit() ;
212    }
213     
214     
215   bool CFile::checkSync(void)
216   {
217     CContext* context = CContext::getCurrent() ;
218     CDate& currentDate=context->calendar->getCurrentDate() ;
219     if (! sync_freq.isEmpty())
220     {
221       if (*lastSync+syncFreq <= currentDate)
222       {
223         *lastSync=currentDate ;
224         data_out->syncFile() ;
225         return true ;
226        }
227      }
228      return false ;
229    }
230   
231   
232    bool CFile::checkSplit(void)
233    {
234      CContext* context = CContext::getCurrent() ;
235      CDate& currentDate=context->calendar->getCurrentDate() ;
236      if (! split_freq.isEmpty())
237      {
238        if (currentDate > *lastSplit+splitFreq)
239        {
240          *lastSplit=*lastSplit+splitFreq ;   
241          std::vector<CField*>::iterator it, end = this->enabledFields.end();
242          for (it = this->enabledFields.begin() ;it != end; it++)  (*it)->resetNStep() ;
243          createHeader() ;
244          return true ;
245        }
246      }
247      return false ;
248    }
249   
250   void CFile::createHeader(void)
251   {
252      CContext* context = CContext::getCurrent() ;
253      CContextServer* server=context->server ;
254     
255      if (!allDomainEmpty)
256      {
257         StdString filename = (!name.isEmpty()) ?   name.getValue() : getId();
258         StdOStringStream oss;
259         oss << filename;
260         if (!name_suffix.isEmpty()) oss << name_suffix.getValue();
261//         if (!split_freq.isEmpty()) oss<<"_"<<lastSplit->getStryyyymmdd()<<"-"<< (*lastSplit+(splitFreq-1*Second)).getStryyyymmdd();
262//         if (!split_freq.isEmpty()) oss<<"_"<<lastSplit->getStr("%y_%mo_%d")<<"-"<< (*lastSplit+(splitFreq-1*Second)).getStr("%y_%mo_%d");
263         if (!split_freq.isEmpty())
264         {
265           string splitFormat ;
266           if (split_freq_format.isEmpty())
267           {
268             if (splitFreq.second!=0) splitFormat="%y%mo%d%h%mi%s";
269             else if (splitFreq.minute!=0) splitFormat="%y%mo%d%h%mi";
270             else if (splitFreq.hour!=0) splitFormat="%y%mo%d%h";
271             else if (splitFreq.day!=0) splitFormat="%y%mo%d";
272             else if (splitFreq.month!=0) splitFormat="%y%mo";
273             else splitFormat="%y";
274           }
275           else splitFormat=split_freq_format ;
276           oss<<"_"<<lastSplit->getStr(splitFormat)<<"-"<< (*lastSplit + splitFreq - 1 * Second).getStr(splitFormat);
277         }
278           
279         bool multifile=true ;
280         if (!type.isEmpty())
281         {
282           if (type==type_attr::one_file) multifile=false ;
283           else if (type==type_attr::multiple_file) multifile=true ;
284
285         } 
286#ifndef USING_NETCDF_PAR
287         if (!multifile)
288         {
289            info(0)<<"!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : "<<filename<<" ..."<<endl ;
290            multifile=true ;
291          }
292#endif
293         if (multifile) 
294         {
295            int commSize, commRank ;
296            MPI_Comm_size(fileComm,&commSize) ;
297            MPI_Comm_rank(fileComm,&commRank) ;
298           
299            if (server->intraCommSize > 1) 
300            {
301              oss << "_"  ;
302              int width=0 ; int n=commSize-1 ;
303              while(n != 0) { n=n/10 ; width++ ;}
304              if (!min_digits.isEmpty()) 
305                if (width<min_digits) width=min_digits ;
306              oss.width(width) ;
307              oss.fill('0') ;
308              oss<<right<< commRank;
309            }
310         }
311         oss << ".nc";
312
313        bool append = !this->append.isEmpty() && this->append.getValue();
314
315         if (isOpen) data_out->closeFile() ;
316         bool isCollective=true ;
317         if (!par_access.isEmpty())
318         {
319           if (par_access.getValue()=="independent") isCollective=false ;
320           else if (par_access.getValue()=="collective") isCollective=true ;
321           else 
322           {
323             ERROR("void Context::createDataOutput(void)",
324                        "incorrect file <par_access> attribut : must be <collective> or <indepedent>, "
325                        <<"having : <"<<type.getValue()<<">") ;
326           }
327         }
328        data_out = shared_ptr<CDataOutput>(new CNc4DataOutput(oss.str(), append, fileComm, multifile, isCollective));
329        isOpen = true;
330
331        data_out->writeFile(CFile::get(this));
332
333        // Do not recreate the file structure if opening an existing file
334        if (!data_out->IsInAppendMode())
335        {
336          std::vector<CField*>::iterator it, end = this->enabledFields.end();
337          for (it = this->enabledFields.begin(); it != end; it++)
338          {
339            CField* field = *it;
340            this->data_out->writeFieldGrid(field);
341          }
342          this->data_out->writeTimeDimension();
343
344          for (it = this->enabledFields.begin(); it != end; it++)
345          {
346            CField* field = *it;
347            this->data_out->writeField(field);
348          }
349
350          vector<CVariable*> listVars = getAllVariables() ;
351          for (vector<CVariable*>::iterator it = listVars.begin(); it != listVars.end(); it++)
352            this->data_out->writeAttribute(*it);
353
354          this->data_out->definition_end();
355        }
356      }
357   }
358
359   void CFile::close(void)
360   {
361     delete lastSync ;
362     delete lastSplit ;
363     if (!allDomainEmpty)
364       if (isOpen) 
365       {
366         this->data_out->closeFile();
367       }
368      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm) ;
369   }
370   //----------------------------------------------------------------
371
372   void CFile::parse(xml::CXMLNode & node)
373   {
374      SuperClass::parse(node);
375     
376      if (node.goToChildElement())
377      {
378        do
379        {
380           if (node.getElementName()=="field" || node.getElementName()=="field_group") this->getVirtualFieldGroup()->parseChild(node);
381           else if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node);
382        } while (node.goToNextElement()) ;
383        node.goToParentElement();
384      }
385
386   }
387   //----------------------------------------------------------------
388
389   StdString CFile::toString(void) const
390   {
391      StdOStringStream oss;
392
393      oss << "<" << CFile::GetName() << " ";
394      if (this->hasId())
395         oss << " id=\"" << this->getId() << "\" ";
396      oss << SuperClassAttribute::toString() << ">" << std::endl;
397      if (this->getVirtualFieldGroup() != NULL)
398         oss << *this->getVirtualFieldGroup() << std::endl;
399      oss << "</" << CFile::GetName() << " >";
400      return (oss.str());
401   }
402
403   //----------------------------------------------------------------
404   
405   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
406   {
407      SuperClassAttribute::setAttributes(parent,apply);
408      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL); 
409      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
410   }
411
412   //----------------------------------------------------------------
413
414   void CFile::processEnabledFile(void)
415   {
416     if (output_freq.isEmpty()) ERROR("void CFile::processEnabledFile(void)",
417                                       <<"File attribute <<output_freq>> is undefined"); 
418     solveFieldRefInheritance(true) ;
419     getEnabledFields() ;
420     processEnabledFields() ;
421   }
422   
423   void CFile::processEnabledFields(void)
424   {
425      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
426      {
427        this->enabledFields[i]->processEnabledField() ;
428      }
429    }
430   
431   void CFile::solveFieldRefInheritance(bool apply)
432   {
433      // Résolution des héritages par référence de chacun des champs contenus dans le fichier.
434      std::vector<CField*> allF = this->getAllFields();
435      for (unsigned int i = 0; i < allF.size(); i++)
436         allF[i]->solveRefInheritance(apply);
437   }
438
439   //----------------------------------------------------------------
440
441   void CFile::solveEFGridRef(void)
442   {
443      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
444         this->enabledFields[i]->solveGridReference();
445   }
446
447   //----------------------------------------------------------------
448
449   void CFile::solveEFOperation(void)
450   {
451      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
452         this->enabledFields[i]->solveOperation();
453   }
454 
455   void CFile::solveEFExpression(void)
456   {
457      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
458         this->enabledFields[i]->buildExpression();
459   }   
460 
461
462   CField* CFile::addField(const string& id)
463   {
464     return vFieldGroup->createChild(id) ;
465   }
466
467   CFieldGroup* CFile::addFieldGroup(const string& id)
468   {
469     return vFieldGroup->createChildGroup(id) ;
470   }
471 
472   CVariable* CFile::addVariable(const string& id)
473   {
474     return vVariableGroup->createChild(id) ;
475   }
476
477   CVariableGroup* CFile::addVariableGroup(const string& id)
478   {
479     return vVariableGroup->createChildGroup(id) ;
480   }
481   
482 
483   void CFile::sendAddField(const string& id)
484   {
485    CContext* context=CContext::getCurrent() ;
486   
487    if (! context->hasServer )
488    {
489       CContextClient* client=context->client ;
490
491       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD) ;   
492       if (client->isServerLeader())
493       {
494         CMessage msg ;
495         msg<<this->getId() ;
496         msg<<id ;
497         event.push(client->getServerLeader(),1,msg) ;
498         client->sendEvent(event) ;
499       }
500       else client->sendEvent(event) ;
501    }
502     
503   }
504   
505   void CFile::sendAddFieldGroup(const string& id)
506   {
507    CContext* context=CContext::getCurrent() ;
508    if (! context->hasServer )
509    {
510       CContextClient* client=context->client ;
511
512       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP) ;   
513       if (client->isServerLeader())
514       {
515         CMessage msg ;
516         msg<<this->getId() ;
517         msg<<id ;
518         event.push(client->getServerLeader(),1,msg) ;
519         client->sendEvent(event) ;
520       }
521       else client->sendEvent(event) ;
522    }
523     
524   }
525   
526   void CFile::recvAddField(CEventServer& event)
527   {
528     
529      CBufferIn* buffer=event.subEvents.begin()->buffer;
530      string id;
531      *buffer>>id ;
532      get(id)->recvAddField(*buffer) ;
533   }
534   
535   
536   void CFile::recvAddField(CBufferIn& buffer)
537   {
538      string id ;
539      buffer>>id ;
540      addField(id) ;
541   }
542
543   void CFile::recvAddFieldGroup(CEventServer& event)
544   {
545     
546      CBufferIn* buffer=event.subEvents.begin()->buffer;
547      string id;
548      *buffer>>id ;
549      get(id)->recvAddFieldGroup(*buffer) ;
550   }
551   
552   
553   void CFile::recvAddFieldGroup(CBufferIn& buffer)
554   {
555      string id ;
556      buffer>>id ;
557      addFieldGroup(id) ;
558   }
559   
560
561
562
563
564
565
566
567
568
569
570   void CFile::sendAddVariable(const string& id)
571   {
572    CContext* context=CContext::getCurrent() ;
573   
574    if (! context->hasServer )
575    {
576       CContextClient* client=context->client ;
577
578       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE) ;   
579       if (client->isServerLeader())
580       {
581         CMessage msg ;
582         msg<<this->getId() ;
583         msg<<id ;
584         event.push(client->getServerLeader(),1,msg) ;
585         client->sendEvent(event) ;
586       }
587       else client->sendEvent(event) ;
588    }
589     
590   }
591   
592   void CFile::sendAddVariableGroup(const string& id)
593   {
594    CContext* context=CContext::getCurrent() ;
595    if (! context->hasServer )
596    {
597       CContextClient* client=context->client ;
598
599       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE_GROUP) ;   
600       if (client->isServerLeader())
601       {
602         CMessage msg ;
603         msg<<this->getId() ;
604         msg<<id ;
605         event.push(client->getServerLeader(),1,msg) ;
606         client->sendEvent(event) ;
607       }
608       else client->sendEvent(event) ;
609    }
610     
611   }
612   
613   void CFile::recvAddVariable(CEventServer& event)
614   {
615     
616      CBufferIn* buffer=event.subEvents.begin()->buffer;
617      string id;
618      *buffer>>id ;
619      get(id)->recvAddVariable(*buffer) ;
620   }
621   
622   
623   void CFile::recvAddVariable(CBufferIn& buffer)
624   {
625      string id ;
626      buffer>>id ;
627      addVariable(id) ;
628   }
629
630   void CFile::recvAddVariableGroup(CEventServer& event)
631   {
632     
633      CBufferIn* buffer=event.subEvents.begin()->buffer;
634      string id;
635      *buffer>>id ;
636      get(id)->recvAddVariableGroup(*buffer) ;
637   }
638   
639   
640   void CFile::recvAddVariableGroup(CBufferIn& buffer)
641   {
642      string id ;
643      buffer>>id ;
644      addVariableGroup(id) ;
645   }
646
647
648
649
650
651   bool CFile::dispatchEvent(CEventServer& event)
652   {
653      if (SuperClass::dispatchEvent(event)) return true ;
654      else
655      {
656        switch(event.type)
657        {
658           case EVENT_ID_ADD_FIELD :
659             recvAddField(event) ;
660             return true ;
661             break ;
662         
663           case EVENT_ID_ADD_FIELD_GROUP :
664             recvAddFieldGroup(event) ;
665             return true ;
666             break ;       
667 
668            case EVENT_ID_ADD_VARIABLE :
669             recvAddVariable(event) ;
670             return true ;
671             break ;
672         
673           case EVENT_ID_ADD_VARIABLE_GROUP :
674             recvAddVariableGroup(event) ;
675             return true ;
676             break ;               
677           default :
678              ERROR("bool CFile::dispatchEvent(CEventServer& event)", <<"Unknown Event") ;
679           return false ;
680        }
681      }
682   }
683   
684   
685   
686   
687   ///---------------------------------------------------------------
688
689} // namespace xios
Note: See TracBrowser for help on using the repository browser.